[
  {
    "path": ".gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n.cxx\nlocal.properties\n/plugin-sentry/~/.m2/\n.build_history/\n/local\n"
  },
  {
    "path": "CLAUDE.md",
    "content": "# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## 项目概述\n\nPrivacySentry 是一个 Android 隐私合规检测工具,通过 ASM 字节码插桩技术在编译期和运行期拦截敏感 API 调用,帮助开发者规避应用市场上架时的隐私合规检测问题。\n\n## 核心架构\n\n### 三层架构设计\n\n1. **plugin-sentry (Gradle 插件层)**\n   - 基于 AGP 8.0+ 和 Booster 框架的 Gradle 插件\n   - 负责在编译期进行字节码转换 (Transform)\n   - 两阶段 Transform:\n     - 第一阶段: 收集需要拦截的敏感函数 (MethodProxyCollectTransform, ClassProxyCollectTransform)\n     - 第二阶段: 替换敏感函数调用 (MethodHookTransform, FieldProxyTransform, ClassProxyTransform)\n   - 关键类: `PrivacySentryPlugin.kt`, `PrivacyTransformTask.kt`\n\n2. **privacy-annotation (注解层)**\n   - 定义编译期注解用于声明需要拦截的方法和字段\n   - 核心注解:\n     - `@PrivacyMethodProxy`: 标记需要代理的方法\n     - `@PrivacyFieldProxy`: 标记需要代理的字段\n     - `@PrivacyClassProxy`: 标记包含代理方法的类\n     - `@PrivacyClassBlack`: 标记不需要拦截的黑名单类\n\n3. **hook-sentry (运行时 Hook 层)**\n   - 提供运行时的 SDK 初始化和日志收集功能\n   - 支持三种缓存策略: 内存缓存 (MemoryCache)、时效性磁盘缓存 (TimeLessDiskCache)、永久磁盘缓存 (DiskCache)\n   - 日志输出到文件 (.xls 格式)\n   - 关键类: `PrivacySentry.kt`, `PrivacySentryBuilder.kt`\n\n4. **privacy-proxy (预置代理实现)**\n   - 提供常用敏感 API 的拦截实现\n   - 通过注解声明拦截规则,由插件在编译期自动收集\n   - 关键类: `PrivacyProxyCall.kt`, `PrivacyTelephonyProxy.kt`, `PrivacySensorProxy.kt`\n\n### 工作原理\n\n1. **编译期**: 插件扫描所有 `@PrivacyMethodProxy` 注解,收集需要拦截的方法列表\n2. **字节码转换**: 将目标方法调用替换为代理方法调用\n3. **运行期**: 代理方法执行实际逻辑,并记录调用堆栈和时机到日志文件\n\n## 常用命令\n\n### 构建项目\n```bash\n./gradlew clean build\n```\n\n### 编译调试 (本地依赖模式)\n修改 `config.gradle`:\n```gradle\nbuild = [\n    local_debug: true,\n    local_debug_dir : \"${rootProject.projectDir}/local\"\n]\n```\n\n### 发布到本地 Maven\n```bash\n./gradlew publishToMavenLocal\n```\n\n### 运行测试应用\n```bash\n./gradlew :app:installDebug\n```\n\n## 项目模块说明\n\n- **app**: 示例应用,演示如何集成和使用 PrivacySentry\n- **plugin-sentry**: Gradle 插件,负责字节码转换\n- **hook-sentry**: 运行时 SDK 核心库\n- **privacy-annotation**: 注解定义模块\n- **privacy-proxy**: 预置的敏感 API 拦截实现\n- **privacy-replace**: 类替换功能 (已废弃,不再维护)\n- **privacy-test**: 测试模块\n\n## 版本兼容性\n\n- **当前版本 (1.3.7_v820_beta4)**: 支持 AGP 8.0+\n- **旧版本 (1.3.6)**: 支持 AGP 8.0 以下版本\n- **最低 Android SDK**: minSdkVersion 19\n- **编译 SDK**: compileSdkVersion 34\n- **Kotlin**: 1.8.10\n\n## 关键配置\n\n### privacy 插件配置 (在 app/build.gradle 中)\n```gradle\nprivacy {\n    // 黑名单包名,不会被字节码修改\n    blackList = []\n\n    // 插件功能总开关\n    enablePrivacy = true\n\n    // 是否 hook 反射方法\n    hookReflex = false\n\n    // 反射拦截配置 (如小米 OAID)\n    reflexMap = [\"com.android.id.impl.IdProviderImpl\":[\"getOAID\",\"getAAID\",\"getVAID\"]]\n\n    // 已废弃的功能开关\n    hookConstructor = false\n    hookField = false\n}\n```\n\n### SDK 初始化示例\n```kotlin\nval builder = PrivacySentryBuilder()\n    .configResultFileName(\"privacy_result\")\n    .syncDebug(true)  // 开启 logcat 输出\n    .enableFileResult(true)  // 开启文件输出\n    .configWatchTime(30 * 60 * 1000)  // 持续监控 30 分钟\n\nPrivacySentry.Privacy.init(application, builder)\n\n// 用户同意隐私协议后必须调用\nPrivacySentry.Privacy.updatePrivacyShow()\n```\n\n## 添加自定义拦截\n\n1. 创建包含 `@PrivacyClassProxy` 注解的类\n2. 在静态方法上添加 `@PrivacyMethodProxy` 注解:\n```kotlin\n@PrivacyClassProxy\nobject CustomProxy {\n    @PrivacyMethodProxy(\n        originalClass = TargetClass::class,\n        originalMethod = \"methodName\",\n        originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n    )\n    @JvmStatic\n    fun proxyMethod(instance: TargetClass, param: String): ReturnType {\n        doFilePrinter(\"methodName\", \"方法说明\")\n        // 自定义逻辑\n        return instance.methodName(param)\n    }\n}\n```\n\n## 注意事项\n\n1. **黑名单配置**: 如引入高德地图或 OpenInstall,需添加到黑名单避免 ASM 版本冲突:\n   ```gradle\n   blackList = [\"com.loc\", \"com.amap.api\", \"io.openinstall.sdk\"]\n   ```\n\n2. **线上环境**: 务必关闭 `enableFileResult`,避免隐私数据泄露\n\n3. **初始化时机**: 尽可能在 `Application.attachBaseContext()` 中第一个调用\n\n4. **动态加载**: 热修复、插件化加载的代码无法被拦截\n\n5. **支持的敏感 API**: 包括 IMEI、MAC、Android ID、位置信息、剪贴板、传感器、应用列表等,详见 README.md\n\n## 调试技巧\n\n- 查看生成的 hook 配置: `privacy_hook.json`\n- 日志 TAG: `PrivacyOfficer`\n- 输出文件路径: `/storage/emulated/0/Android/data/{packageName}/files/privacy/`\n- 拉取文件: `adb pull /storage/emulated/0/Android/data/{packageName}/files/privacy/`\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2022 alleny\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# PrivacySentry\n\n[![](https://jitpack.io/v/allenymt/PrivacySentry.svg)](https://jitpack.io/#allenymt/PrivacySentry)\n[![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![API](https://img.shields.io/badge/API-19%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=19)\n\n> Android 隐私合规检测工具，可规避应用市场上架合规检测的大部分问题\n\n## ✨ 核心特性\n\n- ✅ **编译期字节码插桩**：基于 ASM + Booster 框架，零运行时性能损耗\n- 🎯 **完整的拦截方案**：支持 60+ 敏感 API 拦截，覆盖工信部合规要求\n- 📊 **自动化检测报告**：生成 Excel 格式的详细调用记录和统计分析\n- 🔄 **智能缓存机制**：内存/磁盘多级缓存，优化性能\n- 🌐 **多进程支持**：自动处理多进程场景，独立输出日志\n- 🔧 **灵活可扩展**：支持自定义拦截规则，黑名单配置\n\n## 📚 文档导航\n\n- **[快速开始](#快速开始)** - 5 分钟集成使用\n- **[插件配置详解](#插件配置详解)** - 完整配置说明\n- **[SDK 初始化](#sdk-初始化)** - 运行时配置\n- **[自定义拦截](#自定义拦截)** - 扩展拦截规则\n- **[架构文档](./docs/architecture.md)** - 完整技术架构解析\n- **[开发指南](./CLAUDE.md)** - Claude Code 开发指南\n\n## 📱 社区支持\n\n加作者个人微信，备注来意 PrivacySentry，进社区群\n\n<img width=\"290\" alt=\"image\" src=\"https://github.com/allenymt/PrivacySentry/assets/8003195/76f2124e-f58d-4420-ac2d-8d33b1093907\">\n\n## 🚀 快速开始\n\n### 版本要求\n\n| 组件 | 版本要求 |\n|------|---------|\n| **AGP** | 8.0+ (推荐 8.2.0) |\n| **Gradle** | 8.0+ |\n| **Kotlin** | 1.8.10+ |\n| **minSdk** | 19+ |\n| **compileSdk** | 34+ |\n\n> **注意**：AGP 8.0 以下版本请使用 `1.3.6` 版本\n\n### Step 1: 添加插件依赖\n\n在项目根目录的 `build.gradle` 中添加：\n\n```gradle\nbuildscript {\n    repositories {\n        maven { url 'https://jitpack.io' }\n        mavenCentral()\n        google()\n    }\n\n    dependencies {\n        classpath 'com.github.allenymt.PrivacySentry:plugin-sentry:1.3.7_v820_beta4'\n    }\n}\n\nallprojects {\n    repositories {\n        maven { url 'https://jitpack.io' }\n        mavenCentral()\n        google()\n    }\n}\n```\n\n### Step 2: 应用插件和依赖\n\n在 app 模块的 `build.gradle` 中：\n\n```gradle\n// 应用插件\napply plugin: 'privacy-sentry-plugin'\n\ndependencies {\n    def privacyVersion = \"1.3.7_v820_beta4\"\n\n    // 核心库（必须）\n    implementation \"com.github.allenymt.PrivacySentry:hook-sentry:$privacyVersion\"\n    implementation \"com.github.allenymt.PrivacySentry:privacy-annotation:$privacyVersion\"\n\n    // 预置拦截实现（强烈推荐）\n    implementation \"com.github.allenymt.PrivacySentry:privacy-proxy:$privacyVersion\"\n\n    // 类替换功能（已废弃，不推荐使用）\n    // implementation \"com.github.allenymt.PrivacySentry:privacy-replace:$privacyVersion\"\n}\n```\n\n### Step 3: 插件配置\n\n在 app 模块的 `build.gradle` 中添加 `privacy` 配置块：\n\n```gradle\nprivacy {\n    // ========== 核心配置 ==========\n\n    /**\n     * 插件功能总开关\n     * 类型：Boolean\n     * 默认值：true\n     * 说明：控制 PrivacySentry 插件是否生效\n     *      - true: 启用插件，执行字节码转换\n     *      - false: 禁用插件，相当于未集成\n     */\n    enablePrivacy = true\n\n    /**\n     * 黑名单配置\n     * 类型：Set<String>\n     * 默认值：null (空列表)\n     * 说明：指定不进行字节码修改的包名列表\n     *      - 适用场景：\n     *        1. 使用了其他 ASM 字节码修改工具的三方库（如高德地图）\n     *        2. 已知会导致冲突的 SDK\n     *        3. 不需要监控的系统库或三方库\n     *      - 注意：blackList 中的包不会被插件修改，也无法拦截其中的敏感 API\n     */\n    blackList = []\n\n    // 常见黑名单配置示例：\n    // blackList = [\n    //     \"com.loc\",              // 高德地图（ASM 版本冲突）\n    //     \"com.amap.api\",         // 高德地图 API\n    //     \"io.openinstall.sdk\",   // OpenInstall SDK\n    //     \"com.google.android\",   // Google 服务（可选）\n    //     \"androidx\"              // AndroidX 库（可选）\n    // ]\n\n    /**\n     * 静态扫描结果文件名\n     * 类型：String\n     * 默认值：\"privacy_hook.json\"\n     * 说明：记录所有被代理的方法名和类名的文件名\n     *      - 文件位置：项目根目录\n     *      - 文件格式：JSON\n     *      - 内容包含：\n     *        1. hookServiceList: 被 hook 的 Service 列表\n     *        2. replaceMethodMap: 被替换的方法映射表\n     *      - 设置为 null 或空字符串则不生成文件\n     */\n    replaceFileName = \"privacy_hook.json\"\n\n    // ========== 反射 Hook 配置（可选）==========\n\n    /**\n     * 反射方法 Hook 开关\n     * 类型：Boolean\n     * 默认值：false\n     * 说明：是否拦截通过反射调用的敏感方法\n     *      - true: 拦截反射调用（需配合 reflexMap 使用）\n     *      - false: 不拦截反射调用\n     *      - 适用场景：\n     *        1. 三方 SDK 通过反射获取设备信息（如小米 OAID）\n     *        2. 极光推送、个推、穿山甲等 SDK 的设备标识获取\n     *      - 性能影响：轻微（仅影响 LDC 指令的匹配）\n     */\n    hookReflex = false\n\n    /**\n     * 反射拦截配置映射\n     * 类型：Map<String, List<String>>\n     * 默认值：null\n     * 说明：配置需要拦截的反射调用\n     *      - Key: 类的全限定名\n     *      - Value: 该类中需要拦截的方法名列表\n     *      - 只有 hookReflex = true 时才生效\n     *      - 匹配原理：检测字节码中的 LDC 指令加载的字符串常量\n     */\n    reflexMap = [:]\n\n    // 反射拦截配置示例：\n    // reflexMap = [\n    //     // 小米设备标识服务\n    //     \"com.android.id.impl.IdProviderImpl\": [\n    //         \"getOAID\",   // 开放匿名设备标识符\n    //         \"getAAID\",   // 应用匿名设备标识符\n    //         \"getVAID\"    // 开发者匿名设备标识符\n    //     ],\n    //     // 自定义类的反射方法\n    //     \"com.example.utils.DeviceUtils\": [\n    //         \"getDeviceId\",\n    //         \"getIMEI\"\n    //     ]\n    // ]\n\n    // ========== 已废弃功能（不推荐使用，仅供参考）==========\n\n    /**\n     * 字段 Hook 开关（已废弃）\n     * 类型：Boolean\n     * 默认值：false\n     * 废弃原因：几乎没有业务场景，功能不稳定\n     * 说明：是否 hook 字段访问（如 Build.SERIAL）\n     *      - 不推荐使用，请使用方法 hook 代替\n     */\n    // hookField = false\n\n    /**\n     * 构造函数 Hook 开关（已废弃）\n     * 类型：Boolean\n     * 默认值：false\n     * 废弃原因：实现复杂，稳定性差，已停止维护\n     * 说明：是否 hook 构造函数（主要用于拦截 File 构造函数参数）\n     *      - 相关模块：privacy-replace\n     *      - 不推荐使用\n     */\n    // hookConstructor = false\n\n    /**\n     * Manifest 处理开关（已废弃）\n     * 类型：Boolean\n     * 默认值：false\n     * 废弃原因：功能边界不清晰，已停止维护\n     * 说明：是否处理 AndroidManifest.xml 文件\n     *      - 主要用于处理 Service 的 Priority 和 Export\n     *      - 不推荐使用\n     */\n    // enableProcessManifest = false\n\n    /**\n     * Service Priority 替换开关（已废弃）\n     * 类型：Boolean\n     * 默认值：false\n     * 废弃原因：针对 MIUI 自启动问题的特殊方案，已停止维护\n     * 说明：是否替换 Service 的 Priority 值\n     *      - 部分 Service 设置 Priority = 1000 导致自启动\n     *      - 开启后会将 Priority 替换为 replacePriority 的值\n     *      - 不推荐使用\n     */\n    // enableReplacePriority = false\n\n    /**\n     * Service Priority 替换值（已废弃）\n     * 类型：Int\n     * 默认值：0\n     * 说明：替换后的 Priority 值\n     *      - 配合 enableReplacePriority 使用\n     *      - 不推荐使用\n     */\n    // replacePriority = 0\n\n    /**\n     * Service Export 关闭开关（已废弃）\n     * 类型：Boolean\n     * 默认值：false\n     * 废弃原因：可能影响厂商推送功能，已停止维护\n     * 说明：是否关闭 Service 的 Export 功能\n     *      - 注意：部分厂商推送（小米、VIVO、华为）的 PushService 不能关闭\n     *      - 配合 serviceExportPkgWhiteList 使用\n     *      - 不推荐使用\n     */\n    // enableCloseServiceExport = false\n\n    /**\n     * Service Export 白名单（已废弃）\n     * 类型：Set<String>\n     * 默认值：null\n     * 说明：允许保持 Export 的 Service 包名列表\n     *      - 配合 enableCloseServiceExport 使用\n     *      - 不推荐使用\n     */\n    // serviceExportPkgWhiteList = []\n\n    /**\n     * Service StartCommand Hook 开关（已废弃）\n     * 类型：Boolean\n     * 默认值：false\n     * 废弃原因：针对 MIUI 自启动问题的特殊方案，已停止维护\n     * 说明：是否 hook Service 的 startCommand 方法\n     *      - 不推荐使用\n     */\n    // enableHookServiceStartCommand = false\n}\n```\n\n**配置优先级说明**：\n1. **必须配置**：`enablePrivacy`（总开关）\n2. **强烈推荐**：`blackList`（避免冲突）\n3. **按需配置**：`hookReflex` + `reflexMap`（反射拦截）\n4. **可选配置**：`replaceFileName`（静态扫描文件）\n5. **不推荐使用**：所有标记为 `@Deprecated` 的配置项\n\n### Step 4: SDK 初始化\n\n在 `Application` 中初始化 SDK：\n\n**Kotlin 示例**:\n\n```kotlin\nclass MyApplication : Application() {\n\n    override fun attachBaseContext(base: Context?) {\n        super.attachBaseContext(base)\n\n        // ⚠️ 重要：尽可能在 attachBaseContext 中第一个调用\n        // 这样可以确保捕获所有敏感 API 调用\n        initPrivacySentry()\n    }\n\n    override fun onCreate() {\n        super.onCreate()\n\n        // 展示隐私协议弹窗\n        showPrivacyDialog {\n            // 用户同意后，必须调用此方法\n            PrivacySentry.Privacy.updatePrivacyShow()\n        }\n    }\n\n    private fun initPrivacySentry() {\n        val builder = PrivacySentryBuilder()\n            // 自定义输出文件名\n            .configResultFileName(\"privacy_result\")\n\n            // 开启 debug 模式（可在 logcat 查看日志）\n            .syncDebug(BuildConfig.DEBUG)\n\n            // 开启文件输出（⚠️ 线上版本请关闭）\n            .enableFileResult(BuildConfig.DEBUG)\n\n            // 监控时长（30 分钟）\n            .configWatchTime(30 * 60 * 1000)\n\n            // 文件输出完成回调\n            .configResultCallBack(object : PrivacyResultCallBack {\n                override fun onResultCallBack(filePath: String) {\n                    Log.i(\"PrivacySentry\", \"结果文件：$filePath\")\n                }\n            })\n\n        PrivacySentry.Privacy.init(this, builder)\n    }\n}\n```\n\n**Java 示例**:\n\n```java\npublic class MyApplication extends Application {\n\n    @Override\n    protected void attachBaseContext(Context base) {\n        super.attachBaseContext(base);\n\n        // ⚠️ 重要：尽可能在 attachBaseContext 中第一个调用\n        initPrivacySentry();\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n\n        // 展示隐私协议弹窗\n        showPrivacyDialog(() -> {\n            // 用户同意后，必须调用此方法\n            PrivacySentry.Privacy.INSTANCE.updatePrivacyShow();\n        });\n    }\n\n    private void initPrivacySentry() {\n        PrivacySentryBuilder builder = new PrivacySentryBuilder()\n                .configResultFileName(\"privacy_result\")\n                .syncDebug(BuildConfig.DEBUG)\n                .enableFileResult(BuildConfig.DEBUG)\n                .configWatchTime(30 * 60 * 1000)\n                .configResultCallBack(new PrivacyResultCallBack() {\n                    @Override\n                    public void onResultCallBack(@NonNull String filePath) {\n                        Log.i(\"PrivacySentry\", \"结果文件：\" + filePath);\n                    }\n                });\n\n        PrivacySentry.Privacy.INSTANCE.init(this, builder);\n    }\n}\n```\n\n### Step 5: 查看检测结果\n\n#### 方式 1：Logcat 日志\n\n```bash\n# 实时查看日志\nadb logcat | grep \"PrivacyOfficer\"\n```\n\n#### 方式 2：Excel 文件\n\n```bash\n# 拉取结果文件\nadb pull /storage/emulated/0/Android/data/{your.package.name}/files/privacy/\n\n# 文件名格式\n# 主进程：privacy_result.xls\n# 子进程：{进程名}_privacy_result.xls\n```\n\n**Excel 文件包含两个 Sheet**:\n\n1. **Sheet 1 - 隐私合规明细**：按时间倒序记录所有敏感 API 调用\n   - 调用时间\n   - 方法别名\n   - 函数名\n   - 完整调用堆栈\n\n2. **Sheet 2 - 调用次数统计**：按堆栈聚合统计调用次数\n   - 方法别名\n   - 函数名\n   - 调用堆栈\n   - 调用次数\n\n## ⚙️ 插件配置详解\n\n### 核心配置项完整说明\n\n| 配置项 | 类型 | 默认值 | 说明 |\n|--------|------|--------|------|\n| `enablePrivacy` | Boolean | `true` | **插件功能总开关**<br>- `true`: 启用插件，执行字节码转换<br>- `false`: 禁用插件 |\n| `blackList` | Set\\<String\\> | `null` | **黑名单配置**<br>指定不进行字节码修改的包名列表<br>- 适用场景：ASM 冲突的三方库<br>- 注意：黑名单中的包无法拦截敏感 API |\n| `replaceFileName` | String | `\"privacy_hook.json\"` | **静态扫描结果文件名**<br>记录所有被代理的方法和类<br>- 文件位置：项目根目录<br>- 文件格式：JSON<br>- 设置为 `null` 则不生成 |\n| `hookReflex` | Boolean | `false` | **反射方法 Hook 开关**<br>是否拦截通过反射调用的敏感方法<br>- 需配合 `reflexMap` 使用<br>- 适用：三方 SDK 反射获取设备信息 |\n| `reflexMap` | Map\\<String, List\\<String\\>\\> | `null` | **反射拦截配置**<br>- Key: 类的全限定名<br>- Value: 需要拦截的方法名列表<br>- 只有 `hookReflex=true` 时生效 |\n\n### 已废弃配置项\n\n| 配置项 | 类型 | 默认值 | 废弃原因 |\n|--------|------|--------|---------|\n| `hookField` | Boolean | `false` | 几乎没有业务场景，功能不稳定 |\n| `hookConstructor` | Boolean | `false` | 实现复杂，稳定性差，已停止维护 |\n| `enableProcessManifest` | Boolean | `false` | 功能边界不清晰，已停止维护 |\n| `enableReplacePriority` | Boolean | `false` | 针对 MIUI 特殊问题，已停止维护 |\n| `replacePriority` | Int | `0` | 配合 `enableReplacePriority` 使用 |\n| `enableCloseServiceExport` | Boolean | `false` | 可能影响厂商推送，已停止维护 |\n| `serviceExportPkgWhiteList` | Set\\<String\\> | `null` | 配合 `enableCloseServiceExport` 使用 |\n| `enableHookServiceStartCommand` | Boolean | `false` | 针对 MIUI 特殊问题，已停止维护 |\n\n> ⚠️ **重要提示**：所有标记为\"已废弃\"的配置项均不推荐使用，可能在未来版本中移除。\n\n### 黑名单配置说明\n\n#### 什么情况需要配置黑名单？\n\n1. **ASM 版本冲突**\n   - 使用高德地图 SDK（ASM 9.1 vs 其他版本）\n   - 使用其他字节码修改工具的三方库\n\n2. **已知冲突的 SDK**\n   - OpenInstall SDK\n   - 部分混淆工具\n\n3. **不需要监控的库**\n   - 系统库（可选）\n   - 不涉及隐私的三方库\n\n#### 黑名单工作原理\n\n- 插件在 Transform 阶段会跳过黑名单中的包\n- 黑名单采用**前缀匹配**规则\n- 例如：`\"com.loc\"` 会匹配 `com.loc.*` 下的所有类\n\n#### 配置示例\n\n```gradle\nprivacy {\n    blackList = [\n        // 高德地图（ASM 版本冲突）\n        \"com.loc\",\n        \"com.amap.api\",\n\n        // OpenInstall SDK\n        \"io.openinstall.sdk\",\n\n        // Google 服务（可选）\n        \"com.google.android\",\n\n        // AndroidX 库（可选）\n        \"androidx\",\n\n        // 自定义不需要监控的包\n        \"com.example.thirdparty\"\n    ]\n}\n```\n\n#### 黑名单注意事项\n\n- ✅ **推荐**：只添加确实冲突的包\n- ❌ **不推荐**：盲目添加大量包到黑名单\n- ⚠️ **影响**：黑名单中的包无法拦截敏感 API 调用\n\n### 反射 Hook 配置详解\n\n#### 使用场景\n\n反射 Hook 用于拦截通过**反射方式**调用的敏感方法，常见场景：\n\n1. **设备标识获取**\n   - 小米设备 OAID/AAID/VAID\n   - 华为设备标识\n   - OPPO/VIVO 设备标识\n\n2. **三方 SDK**\n   - 极光推送（JPush）\n   - 个推（GeTui）\n   - 穿山甲广告 SDK\n   - 友盟统计\n\n3. **自定义反射调用**\n   - 项目中通过反射获取的敏感信息\n\n#### 工作原理\n\n```kotlin\n// 原始代码（反射调用）\nClass.forName(\"com.android.id.impl.IdProviderImpl\")\n    .getMethod(\"getOAID\")\n    .invoke(obj)\n\n// 字节码层面\nLDC \"com.android.id.impl.IdProviderImpl\"  // ← hookReflex 检测这里\nLDC \"getOAID\"                              // ← reflexMap 匹配方法名\nINVOKEVIRTUAL Method.invoke()              // ← 替换为代理方法\n```\n\n#### 配置示例\n\n**场景 1：小米设备标识**\n\n```gradle\nprivacy {\n    hookReflex = true\n\n    reflexMap = [\n        \"com.android.id.impl.IdProviderImpl\": [\n            \"getOAID\",   // 开放匿名设备标识符\n            \"getAAID\",   // 应用匿名设备标识符\n            \"getVAID\"    // 开发者匿名设备标识符\n        ]\n    ]\n}\n```\n\n**场景 2：多个 SDK 配置**\n\n```gradle\nprivacy {\n    hookReflex = true\n\n    reflexMap = [\n        // 小米设备标识\n        \"com.android.id.impl.IdProviderImpl\": [\n            \"getOAID\", \"getAAID\", \"getVAID\"\n        ],\n\n        // 华为设备标识\n        \"com.huawei.hms.ads.identifier.AdvertisingIdClient\": [\n            \"getAdvertisingIdInfo\"\n        ],\n\n        // 自定义工具类\n        \"com.example.utils.DeviceUtils\": [\n            \"getDeviceId\",\n            \"getIMEI\",\n            \"getAndroidId\"\n        ]\n    ]\n}\n```\n\n**场景 3：极光推送/个推配置**\n\n```gradle\nprivacy {\n    hookReflex = true\n\n    reflexMap = [\n        // 极光推送反射获取设备信息\n        \"cn.jpush.android.api.JCoreInterface\": [\n            \"getDeviceId\",\n            \"getRegistrationID\"\n        ],\n\n        // 个推反射获取设备信息\n        \"com.igexin.sdk.PushManager\": [\n            \"getClientid\"\n        ]\n    ]\n}\n```\n\n#### 反射 Hook 注意事项\n\n- ✅ **精确匹配**：类名和方法名必须完全匹配\n- ✅ **性能影响**：轻微（仅影响 LDC 指令匹配）\n- ⚠️ **必须启用**：`hookReflex = true` 才生效\n- ⚠️ **无法拦截**：动态生成的类名或方法名\n\n### 静态扫描文件说明\n\n#### replaceFileName 配置\n\n```gradle\nprivacy {\n    // 生成静态扫描文件\n    replaceFileName = \"privacy_hook.json\"\n\n    // 不生成文件\n    // replaceFileName = null\n}\n```\n\n#### 文件内容示例\n\n**文件位置**：项目根目录 `/privacy_hook.json`\n\n```json\n{\n    \"hookServiceList\": [\n        \"com.example.TestService\",\n        \"com.example.BackgroundService\"\n    ],\n\n    \"replaceMethodMap\": {\n        \"android.app.ActivityManager.getRunningTasks\": {\n            \"count\": 5,\n            \"originMethodList\": [\n                {\n                    \"originClassName\": \"com.example.MainActivity\",\n                    \"originMethodName\": \"checkRunningTasks\"\n                },\n                {\n                    \"originClassName\": \"com.example.utils.AppUtils\",\n                    \"originMethodName\": \"getRunningApps\"\n                }\n            ]\n        },\n        \"android.telephony.TelephonyManager.getDeviceId\": {\n            \"count\": 2,\n            \"originMethodList\": [\n                {\n                    \"originClassName\": \"com.example.DeviceManager\",\n                    \"originMethodName\": \"getIMEI\"\n                }\n            ]\n        }\n    }\n}\n```\n\n#### 文件用途\n\n1. **静态分析**：离线分析敏感 API 调用情况\n2. **合规检查**：提供给安全团队审查\n3. **调试参考**：确认插件是否正确拦截了目标方法\n4. **版本对比**：对比不同版本的 API 调用变化\n\n### 配置优先级建议\n\n| 优先级 | 配置项 | 建议值 | 说明 |\n|--------|--------|--------|------|\n| ⭐⭐⭐ 必须 | `enablePrivacy` | `true` | 插件总开关 |\n| ⭐⭐⭐ 强烈推荐 | `blackList` | 根据实际情况 | 避免 ASM 冲突 |\n| ⭐⭐ 推荐 | `replaceFileName` | `\"privacy_hook.json\"` | 生成静态扫描文件 |\n| ⭐ 按需配置 | `hookReflex` | `false` 或 `true` | 根据是否有反射调用 |\n| ⭐ 按需配置 | `reflexMap` | `[:]` 或配置 | 配合 hookReflex 使用 |\n| ❌ 不推荐 | 所有废弃配置 | - | 已停止维护 |\n\n## 🔧 SDK 初始化\n\n### PrivacySentryBuilder 配置项\n\n| 方法 | 参数类型 | 默认值 | 说明 |\n|------|---------|--------|------|\n| `configResultFileName(String)` | String | 自动生成 | 自定义输出文件名 |\n| `syncDebug(Boolean)` | Boolean | `false` | 开启 debug 日志 |\n| `enableFileResult(Boolean)` | Boolean | `true` | 是否输出到文件 |\n| `configWatchTime(Long)` | Long (毫秒) | 180000 (3分钟) | 监控时长 |\n| `configResultCallBack(PrivacyResultCallBack)` | PrivacyResultCallBack | `null` | 文件输出完成回调 |\n| `enableReadClipBoard(Boolean)` | Boolean | `true` | 是否允许读取剪贴板 |\n\n### 最佳实践\n\n#### 1. 初始化时机\n\n```kotlin\nclass MyApplication : Application() {\n    override fun attachBaseContext(base: Context?) {\n        super.attachBaseContext(base)\n\n        // ✅ 推荐：第一个调用\n        PrivacySentry.Privacy.init(this, builder)\n\n        // ❌ 不推荐：在其他初始化之后\n        // MultiDex.install(this)\n        // PrivacySentry.Privacy.init(this, builder)\n    }\n}\n```\n\n**原因**：attachBaseContext 之后才能通过反射获取 ActivityThread 的 application，如果初始化太晚，可能无法捕获早期的敏感 API 调用。\n\n#### 2. Debug vs Release 配置\n\n```kotlin\nprivate fun initPrivacySentry() {\n    val builder = PrivacySentryBuilder()\n        .syncDebug(BuildConfig.DEBUG)           // Debug 开启日志\n        .enableFileResult(BuildConfig.DEBUG)    // Release 关闭文件输出\n        .configWatchTime(\n            if (BuildConfig.DEBUG) 30 * 60 * 1000  // Debug: 30分钟\n            else 3 * 60 * 1000                      // Release: 3分钟（谨慎）\n        )\n\n    PrivacySentry.Privacy.init(this, builder)\n}\n```\n\n#### 3. 隐私协议状态管理\n\n```kotlin\noverride fun onCreate() {\n    super.onCreate()\n\n    // 检查是否已同意隐私协议\n    if (!hasAgreedPrivacyPolicy()) {\n        showPrivacyDialog {\n            // 用户同意后保存状态\n            savePrivacyAgreement()\n\n            // ⚠️ 必须调用，告知 SDK 用户已同意\n            PrivacySentry.Privacy.updatePrivacyShow()\n        }\n    } else {\n        // 已同意，直接告知 SDK\n        PrivacySentry.Privacy.updatePrivacyShow()\n    }\n}\n```\n\n**重要提示**：\n- ✅ 用户同意隐私协议后，**必须**调用 `updatePrivacyShow()`\n- ✅ 调用前的敏感 API 会返回空数据并标记 `check!!!`\n- ✅ 调用后的敏感 API 返回真实数据并记录日志\n\n#### 4. 手动停止监控\n\n```kotlin\n// 手动停止监控和文件写入\nPrivacySentry.Privacy.stop()\n```\n\n## 🎯 自定义拦截\n\n### 创建自定义代理类\n\n```kotlin\nimport androidx.annotation.Keep\nimport com.yl.lib.privacy_annotation.MethodInvokeOpcode\nimport com.yl.lib.privacy_annotation.PrivacyClassProxy\nimport com.yl.lib.privacy_annotation.PrivacyMethodProxy\nimport com.yl.lib.sentry.hook.PrivacySentry\nimport com.yl.lib.sentry.hook.util.PrivacyProxyUtil.Util.doFilePrinter\n\n@Keep\n@PrivacyClassProxy\nobject MyCustomProxy {\n\n    /**\n     * 示例 1：拦截实例方法\n     */\n    @PrivacyMethodProxy(\n        originalClass = YourClass::class,\n        originalMethod = \"getSensitiveData\",\n        originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n    )\n    @JvmStatic\n    fun getSensitiveData(\n        instance: YourClass,  // 第一个参数是实例对象\n        param1: String\n    ): String {\n        // 记录日志\n        doFilePrinter(\"getSensitiveData\", \"获取敏感数据: $param1\")\n\n        // 检查隐私协议状态\n        if (PrivacySentry.Privacy.inDangerousState()) {\n            return \"\"  // 未同意返回空\n        }\n\n        // 调用原始方法\n        return instance.getSensitiveData(param1)\n    }\n\n    /**\n     * 示例 2：拦截静态方法\n     */\n    @PrivacyMethodProxy(\n        originalClass = YourUtilClass::class,\n        originalMethod = \"getDeviceId\",\n        originalOpcode = MethodInvokeOpcode.INVOKESTATIC\n    )\n    @JvmStatic\n    fun getDeviceId(): String {\n        doFilePrinter(\"getDeviceId\", \"获取设备ID\")\n\n        if (PrivacySentry.Privacy.inDangerousState()) {\n            return \"\"\n        }\n\n        return YourUtilClass.getDeviceId()\n    }\n\n    /**\n     * 示例 3：拦截接口方法\n     */\n    @PrivacyMethodProxy(\n        originalClass = YourInterface::class,\n        originalMethod = \"getData\",\n        originalOpcode = MethodInvokeOpcode.INVOKEINTERFACE\n    )\n    @JvmStatic\n    fun getData(instance: YourInterface): String {\n        doFilePrinter(\"getData\", \"接口方法调用\")\n        return instance.getData()\n    }\n}\n```\n\n### Java 自定义代理示例\n\n```java\nimport androidx.annotation.Keep;\nimport com.yl.lib.privacy_annotation.MethodInvokeOpcode;\nimport com.yl.lib.privacy_annotation.PrivacyClassProxy;\nimport com.yl.lib.privacy_annotation.PrivacyMethodProxy;\nimport com.yl.lib.sentry.hook.PrivacySentry;\nimport static com.yl.lib.sentry.hook.util.PrivacyProxyUtil.Util.doFilePrinter;\n\n@Keep\n@PrivacyClassProxy\npublic class MyCustomProxyJava {\n\n    @PrivacyMethodProxy(\n        originalClass = YourClass.class,\n        originalMethod = \"getSensitiveData\",\n        originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n    )\n    public static String getSensitiveData(YourClass instance, String param) {\n        doFilePrinter(\"getSensitiveData\", \"获取敏感数据: \" + param, false);\n\n        if (PrivacySentry.Privacy.INSTANCE.inDangerousState()) {\n            return \"\";\n        }\n\n        return instance.getSensitiveData(param);\n    }\n}\n```\n\n### 方法签名规则\n\n#### 实例方法 (INVOKEVIRTUAL)\n\n```kotlin\n// 原始方法\nclass TargetClass {\n    fun method(param1: String, param2: Int): String\n}\n\n// 代理方法：第一个参数是实例对象\n@JvmStatic\nfun method(\n    instance: TargetClass,  // ⬅️ 额外的第一个参数\n    param1: String,\n    param2: Int\n): String\n```\n\n#### 静态方法 (INVOKESTATIC)\n\n```kotlin\n// 原始方法\nobject TargetClass {\n    fun method(param1: String): String\n}\n\n// 代理方法：参数完全相同\n@JvmStatic\nfun method(param1: String): String\n```\n\n#### 接口方法 (INVOKEINTERFACE)\n\n```kotlin\n// 原始接口\ninterface TargetInterface {\n    fun method(param: String): String\n}\n\n// 代理方法：第一个参数是接口实例\n@JvmStatic\nfun method(\n    instance: TargetInterface,  // ⬅️ 接口实例\n    param: String\n): String\n```\n\n## 📋 支持的敏感 API\n\n### 设备标识\n\n- ✅ IMEI / DeviceId (`TelephonyManager.getDeviceId()`)\n- ✅ IMSI (`TelephonyManager.getSubscriberId()`)\n- ✅ MEID (`TelephonyManager.getMeid()`)\n- ✅ Android ID (`Settings.Secure.getAndroidId()`)\n- ✅ Serial (`Build.getSerial()`, `Build.SERIAL`)\n- ✅ MAC 地址 (`WifiInfo.getMacAddress()`)\n- ✅ ICCID (`TelephonyManager.getSimSerialNumber()`)\n\n### 网络信息\n\n- ✅ WiFi 信息 (`WifiManager.getConnectionInfo()`)\n- ✅ WiFi 扫描结果 (`WifiManager.getScanResults()`)\n- ✅ IP 地址 (`NetworkInterface`, `WifiInfo.getIpAddress()`)\n- ✅ DHCP 信息 (`WifiManager.getDhcpInfo()`)\n\n### 位置信息\n\n- ✅ GPS 定位 (`LocationManager.getLastKnownLocation()`)\n- ✅ 基站信息 (`TelephonyManager.getAllCellInfo()`)\n- ✅ 位置监听 (`LocationManager.requestLocationUpdates()`)\n\n### 应用信息\n\n- ✅ 已安装应用列表 (`PackageManager.getInstalledPackages()`)\n- ✅ 运行中任务 (`ActivityManager.getRunningTasks()`)\n- ✅ 运行中进程 (`ActivityManager.getRunningAppProcesses()`)\n- ✅ 最近任务 (`ActivityManager.getRecentTasks()`)\n\n### 联系人和日历\n\n- ✅ 联系人查询 (`ContentResolver.query()`)\n- ✅ 联系人插入 (`ContentResolver.insert()`)\n- ✅ 日历事件 (Calendar Provider)\n\n### 传感器\n\n- ✅ 传感器列表 (`SensorManager.getSensorList()`)\n- ✅ 传感器注册 (`SensorManager.registerListener()`)\n\n### 其他\n\n- ✅ 剪贴板 (`ClipboardManager.getPrimaryClip()`)\n- ✅ 蓝牙 (`BluetoothAdapter.getAddress()`)\n- ✅ 权限请求 (`requestPermissions()`)\n- ✅ SIM 卡信息 (`TelephonyManager.getSimOperator()`)\n\n> 完整列表请参考 [privacy-proxy](./privacy-proxy) 模块\n\n## 🔍 检测结果说明\n\n### 日志格式\n\n```\n[PrivacyOfficer] getDeviceId-线程名: main | 读取IMEI | com.example.MainActivity.onCreate(MainActivity.kt:42)\n                                                           ↑ 调用堆栈\n```\n\n### 危险状态标记\n\n如果在日志中看到 `check!!!` 标记：\n\n```\ncheck!!! 还未展示隐私协议，Illegal print\n```\n\n**说明**：此时还未同意隐私协议，调用了敏感 API\n\n**解决方法**：\n1. 检查是否在隐私协议同意后调用了 `updatePrivacyShow()`\n2. 优化代码，避免在隐私协议同意前调用敏感 API\n\n## 🛠️ 常见问题\n\n### Q1: 为什么某些 API 没有被拦截？\n\n**可能原因**：\n1. 该 API 未在 privacy-proxy 中实现\n2. 包名在黑名单中\n3. 使用动态加载的代码（热修复、插件化）\n\n**解决方法**：\n1. 查看 `privacy_hook.json` 确认是否包含该 API\n2. 检查黑名单配置\n3. 自定义拦截规则\n\n### Q2: 编译失败或运行时崩溃\n\n**可能原因**：\n1. ASM 版本冲突（特别是高德地图）\n2. AGP 版本不兼容\n\n**解决方法**：\n1. 添加冲突库到黑名单\n2. 升级到 AGP 8.0+\n3. 检查 Gradle 和 Kotlin 版本\n\n### Q3: 如何在线上环境使用？\n\n**建议配置**：\n\n```kotlin\nPrivacySentryBuilder()\n    .syncDebug(false)              // 关闭 debug 日志\n    .enableFileResult(false)       // 关闭文件输出\n    .configWatchTime(3 * 60 * 1000) // 缩短监控时间\n```\n\n**注意**：\n- ❌ 线上版本**不要**开启 `enableFileResult`，避免隐私数据泄露\n- ✅ 可以通过 `configResultCallBack` 上报统计数据\n\n### Q4: 多进程如何处理？\n\nSDK 自动支持多进程，会为不同进程生成独立的日志文件：\n\n```\n主进程：privacy_result.xls\n子进程：com.example.service_privacy_result.xls\n```\n\n### Q5: 性能影响如何？\n\n- **编译时间**：增加 < 2 秒\n- **APK 体积**：增加 ~200KB\n- **运行时性能**：零额外开销（字节码已修改）\n- **内存占用**：缓存数据占用，可通过 watchTime 控制\n\n## 📖 更新日志\n\n### 1.3.7_v820_beta4 (2025-05-18)\n- ✅ 支持 AGP 8.0+\n- ❌ 不兼容 AGP 8.0 以下版本（请使用 1.3.6）\n\n### 1.3.6 (2024-11-01)\n- 修复 `T.(args..):T` 函数 hook 失败的问题\n\n### 1.3.5 (2024-05-08)\n- 修复读取小米系统 OAID 反射代理失败的问题\n- 修复 SHA-256 digest error 问题\n\n### 1.3.4 (2023-09-18)\n- 修复内存缓存数据转换问题\n- 修复 `getSimState` 闪退问题\n\n### 1.3.3 (2023-08-22)\n- 重构 plugin 部分，引入 Booster\n- 适配 AGP 和 Gradle 高版本\n- 支持 AGP 7.0+\n\n> 完整更新日志请查看 [CHANGELOG](./CHANGELOG.md)\n\n## 🤝 贡献指南\n\n欢迎提交 Issue 和 Pull Request！\n\n- **Bug 报告**：请详细描述问题和复现步骤\n- **功能建议**：欢迎提出改进建议\n- **Pull Request**：请先创建 Issue 讨论\n\n## 📄 许可证\n\n本项目采用 [MIT License](LICENSE)\n\n## 💰 打赏支持\n\n如果这个项目对你有帮助，欢迎打赏支持！\n\n<img width=\"290\" alt=\"image\" src=\"https://github.com/user-attachments/assets/4d966c38-e1cb-44cd-bff3-09efed7b16a6\">\n\n<img width=\"290\" alt=\"image\" src=\"https://github.com/user-attachments/assets/1b7c628f-dc72-45b6-8ff6-161a1c90d463\">\n\n## 🌟 Star History\n\n如果觉得有用，请给个 Star ⭭！\n\n## 🔗 相关资源\n\n- **架构文档**：[docs/architecture.md](./docs/architecture.md)\n- **开发指南**：[CLAUDE.md](./CLAUDE.md)\n- **示例项目**：[app](./app)\n- **GitHub Issues**：[提交问题](https://github.com/allenymt/PrivacySentry/issues)\n\n---\n\n**注意事项**：\n\n1. ⚠️ 线上版本请关闭 `enableFileResult`\n2. ⚠️ 尽可能在 `attachBaseContext` 中第一个调用初始化\n3. ⚠️ 用户同意隐私协议后必须调用 `updatePrivacyShow()`\n4. ⚠️ 使用高德地图等三方库需配置黑名单\n5. ⚠️ 动态加载的代码无法被拦截\n\n---\n\n> 如有问题，请提 [Issue](https://github.com/allenymt/PrivacySentry/issues)\n>\n> 兄弟们，走过路过请给个 Star ⭭~~~\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\napply plugin: 'privacy-sentry-plugin'\n\nandroid {\n    compileSdkVersion 34\n    buildToolsVersion \"34.0.0\"\n    namespace \"com.yl.lib.privacysentry\"\n    defaultConfig {\n        applicationId \"com.yl.lib.privacysentry\"\n        minSdkVersion 19\n        targetSdkVersion 34\n        versionCode 1\n        versionName \"1.0\"\n        multiDexEnabled true\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n\n    signingConfigs {\n        release {\n            storeFile file(\"../privacy\")\n            storePassword \"123456\"\n            keyAlias \"privacy\"\n            keyPassword \"123456\"\n            v2SigningEnabled true\n        }\n    }\n\n    buildTypes {\n        debug {\n            debuggable true\n            signingConfig signingConfigs.release //使用release签名\n        }\n        release {\n            debuggable true\n            jniDebuggable false\n            shrinkResources false\n            minifyEnabled true\n            signingConfig signingConfigs.release //使用release签\n            zipAlignEnabled true\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    kotlinOptions {\n        jvmTarget = '1.8'\n    }\n    lintOptions {\n        abortOnError false\n    }\n\n}\n\ndependencies {\n    api fileTree(dir: 'libs', include: ['*.jar'])\n\n    implementation 'androidx.core:core-ktx:1.9.0'\n    implementation 'androidx.appcompat:appcompat:1.6.1'\n    implementation 'com.google.android.material:material:1.9.0'\n    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'\n    implementation \"androidx.multidex:multidex:2.0.1\"\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version\"\n    implementation \"org.jetbrains.kotlin:kotlin-reflect:$kotlin_version\"\n\n    if (rootProject.ext.build.local_debug) {\n        implementation project(\":hook-sentry\")\n        implementation project(\":privacy-proxy\")\n        implementation project(\":privacy-replace\")\n        implementation project(\":privacy-annotation\")\n    } else {\n        def privacyVersion = rootProject.ext.publish_config['version']\n        implementation \"com.github.allenymt.PrivacySentry:hook-sentry:$privacyVersion\"\n        implementation \"com.github.allenymt.PrivacySentry:privacy-annotation:$privacyVersion\"\n        //  测试自定义拦截就注释掉\n        implementation \"com.github.allenymt.PrivacySentry:privacy-proxy:$privacyVersion\"\n        // 新增类替换，主要是为了hook构造函数的参数\n        implementation \"com.github.allenymt.PrivacySentry:privacy-replace:$privacyVersion\"\n    }\n    implementation(project(path: ':privacy-test')) {\n        exclude module: 'privacy-annotation'\n    }\n    implementation \"androidx.exifinterface:exifinterface:1.3.6\"\n    implementation \"androidx.work:work-runtime-ktx:2.8.1\"\n    implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2'\n    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'\n    implementation \"androidx.lifecycle:lifecycle-runtime-ktx:2.6.2\"\n    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'\n    // 测试SHA-256 digest error问题\n//    api \"org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5\"\n    testImplementation 'junit:junit:4.+'\n    androidTestImplementation 'androidx.test.ext:junit:1.1.2'\n    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'\n\n}\n\n\nprivacy {\n    // 设置免hook的名单\n    blackList = []\n    // 开关PrivacySentry插件功能，核心功能开关，默认为true\n    enablePrivacy = true\n\n    // 开启hook反射的方法,默认为false,按需打开\n    hookReflex = false\n    // 配置反射拦截 反射获取小米系统的oaid、aaid、vaid,例如极光、个推、穿山甲等SDK都有获取\n    reflexMap = [\"com.android.id.impl.IdProviderImpl\":[\"getOAID\",\"getAAID\",\"getVAID\"]]\n\n\n    ///// *************后续不再维护，只保留hook方法的核心功能****************\n    // 默认为false,按需打开\n    hookConstructor = false\n    // 默认为false,按需打开\n    hookField = false\n\n\n    //*************以下是分割线，主要是对Service的自启动优化处理,默认为false,按需打开****************\n    // 处理Manifest文件，主要是处理Service的Priority ， 关闭Service的Export\n    enableProcessManifest = false\n    // hook Service的部分代码，修复在MIUI上的自启动问题\n    // 部分Service把自己的Priority设置为1000，这里开启代理功能，可以代理成0\n    enableReplacePriority = false\n    replacePriority = 1\n\n    // 支持关闭Service的Export功能，默认为false，注意部分厂商通道之类的push(xiaomi、vivo、huawei等厂商的pushService)，不能关闭\n    enableCloseServiceExport = false\n    // Export白名单Service\n    serviceExportPkgWhiteList = [\"white\"]\n    enableHookServiceStartCommand = false\n}\n\nproject.afterEvaluate {\n    project.gradle.taskGraph.whenReady {\n        println(\"=======> print allTasks\")\n        println(project.gradle.taskGraph.allTasks)\n    }\n}\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile"
  },
  {
    "path": "app/src/androidTest/java/com/yl/lib/privacysentry/ExampleInstrumentedTest.kt",
    "content": "package com.yl.lib.privacysentry\n\nimport androidx.test.platform.app.InstrumentationRegistry\nimport androidx.test.ext.junit.runners.AndroidJUnit4\n\nimport org.junit.Test\nimport org.junit.runner.RunWith\n\nimport org.junit.Assert.*\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * See [testing documentation](http://d.android.com/tools/testing).\n */\n@RunWith(AndroidJUnit4::class)\nclass ExampleInstrumentedTest {\n    @Test\n    fun useAppContext() {\n        // Context of the app under test.\n        val appContext = InstrumentationRegistry.getInstrumentation().targetContext\n        assertEquals(\"com.yl.lib.privacysentry\", appContext.packageName)\n    }\n}"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.BLUETOOTH\" />\n    <uses-permission android:name=\"android.permission.READ_PHONE_STATE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n    <uses-permission android:name=\"adnroid.permission.CHANGE_WIFI_STATE\" />\n    <uses-permission android:name=\"android.permission.READ_CONTACTS\" />\n    <uses-permission android:name=\"android.permission.WRITE_CONTACTS\" />\n    <uses-permission android:name=\"android.permission.READ_CALENDAR\" />\n    <uses-permission android:name=\"android.permission.WRITE_CALENDAR\" />\n    <uses-permission android:name=\"android.permission.READ_CALL_LOG\" />\n    <uses-permission android:name=\"android.permission.READ_PRIVILEGED_PHONE_STATE\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.ACCESS_BACKGROUND_LOCATION\" />\n    <uses-permission android:name=\"android.permission.CAMERA\" />\n    <uses-permission android:name=\"android.permission.BODY_SENSORS\" />\n\n    <application\n        android:name=\".APP\"\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/Theme.PrivacySentry\">\n        <activity\n            android:name=\".test.TestFragmentActivity\"\n            android:exported=\"false\" />\n        <activity\n            android:name=\".telephony.TelephonyTestActivity\"\n            android:exported=\"false\" />\n        <activity\n            android:name=\".location.LocationTestActivity\"\n            android:exported=\"false\" />\n        <activity\n            android:name=\".calendar.CalenderActivity\"\n            android:exported=\"true\" />\n        <activity\n            android:name=\".contact.ContactActivity\"\n            android:exported=\"true\" />\n        <activity\n            android:name=\".MainActivity\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n\n        <service\n            android:name=\".process.MultiProcessB\"\n            android:exported=\"false\"\n            android:process=\":MultiProcessB\" />\n\n        <service\n            android:name=\".test.TestService\"\n            android:enabled=\"true\"\n            android:exported=\"true\"\n            android:priority=\"10\"/>\n    </application>\n\n</manifest>"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/APP.kt",
    "content": "package com.yl.lib.privacysentry\n\nimport android.app.Application\nimport android.content.Context\nimport android.os.Build\nimport androidx.multidex.MultiDex\nimport com.yl.lib.privacysentry.test.PrivacyMethod\nimport com.yl.lib.sentry.hook.PrivacyResultCallBack\nimport com.yl.lib.sentry.hook.PrivacySentry\nimport com.yl.lib.sentry.hook.PrivacySentryBuilder\nimport com.yl.lib.sentry.hook.util.PrivacyLog\n\n/**\n * @author yulun\n * @sinice 2021-11-19 10:20\n */\nclass APP : Application() {\n    override fun onCreate() {\n        super.onCreate()\n        var str = testJustSerial()\n    }\n\n    override fun attachBaseContext(base: Context?) {\n        super.attachBaseContext(base)\n        // 注意尽可能在attachBaseContext里第一个调用，因为attachBaseContext之后才能反射拿到ActivityThread的application\n        // 所以如果是在attachBaseContext中，且隐私合规SDK未初始化，不管是不是首次启动，都会认为是危险期，无法调用敏感api\n        PrivacyMethod.PrivacyMethod.getAndroidId(base!!)\n        MultiDex.install(this)\n        Thread { initPrivacyTransformComplete() }.start()\n\n    }\n\n    private fun initPrivacyTransform() {\n        PrivacySentry.Privacy.initTransform(this)\n    }\n\n\n    private fun initPrivacyTransformComplete() {\n\n        // 完整版配置\n        var builder = PrivacySentryBuilder()\n            // 自定义文件结果的输出名\n            .configResultFileName(\"demo_test\")\n            //自定义检测时间，也支持主动停止检测 PrivacySentry.Privacy.stopWatch()\n            .configWatchTime(10 * 60 * 1000)\n            // 打开写入文件开关\n            .enableFileResult(true)\n            .syncDebug(true)\n            // 文件输出后的回调\n            .configResultCallBack(object : PrivacyResultCallBack {\n                override fun onResultCallBack(filePath: String) {\n                    PrivacyLog.i(\"result file patch is $filePath\")\n                }\n            })\n        // 添加默认结果输出，包含log输出和文件输出\n        PrivacySentry.Privacy.init(this, builder)\n        // 简易版配置\n//        PrivacySentry.Privacy.init(this)\n    }\n\n    fun testJustSerial() {\n        val serialNum = android.os.Build.SERIAL\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/MainActivity.kt",
    "content": "package com.yl.lib.privacysentry\n\nimport android.Manifest\nimport android.app.ActivityManager\nimport android.app.AlertDialog\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Build\nimport android.os.Bundle\nimport android.view.View\nimport android.widget.Button\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.fragment.app.FragmentActivity\nimport androidx.lifecycle.lifecycleScope\nimport com.yl.lib.privacy_test.PrivacyProxySelfTest2\nimport com.yl.lib.privacy_test.TestMethod\nimport com.yl.lib.privacy_test.TestMethodInJava\nimport com.yl.lib.privacysentry.calendar.CalenderActivity\nimport com.yl.lib.privacysentry.contact.ContactActivity\nimport com.yl.lib.privacysentry.location.LocationTestActivity\nimport com.yl.lib.privacysentry.process.MultiProcessB\nimport com.yl.lib.privacysentry.process.MultiProcessC\nimport com.yl.lib.privacysentry.telephony.TelephonyTestActivity\nimport com.yl.lib.privacysentry.test.*\nimport com.yl.lib.sentry.hook.PrivacySentry\nimport com.yl.lib.sentry.hook.util.MainProcessUtil\nimport com.yl.lib.sentry.hook.util.PrivacyClipBoardManager\nimport com.yl.lib.sentry.hook.util.PrivacyLog\n\nclass MainActivity : AppCompatActivity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_main)\n\n        findViewById<Button>(R.id.btn_androidId).setOnClickListener {\n            var androidId = PrivacyMethod.PrivacyMethod.getAndroidId(this)\n            TestMethodInJava.getAndroidId(this)\n            TestMethodInJava.getAndroidIdSystem(this)\n            PrivacyLog.i(\"androidId is $androidId\")\n\n            Thread{\n                TestInJava.testHttpUrlConnection()\n            }\n\n            val preferences = getSharedPreferences(\"my_preferences\", MODE_PRIVATE)\n            val editor = preferences.edit()\n            editor.putString(\"key\", \"value\")\n            editor.apply()\n        }\n\n        findViewById<Button>(R.id.btn_mac_address).setOnClickListener {\n            var macRaw = PrivacyMethod.PrivacyMethod.getMacRaw(this)\n            PrivacyLog.i(\"macRaw is $macRaw\")\n            PrivacyTestMacAddress.getMacAddress()\n            PrivacyMethod.PrivacyMethod.getIp(this)\n            PrivacyMethod.PrivacyMethod.getScanResults(this)\n\n            TestMethodInJava.getAndroidId2(this)\n        }\n\n        findViewById<Button>(R.id.btn_installed_packages).setOnClickListener {\n            var privacySentryInstalled =\n                PrivacyMethod.PrivacyMethod.isInstalled(application, \"com.yl.lib.privacysentry123\")\n            PrivacyLog.i(\"privacySentryInstalled is $privacySentryInstalled\")\n\n            var privacySentryInstalled2 =\n                PrivacyMethod.PrivacyMethod.isInstalled2(\n                    application,\n                    this,\n                    \"com.yl.lib.privacysentry123\"\n                )\n            PrivacyLog.i(\"privacySentryInstalled2 is $privacySentryInstalled2\")\n\n            PrivacyLog.i(\n                \"privacySentryInstalled2 is ${\n                    PrivacyMethod.PrivacyMethod.queryActivityInfo(\n                        application,\n                        this\n                    )\n                }\"\n            )\n\n            PrivacyLog.i(\n                \"privacySentryInstalled3 is ${\n                    PrivacyMethod.PrivacyMethod.isInstalled3(\n                        application,\n                        \"com.xx.xx.xx\"\n                    )\n                }\"\n            )\n        }\n\n        findViewById<Button>(R.id.btn_test_cms).setOnClickListener {\n            PrivacyMethod.PrivacyMethod.testHookCms(application)\n            PrivacyLog.i(\"testHookCms\")\n        }\n\n        findViewById<Button>(R.id.btn_clipboard_readable).setOnClickListener {\n            var enableClipRead = PrivacyClipBoardManager.isReadClipboardEnable()\n            if (enableClipRead) {\n                PrivacyClipBoardManager.closeReadClipboard()\n            } else {\n                PrivacyClipBoardManager.openReadClipboard()\n            }\n            configClipReadText(it as Button)\n        }\n        configClipReadText(findViewById<Button>(R.id.btn_clipboard_readable))\n\n        findViewById<Button>(R.id.btn_test_ams_process).setOnClickListener {\n            PrivacyMethod.PrivacyMethod.testRunningProcess(application)\n            PrivacyMethod.PrivacyMethod.testRunningTask(application)\n        }\n\n        findViewById<Button>(R.id.btn_main_process).setOnClickListener {\n            var mainProcess = MainProcessUtil.MainProcessChecker.isMainProcess(this)\n            var currentProcessName = MainProcessUtil.MainProcessChecker.getProcessName(this)\n            PrivacyLog.i(\"mainProcess currentProcessName is $currentProcessName  is $mainProcess\")\n\n            PrivacyProxyCallJava.getRunningTasks(\n                getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager,\n                1\n            )\n            PrivacyProxySelfTest2.getRunningTasks456(\n                getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager,\n                1\n            )\n        }\n\n\n        findViewById<Button>(R.id.btn_force_finish).setOnClickListener {\n            PrivacySentry.Privacy.stop()\n        }\n\n        findViewById<Button>(R.id.btn_test_processB).setOnClickListener {\n            startService(Intent(this, MultiProcessB::class.java))\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n                startService(Intent(this, MultiProcessC::class.java))\n            }\n        }\n\n        findViewById<Button>(R.id.btn_test_lib_method).setOnClickListener {\n            TestMethod.PrivacyMethod.getDeviceId(applicationContext)\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                TestMethod.PrivacyMethod.getDeviceId1(applicationContext)\n            }\n            TestMethod.PrivacyMethod.getICCID(applicationContext)\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                TestMethod.PrivacyMethod.getIMEI(applicationContext)\n            }\n            TestMethod.PrivacyMethod.getIMSI(applicationContext)\n            TestMethod.PrivacyMethod.testHookCms(applicationContext)\n            TestMethod.PrivacyMethod.testRunningProcess(applicationContext)\n            TestMethod.PrivacyMethod.testRunningTask(applicationContext)\n        }\n\n\n        // 变量hook测试\n        findViewById<Button>(R.id.btn_test_sn).setOnClickListener {\n            var sn = PrivacyMethod.PrivacyMethod.getSerial()\n            var brand = android.os.Build.BRAND\n            PrivacyLog.i(\"Android SN is $sn brand is $brand\")\n        }\n\n\n        findViewById<Button>(R.id.btn_to_calender).setOnClickListener {\n            startActivity(Intent(this, CalenderActivity::class.java))\n        }\n\n        findViewById<Button>(R.id.btn_to_telephony).setOnClickListener {\n            startActivity(Intent(this, TelephonyTestActivity::class.java))\n        }\n\n        findViewById<Button>(R.id.btn_to_contact).setOnClickListener {\n            startActivity(Intent(this, ContactActivity::class.java))\n        }\n\n        findViewById<Button>(R.id.btn_test_sensor).setOnClickListener {\n            PrivacyMethod.PrivacyMethod.testSensor(this)\n        }\n\n        findViewById<Button>(R.id.btn_thread_cache).setOnClickListener {\n            for (index in 1..20) {\n                Thread(Thread.currentThread().threadGroup, {\n                    var result = PrivacyMethod.PrivacyMethod.getAndroidId(this@MainActivity)\n                    PrivacyLog.e(\"btn_thread_cache result is $result\")\n\n                    PrivacyMethod.PrivacyMethod.getDeviceId(this@MainActivity)\n\n                    PrivacyMethod.PrivacyMethod.getDeviceId1(this@MainActivity)\n\n                    PrivacyMethod.PrivacyMethod.getICCID(this@MainActivity)\n\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                        PrivacyMethod.PrivacyMethod.getIMEI(this@MainActivity)\n                    }\n\n                    PrivacyMethod.PrivacyMethod.getIMSI(this@MainActivity)\n\n                    PrivacyMethod.PrivacyMethod.getMacRaw(this@MainActivity)\n\n                    PrivacyMethod.PrivacyMethod.getMacV2()\n\n                    PrivacyMethod.PrivacyMethod.getMeid(this@MainActivity)\n\n                    PrivacyMethod.PrivacyMethod.getSerial()\n                }, \"test_thread_$index\", 0).start()\n            }\n        }\n\n        findViewById<Button>(R.id.btn_test_ExternalStorageDirectory).setOnClickListener {\n            PrivacyMethod.PrivacyMethod.getSdcardRoot(this)\n        }\n\n        findViewById<Button>(R.id.btn_test_get_all_sensor).setOnClickListener {\n            PrivacyMethod.PrivacyMethod.testGetSensorList(this)\n        }\n\n        findViewById<Button>(R.id.btn_to_location).setOnClickListener {\n            startActivity(Intent(this, LocationTestActivity::class.java))\n        }\n\n        findViewById<Button>(R.id.btn_to_fragment).setOnClickListener {\n            startActivity(Intent(this, TestFragmentActivity::class.java))\n        }\n\n        findViewById<Button>(R.id.btn_test_reflex).setOnClickListener {\n            var ap = packageManager\n            TestReflex().test(this)\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                TestReflexJava().test(this)\n                TestReflexJava().reflex3(this, \"123\")\n            }\n            TestInJava.testReflexClipManager()\n            TestInJava.testReflexClipManagerOpen()\n            TestInJava.testReflexClipManagerClose()\n        }\n\n        AlertDialog.Builder(this).setMessage(\"确认隐私协议\").setPositiveButton(\n            \"确定\"\n        ) { dialog, which ->\n            PrivacySentry.Privacy.updatePrivacyShow()\n            PrivacySentry.Privacy.closeVisitorModel()\n        }.create().show()\n\n        //Android Q开始，READ_PHONE_STATE 不再有用，不用全局弹框\n        var permissions = arrayOf(\n            Manifest.permission.WRITE_EXTERNAL_STORAGE,\n            Manifest.permission.READ_PHONE_STATE\n        )\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            requestPermissions(permissions, 1000)\n        }\n\n        PrivacySentry.Privacy.initTransform(application)\n    }\n\n\n    fun testGetOaid(view: View) {\n        TestOaidGetter.getOaid(this);\n    }\n\n    override fun onRequestPermissionsResult(\n        requestCode: Int,\n        permissions: Array<out String>,\n        grantResults: IntArray\n    ) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults)\n        if (requestCode == 1000) {\n            PrivacyLog.i(\"requestPermissions ${permissions[0]} success\")\n        } else {\n            PrivacyLog.i(\"requestPermissions ${permissions[0]} fail\")\n        }\n    }\n\n    private fun configClipReadText(btn: Button) {\n        var enableClipRead = PrivacyClipBoardManager.isReadClipboardEnable()\n        var btnText = \"\"\n        btnText = if (enableClipRead) {\n            \"关闭读取剪切板\"\n        } else {\n            \"开启剪贴板\"\n        }\n        btn.text = btnText\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/ReflexObjectUtil.java",
    "content": "package com.yl.lib.privacysentry;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.util.Scanner;\n\n/**\n * @author yulun\n * @since 2023-08-29 18:04\n */\npublic class ReflexObjectUtil {\n\n    public static void test(String className) {\n        try {\n            Class cl = Class.forName(className);\n            Class supercl = cl.getSuperclass();\n            String modifiers = Modifier.toString(cl.getModifiers());\n            if (modifiers.length() > 0) System.out.print(modifiers + \" \");\n            System.out.print(\"class \" + className);\n            if (supercl != null && supercl != Object.class) {\n                System.out.print(\"extends \" + supercl.getName());\n            }\n            System.out.print(\"\\n{\\n\");\n\n            printFields(cl);\n            System.out.println();\n            printConstructors(cl);\n            System.out.println();\n            printMethods(cl);\n            System.out.print(\"}\\n\");\n\n        } catch (Exception e) {\n\n            // TODO: handle exception\n        }\n    }\n\n    public static void printConstructors(Class cl) {\n        Constructor[] constructors = cl.getConstructors();\n        for (Constructor c : constructors) {\n            System.out.print(\"  \");\n            String name = c.getName();\n            String modifiers = Modifier.toString(c.getModifiers());\n            if (modifiers.length() > 0) System.out.print(modifiers + \" \");\n            System.out.print(name + \" (\");\n            Class[] paramType = c.getParameterTypes();\n            for (int j = 0; j < paramType.length; j++) {\n                if (j > 0) System.out.print(\", \");\n                System.out.print(paramType[j].getName());\n            }\n            System.out.print(\")\");\n        }\n        System.out.println();\n    }\n\n    public static void printMethods(Class cl) {\n        Method[] methods = cl.getDeclaredMethods();\n        for (Method m : methods) {\n            System.out.print(\"  \");\n            String name = m.getName();\n            String modifiers = Modifier.toString(m.getModifiers());\n            if (modifiers.length() > 0) System.out.print(modifiers + \" \");\n            Class returnType = m.getReturnType();\n            System.out.print(returnType.getName() + \" \");\n            System.out.print(name + \" (\");\n            Class[] paramType = m.getParameterTypes();\n            for (int j = 0; j < paramType.length; j++) {\n                if (j > 0) System.out.print(\", \");\n                System.out.print(paramType[j].getName());\n            }\n            System.out.print(\")\");\n            System.out.println();\n        }\n        System.out.println();\n    }\n\n    public static void printFields(Class cl) {\n        Field[] fields = cl.getDeclaredFields();\n        for (Field f : fields) {\n            System.out.print(\"  \");\n            String name = f.getName();\n            Class type = f.getType();\n            String modifiers = Modifier.toString(f.getModifiers());\n            if (modifiers.length() > 0) System.out.print(modifiers + \" \");\n            System.out.println(type.getName() + \" \" + name + \";\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/calendar/CalendarManager.kt",
    "content": "package com.yl.lib.privacysentry.calendar\n\nimport android.content.ContentUris\nimport android.content.ContentValues\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.database.Cursor\nimport android.graphics.Color\nimport android.net.Uri\nimport android.os.Build\nimport android.provider.CalendarContract\nimport android.widget.Toast\nimport java.text.SimpleDateFormat\nimport java.util.*\nimport kotlin.collections.ArrayList\n\n\n/**\n * @author yulun\n * @since 2022-01-13 19:53\n * 测试日历相关 代码从 https://github.com/kylechandev/CalendarProviderManager拷贝\n */\nclass CalendarManager {\n\n    object Manager {\n        private val builder = StringBuilder()\n\n        /*\n           TIP: 要向系统日历插入事件,前提系统中必须存在至少1个日历账户\n         */\n\n\n        /*\n           TIP: 要向系统日历插入事件,前提系统中必须存在至少1个日历账户\n         */\n        // ----------------------- 创建日历账户时账户名使用 ---------------------------\n        private var CALENDAR_NAME = \"KyleC\"\n        private var CALENDAR_ACCOUNT_NAME = \"KYLE\"\n        private var CALENDAR_DISPLAY_NAME = \"KYLE的账户\"\n\n\n        // ------------------------------- 日历账户 -----------------------------------\n\n        // ------------------------------- 日历账户 -----------------------------------\n        /**\n         * 获取日历账户ID(若没有则会自动创建一个)\n         *\n         * @return success: 日历账户ID  failed : -1  permission deny : -2\n         */\n        fun obtainCalendarAccountID(context: Context): Long {\n            val calID = checkCalendarAccount(context)\n            return if (calID >= 0) {\n                calID\n            } else {\n                createCalendarAccount(context)\n            }\n        }\n\n        /**\n         * 检查是否存在日历账户\n         *\n         * @return 存在：日历账户ID  不存在：-1\n         */\n        private fun checkCalendarAccount(context: Context): Long {\n            context.getContentResolver().query(\n                CalendarContract.Calendars.CONTENT_URI,\n                null, null, null, null\n            ).use({ cursor ->\n                // 不存在日历账户\n                if (null == cursor) {\n                    return -1\n                }\n                val count: Int = cursor.getCount()\n                // 存在日历账户，获取第一个账户的ID\n                return if (count > 0) {\n                    cursor.moveToFirst()\n                    cursor.getInt(cursor.getColumnIndex(CalendarContract.Calendars._ID)).toLong()\n                } else {\n                    -1\n                }\n            })\n        }\n\n        /**\n         * 创建一个新的日历账户\n         *\n         * @return success：ACCOUNT ID , create failed：-1 , permission deny：-2\n         */\n        private fun createCalendarAccount(context: Context): Long {\n            // 系统日历表\n            var uri: Uri = CalendarContract.Calendars.CONTENT_URI\n\n            // 要创建的账户\n            val accountUri: Uri\n\n            // 开始组装账户数据\n            val account = ContentValues()\n            // 账户类型：本地\n            // 在添加账户时，如果账户类型不存在系统中，则可能该新增记录会被标记为脏数据而被删除\n            // 设置为ACCOUNT_TYPE_LOCAL可以保证在不存在账户类型时，该新增数据不会被删除\n            account.put(\n                CalendarContract.Calendars.ACCOUNT_TYPE,\n                CalendarContract.ACCOUNT_TYPE_LOCAL\n            )\n            // 日历在表中的名称\n            account.put(CalendarContract.Calendars.NAME, CALENDAR_NAME)\n            // 日历账户的名称\n            account.put(CalendarContract.Calendars.ACCOUNT_NAME, CALENDAR_ACCOUNT_NAME)\n            // 账户显示的名称\n            account.put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, CALENDAR_DISPLAY_NAME)\n            // 日历的颜色\n            account.put(CalendarContract.Calendars.CALENDAR_COLOR, Color.parseColor(\"#515bd4\"))\n            // 用户对此日历的获取使用权限等级\n            account.put(\n                CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL,\n                CalendarContract.Calendars.CAL_ACCESS_OWNER\n            )\n            // 设置此日历可见\n            account.put(CalendarContract.Calendars.VISIBLE, 1)\n            // 日历时区\n            account.put(\n                CalendarContract.Calendars.CALENDAR_TIME_ZONE,\n                TimeZone.getDefault().getID()\n            )\n            // 可以修改日历时区\n            account.put(CalendarContract.Calendars.CAN_MODIFY_TIME_ZONE, 1)\n            // 同步此日历到设备上\n            account.put(CalendarContract.Calendars.SYNC_EVENTS, 1)\n            // 拥有者的账户\n            account.put(CalendarContract.Calendars.OWNER_ACCOUNT, CALENDAR_ACCOUNT_NAME)\n            // 可以响应事件\n            account.put(CalendarContract.Calendars.CAN_ORGANIZER_RESPOND, 1)\n            // 单个事件设置的最大的提醒数\n            account.put(CalendarContract.Calendars.MAX_REMINDERS, 8)\n            // 设置允许提醒的方式\n            account.put(CalendarContract.Calendars.ALLOWED_REMINDERS, \"0,1,2,3,4\")\n            // 设置日历支持的可用性类型\n            account.put(CalendarContract.Calendars.ALLOWED_AVAILABILITY, \"0,1,2\")\n            // 设置日历允许的出席者类型\n            account.put(CalendarContract.Calendars.ALLOWED_ATTENDEE_TYPES, \"0,1,2\")\n\n            /*\n                TIP: 修改或添加ACCOUNT_NAME只能由SYNC_ADAPTER调用\n                对uri设置CalendarContract.CALLER_IS_SYNCADAPTER为true,即标记当前操作为SYNC_ADAPTER操作\n                在设置CalendarContract.CALLER_IS_SYNCADAPTER为true时,必须带上参数ACCOUNT_NAME和ACCOUNT_TYPE(任意)\n             */uri = uri.buildUpon()\n                .appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, \"true\")\n                .appendQueryParameter(\n                    CalendarContract.Calendars.ACCOUNT_NAME,\n                    CALENDAR_ACCOUNT_NAME\n                )\n                .appendQueryParameter(\n                    CalendarContract.Calendars.ACCOUNT_TYPE,\n                    CalendarContract.Calendars.CALENDAR_LOCATION\n                )\n                .build()\n            accountUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                // 检查日历权限\n                if (PackageManager.PERMISSION_GRANTED == context.checkSelfPermission(\n                        \"android.permission.WRITE_CALENDAR\"\n                    )\n                ) {\n                    context.getContentResolver().insert(uri, account)!!\n                } else {\n                    return -2\n                }\n            } else {\n                context.getContentResolver().insert(uri, account)!!\n            }\n            return if (accountUri == null) -1 else ContentUris.parseId(accountUri)\n        }\n\n        /**\n         * 删除创建的日历账户\n         *\n         * @return -2: permission deny  0: No designated account  1: delete success\n         */\n        fun deleteCalendarAccountByName(context: Context): Int {\n            val deleteCount: Int\n            val uri: Uri = CalendarContract.Calendars.CONTENT_URI\n            val selection = (\"((\" + CalendarContract.Calendars.ACCOUNT_NAME + \" = ?) AND (\"\n                    + CalendarContract.Calendars.ACCOUNT_TYPE + \" = ?))\")\n            val selectionArgs = arrayOf(CALENDAR_ACCOUNT_NAME, CalendarContract.ACCOUNT_TYPE_LOCAL)\n            deleteCount = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                if (PackageManager.PERMISSION_GRANTED == context.checkSelfPermission(\n                        \"android.permission.WRITE_CALENDAR\"\n                    )\n                ) {\n                    context.getContentResolver().delete(uri, selection, selectionArgs)\n                } else {\n                    return -2\n                }\n            } else {\n                context.getContentResolver().delete(uri, selection, selectionArgs)\n            }\n            return deleteCount\n        }\n\n\n        // ------------------------------- 添加日历事件 -----------------------------------\n\n        // ------------------------------- 添加日历事件 -----------------------------------\n        /**\n         * 添加日历事件\n         *\n         * @param calendarEvent 日历事件(详细参数说明请参看[CalendarEvent]构造方法)\n         * @return 0: success  -1: failed  -2: permission deny\n         */\n        fun addCalendarEvent(context: Context, calendarEvent: CalendarEvent): Int {\n            /*\n                TIP: 插入一个新事件的规则：\n                 1.  必须包含CALENDAR_ID和DTSTART字段\n                 2.  必须包含EVENT_TIMEZONE字段,使用TimeZone.getDefault().getID()方法获取默认时区\n                 3.  对于非重复发生的事件,必须包含DTEND字段\n                 4.  对重复发生的事件,必须包含一个附加了RRULE或RDATE字段的DURATION字段\n             */\n\n            // 获取日历账户ID，也就是要将事件插入到的账户\n            val calID = obtainCalendarAccountID(context)\n\n            // 系统日历事件表\n            val uri1: Uri = CalendarContract.Events.CONTENT_URI\n            // 创建的日历事件\n            val eventUri: Uri\n\n            // 系统日历事件提醒表\n            val uri2: Uri = CalendarContract.Reminders.CONTENT_URI\n            // 创建的日历事件提醒\n            val reminderUri: Uri\n\n            // 开始组装事件数据\n            val event = ContentValues()\n            // 事件要插入到的日历账户\n            event.put(CalendarContract.Events.CALENDAR_ID, calID)\n            setupEvent(calendarEvent, event)\n            eventUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                // 判断权限\n                if (PackageManager.PERMISSION_GRANTED == context.checkSelfPermission(\n                        \"android.permission.WRITE_CALENDAR\"\n                    )\n                ) {\n                    context.getContentResolver().insert(uri1, event)!!\n                } else {\n                    return -2\n                }\n            } else {\n                context.getContentResolver().insert(uri1, event)!!\n            }\n            if (null == eventUri) {\n                return -1\n            }\n            if (-2 != calendarEvent.getAdvanceTime()) {\n                // 获取事件ID\n                val eventID = ContentUris.parseId(eventUri)\n\n                // 开始组装事件提醒数据\n                val reminders = ContentValues()\n                // 此提醒所对应的事件ID\n                reminders.put(CalendarContract.Reminders.EVENT_ID, eventID)\n                // 设置提醒提前的时间(0：准时  -1：使用系统默认)\n                reminders.put(CalendarContract.Reminders.MINUTES, calendarEvent.getAdvanceTime())\n                // 设置事件提醒方式为通知警报\n                reminders.put(\n                    CalendarContract.Reminders.METHOD,\n                    CalendarContract.Reminders.METHOD_ALERT\n                )\n                reminderUri = context.getContentResolver().insert(uri2, reminders)!!\n                if (null == reminderUri) {\n                    return -1\n                }\n            }\n            return 0\n        }\n\n\n        // ------------------------------- 更新日历事件 -----------------------------------\n\n        // ------------------------------- 更新日历事件 -----------------------------------\n        /**\n         * 更新指定ID的日历事件\n         *\n         * @param newCalendarEvent 更新的日历事件\n         * @return -2: permission deny  else success\n         */\n        fun updateCalendarEvent(\n            context: Context,\n            eventID: Long,\n            newCalendarEvent: CalendarEvent\n        ): Int {\n            val updatedCount1: Int\n            val uri1: Uri = CalendarContract.Events.CONTENT_URI\n            val uri2: Uri = CalendarContract.Reminders.CONTENT_URI\n            val event = ContentValues()\n            setupEvent(newCalendarEvent, event)\n\n            // 更新匹配条件\n            val selection1 = \"(\" + CalendarContract.Events._ID + \" = ?)\"\n            val selectionArgs1 = arrayOf(eventID.toString())\n            updatedCount1 = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                if (PackageManager.PERMISSION_GRANTED == context.checkSelfPermission(\n                        \"android.permission.WRITE_CALENDAR\"\n                    )\n                ) {\n                    context.getContentResolver().update(uri1, event, selection1, selectionArgs1)\n                } else {\n                    return -2\n                }\n            } else {\n                context.getContentResolver().update(uri1, event, selection1, selectionArgs1)\n            }\n            val reminders = ContentValues()\n            reminders.put(CalendarContract.Reminders.MINUTES, newCalendarEvent.getAdvanceTime())\n            reminders.put(\n                CalendarContract.Reminders.METHOD,\n                CalendarContract.Reminders.METHOD_ALERT\n            )\n\n            // 更新匹配条件\n            val selection2 = \"(\" + CalendarContract.Reminders.EVENT_ID + \" = ?)\"\n            val selectionArgs2 = arrayOf(eventID.toString())\n            val updatedCount2: Int =\n                context.getContentResolver().update(uri2, reminders, selection2, selectionArgs2)\n            return (updatedCount1 + updatedCount2) / 2\n        }\n\n        /**\n         * 更新指定ID事件的开始时间\n         *\n         * @return If successfully returns 1\n         */\n        fun updateCalendarEventbeginTime(context: Context, eventID: Long, newBeginTime: Long): Int {\n            val uri: Uri = CalendarContract.Events.CONTENT_URI\n\n            // 新的数据\n            val event = ContentValues()\n            event.put(CalendarContract.Events.DTSTART, newBeginTime)\n\n            // 匹配条件\n            val selection = \"(\" + CalendarContract.Events._ID + \" = ?)\"\n            val selectionArgs = arrayOf(eventID.toString())\n            return context.getContentResolver().update(uri, event, selection, selectionArgs)\n        }\n\n        /**\n         * 更新指定ID事件的结束时间\n         *\n         * @return If successfully returns 1\n         */\n        fun updateCalendarEventEndTime(context: Context, eventID: Long, newEndTime: Long): Int {\n            val uri: Uri = CalendarContract.Events.CONTENT_URI\n\n            // 新的数据\n            val event = ContentValues()\n            event.put(CalendarContract.Events.DTEND, newEndTime)\n\n\n            // 匹配条件\n            val selection = \"(\" + CalendarContract.Events._ID + \" = ?)\"\n            val selectionArgs = arrayOf(eventID.toString())\n            return context.getContentResolver().update(uri, event, selection, selectionArgs)\n        }\n\n        /**\n         * 更新指定ID事件的起始时间\n         *\n         * @return If successfully returns 1\n         */\n        fun updateCalendarEventTime(\n            context: Context, eventID: Long, newBeginTime: Long,\n            newEndTime: Long\n        ): Int {\n            val uri: Uri = CalendarContract.Events.CONTENT_URI\n\n            // 新的数据\n            val event = ContentValues()\n            event.put(CalendarContract.Events.DTSTART, newBeginTime)\n            event.put(CalendarContract.Events.DTEND, newEndTime)\n\n\n            // 匹配条件\n            val selection = \"(\" + CalendarContract.Events._ID + \" = ?)\"\n            val selectionArgs = arrayOf(eventID.toString())\n            return context.getContentResolver().update(uri, event, selection, selectionArgs)\n        }\n\n        /**\n         * 更新指定ID事件的标题\n         *\n         * @return If successfully returns 1\n         */\n        fun updateCalendarEventTitle(context: Context, eventID: Long, newTitle: String?): Int {\n            val uri: Uri = CalendarContract.Events.CONTENT_URI\n\n            // 新的数据\n            val event = ContentValues()\n            event.put(CalendarContract.Events.TITLE, newTitle)\n\n\n            // 匹配条件\n            val selection = \"(\" + CalendarContract.Events._ID + \" = ?)\"\n            val selectionArgs = arrayOf(eventID.toString())\n            return context.getContentResolver().update(uri, event, selection, selectionArgs)\n        }\n\n        /**\n         * 更新指定ID事件的描述\n         *\n         * @return If successfully returns 1\n         */\n        fun updateCalendarEventDes(context: Context, eventID: Long, newEventDes: String?): Int {\n            val uri: Uri = CalendarContract.Events.CONTENT_URI\n\n            // 新的数据\n            val event = ContentValues()\n            event.put(CalendarContract.Events.DESCRIPTION, newEventDes)\n\n\n            // 匹配条件\n            val selection = \"(\" + CalendarContract.Events._ID + \" = ?)\"\n            val selectionArgs = arrayOf(eventID.toString())\n            return context.getContentResolver().update(uri, event, selection, selectionArgs)\n        }\n\n        /**\n         * 更新指定ID事件的地点\n         *\n         * @return If successfully returns 1\n         */\n        fun updateCalendarEventLocation(\n            context: Context,\n            eventID: Long,\n            newEventLocation: String?\n        ): Int {\n            val uri: Uri = CalendarContract.Events.CONTENT_URI\n\n            // 新的数据\n            val event = ContentValues()\n            event.put(CalendarContract.Events.EVENT_LOCATION, newEventLocation)\n\n\n            // 匹配条件\n            val selection = \"(\" + CalendarContract.Events._ID + \" = ?)\"\n            val selectionArgs = arrayOf(eventID.toString())\n            return context.getContentResolver().update(uri, event, selection, selectionArgs)\n        }\n\n        /**\n         * 更新指定ID事件的标题和描述\n         *\n         * @return If successfully returns 1\n         */\n        fun updateCalendarEventTitAndDes(\n            context: Context, eventID: Long, newEventTitle: String?,\n            newEventDes: String?\n        ): Int {\n            val uri: Uri = CalendarContract.Events.CONTENT_URI\n\n            // 新的数据\n            val event = ContentValues()\n            event.put(CalendarContract.Events.TITLE, newEventTitle)\n            event.put(CalendarContract.Events.DESCRIPTION, newEventDes)\n\n\n            // 匹配条件\n            val selection = \"(\" + CalendarContract.Events._ID + \" = ?)\"\n            val selectionArgs = arrayOf(eventID.toString())\n            return context.getContentResolver().update(uri, event, selection, selectionArgs)\n        }\n\n        /**\n         * 更新指定ID事件的常用信息(标题、描述、地点)\n         *\n         * @return If successfully returns 1\n         */\n        fun updateCalendarEventCommonInfo(\n            context: Context, eventID: Long, newEventTitle: String?,\n            newEventDes: String?, newEventLocation: String?\n        ): Int {\n            val uri: Uri = CalendarContract.Events.CONTENT_URI\n\n            // 新的数据\n            val event = ContentValues()\n            event.put(CalendarContract.Events.TITLE, newEventTitle)\n            event.put(CalendarContract.Events.DESCRIPTION, newEventDes)\n            event.put(CalendarContract.Events.EVENT_LOCATION, newEventLocation)\n\n\n            // 匹配条件\n            val selection = \"(\" + CalendarContract.Events._ID + \" = ?)\"\n            val selectionArgs = arrayOf(eventID.toString())\n            return context.getContentResolver().update(uri, event, selection, selectionArgs)\n        }\n\n        /**\n         * 更新指定ID事件的提醒方式\n         *\n         * @return If successfully returns 1\n         */\n        private fun updateCalendarEventReminder(\n            context: Context,\n            eventID: Long,\n            newAdvanceTime: Long\n        ): Int {\n            val uri: Uri = CalendarContract.Reminders.CONTENT_URI\n            val reminders = ContentValues()\n            reminders.put(CalendarContract.Reminders.MINUTES, newAdvanceTime)\n\n            // 更新匹配条件\n            val selection2 = \"(\" + CalendarContract.Reminders.EVENT_ID + \" = ?)\"\n            val selectionArgs2 = arrayOf(eventID.toString())\n            return context.getContentResolver().update(uri, reminders, selection2, selectionArgs2)\n        }\n\n        /**\n         * 更新指定ID事件的提醒重复规则\n         *\n         * @return If successfully returns 1\n         */\n        private fun updateCalendarEventRRule(\n            context: Context,\n            eventID: Long,\n            newRRule: String\n        ): Int {\n            val uri: Uri = CalendarContract.Events.CONTENT_URI\n\n            // 新的数据\n            val event = ContentValues()\n            event.put(CalendarContract.Events.RRULE, newRRule)\n\n            // 匹配条件\n            val selection = \"(\" + CalendarContract.Events._ID + \" = ?)\"\n            val selectionArgs = arrayOf(eventID.toString())\n            return context.getContentResolver().update(uri, event, selection, selectionArgs)\n        }\n\n\n        // ------------------------------- 删除日历事件 -----------------------------------\n\n        // ------------------------------- 删除日历事件 -----------------------------------\n        /**\n         * 删除日历事件\n         *\n         * @param eventID 事件ID\n         * @return -2: permission deny  else success\n         */\n        fun deleteCalendarEvent(context: Context, eventID: Long): Int {\n            val deletedCount1: Int\n            val uri1: Uri = CalendarContract.Events.CONTENT_URI\n            val uri2: Uri = CalendarContract.Reminders.CONTENT_URI\n\n            // 删除匹配条件\n            val selection = \"(\" + CalendarContract.Events._ID + \" = ?)\"\n            val selectionArgs = arrayOf(eventID.toString())\n            deletedCount1 = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                if (PackageManager.PERMISSION_GRANTED == context.checkSelfPermission(\n                        \"android.permission.WRITE_CALENDAR\"\n                    )\n                ) {\n                    context.getContentResolver().delete(uri1, selection, selectionArgs)\n                } else {\n                    return -2\n                }\n            } else {\n                context.getContentResolver().delete(uri1, selection, selectionArgs)\n            }\n\n            // 删除匹配条件\n            val selection2 = \"(\" + CalendarContract.Reminders.EVENT_ID + \" = ?)\"\n            val selectionArgs2 = arrayOf(eventID.toString())\n            val deletedCount2: Int =\n                context.getContentResolver().delete(uri2, selection2, selectionArgs2)\n            return (deletedCount1 + deletedCount2) / 2\n        }\n\n\n        // ------------------------------- 查询日历事件 -----------------------------------\n\n        // ------------------------------- 查询日历事件 -----------------------------------\n        /**\n         * 查询指定日历账户下的所有事件\n         *\n         * @return If failed return null else return List<CalendarEvent>\n        </CalendarEvent> */\n        fun queryAccountEvent(context: Context, calID: Long): List<CalendarEvent>? {\n            val EVENT_PROJECTION = arrayOf(\n                CalendarContract.Events.CALENDAR_ID,  // 在表中的列索引0\n                CalendarContract.Events.TITLE,  // 在表中的列索引1\n                CalendarContract.Events.DESCRIPTION,  // 在表中的列索引2\n                CalendarContract.Events.EVENT_LOCATION,  // 在表中的列索引3\n                CalendarContract.Events.DISPLAY_COLOR,  // 在表中的列索引4\n                CalendarContract.Events.STATUS,  // 在表中的列索引5\n                CalendarContract.Events.DTSTART,  // 在表中的列索引6\n                CalendarContract.Events.DTEND,  // 在表中的列索引7\n                CalendarContract.Events.DURATION,  // 在表中的列索引8\n                CalendarContract.Events.EVENT_TIMEZONE,  // 在表中的列索引9\n                CalendarContract.Events.EVENT_END_TIMEZONE,  // 在表中的列索引10\n                CalendarContract.Events.ALL_DAY,  // 在表中的列索引11\n                CalendarContract.Events.ACCESS_LEVEL,  // 在表中的列索引12\n                CalendarContract.Events.AVAILABILITY,  // 在表中的列索引13\n                CalendarContract.Events.HAS_ALARM,  // 在表中的列索引14\n                CalendarContract.Events.RRULE,  // 在表中的列索引15\n                CalendarContract.Events.RDATE,  // 在表中的列索引16\n                CalendarContract.Events.HAS_ATTENDEE_DATA,  // 在表中的列索引17\n                CalendarContract.Events.LAST_DATE,  // 在表中的列索引18\n                CalendarContract.Events.ORGANIZER,  // 在表中的列索引19\n                CalendarContract.Events.IS_ORGANIZER,  // 在表中的列索引20\n                CalendarContract.Events._ID // 在表中的列索引21\n            )\n\n            // 事件匹配\n            val uri: Uri = CalendarContract.Events.CONTENT_URI\n            val uri2: Uri = CalendarContract.Reminders.CONTENT_URI\n            val selection = \"(\" + CalendarContract.Events.CALENDAR_ID + \" = ?)\"\n            val selectionArgs = arrayOf(calID.toString())\n            val cursor: Cursor\n            cursor = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                if (PackageManager.PERMISSION_GRANTED == context.checkSelfPermission(\n                        \"android.permission.READ_CALENDAR\"\n                    )\n                ) {\n                    context.getContentResolver().query(\n                        uri, EVENT_PROJECTION, selection,\n                        selectionArgs, null\n                    )!!\n                } else {\n                    return null\n                }\n            } else {\n                context.getContentResolver().query(\n                    uri, EVENT_PROJECTION, selection,\n                    selectionArgs, null\n                )!!\n            }\n            if (null == cursor) {\n                return null\n            }\n\n            // 查询结果\n            val result: MutableList<CalendarEvent> = ArrayList()\n\n            // 开始查询数据\n            if (cursor.moveToFirst()) {\n                do {\n                    val calendarEvent = CalendarEvent()\n                    result.add(calendarEvent)\n                    calendarEvent.setId(\n                        cursor.getLong(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events._ID\n                            )\n                        )\n                    )\n                    calendarEvent.setCalID(\n                        cursor.getLong(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.CALENDAR_ID\n                            )\n                        )\n                    )\n                    calendarEvent.setTitle(\n                        cursor.getString(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.TITLE\n                            )\n                        )\n                    )\n                    calendarEvent.setDescription(\n                        cursor.getString(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.DESCRIPTION\n                            )\n                        )\n                    )\n                    calendarEvent.setEventLocation(\n                        cursor.getString(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.EVENT_LOCATION\n                            )\n                        )\n                    )\n                    calendarEvent.setDisplayColor(\n                        cursor.getInt(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.DISPLAY_COLOR\n                            )\n                        )\n                    )\n                    calendarEvent.setStatus(\n                        cursor.getInt(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.STATUS\n                            )\n                        )\n                    )\n                    calendarEvent.setStart(\n                        cursor.getLong(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.DTSTART\n                            )\n                        )\n                    )\n                    calendarEvent.setEnd(\n                        cursor.getLong(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.DTEND\n                            )\n                        )\n                    )\n                    calendarEvent.setDuration(\n                        cursor.getString(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.DURATION\n                            )\n                        )\n                    )\n                    calendarEvent.setEventTimeZone(\n                        cursor.getString(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.EVENT_TIMEZONE\n                            )\n                        )\n                    )\n                    calendarEvent.setEventEndTimeZone(\n                        cursor.getString(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.EVENT_END_TIMEZONE\n                            )\n                        )\n                    )\n                    calendarEvent.setAllDay(\n                        cursor.getInt(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.ALL_DAY\n                            )\n                        )\n                    )\n                    calendarEvent.setAccessLevel(\n                        cursor.getInt(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.ACCESS_LEVEL\n                            )\n                        )\n                    )\n                    calendarEvent.setAvailability(\n                        cursor.getInt(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.AVAILABILITY\n                            )\n                        )\n                    )\n                    calendarEvent.setHasAlarm(\n                        cursor.getInt(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.HAS_ALARM\n                            )\n                        )\n                    )\n                    calendarEvent.setRRule(\n                        cursor.getString(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.RRULE\n                            )\n                        )\n                    )\n                    calendarEvent.setRDate(\n                        cursor.getString(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.RDATE\n                            )\n                        )\n                    )\n                    calendarEvent.setHasAttendeeData(\n                        cursor.getInt(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.HAS_ATTENDEE_DATA\n                            )\n                        )\n                    )\n                    calendarEvent.setLastDate(\n                        cursor.getInt(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.LAST_DATE\n                            )\n                        )\n                    )\n                    calendarEvent.setOrganizer(\n                        cursor.getString(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.ORGANIZER\n                            )\n                        )\n                    )\n                    calendarEvent.setIsOrganizer(\n                        cursor.getString(\n                            cursor.getColumnIndex(\n                                CalendarContract.Events.IS_ORGANIZER\n                            )\n                        )\n                    )\n\n\n                    // ----------------------- 开始查询事件提醒 ------------------------------\n                    val REMINDER_PROJECTION = arrayOf(\n                        CalendarContract.Reminders._ID,  // 在表中的列索引0\n                        CalendarContract.Reminders.EVENT_ID,  // 在表中的列索引1\n                        CalendarContract.Reminders.MINUTES,  // 在表中的列索引2\n                        CalendarContract.Reminders.METHOD\n                    )\n                    val selection2 = \"(\" + CalendarContract.Reminders.EVENT_ID + \" = ?)\"\n                    val selectionArgs2 =\n                        arrayOf<String>(java.lang.String.valueOf(calendarEvent.getId()))\n                    context.getContentResolver().query(\n                        uri2, REMINDER_PROJECTION,\n                        selection2, selectionArgs2, null\n                    ).use { reminderCursor ->\n                        if (null != reminderCursor) {\n                            if (reminderCursor.moveToFirst()) {\n                                val reminders: MutableList<EventReminders> = ArrayList()\n                                do {\n                                    val reminders1: EventReminders =\n                                        EventReminders()\n                                    reminders.add(reminders1)\n                                    reminders1.reminderId =\n                                        reminderCursor.getLong(\n                                            reminderCursor.getColumnIndex(CalendarContract.Reminders._ID)\n                                        )\n\n                                    reminders1.reminderEventID =\n                                        reminderCursor.getLong(\n                                            reminderCursor.getColumnIndex(CalendarContract.Reminders.EVENT_ID)\n                                        )\n\n                                    reminders1.reminderMinute =\n                                        reminderCursor.getInt(\n                                            reminderCursor.getColumnIndex(CalendarContract.Reminders.MINUTES)\n                                        )\n\n                                    reminders1.reminderMethod =\n                                        reminderCursor.getInt(\n                                            reminderCursor.getColumnIndex(CalendarContract.Reminders.METHOD)\n                                        )\n                                } while (reminderCursor.moveToNext())\n                                calendarEvent.setReminders(reminders)\n                            }\n                        }\n                    }\n                } while (cursor.moveToNext())\n                cursor.close()\n            }\n            return result\n        }\n\n        /**\n         * 判断日历账户中是否已经存在此事件\n         *\n         * @param begin 事件开始时间\n         * @param end   事件结束时间\n         * @param title 事件标题\n         */\n        fun isEventAlreadyExist(context: Context, begin: Long, end: Long, title: String?): Boolean {\n            val projection = arrayOf(\n                CalendarContract.Instances.BEGIN,\n                CalendarContract.Instances.END,\n                CalendarContract.Instances.TITLE\n            )\n            val cursor: Cursor? = CalendarContract.Instances.query(\n                context.getContentResolver(), projection, begin, end, title\n            )\n            return (null != cursor && cursor.moveToFirst()\n                    && cursor.getString(\n                cursor.getColumnIndex(CalendarContract.Instances.TITLE)\n            ).equals(title))\n        }\n\n\n        // ------------------------------- 日历事件相关 -----------------------------------\n\n        // ------------------------------- 日历事件相关 -----------------------------------\n        /**\n         * 组装日历事件\n         */\n        private fun setupEvent(calendarEvent: CalendarEvent, event: ContentValues) {\n            // 事件开始时间\n            event.put(CalendarContract.Events.DTSTART, calendarEvent.getStart())\n            // 事件结束时间\n            event.put(CalendarContract.Events.DTEND, calendarEvent.getEnd())\n            // 事件标题\n            event.put(CalendarContract.Events.TITLE, calendarEvent.getTitle())\n            // 事件描述(对应手机系统日历备注栏)\n            event.put(CalendarContract.Events.DESCRIPTION, calendarEvent.getDescription())\n            // 事件地点\n            event.put(CalendarContract.Events.EVENT_LOCATION, calendarEvent.getEventLocation())\n            // 事件时区\n            event.put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().getID())\n            // 定义事件的显示，默认即可\n            event.put(CalendarContract.Events.ACCESS_LEVEL, CalendarContract.Events.ACCESS_DEFAULT)\n            // 事件的状态\n            event.put(CalendarContract.Events.STATUS, 0)\n            // 设置事件提醒警报可用\n            event.put(CalendarContract.Events.HAS_ALARM, 1)\n            // 设置事件忙\n            event.put(\n                CalendarContract.Events.AVAILABILITY,\n                CalendarContract.Events.AVAILABILITY_BUSY\n            )\n            if (null != calendarEvent.getRRule()) {\n                // 设置事件重复规则\n                event.put(\n                    CalendarContract.Events.RRULE,\n                    getFullRRuleForRRule(\n                        calendarEvent.getRRule()!!,\n                        calendarEvent.getStart(), calendarEvent.getEnd()\n                    )\n                )\n            }\n        }\n\n        /**\n         * 获取完整的重复规则(包含终止时间)\n         *\n         * @param rRule     重复规则\n         * @param beginTime 开始时间\n         * @param endTime   结束时间\n         */\n        private fun getFullRRuleForRRule(rRule: String, beginTime: Long, endTime: Long): String? {\n            builder.delete(0, builder.length)\n            return when (rRule) {\n                RRuleConstant.REPEAT_WEEKLY_BY_MO, RRuleConstant.REPEAT_WEEKLY_BY_TU, RRuleConstant.REPEAT_WEEKLY_BY_WE, RRuleConstant.REPEAT_WEEKLY_BY_TH, RRuleConstant.REPEAT_WEEKLY_BY_FR, RRuleConstant.REPEAT_WEEKLY_BY_SA, RRuleConstant.REPEAT_WEEKLY_BY_SU -> builder.append(\n                    rRule\n                ).append(Util.Util.getFinalRRuleMode(endTime)).toString()\n                RRuleConstant.REPEAT_CYCLE_WEEKLY -> builder.append(rRule)\n                    .append(Util.Util.getWeekForDate(beginTime)).append(\"; UNTIL = \")\n                    .append(Util.Util.getFinalRRuleMode(endTime)).toString()\n                RRuleConstant.REPEAT_CYCLE_MONTHLY -> builder.append(rRule)\n                    .append(Util.Util.getDayOfMonth(beginTime))\n                    .append(\"; UNTIL = \").append(Util.Util.getFinalRRuleMode(endTime)).toString()\n                else -> rRule\n            }\n        }\n\n\n        // ------------------------------- 通过Intent启动系统日历 -----------------------------------\n\n        /*\n            日历的Intent对象：\n               动作                  描述                         附加功能\n            ACTION_VIEW        打开指定时间的日历                    无\n            ACTION_VIEW        查看由EVENT_ID指定的事件        开始时间，结束时间\n            ACTION_EDIT        编辑由EVENT_ID指定的事件        开始时间，结束时间\n            ACTION_INSERT      创建一个事件                         所有\n            Intent对象的附加功能：\n            Events.TITLE                                        事件标题\n            CalendarContract.EXTRA_EVENT_BEGIN_TIME             开始时间\n            CalendarContract.EXTRA_EVENT_END_TIME               结束时间\n            CalendarContract.EXTRA_EVENT_ALL_DAY                是否全天\n            Events.EVENT_LOCATION                               事件地点\n            Events.DESCRIPTION                                  事件描述\n            Intent.EXTRA_EMALL                                  受邀者电子邮件,用逗号分隔\n            Events.RRULE                                        事件重复规则\n            Events.ACCESS_LEVEL                                 事件私有还是公有\n            Events.AVAILABILITY                                 预定事件是在忙时计数还是闲时计数\n         */\n\n        // ------------------------------- 通过Intent启动系统日历 -----------------------------------\n        /*\n            日历的Intent对象：\n               动作                  描述                         附加功能\n            ACTION_VIEW        打开指定时间的日历                    无\n            ACTION_VIEW        查看由EVENT_ID指定的事件        开始时间，结束时间\n            ACTION_EDIT        编辑由EVENT_ID指定的事件        开始时间，结束时间\n            ACTION_INSERT      创建一个事件                         所有\n            Intent对象的附加功能：\n            Events.TITLE                                        事件标题\n            CalendarContract.EXTRA_EVENT_BEGIN_TIME             开始时间\n            CalendarContract.EXTRA_EVENT_END_TIME               结束时间\n            CalendarContract.EXTRA_EVENT_ALL_DAY                是否全天\n            Events.EVENT_LOCATION                               事件地点\n            Events.DESCRIPTION                                  事件描述\n            Intent.EXTRA_EMALL                                  受邀者电子邮件,用逗号分隔\n            Events.RRULE                                        事件重复规则\n            Events.ACCESS_LEVEL                                 事件私有还是公有\n            Events.AVAILABILITY                                 预定事件是在忙时计数还是闲时计数\n         */\n        /**\n         * 通过Intent启动系统日历新建事件界面插入新的事件\n         *\n         *\n         * TIP: 这将不再需要声明读写日历数据的权限\n         *\n         * @param beginTime 事件开始时间\n         * @param endTime   事件结束时间\n         * @param title     事件标题\n         * @param des       事件描述\n         * @param location  事件地点\n         * @param isAllDay  事件是否全天\n         */\n        fun startCalendarForIntentToInsert(\n            context: Context, beginTime: Long, endTime: Long,\n            title: String?, des: String?, location: String?,\n            isAllDay: Boolean\n        ) {\n            checkCalendarAccount(context)\n\n\n            // FIXME: 2019/3/6 VIVO手机无法打开界面，找不到对应的Activity  com.bbk.calendar\n            val intent = Intent(Intent.ACTION_INSERT)\n                .setData(CalendarContract.Events.CONTENT_URI)\n                .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime)\n                .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime)\n                .putExtra(CalendarContract.Events.ALL_DAY, isAllDay)\n                .putExtra(CalendarContract.Events.TITLE, title)\n                .putExtra(CalendarContract.Events.DESCRIPTION, des)\n                .putExtra(CalendarContract.Events.EVENT_LOCATION, location)\n            if (null != intent.resolveActivity(context.getPackageManager())) {\n                context.startActivity(intent)\n            }\n        }\n\n        /**\n         * 通过Intent启动系统日历来编辑指定ID的事件\n         *\n         *\n         *\n         * @param eventID 要编辑的事件ID\n         */\n        fun startCalendarForIntentToEdit(context: Context, eventID: Long) {\n            checkCalendarAccount(context)\n            val uri: Uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventID)\n            val intent = Intent(Intent.ACTION_EDIT).setData(uri)\n            if (null != intent.resolveActivity(context.getPackageManager())) {\n                context.startActivity(intent)\n            }\n        }\n\n        /**\n         * 通过Intent启动系统日历来查看指定ID的事件\n         *\n         * @param eventID 要查看的事件ID\n         */\n        fun startCalendarForIntentToView(context: Context, eventID: Long) {\n            checkCalendarAccount(context)\n            val uri: Uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventID)\n            val intent = Intent(Intent.ACTION_VIEW).setData(uri)\n            if (null != intent.resolveActivity(context.getPackageManager())) {\n                context.startActivity(intent)\n            }\n        }\n\n\n        // ----------------------------- 日历账户名相关设置 -----------------------------------\n\n        // ----------------------------- 日历账户名相关设置 -----------------------------------\n        fun getCalendarName(): String? {\n            return CALENDAR_NAME\n        }\n\n        fun setCalendarName(calendarName: String) {\n            CALENDAR_NAME = calendarName\n        }\n\n        fun getCalendarAccountName(): String? {\n            return CALENDAR_ACCOUNT_NAME\n        }\n\n        fun setCalendarAccountName(calendarAccountName: String) {\n            CALENDAR_ACCOUNT_NAME = calendarAccountName\n        }\n\n        fun getCalendarDisplayName(): String? {\n            return CALENDAR_DISPLAY_NAME\n        }\n\n        fun setCalendarDisplayName(calendarDisplayName: String) {\n            CALENDAR_DISPLAY_NAME = calendarDisplayName\n        }\n    }\n\n\n}\n\nclass CalendarEvent {\n    // ----------------------- 事件属性 -----------------------\n\n    // ----------------------- 事件属性 -----------------------\n    /**\n     * 事件在表中的ID\n     */\n    private var id: Long = 0\n\n    /**\n     * 事件所属日历账户的ID\n     */\n    private var calID: Long = 0\n    private var title: String? = null\n    private var description: String? = null\n    private var eventLocation: String? = null\n    private var displayColor = 0\n    private var status = 0\n    private var start: Long = 0\n    private var end: Long = 0\n    private var duration: String? = null\n    private var eventTimeZone: String? = null\n    private var eventEndTimeZone: String? = null\n    private var allDay = 0\n    private var accessLevel = 0\n    private var availability = 0\n    private var hasAlarm = 0\n    private var rRule: String? = null\n    private var rDate: String? = null\n    private var hasAttendeeData = 0\n    private var lastDate = 0\n    private var organizer: String? = null\n    private var isOrganizer: String? = null\n\n\n    // ----------------------------------------------------------------------------------------\n    // ----------------------------------------------------------------------------------------\n    /**\n     * 注：此属性不属于CalendarEvent\n     * 这里只是为了方便构造方法提供事件提醒时间\n     */\n    private var advanceTime = 0\n    // ----------------------------------------------------------------------------------------\n\n\n    // ----------------------------------------------------------------------------------------\n    // ----------------------- 事件提醒属性 -----------------------\n    private var reminders: List<EventReminders?>? = null\n\n    constructor() {}\n\n    /**\n     * 用于方便添加完整日历事件提供一个构造方法\n     *\n     * @param title         事件标题\n     * @param description   事件描述\n     * @param eventLocation 事件地点\n     * @param start         事件开始时间\n     * @param end           事件结束时间  If is not a repeat event, this param is must need else null\n     * @param advanceTime   事件提醒时间[AdvanceTime]\n     * (If you don't need to remind the incoming parameters -2)\n     * @param rRule         事件重复规则  [RRuleConstant]  `null` if dose not need\n     */\n    constructor(\n        title: String?, description: String?, eventLocation: String?,\n        start: Long, end: Long, advanceTime: Int, rRule: String?\n    ) {\n        this.title = title\n        this.description = description\n        this.eventLocation = eventLocation\n        this.start = start\n        this.end = end\n        this.advanceTime = advanceTime\n        this.rRule = rRule\n    }\n\n    fun getAdvanceTime(): Int {\n        return advanceTime\n    }\n\n    fun setAdvanceTime(advanceTime: Int) {\n        this.advanceTime = advanceTime\n    }\n\n    fun getId(): Long {\n        return id\n    }\n\n    fun setId(id: Long) {\n        this.id = id\n    }\n\n    fun getCalID(): Long {\n        return calID\n    }\n\n    fun setCalID(calID: Long) {\n        this.calID = calID\n    }\n\n    fun getTitle(): String? {\n        return title\n    }\n\n    fun setTitle(title: String?) {\n        this.title = title\n    }\n\n    fun getDescription(): String? {\n        return description\n    }\n\n    fun setDescription(description: String?) {\n        this.description = description\n    }\n\n    fun getEventLocation(): String? {\n        return eventLocation\n    }\n\n    fun setEventLocation(eventLocation: String?) {\n        this.eventLocation = eventLocation\n    }\n\n    fun getDisplayColor(): Int {\n        return displayColor\n    }\n\n    fun setDisplayColor(displayColor: Int) {\n        this.displayColor = displayColor\n    }\n\n    fun getStatus(): Int {\n        return status\n    }\n\n    fun setStatus(status: Int) {\n        this.status = status\n    }\n\n    fun getStart(): Long {\n        return start\n    }\n\n    fun setStart(start: Long) {\n        this.start = start\n    }\n\n    fun getEnd(): Long {\n        return end\n    }\n\n    fun setEnd(end: Long) {\n        this.end = end\n    }\n\n    fun getDuration(): String? {\n        return duration\n    }\n\n    fun setDuration(duration: String?) {\n        this.duration = duration\n    }\n\n    fun getEventTimeZone(): String? {\n        return eventTimeZone\n    }\n\n    fun setEventTimeZone(eventTimeZone: String?) {\n        this.eventTimeZone = eventTimeZone\n    }\n\n    fun getEventEndTimeZone(): String? {\n        return eventEndTimeZone\n    }\n\n    fun setEventEndTimeZone(eventEndTimeZone: String?) {\n        this.eventEndTimeZone = eventEndTimeZone\n    }\n\n    fun getAllDay(): Int {\n        return allDay\n    }\n\n    fun setAllDay(allDay: Int) {\n        this.allDay = allDay\n    }\n\n    fun getAccessLevel(): Int {\n        return accessLevel\n    }\n\n    fun setAccessLevel(accessLevel: Int) {\n        this.accessLevel = accessLevel\n    }\n\n    fun getAvailability(): Int {\n        return availability\n    }\n\n    fun setAvailability(availability: Int) {\n        this.availability = availability\n    }\n\n    fun getHasAlarm(): Int {\n        return hasAlarm\n    }\n\n    fun setHasAlarm(hasAlarm: Int) {\n        this.hasAlarm = hasAlarm\n    }\n\n    fun getRRule(): String? {\n        return rRule\n    }\n\n    fun setRRule(rRule: String?) {\n        this.rRule = rRule\n    }\n\n    fun getRDate(): String? {\n        return rDate\n    }\n\n    fun setRDate(rDate: String?) {\n        this.rDate = rDate\n    }\n\n    fun getHasAttendeeData(): Int {\n        return hasAttendeeData\n    }\n\n    fun setHasAttendeeData(hasAttendeeData: Int) {\n        this.hasAttendeeData = hasAttendeeData\n    }\n\n    fun getLastDate(): Int {\n        return lastDate\n    }\n\n    fun setLastDate(lastDate: Int) {\n        this.lastDate = lastDate\n    }\n\n    fun getOrganizer(): String? {\n        return organizer\n    }\n\n    fun setOrganizer(organizer: String?) {\n        this.organizer = organizer\n    }\n\n    fun getIsOrganizer(): String? {\n        return isOrganizer\n    }\n\n    fun setIsOrganizer(isOrganizer: String?) {\n        this.isOrganizer = isOrganizer\n    }\n\n    fun getReminders(): List<EventReminders?>? {\n        return reminders\n    }\n\n    fun setReminders(reminders: List<EventReminders?>?) {\n        this.reminders = reminders\n    }\n\n\n    override fun hashCode(): Int {\n        return (id * 37 + calID).toInt()\n    }\n}\n\n/**\n * 事件提醒\n */\nclass EventReminders {\n    // ----------------------- 事件提醒属性 -----------------------\n    var reminderId: Long = 0\n    var reminderEventID: Long = 0\n    var reminderMinute = 0\n    var reminderMethod = 0\n}\n\nclass Util {\n    object Util {\n        /**\n         * 获取日历事件结束日期\n         *\n         * @param time time in ms\n         */\n        private fun getEndDate(time: Long): String {\n            val date = Date(time)\n            val format = SimpleDateFormat(\"yyyyMMdd\", Locale.getDefault())\n            return format.format(date)\n        }\n\n        /**\n         * 获取最终日历事件重复规则\n         *\n         * @param time time in ms\n         * \"T235959\" [#51][com.kyle.calendarprovider.calendar.RRuleConstant]\n         */\n        fun getFinalRRuleMode(time: Long): String? {\n            return getEndDate(time) + \"T235959Z\"\n        }\n\n        /**\n         * 格式化星期\n         */\n        private fun formatWeek(week: Int): String? {\n            return when (week) {\n                0 -> \"SU\"\n                1 -> \"MO\"\n                2 -> \"TU\"\n                3 -> \"WE\"\n                4 -> \"TH\"\n                5 -> \"FR\"\n                6 -> \"SA\"\n                else -> null\n            }\n        }\n\n        /**\n         * 获取重复周\n         *\n         * @param time time in ms\n         */\n        fun getWeekForDate(time: Long): String? {\n            val date = Date(time)\n            val calendar = Calendar.getInstance()\n            calendar.time = date\n            var week = calendar[Calendar.DAY_OF_WEEK] - 1\n            if (week < 0) {\n                week = 0\n            }\n            return formatWeek(week)\n        }\n\n        /**\n         * 获取指定时间段在一个月中的哪一天\n         *\n         * @param time time in ms\n         */\n        fun getDayOfMonth(time: Long): Int {\n            val date = Date(time)\n            val calendar = Calendar.getInstance()\n            calendar.time = date\n            return calendar[Calendar.DAY_OF_MONTH]\n        }\n\n        /**\n         * check null\n         */\n        fun checkContextNull(context: Context?) {\n            requireNotNull(context) { \"context can not be null\" }\n        }\n    }\n\n\n}\n\n// todo 加入测试\nclass CalendarTest {\n    object Test {\n        fun insert(context: Context) {\n            val calendarEvent = CalendarEvent(\n                \"马上吃饭\",\n                \"吃好吃的\",\n                \"南信院二食堂\",\n                System.currentTimeMillis(),\n                System.currentTimeMillis() + 60000,\n                0, null\n            )\n\n\n            // 添加事件\n            val result: Int = CalendarManager.Manager.addCalendarEvent(context, calendarEvent)\n            if (result == 0) {\n                Toast.makeText(context, \"插入成功\", Toast.LENGTH_SHORT).show()\n            } else if (result == -1) {\n                Toast.makeText(context, \"插入失败\", Toast.LENGTH_SHORT).show()\n            } else if (result == -2) {\n                Toast.makeText(context, \"没有权限\", Toast.LENGTH_SHORT).show()\n            }\n        }\n\n\n        fun delete(context: Context) {\n            // 删除事件\n            // 删除事件\n            val calID2: Long = CalendarManager.Manager.obtainCalendarAccountID(context)\n            val events2: List<CalendarEvent>? =\n                CalendarManager.Manager.queryAccountEvent(context, calID2)\n            if (null != events2) {\n                if (events2.isEmpty()) {\n                    Toast.makeText(context, \"没有事件可以删除\", Toast.LENGTH_SHORT).show()\n                } else {\n                    val eventID = events2[0].getId()\n                    val result2: Int = CalendarManager.Manager.deleteCalendarEvent(context, eventID)\n                    if (result2 == -2) {\n                        Toast.makeText(context, \"没有权限\", Toast.LENGTH_SHORT).show()\n                    } else {\n                        Toast.makeText(context, \"删除成功\", Toast.LENGTH_SHORT).show()\n                    }\n                }\n            } else {\n                Toast.makeText(context, \"查询失败\", Toast.LENGTH_SHORT).show()\n            }\n        }\n\n        fun update(context: Context) {\n            // 更新事件\n            // 更新事件\n            val calID: Long = CalendarManager.Manager.obtainCalendarAccountID(context)\n            val events: List<CalendarEvent>? =\n                CalendarManager.Manager.queryAccountEvent(context, calID)\n            if (null != events) {\n                if (events.isEmpty()) {\n                    Toast.makeText(context, \"没有事件可以更新\", Toast.LENGTH_SHORT).show()\n                } else {\n                    val eventID = events[0].getId()\n                    val result3: Int = CalendarManager.Manager.updateCalendarEventTitle(\n                        context, eventID, \"改吃晚饭的房间第三方监督司法\"\n                    )\n                    if (result3 == 1) {\n                        Toast.makeText(context, \"更新成功\", Toast.LENGTH_SHORT).show()\n                    } else {\n                        Toast.makeText(context, \"更新失败\", Toast.LENGTH_SHORT).show()\n                    }\n                }\n            } else {\n                Toast.makeText(context, \"查询失败\", Toast.LENGTH_SHORT).show()\n            }\n        }\n\n        fun query(context: Context) {\n            // 查询事件\n            // 查询事件\n            val calID4: Long = CalendarManager.Manager.obtainCalendarAccountID(context)\n            val events4: List<CalendarEvent>? =\n                CalendarManager.Manager.queryAccountEvent(context, calID4)\n            val stringBuilder4 = java.lang.StringBuilder()\n            if (null != events4) {\n                for (event in events4) {\n                    stringBuilder4.append(events4.toString()).append(\"\\n\")\n                }\n                Toast.makeText(context, \"查询成功\", Toast.LENGTH_SHORT).show()\n            } else {\n                Toast.makeText(context, \"查询失败\", Toast.LENGTH_SHORT).show()\n            }\n        }\n\n        fun edit(context: Context) {\n            // 启动系统日历进行编辑事件\n            CalendarManager.Manager.startCalendarForIntentToInsert(\n                context, System.currentTimeMillis(),\n                System.currentTimeMillis() + 60000, \"哈\", \"哈哈哈哈\", \"蒂埃纳\",\n                false\n            );\n        }\n\n        fun edit2(context: Context) {\n            // 启动系统日历进行编辑事件\n            if (CalendarManager.Manager.isEventAlreadyExist(\n                    context, 1552986006309L,\n                    155298606609L, \"马上吃饭\"\n                )\n            ) {\n                Toast.makeText(context, \"存在\", Toast.LENGTH_SHORT).show();\n            } else {\n                Toast.makeText(context, \"不存在\", Toast.LENGTH_SHORT).show();\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/calendar/CalenderActivity.kt",
    "content": "package com.yl.lib.privacysentry.calendar\n\nimport android.Manifest\nimport android.os.Bundle\nimport android.widget.Button\nimport androidx.appcompat.app.AppCompatActivity\nimport android.content.pm.PackageManager\nimport androidx.core.app.ActivityCompat\nimport androidx.core.content.ContextCompat\nimport com.yl.lib.privacysentry.R\nimport com.yl.lib.sentry.hook.util.PrivacyLog\n\n\nclass CalenderActivity : AppCompatActivity() {\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_calender)\n\n        findViewById<Button>(R.id.btn_add_calendar).setOnClickListener {\n            CalendarTest.Test.insert(this)\n        }\n\n        findViewById<Button>(R.id.btn_del_calendar).setOnClickListener {\n            CalendarTest.Test.delete(this)\n        }\n\n        findViewById<Button>(R.id.btn_query_calendar).setOnClickListener {\n            CalendarTest.Test.query(this)\n        }\n\n        findViewById<Button>(R.id.btn_edit_calendar).setOnClickListener {\n            CalendarTest.Test.edit(this)\n        }\n\n        findViewById<Button>(R.id.btn_edit2_calendar).setOnClickListener {\n            CalendarTest.Test.edit2(this)\n        }\n\n        if (ContextCompat.checkSelfPermission(\n                this,\n                Manifest.permission.WRITE_CALENDAR\n            ) !== PackageManager.PERMISSION_GRANTED\n        ) {\n            ActivityCompat.requestPermissions(\n                this, arrayOf<String>(\n                    Manifest.permission.WRITE_CALENDAR,\n                    Manifest.permission.READ_CALENDAR\n                ), 1000\n            )\n        }\n    }\n\n    override fun onRequestPermissionsResult(\n        requestCode: Int,\n        permissions: Array<out String>,\n        grantResults: IntArray\n    ) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults)\n        if (requestCode == 1000) {\n            PrivacyLog.i(\"requestPermissions CALENDAR success\")\n        } else {\n            PrivacyLog.i(\"requestPermissions CALENDAR fail\")\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/calendar/RRuleConstant.kt",
    "content": "package com.yl.lib.privacysentry.calendar\n\n/**\n * @author yulun\n * @sinice 2022-01-13 19:57\n */\nclass RRuleConstant {\n\n    companion object {\n        /**\n         * 每天重复 - 永远\n         */\n        val REPEAT_CYCLE_DAILY_FOREVER = \"FREQ=DAILY;INTERVAL=1\"\n\n        /**\n         * 每周某天重复\n         */\n        val REPEAT_CYCLE_WEEKLY = \"FREQ=WEEKLY;INTERVAL=1;WKST=SU;BYDAY=\"\n\n        /**\n         * 每月某天重复\n         */\n        val REPEAT_CYCLE_MONTHLY = \"FREQ=WEEKLY;INTERVAL=2;WKST=SU;BYMONTHDAY =\"\n\n        /**\n         * 每周重复 - 周一\n         */\n        val REPEAT_WEEKLY_BY_MO = \"FREQ=WEEKLY;INTERVAL=1;WKST=MO;BYDAY=MO;UNTIL=\"\n\n        /**\n         * 每周重复 - 周二\n         */\n        val REPEAT_WEEKLY_BY_TU = \"FREQ=WEEKLY;INTERVAL=1;WKST=MO;BYDAY=TU;UNTIL=\"\n\n        /**\n         * 每周重复 - 周三\n         */\n        val REPEAT_WEEKLY_BY_WE = \"FREQ=WEEKLY;INTERVAL=1;WKST=MO;BYDAY=WE;UNTIL=\"\n\n        /**\n         * 每周重复 - 周四\n         */\n        val REPEAT_WEEKLY_BY_TH = \"FREQ=WEEKLY;INTERVAL=1;WKST=MO;BYDAY=TH;UNTIL=\"\n\n        /**\n         * 每周重复 - 周五\n         */\n        val REPEAT_WEEKLY_BY_FR = \"FREQ=WEEKLY;INTERVAL=1;WKST=MO;BYDAY=FR;UNTIL=\"\n\n        /**\n         * 每周重复 - 周六\n         */\n        val REPEAT_WEEKLY_BY_SA = \"FREQ=WEEKLY;INTERVAL=1;WKST=MO;BYDAY=SA;UNTIL=\"\n\n        /**\n         * 每周重复 - 周日\n         */\n        val REPEAT_WEEKLY_BY_SU = \"FREQ=WEEKLY;INTERVAL=1;WKST=MO;BYDAY=SU;UNTIL=\"\n\n        /**\n         * 每年第一天和最后一天 - 永远\n         */\n        val REPEAT_YEARLY_FIRST_AND_LAST_FOREVER = \"FREQ=YEARLY;BYYEARDAY=1,-1\"\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/contact/ContactActivity.kt",
    "content": "package com.yl.lib.privacysentry.contact\n\nimport android.Manifest\nimport android.content.pm.PackageManager\nimport android.os.Build\nimport androidx.appcompat.app.AppCompatActivity\nimport android.os.Bundle\nimport android.widget.Button\nimport androidx.core.app.ActivityCompat\nimport androidx.core.content.ContextCompat\nimport com.yl.lib.privacysentry.R\nimport com.yl.lib.privacysentry.calendar.CalendarTest\nimport com.yl.lib.privacysentry.test.TestReflex\nimport com.yl.lib.sentry.hook.util.PrivacyLog\n\nclass ContactActivity : AppCompatActivity() {\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_contact)\n\n        findViewById<Button>(R.id.btn_get_all_contacts).setOnClickListener {\n            ContactManager.Manager.testGetAllContact(this)\n        }\n\n        findViewById<Button>(R.id.btn_add_contact1).setOnClickListener {\n            ContactManager.Manager.testInsert(this)\n        }\n\n        findViewById<Button>(R.id.btn_add_contact2).setOnClickListener {\n            ContactManager.Manager.testSave(this)\n        }\n\n        if (ContextCompat.checkSelfPermission(\n                this,\n                Manifest.permission.WRITE_CONTACTS\n            ) !== PackageManager.PERMISSION_GRANTED\n        ) {\n\n            var permissions = arrayOf<String>(\n                Manifest.permission.WRITE_CONTACTS,\n                Manifest.permission.READ_CONTACTS,\n                Manifest.permission.READ_CALL_LOG\n            )\n\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                super.requestPermissions(\n                     arrayOf<String>(\n                        Manifest.permission.WRITE_CONTACTS,\n                        Manifest.permission.READ_CONTACTS,\n                        Manifest.permission.READ_CALL_LOG\n                    ), 1000\n                )\n            }\n        }\n    }\n\n    override fun onRequestPermissionsResult(\n        requestCode: Int,\n        permissions: Array<out String>,\n        grantResults: IntArray\n    ) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults)\n        if (requestCode == 1000) {\n            PrivacyLog.i(\"requestPermissions CONTACTS success\")\n        } else {\n            PrivacyLog.i(\"requestPermissions CONTACTS fail\")\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/contact/ContactManager.kt",
    "content": "package com.yl.lib.privacysentry.contact\n\nimport android.Manifest\nimport android.content.*\nimport android.net.Uri\nimport android.provider.ContactsContract\nimport com.yl.lib.sentry.hook.util.PrivacyLog\nimport java.lang.StringBuilder\nimport android.provider.CallLog\n\nimport android.content.pm.PackageManager\nimport android.database.Cursor\nimport androidx.core.app.ActivityCompat\nimport java.text.SimpleDateFormat\nimport java.util.*\n\n\n/**\n * @author yulun\n * @since 2022-01-17 14:42\n */\nclass ContactManager {\n    object Manager{\n        /**\n         * 获取通讯录中所有联系人的简单信息\n         * @throws Throwable\n         */\n        fun testGetAllContact(context: Context) {\n            //获取联系人信息的Uri\n            val uri: Uri = ContactsContract.Contacts.CONTENT_URI\n            //获取ContentResolver\n            val contentResolver: ContentResolver = context.getContentResolver()\n            //查询数据，返回Cursor\n            val cursor = contentResolver.query(uri, null, null, null, null)\n            while (cursor!!.moveToNext()) {\n                val sb = StringBuilder()\n                //获取联系人的ID\n                val contactId =\n                    cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID))\n                //获取联系人的姓名\n                val name =\n                    cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))\n                //构造联系人信息\n                sb.append(\"contactId=\").append(contactId).append(\",Name=\").append(name)\n                //查询电话类型的数据操作\n                val phones = contentResolver.query(\n                    ContactsContract.CommonDataKinds.Phone.CONTENT_URI,\n                    null,\n                    ContactsContract.CommonDataKinds.Phone.CONTACT_ID + \" = \" + contactId,\n                    null, null\n                )\n                while (phones!!.moveToNext()) {\n                    val phoneNumber = phones.getString(\n                        phones.getColumnIndex(\n                            ContactsContract.CommonDataKinds.Phone.NUMBER\n                        )\n                    )\n                    //添加Phone的信息\n                    sb.append(\",Phone=\").append(phoneNumber)\n                }\n                phones.close()\n\n                //查询Email类型的数据操作\n                val emails = contentResolver.query(\n                    ContactsContract.CommonDataKinds.Email.CONTENT_URI,\n                    null,\n                    ContactsContract.CommonDataKinds.Email.CONTACT_ID + \" = \" + contactId,\n                    null, null\n                )\n                while (emails!!.moveToNext()) {\n                    val emailAddress = emails.getString(\n                        emails.getColumnIndex(\n                            ContactsContract.CommonDataKinds.Email.DATA\n                        )\n                    )\n                    //添加Email的信息\n                    sb.append(\",Email=\").append(emailAddress)\n                }\n                emails.close()\n                PrivacyLog.i(\"读取联系人 ${sb.toString()}\")\n            }\n            cursor.close()\n        }\n\n        /**添加联系人的第一种方法：\n         * 首先向RawContacts.CONTENT_URI执行一个空值插入，目的是获取系统返回的rawContactId\n         * 这时后面插入data表的依据，只有执行空值插入，才能使插入的联系人在通讯录里面可见\n         */\n        fun testInsert(context: Context) {\n            val values = ContentValues()\n            //首先向RawContacts.CONTENT_URI执行一个空值插入，目的是获取系统返回的rawContactId\n            val rawContactUri: Uri =\n                context.getContentResolver().insert(ContactsContract.RawContacts.CONTENT_URI, values)!!\n            //获取id\n            val rawContactId = ContentUris.parseId(rawContactUri)\n            //往data表入姓名数据\n            values.clear()\n            values.put(ContactsContract.Contacts.Data.RAW_CONTACT_ID, rawContactId) //添加id\n            values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) //添加内容类型（MIMETYPE）\n            values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, \"凯风自南\") //添加名字，添加到first name位置\n            context.getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values)\n            //往data表入电话数据\n            values.clear()\n            values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId)\n            values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)\n            values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, \"13921009789\")\n            values.put(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE)\n            context.getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values)\n            //往data表入Email数据\n            values.clear()\n            values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId)\n            values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)\n            values.put(ContactsContract.CommonDataKinds.Email.DATA, \"kesenhoo@gmail.com\")\n            values.put(ContactsContract.CommonDataKinds.Email.TYPE, ContactsContract.CommonDataKinds.Email.TYPE_WORK)\n            context.getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values)\n        }\n\n        /**添加联系人的第二种方法：\n         * 批量添加联系人\n         * @throws Throwable\n         */\n        fun testSave(context: Context) {\n            //官方文档位置：reference\\android\\provider\\ContactsContract.RawContacts.html\n            //建立一个ArrayList存放批量的参数\n            val ops = ArrayList<ContentProviderOperation>()\n            val rawContactInsertIndex: Int = ops.size\n            ops.add(\n                ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)\n                    .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)\n                    .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)\n                    .build()\n            )\n            //官方文档位置：reference\\android\\provider\\ContactsContract.Data.html\n            //withValueBackReference后退引用前面联系人的id\n            ops.add(\n                ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)\n                    .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawContactInsertIndex)\n                    .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)\n                    .withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, \"小明\")\n                    .build()\n            )\n            ops.add(\n                ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)\n                    .withValueBackReference(\n                        ContactsContract.Data.RAW_CONTACT_ID, rawContactInsertIndex)\n                    .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)\n                    .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, \"13671323809\")\n                    .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE)\n                    .withValue(ContactsContract.CommonDataKinds.Phone.LABEL, \"手机号\")\n                    .build()\n            )\n            ops.add(\n                ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)\n                    .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawContactInsertIndex)\n                    .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)\n                    .withValue(ContactsContract.CommonDataKinds.Email.DATA, \"kesen@gmail.com\")\n                    .withValue(ContactsContract.CommonDataKinds.Email.TYPE, ContactsContract.CommonDataKinds.Email.TYPE_WORK)\n                    .build()\n            )\n            val results: Array<ContentProviderResult> = context.getContentResolver()\n                .applyBatch(ContactsContract.AUTHORITY, ops)\n            for (result in results) {\n                PrivacyLog.i(\"增加联系人 sb.toString()\")\n            }\n        }\n\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/location/LocationTestActivity.java",
    "content": "package com.yl.lib.privacysentry.location;\n\nimport android.Manifest;\nimport android.content.pm.PackageManager;\nimport android.location.Address;\nimport android.location.Geocoder;\nimport android.location.Location;\nimport android.location.LocationListener;\nimport android.location.LocationManager;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.core.app.ActivityCompat;\n\nimport com.yl.lib.privacysentry.R;\n\nimport java.io.IOException;\nimport java.util.List;\n\n/**\n * @author yulun\n * @since 2022-06-13 15:05\n */\npublic class LocationTestActivity extends AppCompatActivity {\n\n    private Handler mHandler = new Handler(Looper.myLooper());\n    private TextView textView;\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_location_test);\n\n        textView = findViewById(R.id.location_text);\n        // 判断当前是否拥有使用GPS的权限\n        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {\n            // 申请权限\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                requestPermissions(\n                        new String[]{\n                                Manifest.permission.ACCESS_FINE_LOCATION,\n                                Manifest.permission.ACCESS_COARSE_LOCATION,\n                                Manifest.permission.ACCESS_BACKGROUND_LOCATION,\n                        },\n                        100);\n            }\n        } else {\n\n        }\n\n        findViewById(R.id.location).setOnClickListener(v -> {\n            getLocation();\n        });\n\n        findViewById(R.id.last_location).setOnClickListener(v -> {\n            LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);\n            Location l = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);\n            printLocation(l, LocationManager.NETWORK_PROVIDER + \"last\");\n        });\n    }\n\n    private void doNextLocation() {\n        textView.setText(\"location is null ,doNextLocation\");\n        mHandler.postDelayed(locationRunnable, 500);\n    }\n\n    private void getLocation() {\n        // 获取当前位置管理器\n        LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);\n        // 启动位置请求\n        // LocationManager.GPS_PROVIDER GPS定位\n        // LocationManager.NETWORK_PROVIDER 网络定位\n        // LocationManager.PASSIVE_PROVIDER 被动接受定位信息\n        try {\n            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {\n                // TODO: Consider calling\n                //    ActivityCompat#requestPermissions\n                // here to request the missing permissions, and then overriding\n                //   public void onRequestPermissionsResult(int requestCode, String[] permissions,\n                //                                          int[] grantResults)\n                // to handle the case where the user grants the permission. See the documentation\n                // for ActivityCompat#requestPermissions for more details.\n                return;\n            }\n            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1000, new LocationListener() {\n                @Override\n                public void onLocationChanged(@NonNull Location location) {\n                    printLocation(location, LocationManager.GPS_PROVIDER);\n                }\n            });\n            mHandler.postDelayed(locationRunnable, 200);\n\n            locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 1000, new LocationListener() {\n                @Override\n                public void onLocationChanged(@NonNull Location location) {\n                    printLocation(location, LocationManager.NETWORK_PROVIDER);\n                }\n            });\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    private void printLocation(Location location, String provider) {\n        if (location == null) {\n            return;\n        }\n        double lat = location.getLatitude();\n        double lng = location.getLongitude();\n\n        List<Address> list = null;\n        Geocoder gd = new Geocoder(this);\n\n        try {\n            list = gd.getFromLocation(lat, lng, 2);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n\n        // 城市转换\n        String cityHome = \"provider is \" + provider + \"x y is\" + location.getLatitude() + \"__\" + location.getLongitude();\n        if (list != null && list.size() > 0) {\n            for (int i = 0; i < list.size(); i++) {\n                Address address = list.get(i);\n                cityHome = cityHome + \"__\" + address.getLocality();\n            }\n        }\n\n        textView.setText(cityHome);\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n    }\n\n    private Runnable locationRunnable = new Runnable() {\n        @Override\n        public void run() {\n            if (ActivityCompat.checkSelfPermission(LocationTestActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(LocationTestActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {\n                // TODO: Consider calling\n                //    ActivityCompat#requestPermissions\n                // here to request the missing permissions, and then overriding\n                //   public void onRequestPermissionsResult(int requestCode, String[] permissions,\n                //                                          int[] grantResults)\n                // to handle the case where the user grants the permission. See the documentation\n                // for ActivityCompat#requestPermissions for more details.\n                return;\n            }\n            LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);\n            Location lGps = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);\n            if (lGps != null) {\n                printLocation(lGps, LocationManager.GPS_PROVIDER);\n            }\n\n            Location lNet = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);\n            if (lNet != null) {\n                printLocation(lNet, LocationManager.NETWORK_PROVIDER);\n            }\n\n            if (lGps == null && lNet == null) {\n                doNextLocation();\n\n            }\n        }\n    };\n\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/process/MultiProcessB.kt",
    "content": "package com.yl.lib.privacysentry.process\n\nimport android.app.Application\nimport android.app.IntentService\nimport android.content.Intent\nimport android.os.Build\nimport com.yl.lib.privacysentry.test.PrivacyMethod\nimport com.yl.lib.sentry.hook.util.MainProcessUtil\nimport com.yl.lib.sentry.hook.util.PrivacyLog\n\n/**\n * @author yulun\n * @sinice 2021-07-06 15:47\n */\nclass MultiProcessB : IntentService(\"MultiProcessB\") {\n\n    override fun onHandleIntent(intent: Intent?) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n            PrivacyLog.i(\"mutliProcss \" + Application.getProcessName())\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            PrivacyMethod.PrivacyMethod.getIMEI(context = this)\n        }\n        PrivacyMethod.PrivacyMethod.isInstalled(\n            context = this,\n            pkgName = MainProcessUtil.MainProcessChecker.getProcessName(this)\n        )\n    }\n\n    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {\n        return super.onStartCommand(intent, flags, startId)\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/process/MultiProcessC.kt",
    "content": "package com.yl.lib.privacysentry.process\n\nimport android.app.Application\nimport android.app.IntentService\nimport android.app.job.JobParameters\nimport android.app.job.JobService\nimport android.content.Intent\nimport android.os.Build\nimport androidx.annotation.RequiresApi\nimport com.yl.lib.privacysentry.test.PrivacyMethod\nimport com.yl.lib.sentry.hook.util.MainProcessUtil\nimport com.yl.lib.sentry.hook.util.PrivacyLog\n\n/**\n * @author yulun\n * @sinice 2021-07-06 15:47\n */\n@RequiresApi(Build.VERSION_CODES.LOLLIPOP)\nclass MultiProcessC : JobService() {\n\n//    override fun onHandleIntent(intent: Intent?) {\n//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n//            PrivacyLog.i(\"mutliProcss \" + Application.getProcessName())\n//        }\n//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n//            PrivacyMethod.PrivacyMethod.getIMEI(context = this)\n//        }\n//        PrivacyMethod.PrivacyMethod.isInstalled(\n//            context = this,\n//            pkgName = MainProcessUtil.MainProcessChecker.getProcessName(this)\n//        )\n//    }\n\n    override fun onStartJob(params: JobParameters?): Boolean {\n        return  true\n    }\n\n    override fun onStopJob(params: JobParameters?): Boolean {\n        return  true\n    }\n\n    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {\n        return super.onStartCommand(intent, flags, startId)\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/telephony/TelephonyTestActivity.kt",
    "content": "package com.yl.lib.privacysentry.telephony\n\nimport android.Manifest\nimport android.os.Build\nimport androidx.appcompat.app.AppCompatActivity\nimport android.os.Bundle\nimport android.widget.Button\nimport com.yl.lib.privacysentry.R\nimport com.yl.lib.privacysentry.test.PrivacyMethod\nimport com.yl.lib.sentry.hook.util.PrivacyLog\n\nclass TelephonyTestActivity : AppCompatActivity() {\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_telephony_test)\n\n        findViewById<Button>(R.id.btn_deviceId).setOnClickListener {\n            var deviceId = PrivacyMethod.PrivacyMethod.getDeviceId(this)\n            PrivacyLog.i(\"deviceId is $deviceId\")\n\n            var deviceId1 = PrivacyMethod.PrivacyMethod.getDeviceId1(this)\n            PrivacyLog.i(\"deviceId is $deviceId1\")\n\n            PrivacyLog.i(\"deviceId is ${PrivacyMethod.PrivacyMethod.getMeid(this)}\")\n        }\n\n\n        findViewById<Button>(R.id.btn_iccid).setOnClickListener {\n            var iccid = PrivacyMethod.PrivacyMethod.getICCID(this)\n            PrivacyLog.i(\"iccid is $iccid\")\n        }\n\n        findViewById<Button>(R.id.btn_imei).setOnClickListener {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                var imei = PrivacyMethod.PrivacyMethod.getIMEI(this)\n                PrivacyLog.i(\"imei is $imei\")\n            }\n        }\n\n        findViewById<Button>(R.id.btn_sim_operator).setOnClickListener {\n            var simOperator = PrivacyMethod.PrivacyMethod.getSimOperator(this)\n            PrivacyLog.i(\"simOperator is $simOperator\")\n\n            var networkOperator = PrivacyMethod.PrivacyMethod.getNetworkOperator(this)\n            PrivacyLog.i(\"networkOperator is $networkOperator\")\n        }\n\n        findViewById<Button>(R.id.btn_sim_state).setOnClickListener {\n            var simOperator = PrivacyMethod.PrivacyMethod.getSimState(this)\n            PrivacyLog.i(\"simOperator is $simOperator\")\n        }\n\n        //Android Q开始，READ_PHONE_STATE 不再有用，不用全局弹框\n        var permissions = arrayOf(\n            Manifest.permission.READ_PHONE_STATE\n        )\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            requestPermissions(permissions, 1000)\n        }\n    }\n\n    override fun onRequestPermissionsResult(\n        requestCode: Int,\n        permissions: Array<out String>,\n        grantResults: IntArray\n    ) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults)\n        if (requestCode == 1000) {\n            PrivacyLog.i(\"requestPermissions ${permissions[0]} success\")\n        } else {\n            PrivacyLog.i(\"requestPermissions ${permissions[0]} fail\")\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/test/PrivacyMethod.kt",
    "content": "package com.yl.lib.privacysentry.test\n\nimport android.Manifest\nimport android.annotation.SuppressLint\nimport android.app.Activity\nimport android.app.ActivityManager\nimport android.app.Application\nimport android.bluetooth.BluetoothAdapter\nimport android.content.ClipData\nimport android.content.ClipboardManager\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageInfo\nimport android.content.pm.PackageManager\nimport android.hardware.Sensor\nimport android.hardware.SensorEvent\nimport android.hardware.SensorEventCallback\nimport android.hardware.SensorManager\nimport android.net.wifi.ScanResult\nimport android.net.wifi.WifiManager\nimport android.os.Build\nimport android.os.Environment\nimport android.provider.Settings\nimport android.telephony.TelephonyManager\nimport android.telephony.TelephonyManager.SIM_STATE_UNKNOWN\nimport android.text.TextUtils\nimport androidx.annotation.NonNull\nimport androidx.annotation.RequiresApi\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.core.content.ContextCompat.getSystemService\nimport com.yl.lib.privacysentry.MainActivity\nimport com.yl.lib.sentry.hook.util.PrivacyLog\nimport java.io.File\nimport java.net.NetworkInterface\nimport java.net.SocketException\nimport java.util.*\n\n\n/**\n * @author yulun\n * @sinice 2021-11-16 15:08\n */\nclass PrivacyMethod {\n    object PrivacyMethod {\n\n\n        /**TMS START================================**/\n        /**\n         * test for device id\n         */\n        fun getDeviceId(context: Context?): String {\n            if (context == null) {\n                return \"\"\n            }\n//        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {\n//            return \"\"\n//        }\n            var imei = \"\"\n            // 在某些平板上可能会抛出异常\n            try {\n                val mTelephonyMgr = context\n                    .getSystemService(AppCompatActivity.TELEPHONY_SERVICE) as TelephonyManager\n                imei = mTelephonyMgr.getDeviceId()\n            } catch (e: Throwable) {\n                e.printStackTrace()\n            }\n            return imei ?: \"\"\n        }\n\n\n        fun getDeviceId1(context: Context?): String {\n            if (context == null) {\n                return \"\"\n            }\n//        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {\n//            return \"\"\n//        }\n            var imei = \"\"\n            // 在某些平板上可能会抛出异常\n            try {\n                if (checkPermissions(\n                        context,\n                        Manifest.permission.READ_PHONE_STATE\n                    )\n                ) {\n                    val mTelephonyMgr = context\n                        .getSystemService(AppCompatActivity.TELEPHONY_SERVICE) as TelephonyManager\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                        imei = mTelephonyMgr.getDeviceId(1)\n                    }\n                }\n            } catch (e: Throwable) {\n//                e.printStackTrace()\n            }\n            return imei ?: \"\"\n        }\n\n\n        fun getMeid(context: Context?): String {\n            if (context == null) {\n                return \"\"\n            }\n//        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {\n//            return \"\"\n//        }\n            var imei = \"\"\n            // 在某些平板上可能会抛出异常\n            try {\n                val mTelephonyMgr = context\n                    .getSystemService(AppCompatActivity.TELEPHONY_SERVICE) as TelephonyManager\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                    imei = mTelephonyMgr.getMeid()\n                }\n            } catch (e: Throwable) {\n                e.printStackTrace()\n            }\n            return imei ?: \"\"\n        }\n\n        /**\n         * imei\n         */\n        @RequiresApi(Build.VERSION_CODES.O)\n        fun getIMEI(context: Context?): String {\n            if (context == null) {\n                return \"\"\n            }\n//        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {\n//            return \"\"\n//        }\n            var imei = \"\"\n            // 在某些平板上可能会抛出异常\n            try {\n                if (checkPermissions(\n                        context,\n                        Manifest.permission.READ_PHONE_STATE\n                    )\n                ) {\n                    val mTelephonyMgr = context\n                        .getSystemService(AppCompatActivity.TELEPHONY_SERVICE) as TelephonyManager\n                    imei = mTelephonyMgr.imei\n                }\n            } catch (e: Throwable) {\n                e.printStackTrace()\n            }\n            return imei ?: \"\"\n        }\n\n        /**\n         * 获得imsi\n         * @return\n         */\n        @SuppressLint(\"HardwareIds\")\n        fun getIMSI(context: Context?): String? {\n            if (context == null) {\n                return \"\"\n            }\n//        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {\n//            return \"\"\n//        }\n            var imsi = \"\"\n            try {\n                if (checkPermissions(\n                        context,\n                        Manifest.permission.READ_PHONE_STATE\n                    )\n                ) {\n                    val mTelephonyMgr = context\n                        .getSystemService(AppCompatActivity.TELEPHONY_SERVICE) as TelephonyManager\n                        ?: return \"\"\n                    imsi =\n                        mTelephonyMgr.subscriberId\n                }\n            } catch (e: Throwable) {\n                e.printStackTrace()\n            }\n            return imsi ?: \"\"\n        }\n\n        fun getIp(context: Context) {\n            var ip1 = TestInJava.getHostIp()\n            PrivacyLog.i(\"ip1 is $ip1\")\n            Thread {\n                var ip2 = TestInJava.getIpAddress(context)\n                PrivacyLog.i(\" ip2 is $ip2\")\n            }.start()\n        }\n\n\n        // 获取sim卡操作码\n        fun getSimOperator(context: Context?): String? {\n            if (context == null) {\n                return \"\"\n            }\n            var simOperator = \"\"\n            try {\n\n                val mTelephonyMgr = context\n                    .getSystemService(AppCompatActivity.TELEPHONY_SERVICE) as TelephonyManager\n                simOperator =\n                    mTelephonyMgr.simOperator\n            } catch (e: Throwable) {\n                e.printStackTrace()\n            }\n            return simOperator\n        }\n\n        fun getSimState(context: Context?): Int {\n            if (context == null) {\n                return SIM_STATE_UNKNOWN\n            }\n            var simState  = SIM_STATE_UNKNOWN\n//            try {\n\n                val mTelephonyMgr = context\n                    .getSystemService(AppCompatActivity.TELEPHONY_SERVICE) as TelephonyManager\n                simState =\n                    mTelephonyMgr.simState\n//            } catch (e: Throwable) {\n//                e.printStackTrace()\n//            }\n            return simState\n        }\n\n\n        fun getNetworkOperator(context: Context?): String? {\n            if (context == null) {\n                return \"\"\n            }\n            var networkOperator = \"\"\n            try {\n\n                val mTelephonyMgr = context\n                    .getSystemService(AppCompatActivity.TELEPHONY_SERVICE) as TelephonyManager\n                networkOperator =\n                    mTelephonyMgr.networkOperator\n            } catch (e: Throwable) {\n                e.printStackTrace()\n            }\n            return networkOperator\n        }\n\n        /**\n         * 获取sim卡唯一标示\n         *\n         * @param context\n         * @return\n         */\n        @SuppressLint(\"HardwareIds\")\n        fun getICCID(context: Context?): String? {\n            if (context == null) {\n                return \"\"\n            }\n            var iccid = \"\"\n            try {\n\n                val mTelephonyMgr = context\n                    .getSystemService(AppCompatActivity.TELEPHONY_SERVICE) as TelephonyManager\n                    ?: return \"\"\n                iccid =\n                    mTelephonyMgr.simSerialNumber\n            } catch (e: Throwable) {\n                e.printStackTrace()\n            }\n            return iccid ?: \"\"\n        }\n\n        /**TMS END================================**/\n\n\n        val MAC_DEFAULT = \"00:00:00:00:00:00\"\n        val MAC_SYSTEM = \"02:00:00:00:00:00\"\n\n        /**\n         *  wifiInfo.macAddress\n         *  networkInterface.hardwareAddress\n         *  BluetoothAdapter.address\n         */\n        fun getMacRaw(context: Context?): String? {\n            var mac: String? = MAC_DEFAULT\n            if (context == null) {\n                return mac\n            }\n\n            // 蓝牙\n            try {\n                BluetoothAdapter.getDefaultAdapter().address\n            } catch (e: Exception) {\n                e.printStackTrace()\n            }\n\n            try {\n                val wifiManager =\n                    context.applicationContext.getSystemService(AppCompatActivity.WIFI_SERVICE) as WifiManager\n                wifiManager.isWifiEnabled\n                if (wifiManager != null) {\n                    val wifiInfo = wifiManager.connectionInfo\n                    if (wifiInfo != null) {\n                        val result = wifiInfo.macAddress\n                        if (result != null && result.length > 0) {\n                            mac = result\n                            mac = mac.replace(\"\\u0000\".toRegex(), \"\")\n                            mac = mac.replace(\"null\".toRegex(), \"\")\n                        }\n                    }\n                }\n            } catch (e: Exception) {\n                e.printStackTrace()\n            }\n\n            //7.0以上获取不到，获得的都是02:00:00:00:00:00\n            getMacV2()\n            return if (TextUtils.isEmpty(mac)) MAC_DEFAULT else mac\n        }\n\n\n        fun getMacV2(): String? {\n            try {\n                val networkInterfaces: Enumeration<*> = NetworkInterface.getNetworkInterfaces()\n                while (networkInterfaces.hasMoreElements()) {\n                    val networkInterface = networkInterfaces.nextElement() as NetworkInterface\n                    val hardwareAddress = networkInterface.hardwareAddress\n                    if (hardwareAddress != null && hardwareAddress.size != 0) {\n                        val stringBuffer = java.lang.StringBuilder()\n                        val var5 = hardwareAddress.size\n                        for (var6 in 0 until var5) {\n                            val hardwareAddres = hardwareAddress[var6]\n                            stringBuffer.append(String.format(\"%02X:\", hardwareAddres))\n                        }\n                        if (stringBuffer.length > 0) {\n                            stringBuffer.deleteCharAt(stringBuffer.length - 1)\n                        }\n                        return stringBuffer.toString()\n                    }\n                }\n            } catch (e: SocketException) {\n                e.printStackTrace()\n            } catch (e: java.lang.Exception) {\n                e.printStackTrace()\n            }\n            return \"\"\n        }\n\n\n        private fun checkPermissions(context: Context, permission: String): Boolean {\n//            val localPackageManager = context.packageManager ?: return false\n//            return localPackageManager.checkPermission(\n//                permission,\n//                context.packageName\n//            ) == PackageManager.PERMISSION_GRANTED\n            return true\n        }\n\n\n        /**PMS START================================**/\n        /**\n         * 判断指定app应用是否已安装\n         *\n         * @param context 上下文\n         * @param pkgName app 包名\n         * @return 指定app应用是否已安装\n         */\n        fun isInstalled(@NonNull context: Context, pkgName: String): Boolean {\n            if (TextUtils.isEmpty(pkgName)) {\n                return false\n            }\n            // 获取所有已安装程序的包信息\n            val packages = getInstalledPackages(context)\n            for (i in packages.indices) {\n                // 循环判断是否存在指定包名\n                if (packages[i].packageName == pkgName) {\n                    return true\n                }\n            }\n            return false\n        }\n\n        fun isInstalled2(\n            context: Application,\n            @NonNull activity: Activity,\n            pkgName: String\n        ): Boolean {\n            if (TextUtils.isEmpty(pkgName)) {\n                return false\n            }\n            // 获取所有已安装程序的包信息\n            val packageManager = context.packageManager\n            return (packageManager.queryIntentActivities(\n                Intent(\n                    activity,\n                    MainActivity::javaClass.javaClass\n                ), 0\n            )).isNotEmpty()\n        }\n\n        fun isInstalled3(\n            context: Application,\n            pkgName: String\n        ): Boolean {\n            if (TextUtils.isEmpty(pkgName)) {\n                return false\n            }\n            // 获取所有已安装程序的包信息\n            val packageManager = context.packageManager\n            try {\n                var info = packageManager.getPackageInfo(\n                    pkgName, 0\n                )\n                return info != null\n            } catch (e: Exception) {\n                e.printStackTrace()\n            }\n\n            return false\n        }\n\n        fun queryActivityInfo(\n            context: Application,\n            @NonNull activity: Activity\n        ): Boolean {\n\n            // 获取所有已安装程序的包信息\n            val packageManager = context.packageManager\n            return (packageManager.queryIntentActivityOptions(\n                null, null,\n                Intent(\n                    activity,\n                    MainActivity::javaClass.javaClass\n                ), 0\n            )).isNotEmpty()\n        }\n\n        /**\n         * 获取手机中所有安装的app应用\n         *\n         * @param context 上下文\n         * @return 所有安装的app应用信息\n         */\n        private fun getInstalledPackages(@NonNull context: Context): List<PackageInfo> {\n            val packageManager = context.packageManager\n            return packageManager.getInstalledPackages(0)\n        }\n        /**PMS END================================**/\n\n        /**CMS START================================**/\n        fun testHookCms(@NonNull context: Context) {\n            //获取剪切板服务\n            val cm: ClipboardManager? =\n                context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager?\n            cm?.hasPrimaryClip()\n            //设置剪切板内容\n            cm?.setPrimaryClip(ClipData.newPlainText(\"data\", \"yl_vd\"))\n            val cd: ClipData? = cm?.primaryClip\n\n            cm?.text = (\"yl_vd123\")\n            //获取剪切板数据对象\n            cm?.text\n\n            cm?.primaryClipDescription\n            val clipStr = cd?.getItemAt(0)?.text.toString()\n//            PrivacyLog.i(\"testHookCms cms data is :$clipStr\")\n        }\n\n        /**CMS END================================**/\n\n        fun testRunningProcess(@NonNull context: Context) {\n            val manager = context\n                .getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager\n            val runningAppProcesses = manager\n                .runningAppProcesses\n        }\n\n        fun testRunningTask(@NonNull context: Context) {\n            val manager = context\n                .getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager\n            val runningAppProcesses = manager\n                .getRunningTasks(100)\n        }\n\n        fun getAndroidId(context: Context): String? {\n            return \"\" + Settings.Secure.getString(context.contentResolver, \"android_id\")\n        }\n\n        //读取 Android SN(Serial)\n        fun getSerial(): String {\n            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                try {\n                    android.os.Build.getSerial()\n                } catch (e: Exception) {\n                    e.printStackTrace()\n                    return \"\"\n                }\n            } else {\n                android.os.Build.SERIAL\n            }\n        }\n\n        fun testSensor(context: Context) {\n            var sensorManager: SensorManager? = null\n            var callback: SensorEventCallback? = null\n            // 摇一摇注册\n            // 摇一摇注册\n            sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager\n            var sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);\n\n            // 获得重力传感器\n            sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)\n            // 注册\n            var lastUpdateTime: Long = 0\n            var lastX = 0f\n            var lastY = 0f\n            var lastZ = 0f\n            if (sensor != null) {\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                    callback = object : SensorEventCallback() {\n                        override fun onSensorChanged(event: SensorEvent) {\n                            // 现在检测时间\n                            val currentUpdateTime = System.currentTimeMillis()\n                            // 两次检测的时间间隔\n                            val timeInterval: Long = currentUpdateTime - lastUpdateTime\n\n                            // 判断是否达到了检测时间间隔\n                            if (timeInterval < 70) return\n                            // 现在的时间变成last时间\n                            lastUpdateTime = currentUpdateTime\n\n                            // 获得x,y,z坐标\n                            val x = event.values[0]\n                            val y = event.values[1]\n                            val z = event.values[2]\n\n                            // 获得x,y,z的变化值\n                            val deltaX: Float = x - lastX\n                            val deltaY: Float = y - lastY\n                            val deltaZ: Float = z - lastZ\n\n                            // 将现在的坐标变成last坐标\n                            lastX = x\n                            lastY = y\n                            lastZ = z\n//                           PrivacyLog.i(\" 摇了摇 $deltaX,$deltaY,$deltaZ\")\n                            val speed =\n                                Math.sqrt((deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ).toDouble()) / timeInterval * 10000\n                            // 达到速度阀值，发出提示\n                            if (speed >= 3000) {\n                                PrivacyLog.i(\" 摇了摇  😂😂\")\n                                sensorManager.unregisterListener(this)\n                            }\n                        }\n                    }\n                    sensorManager.registerListener(\n                        callback,\n                        sensor,\n                        SensorManager.SENSOR_DELAY_GAME\n                    )\n                }\n            }\n        }\n\n        fun testGetSensorList(context: Context) {\n            var sensorManager: SensorManager? =\n                context.getSystemService(Context.SENSOR_SERVICE) as SensorManager\n            // 获取传感器列表\n            var sensor: List<Sensor>? = sensorManager?.getSensorList(Sensor.TYPE_ACCELEROMETER)\n            PrivacyLog.i(\"sensor size is :${sensor?.size}\")\n        }\n\n        /**\n         * 返回SD卡根路径\n         *\n         * @return\n         */\n        fun getSdcardRoot(context: Context): String? {\n            var path: String? = null\n            if (isSdcardReady()\n                && hasExternalStoragePermission(context)\n            ) {\n                val sdDir = Environment.getExternalStorageDirectory()\n                path = sdDir.absolutePath\n            }\n            var newPath = getPath(context)\n            return path\n        }\n\n        fun isSdcardReady(): Boolean {\n            return Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED\n        }\n\n        fun getPath(context: Context): String? {\n            var dir: File? = null\n            val state = Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED\n            dir = if (state) {\n                if (Build.VERSION.SDK_INT >= 29) {\n                    //Android10之后\n                    context.getExternalFilesDir(null)\n                } else {\n                    Environment.getExternalStorageDirectory()\n                }\n            } else {\n                Environment.getRootDirectory()\n            }\n            return dir.toString()\n        }\n\n        /**\n         * 是否有写扩展存储的权限\n         *\n         * @param context\n         * @return\n         */\n        fun hasExternalStoragePermission(context: Context): Boolean {\n            val perm =\n                context.checkCallingOrSelfPermission(\"android.permission.WRITE_EXTERNAL_STORAGE\")\n            return perm == PackageManager.PERMISSION_GRANTED\n        }\n\n        fun getScanResults(context: Context){\n            val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager?\n            val scanResults: List<ScanResult> = wifiManager!!.scanResults\n            for (scanResult in scanResults) {\n                val ssid: String = scanResult.SSID // Wi-Fi 名称\n                val bssid: String = scanResult.BSSID // Wi-Fi MAC 地址\n                val level: Int = scanResult.level // 信号强度\n                val frequency: Int = scanResult.frequency // 频率\n                val capabilities: String = scanResult.capabilities // 加密类型\n                // 处理扫描结果\n                PrivacyLog.i(\"getScanResults ssid is :$ssid,bssid is :$bssid,level is :$level,frequency is :$frequency,capabilities is :$capabilities\")\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/test/PrivacyProxyCallJava.java",
    "content": "package com.yl.lib.privacysentry.test;\n\nimport android.app.ActivityManager;\nimport android.content.SharedPreferences;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\n\nimport com.yl.lib.privacy_annotation.MethodInvokeOpcode;\nimport com.yl.lib.privacy_annotation.PrivacyClassProxy;\nimport com.yl.lib.privacy_annotation.PrivacyMethodProxy;\nimport com.yl.lib.sentry.hook.PrivacySentry;\nimport com.yl.lib.sentry.hook.printer.BasePrinter;\nimport com.yl.lib.sentry.hook.util.PrivacyProxyUtil;\nimport com.yl.lib.sentry.hook.util.PrivacyUtil;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport kotlin.jvm.JvmStatic;\n\n/**\n * @author yulun\n * @sinice 2022-01-05 19:31\n */\n@PrivacyClassProxy\npublic class PrivacyProxyCallJava {\n\n    public static List<ActivityManager.RunningTaskInfo> getRunningTasks(\n            ActivityManager manager,\n            int maxNum\n    ) {\n        doFilePrinter(\"getRunningTasks\", \"获取当前运行中的任务\", \"\");\n        return manager.getRunningTasks(maxNum);\n    }\n\n    @PrivacyMethodProxy(\n            originalClass = SharedPreferences.Editor.class,\n            originalMethod = \"putString\",\n            originalOpcode = MethodInvokeOpcode.INVOKEINTERFACE\n    )\n    public static SharedPreferences.Editor putString(SharedPreferences.Editor editor, String var1,String var2) {\n       return editor.putString(var1, var2);\n    }\n\n    private static void doFilePrinter(\n            String funName,\n            String methodDocumentDesc,\n            String args\n    ) {\n        for (BasePrinter p :\n                PrivacySentry.Privacy.INSTANCE.getBuilder().getPrinterList()) {\n            p.filePrint(\n                    funName,\n                    methodDocumentDesc + (args.isEmpty() ? \"\" : \"--参数: \" + args),\n                    PrivacyUtil.Util.INSTANCE.getStackTrace()\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/test/PrivacyProxySelfTest.kt",
    "content": "package com.yl.lib.privacysentry.test\n\nimport android.app.ActivityManager\nimport android.content.SharedPreferences\nimport androidx.annotation.Keep\nimport com.yl.lib.privacy_annotation.MethodInvokeOpcode\nimport com.yl.lib.privacy_annotation.PrivacyClassProxy\nimport com.yl.lib.privacy_annotation.PrivacyMethodProxy\nimport com.yl.lib.sentry.hook.util.PrivacyLog\nimport java.net.HttpURLConnection\n\n/**\n * @author yulun\n * @since 2022-06-15 20:01\n */\n@Keep\nclass PrivacyProxySelfTest {\n    // kotlin里实际解析的是这个PrivacyProxyCall$Proxy 内部类\n    @PrivacyClassProxy\n    @Keep\n    object Proxy {\n        // 这个方法的注册放在了PrivacyProxyCall2中，提供了一个java注册的例子\n        @PrivacyMethodProxy(\n            originalClass = ActivityManager::class,\n            originalMethod = \"getRunningTasks\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getRunningTasks123(\n            manager: ActivityManager,\n            maxNum: Int\n        ): List<ActivityManager.RunningTaskInfo?>? {\n            return manager.getRunningTasks(maxNum)\n        }\n\n\n        @PrivacyMethodProxy(\n            originalClass = HttpURLConnection::class,\n            originalMethod = \"connect\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun connect(httpURLConnection: HttpURLConnection) {\n            PrivacyLog.i(\"HttpURLConnection connect\")\n            httpURLConnection.connect()\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = SharedPreferences.Editor::class,\n            originalMethod = \"apply\",\n            originalOpcode = MethodInvokeOpcode.INVOKEINTERFACE\n        )\n        @JvmStatic\n        fun apply(\n            editor: SharedPreferences.Editor\n        ): Unit {\n            editor.apply()\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/test/PrivacyTestMacAddress.java",
    "content": "package com.yl.lib.privacysentry.test;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\n\n/**\n * @author yulun\n * @since 2022-11-18 10:03\n */\npublic class PrivacyTestMacAddress {\n    public static void getMacAddress() {\n        FileInputStream fis_name = null;\n        FileInputStream fis = null;\n        String mac = \"\";\n        //interfaceName可以直接填写 eth0\n        String path = \"sys/class/net/eth0/address\";\n\n        try {\n            fis_name = new FileInputStream(path);\n\n            byte[] buffer_name = new byte[1024 * 8];\n            int byteCount_name = fis_name.read(buffer_name);\n            if (byteCount_name > 0) {\n                mac = new String(buffer_name, 0, byteCount_name, \"utf-8\");\n            }\n            if (mac.length() == 0) {\n                path = \"sys/class/net/eth0/wlan0\";\n                fis = new FileInputStream(path);\n                byte[] buffer = new byte[1024 * 8];\n                int byteCount = fis.read(buffer);\n                if (byteCount > 0) {\n                    mac = new String(buffer, 0, byteCount, \"utf-8\");\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            if (fis_name != null) {\n                try {\n                    fis_name.close();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n            }\n            if (fis != null) {\n                try {\n                    fis.close();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n            }\n\n        }\n\n    }\n\n\n    public static void testNewFile() {\n        String path = \"sys/class/net/eth0/address\";\n        new File(path);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/test/TestBCSeri.java",
    "content": "package com.yl.lib.privacysentry.test;\n\nimport android.os.Build;\n\n/**\n * @author yulun\n * @since 2022-02-25 11:37\n */\npublic class TestBCSeri {\n    public TestBCSeri() {\n\n    }\n\n    public void testAAAA() {\n        String seri = Build.SERIAL;\n    }\n\n    public boolean test1() {\n        return false;\n    }\n\n    public Boolean test2() {\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/test/TestFragmentActivity.kt",
    "content": "package com.yl.lib.privacysentry.test\n\nimport androidx.appcompat.app.AppCompatActivity\nimport android.os.Bundle\nimport com.yl.lib.privacysentry.R\nimport com.yl.lib.privacysentry.test.ui.main.TestPermissionFragment\n\nclass TestFragmentActivity : AppCompatActivity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_test_frament)\n        if (savedInstanceState == null) {\n            supportFragmentManager.beginTransaction()\n                .replace(R.id.container, TestPermissionFragment.newInstance())\n                .commitNow()\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/test/TestInJava.java",
    "content": "package com.yl.lib.privacysentry.test;\n\nimport android.annotation.SuppressLint;\nimport android.app.Activity;\nimport android.content.Context;\nimport android.net.ConnectivityManager;\nimport android.net.NetworkInfo;\nimport android.net.wifi.WifiInfo;\nimport android.net.wifi.WifiManager;\nimport android.os.Build;\nimport android.text.format.Formatter;\n\nimport androidx.annotation.RequiresApi;\n\nimport com.yl.lib.privacy_annotation.MethodInvokeOpcode;\nimport com.yl.lib.privacy_annotation.PrivacyMethodProxy;\nimport com.yl.lib.sentry.hook.PrivacySentry;\nimport com.yl.lib.sentry.hook.PrivacySentryBuilder;\nimport com.yl.lib.sentry.hook.util.PrivacyLog;\n\nimport org.json.JSONObject;\n\nimport java.io.BufferedReader;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.net.HttpURLConnection;\nimport java.net.Inet4Address;\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.util.Enumeration;\n\n/**\n * @author yulun\n * @sinice 2021-12-26 13:30\n */\npublic class TestInJava {\n\n    // 测试hook http url connection\n    // 思考： 如何解决还没有暴露的合规问题？比如某天规则增加了？线上如何做？如何减少调整？你有没有比较好的解决方案?\n    // 由于是基于编译期，那是否可以通过 替换新的产物来解决，通过patch的方式，因为本质上是替换方法的调用\n    // 动态替换拦不了的\n    public static void testHttpUrlConnection() {\n\n        URL url = null;\n        try {\n            url = new URL(\"https://www.baidu.com\");\n            URLConnection rulConnection = url.openConnection();// 此处的urlConnection对象实际上是根据URL的\n            HttpURLConnection httpUrlConnection = (HttpURLConnection) rulConnection;\n            // 设定请求的方法为\"POST\"，默认是GET\n            httpUrlConnection.setRequestMethod(\"POST\");\n            // 设置是否向httpUrlConnection输出，因为这个是post请求，参数要放在\n            // http正文内，因此需要设为true, 默认情况下是false;\n            httpUrlConnection.setDoOutput(true);\n            // 设置是否从httpUrlConnection读入，默认情况下是true;\n            httpUrlConnection.setDoInput(true);\n            // Post 请求不能使用缓存\n            httpUrlConnection.setUseCaches(false);\n            // 设定传送的内容类型是可序列化的java对象\n            // (如果不设此项,在传送序列化对象时,当WEB服务默认的不是这种类型时可能抛java.io.EOFException)\n            httpUrlConnection.setRequestProperty(\"Content-type\", \"application/x-java-serialized-object\");\n            // 连接，从上述url.openConnection()至此的配置必须要在connect之前完成，\n            httpUrlConnection.connect();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n\n    }\n\n    public static void testInitJava() {\n        // 完整版配置\n        PrivacySentryBuilder builder = new PrivacySentryBuilder()\n                // 自定义文件结果的输出名\n                .configResultFileName(\"demo_test\")\n                //自定义检测时间，也支持主动停止检测 PrivacySentry.Privacy.stopWatch()\n                .configWatchTime(10 * 60 * 1000);\n        // 添加默认结果输出，包含log输出和文件输出\n        PrivacySentry.Privacy.INSTANCE.init(null, builder);\n    }\n\n    // 获取有限网IP\n    public static String getHostIp() {\n        try {\n            for (Enumeration<NetworkInterface> en = NetworkInterface\n                    .getNetworkInterfaces(); en.hasMoreElements(); ) {\n                NetworkInterface intf = en.nextElement();\n                for (Enumeration<InetAddress> enumIpAddr = intf\n                        .getInetAddresses(); enumIpAddr.hasMoreElements(); ) {\n                    InetAddress inetAddress = enumIpAddr.nextElement();\n                    if (!inetAddress.isLoopbackAddress()\n                            && inetAddress instanceof Inet4Address) {\n                        return inetAddress.getHostAddress();\n                    }\n                }\n            }\n        } catch (Exception ex) {\n            ex.printStackTrace();\n        }\n        return \"0.0.0.0\";\n    }\n\n    @SuppressLint(\"MissingPermission\")\n    public static String getIpAddress(Context context) {\n        if (context == null) {\n            return \"\";\n        }\n        ConnectivityManager conManager = (ConnectivityManager) context\n                .getSystemService(Context.CONNECTIVITY_SERVICE);\n        try {\n            NetworkInfo info = conManager.getActiveNetworkInfo();\n            if (info != null && info.isConnected()) {\n                // 3/4g网络\n                if (info.getType() == ConnectivityManager.TYPE_MOBILE) {\n                    return getHostIp();\n                } else if (info.getType() == ConnectivityManager.TYPE_WIFI) {\n                    getIPByWifiInfo(context);\n                    return getOutNetIP(); // 外网地址\n                } else if (info.getType() == ConnectivityManager.TYPE_ETHERNET) {\n                    // 以太网有限网络\n                    return getHostIp();\n                }\n            }\n        } catch (Exception e) {\n            return \"\";\n        }\n        return \"\";\n    }\n\n    /**\n     * 获取外网ip地址（非本地局域网地址）的方法\n     */\n    public static String getOutNetIP() {\n        String ipAddress = \"\";\n        try {\n            String address = \"https://ip.taobao.com/service/getIpInfo2.php?ip=myip\";\n            URL url = new URL(address);\n            HttpURLConnection connection = (HttpURLConnection) url\n                    .openConnection();\n            connection.setUseCaches(false);\n            connection.setRequestMethod(\"GET\");\n            connection.setRequestProperty(\"user-agent\",\n                    \"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.7 Safari/537.36\"); //设置浏览器ua 保证不出现503\n            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {\n                InputStream in = connection.getInputStream();\n                // 将流转化为字符串\n                BufferedReader reader = new BufferedReader(\n                        new InputStreamReader(in));\n                String tmpString;\n                StringBuilder retJSON = new StringBuilder();\n                while ((tmpString = reader.readLine()) != null) {\n                    retJSON.append(tmpString + \"\\n\");\n                }\n                JSONObject jsonObject = new JSONObject(retJSON.toString());\n                String code = jsonObject.getString(\"code\");\n                PrivacyLog.Log.e(\"提示：\" + retJSON.toString());\n                if (code.equals(\"0\")) {\n                    JSONObject data = jsonObject.getJSONObject(\"data\");\n                    ipAddress = data.getString(\"ip\")/* + \"(\" + data.getString(\"country\")\n              + data.getString(\"area\") + \"区\"\n              + data.getString(\"region\") + data.getString(\"city\")\n              + data.getString(\"isp\") + \")\"*/;\n                    PrivacyLog.Log.e(\"您的IP地址是：\" + ipAddress);\n                } else {\n                    PrivacyLog.Log.e(\"IP接口异常，无法获取IP地址！\");\n                }\n            } else {\n                PrivacyLog.Log.e(\"网络连接异常，无法获取IP地址！\");\n            }\n        } catch (Exception e) {\n            PrivacyLog.Log.e(\"获取IP地址时出现异常，异常信息是：\" + e.toString());\n        }\n        return ipAddress;\n    }\n\n    public static void getIPByWifiInfo(Context context){\n        WifiManager wifiMgr = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);\n        WifiInfo wifiInfo = wifiMgr.getConnectionInfo();\n        int ipAddress = wifiInfo.getIpAddress();\n        String ip = Formatter.formatIpAddress(ipAddress);\n    }\n\n    public static void testReflexClipManager() {\n        try {\n            Class<?> companionClass = Class.forName(\"com.yl.lib.sentry.hook.util.PrivacyClipBoardManager$Companion\");\n            Class<?> privacyClipBoardManagerClass = Class.forName(\"com.yl.lib.sentry.hook.util.PrivacyClipBoardManager\");\n            Field companion = privacyClipBoardManagerClass.getField(\"Companion\");\n            Method m1 = companionClass.getDeclaredMethod(\"isReadClipboardEnable\", (Class[]) null);\n            boolean open = (Boolean) m1.invoke(companion.get(null), (Object[]) null);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static void testReflexClipManagerOpen() {\n        try {\n            Class<?> companionClass = Class.forName(\"com.yl.lib.sentry.hook.util.PrivacyClipBoardManager$Companion\");\n            Class<?> privacyClipBoardManagerClass = Class.forName(\"com.yl.lib.sentry.hook.util.PrivacyClipBoardManager\");\n            Field companion = privacyClipBoardManagerClass.getField(\"Companion\");\n            Method m1 = companionClass.getDeclaredMethod(\"openReadClipboard\", (Class[]) null);\n            m1.invoke(companion.get(null), (Object[]) null);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static void testReflexClipManagerClose() {\n        try {\n            Class<?> companionClass = Class.forName(\"com.yl.lib.sentry.hook.util.PrivacyClipBoardManager$Companion\");\n            Class<?> privacyClipBoardManagerClass = Class.forName(\"com.yl.lib.sentry.hook.util.PrivacyClipBoardManager\");\n            Field companion = privacyClipBoardManagerClass.getField(\"Companion\");\n            Method m1 = companionClass.getDeclaredMethod(\"closeReadClipboard\", (Class[]) null);\n            m1.invoke(companion.get(null), (Object[]) null);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/test/TestOaidGetter.java",
    "content": "package com.yl.lib.privacysentry.test;\n\nimport android.content.Context;\nimport android.os.Build;\n\nimport org.json.JSONObject;\n\nimport java.lang.reflect.Method;\n\n/**\n * @author yulun\n * @since 2024-04-25 15:43\n */\npublic class TestOaidGetter {\n    public static String getOaid(Context var0) {\n        try {\n            String var1 = \"com.android.id.impl.IdProviderImpl\";\n            Class var2 = a(var0, var1);\n            Object var3 = var2.newInstance();\n            String var4 = \"getOAID\";\n            Method var5 = var2.getMethod(var4, Context.class);\n            String var6 = \"getAAID\";\n            Method var7 = var2.getMethod(var6, Context.class);\n            String var8 = \"getVAID\";\n            Method var9 = var2.getMethod(var8, Context.class);\n            Object var10 = var9.invoke(var3, var0);\n            Object var11 = var7.invoke(var3, var0);\n            Object var12 = var5.invoke(var3, var0);\n            JSONObject var13 = new JSONObject();\n            var13.put(\"joad\", var12);\n            var13.put(\"jvad\", var11);\n            var13.put(\"jaad\", var10);\n            return var13.toString();\n        } catch (Throwable var14) {\n            return \"\";\n        }\n    }\n\n    private static Class<?> a(Context var0, String var1) throws ClassNotFoundException {\n        if (var1 != null && var1.trim().length() != 0) {\n            boolean var2 = var0 != null;\n            if (var2 && Build.VERSION.SDK_INT >= 29) {\n                try {\n                    return var0.getClassLoader().loadClass(var1);\n                } catch (ClassNotFoundException var5) {\n                }\n            }\n\n            try {\n                return Class.forName(var1);\n            } catch (ClassNotFoundException var4) {\n                throw new ClassNotFoundException(\"loadClass fail \", var4);\n            }\n        } else {\n            throw new ClassNotFoundException(\"class is empty\");\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/test/TestReflex.kt",
    "content": "package com.yl.lib.privacysentry.test\n\nimport android.content.Context\nimport android.content.Context.TELEPHONY_SERVICE\nimport android.telephony.TelephonyManager\nimport com.yl.lib.sentry.hook.util.ReflectUtils\nimport java.lang.reflect.InvocationTargetException\nimport java.lang.reflect.Method\n\n/**\n * @author yulun\n * @since 2022-10-20 10:21\n */\nclass TestReflex {\n    fun test(var1: Context) {\n        val var2 = var1.applicationContext.getSystemService(TELEPHONY_SERVICE) as TelephonyManager\n        try {\n            val ctm = Class.forName(\"android.telephony.TelephonyManager\")\n            val method = ctm.getDeclaredMethod(\"getDeviceId\", Int::class.javaPrimitiveType)\n            method.invoke(var2, 2)\n        } catch (e: ClassNotFoundException) {\n            e.printStackTrace()\n        } catch (e: NoSuchMethodException) {\n            e.printStackTrace()\n        } catch (e: IllegalAccessException) {\n            e.printStackTrace()\n        } catch (e: InvocationTargetException) {\n            e.printStackTrace()\n        } catch (e: SecurityException){\n            e.printStackTrace()\n        }\n    }\n\n    fun test2(obj: Any,\n              name: String,\n              types: Array<Class<*>>,\n              args: Array<Any?>){\n        try {\n            val method: Method? =\n               getMethod(obj.javaClass.superclass, name, types)\n            if (null != method) {\n                method.isAccessible = true\n                method.invoke(obj, *args)\n            }\n        } catch (t: Throwable) {\n            t.printStackTrace()\n        }\n    }\n\n    private fun getMethod(klass: Class<*>, name: String, types: Array<Class<*>>): Method? {\n        return try {\n            klass.getDeclaredMethod(name, *types)\n        } catch (e: NoSuchMethodException) {\n            val parent = klass.superclass ?: return null\n            getMethod(parent, name, types)\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/test/TestReflexJava.java",
    "content": "package com.yl.lib.privacysentry.test;\n\nimport static android.content.Context.INPUT_METHOD_SERVICE;\nimport static android.content.Context.TELEPHONY_SERVICE;\n\nimport android.content.Context;\nimport android.inputmethodservice.InputMethodService;\nimport android.os.Build;\nimport android.telephony.TelephonyManager;\nimport android.text.TextUtils;\nimport android.view.inputmethod.InputMethodManager;\n\nimport androidx.annotation.RequiresApi;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\n\n/**\n * @author yulun\n * @since 2022-10-20 10:27\n */\npublic class TestReflexJava {\n    public String c(Context var0, String var1) {\n        String var2 = null;\n\n        try {\n            TelephonyManager var3 = (TelephonyManager) var0.getSystemService(TELEPHONY_SERVICE);\n            Method var4 = TelephonyManager.class.getMethod(\"getSubscriberId\");\n            var2 = (String) var4.invoke(var3);\n        } catch (Throwable var5) {\n        }\n\n        if (TextUtils.isEmpty(var2)) {\n            var2 = var1;\n        }\n\n        return var2;\n    }\n\n    public  String reflex1(Context var0, String var1) {\n        String var2 = null;\n        try {\n            TelephonyManager var3 = (TelephonyManager) var0.getSystemService(TELEPHONY_SERVICE);\n            Method var4 = TelephonyManager.class.getMethod(\"getSubscriberId\");\n            reflex2(var4, var3);\n        } catch (Throwable var5) {\n        }\n        return var2;\n    }\n\n    public  void reflex2(Method var4, Object var3) {\n\n        try {\n            String var2 = (String) var4.invoke(var3);\n        } catch (Throwable var5) {\n        }\n    }\n\n    public String reflex3(Context var0, String var1) {\n        String var2 = null;\n        try {\n            InputMethodManager var3 = (InputMethodManager) var0.getSystemService(INPUT_METHOD_SERVICE);\n            Method var4 = InputMethodManager.class.getMethod(\"dasdsad\");\n            var4.invoke(var3 );\n        } catch (Throwable var5) {\n        }\n        return var2;\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.M)\n    public void test(Context var1) {\n        TelephonyManager var2 = (TelephonyManager) var1.getApplicationContext().getSystemService(TELEPHONY_SERVICE);\n        try {\n            Class ctm = Class.forName(\"android.telephony.TelephonyManager\");\n            Method method = ctm.getDeclaredMethod(\"getSubscriberId\");\n            method.invoke(var2);\n        } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/test/TestService.kt",
    "content": "package com.yl.lib.privacysentry.test\n\n/**\n * @author yulun\n * @since 2025-05-14 10:07\n */\nimport android.app.Service\nimport android.content.Intent\nimport android.os.IBinder\n\nclass TestService : Service() {\n\n    override fun onBind(intent: Intent): IBinder {\n        TODO(\"Return the communication channel to the service.\")\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/test/constructor/TestFileConstructor.java",
    "content": "package com.yl.lib.privacysentry.test.constructor;\n\nimport android.os.Build;\nimport android.system.Os;\n\nimport androidx.annotation.NonNull;\n\nimport java.io.File;\nimport java.io.FileDescriptor;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * @author yulun\n * @since 2022-11-22 16:36\n */\npublic class TestFileConstructor {\n    public TestFileConstructor(@NonNull File file) throws IOException {\n        if (file == null) {\n            throw new NullPointerException(\"file cannot be null\");\n        }\n        file.getAbsolutePath();\n    }\n\n    public TestFileConstructor(@NonNull String filename) throws IOException {\n        if (filename == null) {\n            throw new NullPointerException(\"filename cannot be null\");\n        }\n        new File(filename).getAbsolutePath();\n    }\n\n    public TestFileConstructor(@NonNull FileDescriptor fileDescriptor) throws IOException {\n        if (fileDescriptor == null) {\n            throw new NullPointerException(\"fileDescriptor cannot be null\");\n        }\n        boolean isFdDuped = false;\n        try {\n            // asm 7.1的时候，这个写法，会导致数组越界，升级到9.1好了，浪费了一天时间 坑爹\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n                fileDescriptor = Os.dup(fileDescriptor);\n            }\n                isFdDuped = true;\n        } catch (Exception e) {\n            throw new IOException(\"Failed to duplicate file descriptor\", e);\n        }\n\n        FileInputStream in = null;\n        try {\n            in = new FileInputStream(fileDescriptor);\n        } finally {\n            if (isFdDuped) {\n                in.close();\n            }\n        }\n    }\n\n    public TestFileConstructor(@NonNull InputStream inputStream) throws IOException {\n        if (inputStream == null) {\n            throw new NullPointerException(\"inputStream cannot be null\");\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/yl/lib/privacysentry/test/ui/main/TestPermissionFragment.kt",
    "content": "package com.yl.lib.privacysentry.test.ui.main\n\nimport android.Manifest\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.fragment.app.Fragment\nimport com.yl.lib.privacysentry.R\nimport com.yl.lib.sentry.hook.util.PrivacyLog\nimport com.yl.lib.sentry.hook.util.PrivacyUtil\n\nclass TestPermissionFragment : Fragment() {\n\n    companion object {\n        fun newInstance() = TestPermissionFragment()\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        val requestMultiplePermissions = registerForActivityResult(\n            ActivityResultContracts.RequestMultiplePermissions()\n        ) { permissions ->\n            Thread.currentThread().stackTrace\n            permissions.entries.forEach {\n\n                PrivacyLog.i(\"TestFragmentFragment ${PrivacyUtil.Util.getStackTrace()} \\n ${it.key} = ${it.value}\")\n            }\n        }\n\n        requestMultiplePermissions.launch(\n            arrayOf(\n                Manifest.permission.CAMERA\n            )\n        )\n    }\n\n    override fun onCreateView(\n        inflater: LayoutInflater, container: ViewGroup?,\n        savedInstanceState: Bundle?\n    ): View {\n        return inflater.inflate(R.layout.fragment_main, container, false)\n    }\n\n    override fun onActivityCreated(savedInstanceState: Bundle?) {\n        super.onActivityCreated(savedInstanceState)\n    }\n\n    override fun onStart() {\n        super.onStart()\n        requestPermissions(arrayOf(\n            Manifest.permission.BODY_SENSORS\n        ),10000)\n    }\n}"
  },
  {
    "path": "app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path\n        android:fillColor=\"#3DDC84\"\n        android:pathData=\"M0,0h108v108h-108z\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <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\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"85.84757\"\n                android:endY=\"92.4963\"\n                android:startX=\"42.9492\"\n                android:startY=\"49.59793\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\" />\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        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\"\n        android:strokeWidth=\"1\"\n        android:strokeColor=\"#00000000\" />\n</vector>"
  },
  {
    "path": "app/src/main/res/layout/activity_calender.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    tools:context=\".calendar.CalenderActivity\">\n\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"vertical\">\n\n            <Button\n                android:id=\"@+id/btn_add_calendar\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"新增一个日历事件\" />\n\n            <Button\n                android:id=\"@+id/btn_query_calendar\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"查询一个日历事件\" />\n\n            <Button\n                android:id=\"@+id/btn_del_calendar\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"删除一个日历事件\" />\n\n            <Button\n                android:id=\"@+id/btn_edit_calendar\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"编辑一个日历事件\" />\n\n            <Button\n                android:id=\"@+id/btn_edit2_calendar\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"编辑一个日历事件2\" />\n        </LinearLayout>\n\n    </ScrollView>\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_contact.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    tools:context=\".contact.ContactActivity\">\n\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"vertical\">\n\n            <Button\n                android:id=\"@+id/btn_get_all_contacts\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"获取所有联系人\" />\n\n            <Button\n                android:id=\"@+id/btn_add_contact1\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"添加联系人1\" />\n\n            <Button\n                android:id=\"@+id/btn_add_contact2\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"添加联系人2\" />\n\n        </LinearLayout>\n\n    </ScrollView>\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_location_test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    tools:context=\".location.LocationTestActivity\">\n\n    <TextView\n        android:id=\"@+id/location_text\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"100dp\"\n        android:layout_gravity=\"center\" />\n\n    <Button\n        android:id=\"@+id/location\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        android:layout_marginLeft=\"20dp\"\n        android:layout_marginTop=\"20dp\"\n        android:layout_marginRight=\"20dp\"\n        android:text=\"开始定位\" />\n\n    <Button\n        android:id=\"@+id/last_location\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        android:layout_marginLeft=\"20dp\"\n        android:layout_marginTop=\"20dp\"\n        android:layout_marginRight=\"20dp\"\n        android:text=\"获取上次定位的位置\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    tools:context=\".MainActivity\">\n\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"vertical\"\n            android:paddingLeft=\"20dp\"\n            android:paddingRight=\"20dp\">\n\n            <Button\n                android:id=\"@+id/btn_androidId\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"测试AndroidId\" />\n\n\n            <Button\n                android:id=\"@+id/btn_mac_address\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"测试mac地址和IP地址\" />\n\n\n            <Button\n                android:id=\"@+id/btn_installed_packages\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"测试已安装包列表\" />\n\n            <Button\n                android:id=\"@+id/btn_main_process\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"判断主进程，跳过当前敏感函数\" />\n\n            <Button\n                android:id=\"@+id/btn_clipboard_readable\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"设置系统剪贴板开关\" />\n\n            <Button\n                android:id=\"@+id/btn_test_cms\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"测试剪贴板服务\" />\n\n            <Button\n                android:id=\"@+id/btn_test_ams_process\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"测试读取运行中的进程\" />\n\n            <Button\n                android:id=\"@+id/btn_test_processB\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"启动进程B\" />\n\n            <Button\n                android:id=\"@+id/btn_test_lib_method\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"测试子lib的方法\" />\n\n            <Button\n                android:id=\"@+id/btn_test_sn\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"测试Android SN\" />\n\n\n\n            <Button\n                android:id=\"@+id/btn_thread_cache\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"多线程缓存测试\" />\n\n            <Button\n                android:id=\"@+id/btn_test_sensor\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"注册传感器\" />\n\n            <Button\n                android:id=\"@+id/btn_test_get_all_sensor\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"获取传感器列表\" />\n\n            <Button\n                android:id=\"@+id/btn_test_ExternalStorageDirectory\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"获取SD卡根路径\" />\n\n            <Button\n                android:id=\"@+id/btn_test_reflex\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"测试反射\" />\n\n\n            <Button\n                android:id=\"@+id/btn_to_telephony\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"跳转Telephony页面\" />\n\n            <Button\n                android:id=\"@+id/btn_to_calender\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"跳转日历测试Ac\" />\n\n            <Button\n                android:id=\"@+id/btn_to_contact\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"跳转联系人测试Ac\" />\n\n            <Button\n                android:id=\"@+id/btn_to_location\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"跳转定位测试页面\" />\n\n            <Button\n                android:id=\"@+id/btn_to_fragment\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"跳转fragment申请权限页面\" />\n\n\n            <Button\n                android:id=\"@+id/btn_test_oaid\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:onClick=\"testGetOaid\"\n                android:text=\"反射测试获取OAID\" />\n\n\n            <Button\n                android:id=\"@+id/btn_force_finish\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"结束当前检测-导出结果\" />\n\n        </LinearLayout>\n\n    </ScrollView>\n\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_telephony_test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    tools:context=\".telephony.TelephonyTestActivity\">\n\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"vertical\"\n            android:paddingLeft=\"20dp\"\n            android:paddingRight=\"20dp\">\n\n            <Button\n                android:id=\"@+id/btn_deviceId\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"测试DeviceId\" />\n\n\n            <Button\n                android:id=\"@+id/btn_imei\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"测试Imei\" />\n\n            <Button\n                android:id=\"@+id/btn_imsi\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"测试Imsi\" />\n\n            <Button\n                android:id=\"@+id/btn_iccid\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"测试sim卡唯一标识符\" />\n\n            <Button\n                android:id=\"@+id/btn_sim_operator\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"测试sim卡操作码？\" />\n\n            <Button\n                android:id=\"@+id/btn_sim_state\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"测试sim状态码？\" />\n\n        </LinearLayout>\n\n    </ScrollView>\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_test_frament.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/container\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".test.TestFragmentActivity\" />"
  },
  {
    "path": "app/src/main/res/layout/fragment_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/test_frament\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:id=\"@+id/message\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"TestPermissionFragment\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"purple_200\">#FFBB86FC</color>\n    <color name=\"purple_500\">#FF6200EE</color>\n    <color name=\"purple_700\">#FF3700B3</color>\n    <color name=\"teal_200\">#FF03DAC5</color>\n    <color name=\"teal_700\">#FF018786</color>\n    <color name=\"black\">#FF000000</color>\n    <color name=\"white\">#FFFFFFFF</color>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">PrivacySentry</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/themes.xml",
    "content": "<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <!-- Base application theme. -->\n    <style name=\"Theme.PrivacySentry\" parent=\"Theme.MaterialComponents.DayNight.DarkActionBar\">\n        <!-- Primary brand color. -->\n        <item name=\"colorPrimary\">@color/purple_500</item>\n        <item name=\"colorPrimaryVariant\">@color/purple_700</item>\n        <item name=\"colorOnPrimary\">@color/white</item>\n        <!-- Secondary brand color. -->\n        <item name=\"colorSecondary\">@color/teal_200</item>\n        <item name=\"colorSecondaryVariant\">@color/teal_700</item>\n        <item name=\"colorOnSecondary\">@color/black</item>\n        <!-- Status bar color. -->\n        <item name=\"android:statusBarColor\" tools:targetApi=\"l\">?attr/colorPrimaryVariant</item>\n        <!-- Customize your theme here. -->\n    </style>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-night/themes.xml",
    "content": "<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <!-- Base application theme. -->\n    <style name=\"Theme.PrivacySentry\" parent=\"Theme.MaterialComponents.DayNight.DarkActionBar\">\n        <!-- Primary brand color. -->\n        <item name=\"colorPrimary\">@color/purple_200</item>\n        <item name=\"colorPrimaryVariant\">@color/purple_700</item>\n        <item name=\"colorOnPrimary\">@color/black</item>\n        <!-- Secondary brand color. -->\n        <item name=\"colorSecondary\">@color/teal_200</item>\n        <item name=\"colorSecondaryVariant\">@color/teal_200</item>\n        <item name=\"colorOnSecondary\">@color/black</item>\n        <!-- Status bar color. -->\n        <item name=\"android:statusBarColor\" tools:targetApi=\"l\">?attr/colorPrimaryVariant</item>\n        <!-- Customize your theme here. -->\n    </style>\n</resources>"
  },
  {
    "path": "app/src/test/java/com/yl/lib/privacysentry/ExampleUnitTest.kt",
    "content": "package com.yl.lib.privacysentry\n\nimport org.junit.Test\n\nimport org.junit.Assert.*\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * See [testing documentation](http://d.android.com/tools/testing).\n */\nclass ExampleUnitTest {\n    @Test\n    fun addition_isCorrect() {\n        assertEquals(4, 2 + 2)\n    }\n}"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\nbuildscript {\n    apply from: \"config.gradle\"\n    rootProject.ext.kotlin_version = \"1.8.10\"\n    repositories {\n        if (rootProject.ext.build.local_debug) {\n            maven { url uri(rootProject.ext.build.local_debug_dir) }\n        }\n        maven { url 'https://jitpack.io' }\n        mavenCentral()\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath \"com.android.tools.build:gradle:8.2.0\"\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n        classpath \"com.github.allenymt.PrivacySentry:plugin-sentry:${rootProject.ext.publish_config[\"version\"]}\"\n    }\n}\n\nallprojects {\n    repositories {\n        if (rootProject.ext.build.local_debug) {\n            maven { url uri(rootProject.ext.build.local_debug_dir) }\n        }\n        maven { url 'https://jitpack.io' }\n        mavenCentral()\n        google()\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "config.gradle",
    "content": "ext {\n    publish_config = [\n            version : '1.3.7_v820_beta4'\n    ]\n    build = [\n            local_debug: false,\n            local_debug_dir : \"${rootProject.projectDir}/local\",\n    ]\n\n}"
  },
  {
    "path": "docs/README.md",
    "content": "# PrivacySentry 文档中心\n\n欢迎访问 PrivacySentry 项目文档！\n\n## 📚 文档列表\n\n### 架构文档\n\n- **[架构深度分析 (Markdown)](./architecture.md)** - 完整的技术架构解析文档\n- **[架构深度分析 (HTML)](./architecture.html)** - 美化的在线阅读版本\n\n## 📖 文档内容概览\n\n### 架构深度分析\n\n这份文档提供了 PrivacySentry 项目的完整技术解析，包括：\n\n1. **执行摘要** - 项目概述和核心技术栈\n2. **架构总体设计** - 四层架构模型和模块说明\n3. **注解层详细分析** - 核心注解系统的设计和实现\n4. **插件层详细分析** - Gradle 插件和字节码转换机制\n5. **Hook 层详细分析** - 运行时 SDK 和缓存机制\n6. **代理层详细分析** - 预置的 API 拦截实现\n7. **完整数据流分析** - 从注解到字节码替换的完整流程\n8. **关键交互关系** - 模块间的依赖关系\n9. **高级特性** - 反射 Hook、多进程支持等\n10. **生成的产物分析** - privacy_hook.json 和 Excel 文件\n11. **完整工作流程示例** - 实际拦截案例\n12. **架构优势和设计模式** - 设计模式和核心优势\n13. **使用建议和最佳实践** - 集成步骤和调试技巧\n\n## 🚀 快速开始\n\n### 阅读 Markdown 版本\n\n```bash\n# 在终端中阅读\ncat docs/architecture.md\n\n# 或在支持 Markdown 的编辑器中打开\ncode docs/architecture.md\n```\n\n### 阅读 HTML 版本\n\n```bash\n# 在浏览器中打开\nopen docs/architecture.html\n```\n\n## 📝 文档信息\n\n- **文档版本**: v1.0\n- **最后更新**: 2024-12-30\n- **项目版本**: PrivacySentry 1.3.7_v820_beta4\n- **作者**: Claude Code 自动生成\n\n## 🔗 相关链接\n\n- [项目主页](https://github.com/allenymt/PrivacySentry)\n- [主 README](../README.md)\n- [CLAUDE.md](../CLAUDE.md) - Claude Code 开发指南\n\n## 📄 许可证\n\n本文档遵循项目的 MIT 许可证。\n"
  },
  {
    "path": "docs/architecture.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>PrivacySentry 架构深度分析</title>\n    <style>\n        :root {\n            --primary-color: #2c3e50;\n            --secondary-color: #3498db;\n            --accent-color: #e74c3c;\n            --success-color: #27ae60;\n            --warning-color: #f39c12;\n            --bg-color: #f8f9fa;\n            --code-bg: #282c34;\n            --border-color: #dee2e6;\n        }\n\n        * {\n            margin: 0;\n            padding: 0;\n            box-sizing: border-box;\n        }\n\n        body {\n            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB',\n                         'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n            line-height: 1.8;\n            color: var(--primary-color);\n            background-color: var(--bg-color);\n        }\n\n        .container {\n            max-width: 1200px;\n            margin: 0 auto;\n            padding: 20px;\n        }\n\n        header {\n            background: linear-gradient(135deg, var(--secondary-color), var(--primary-color));\n            color: white;\n            padding: 60px 20px;\n            text-align: center;\n            margin-bottom: 40px;\n            box-shadow: 0 4px 6px rgba(0,0,0,0.1);\n        }\n\n        header h1 {\n            font-size: 2.5em;\n            margin-bottom: 10px;\n            font-weight: 700;\n        }\n\n        header p {\n            font-size: 1.2em;\n            opacity: 0.9;\n        }\n\n        nav {\n            background: white;\n            padding: 20px;\n            margin-bottom: 30px;\n            border-radius: 8px;\n            box-shadow: 0 2px 4px rgba(0,0,0,0.05);\n            position: sticky;\n            top: 20px;\n            z-index: 100;\n        }\n\n        nav h3 {\n            margin-bottom: 15px;\n            color: var(--secondary-color);\n            font-size: 1.2em;\n        }\n\n        nav ul {\n            list-style: none;\n            display: grid;\n            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n            gap: 10px;\n        }\n\n        nav a {\n            color: var(--primary-color);\n            text-decoration: none;\n            padding: 8px 12px;\n            display: block;\n            border-radius: 4px;\n            transition: all 0.3s;\n            border-left: 3px solid transparent;\n        }\n\n        nav a:hover {\n            background: var(--bg-color);\n            border-left-color: var(--secondary-color);\n            padding-left: 16px;\n        }\n\n        section {\n            background: white;\n            padding: 40px;\n            margin-bottom: 30px;\n            border-radius: 8px;\n            box-shadow: 0 2px 8px rgba(0,0,0,0.08);\n        }\n\n        h2 {\n            color: var(--primary-color);\n            font-size: 2em;\n            margin-bottom: 20px;\n            padding-bottom: 10px;\n            border-bottom: 3px solid var(--secondary-color);\n        }\n\n        h3 {\n            color: var(--secondary-color);\n            font-size: 1.6em;\n            margin: 30px 0 15px;\n        }\n\n        h4 {\n            color: var(--primary-color);\n            font-size: 1.3em;\n            margin: 25px 0 12px;\n        }\n\n        p {\n            margin-bottom: 15px;\n        }\n\n        pre {\n            background: var(--code-bg);\n            color: #abb2bf;\n            padding: 20px;\n            border-radius: 6px;\n            overflow-x: auto;\n            margin: 20px 0;\n            border-left: 4px solid var(--secondary-color);\n        }\n\n        code {\n            font-family: 'Consolas', 'Monaco', 'Courier New', monospace;\n            font-size: 0.9em;\n        }\n\n        p code, li code {\n            background: #f4f4f4;\n            color: var(--accent-color);\n            padding: 2px 6px;\n            border-radius: 3px;\n            font-size: 0.9em;\n        }\n\n        table {\n            width: 100%;\n            border-collapse: collapse;\n            margin: 20px 0;\n            box-shadow: 0 2px 4px rgba(0,0,0,0.05);\n        }\n\n        th {\n            background: var(--secondary-color);\n            color: white;\n            padding: 12px;\n            text-align: left;\n            font-weight: 600;\n        }\n\n        td {\n            padding: 12px;\n            border-bottom: 1px solid var(--border-color);\n        }\n\n        tr:hover {\n            background: var(--bg-color);\n        }\n\n        .highlight-box {\n            background: #fff3cd;\n            border-left: 4px solid var(--warning-color);\n            padding: 15px 20px;\n            margin: 20px 0;\n            border-radius: 4px;\n        }\n\n        .success-box {\n            background: #d4edda;\n            border-left: 4px solid var(--success-color);\n            padding: 15px 20px;\n            margin: 20px 0;\n            border-radius: 4px;\n        }\n\n        .info-box {\n            background: #d1ecf1;\n            border-left: 4px solid var(--secondary-color);\n            padding: 15px 20px;\n            margin: 20px 0;\n            border-radius: 4px;\n        }\n\n        .diagram {\n            background: white;\n            border: 2px solid var(--border-color);\n            padding: 20px;\n            margin: 20px 0;\n            border-radius: 8px;\n            font-family: 'Courier New', monospace;\n            overflow-x: auto;\n            white-space: pre;\n            line-height: 1.5;\n        }\n\n        ul, ol {\n            margin-left: 30px;\n            margin-bottom: 15px;\n        }\n\n        li {\n            margin-bottom: 8px;\n        }\n\n        .badge {\n            display: inline-block;\n            padding: 4px 10px;\n            border-radius: 12px;\n            font-size: 0.85em;\n            font-weight: 600;\n            margin-right: 8px;\n        }\n\n        .badge-primary {\n            background: var(--secondary-color);\n            color: white;\n        }\n\n        .badge-success {\n            background: var(--success-color);\n            color: white;\n        }\n\n        .badge-warning {\n            background: var(--warning-color);\n            color: white;\n        }\n\n        .badge-danger {\n            background: var(--accent-color);\n            color: white;\n        }\n\n        footer {\n            text-align: center;\n            padding: 40px;\n            color: #6c757d;\n            border-top: 1px solid var(--border-color);\n            margin-top: 40px;\n        }\n\n        @media (max-width: 768px) {\n            header h1 {\n                font-size: 1.8em;\n            }\n\n            section {\n                padding: 20px;\n            }\n\n            nav ul {\n                grid-template-columns: 1fr;\n            }\n        }\n\n        .scroll-top {\n            position: fixed;\n            bottom: 30px;\n            right: 30px;\n            background: var(--secondary-color);\n            color: white;\n            width: 50px;\n            height: 50px;\n            border-radius: 50%;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            cursor: pointer;\n            box-shadow: 0 4px 8px rgba(0,0,0,0.2);\n            transition: all 0.3s;\n            opacity: 0;\n            pointer-events: none;\n        }\n\n        .scroll-top.visible {\n            opacity: 1;\n            pointer-events: all;\n        }\n\n        .scroll-top:hover {\n            background: var(--primary-color);\n            transform: translateY(-5px);\n        }\n    </style>\n</head>\n<body>\n    <header>\n        <div class=\"container\">\n            <h1>PrivacySentry 架构深度分析</h1>\n            <p>Android 隐私合规检测工具的完整技术解析</p>\n        </div>\n    </header>\n\n    <div class=\"container\">\n        <nav>\n            <h3>📑 目录导航</h3>\n            <ul>\n                <li><a href=\"#summary\">执行摘要</a></li>\n                <li><a href=\"#part1\">第一部分：架构总体设计</a></li>\n                <li><a href=\"#part2\">第二部分：注解层详细分析</a></li>\n                <li><a href=\"#part3\">第三部分：插件层详细分析</a></li>\n                <li><a href=\"#part4\">第四部分：Hook 层详细分析</a></li>\n                <li><a href=\"#part5\">第五部分：代理层详细分析</a></li>\n                <li><a href=\"#part6\">第六部分：完整数据流分析</a></li>\n                <li><a href=\"#part7\">第七部分：关键交互关系</a></li>\n                <li><a href=\"#part8\">第八部分：高级特性</a></li>\n                <li><a href=\"#part9\">第九部分：生成的产物分析</a></li>\n                <li><a href=\"#part10\">第十部分：工作流程示例</a></li>\n                <li><a href=\"#part11\">第十一部分：架构优势和设计模式</a></li>\n                <li><a href=\"#part12\">第十二部分：使用建议和最佳实践</a></li>\n            </ul>\n        </nav>\n\n        <section id=\"summary\">\n            <h2>执行摘要</h2>\n            <p>PrivacySentry 是一套完整的 Android 隐私合规检测解决方案，采用<strong>编译期注解 + 字节码插桩 + 运行时 Hook</strong> 的三层架构设计。总共包含 67 个 Kotlin/Java 文件，通过 ASM 和 Booster 框架在编译期对敏感 API 调用进行拦截和代理，运行时记录完整的隐私合规数据。</p>\n\n            <h3>核心技术栈</h3>\n            <ul>\n                <li><span class=\"badge badge-primary\">Gradle Plugin</span> 基于 AGP 8.0+</li>\n                <li><span class=\"badge badge-primary\">字节码操作</span> ASM 9.1</li>\n                <li><span class=\"badge badge-primary\">Transform 框架</span> Booster</li>\n                <li><span class=\"badge badge-primary\">语言</span> Kotlin 1.8.10 + Java 8</li>\n                <li><span class=\"badge badge-primary\">最低支持</span> Android API 19</li>\n            </ul>\n        </section>\n\n        <section id=\"part1\">\n            <h2>第一部分：架构总体设计</h2>\n\n            <h3>1.1 四层架构模型</h3>\n            <div class=\"diagram\">\n┌─────────────────────────────────────────────────────────────┐\n│  4. 代理层 (privacy-proxy)                                  │\n│  - 预置的 API 拦截实现                                      │\n│  - 使用注解声明拦截规则                                    │\n└─────────────────────────────────────────────────────────────┘\n                           ↑\n┌─────────────────────────────────────────────────────────────┐\n│  3. Hook 层 (hook-sentry)                                   │\n│  - 运行时 SDK 初始化和管理                                  │\n│  - 缓存机制（内存、磁盘）                                  │\n│  - 日志收集和文件输出                                      │\n└─────────────────────────────────────────────────────────────┘\n                           ↑\n┌─────────────────────────────────────────────────────────────┐\n│  2. 插件层 (plugin-sentry)                                  │\n│  - Gradle 编译期 Transform 执行                             │\n│  - ASM 字节码操作和修改                                     │\n│  - Booster 框架集成                                        │\n└─────────────────────────────────────────────────────────────┘\n                           ↑\n┌─────────────────────────────────────────────────────────────┐\n│  1. 注解层 (privacy-annotation)                             │\n│  - 编译期注解定义                                          │\n│  - 运行时不可见 (@Retention(CLASS))                        │\n└─────────────────────────────────────────────────────────────┘\n            </div>\n\n            <h3>1.2 项目模块说明</h3>\n            <table>\n                <tr>\n                    <th>模块</th>\n                    <th>路径</th>\n                    <th>职责</th>\n                    <th>关键类</th>\n                </tr>\n                <tr>\n                    <td><strong>privacy-annotation</strong></td>\n                    <td>/privacy-annotation</td>\n                    <td>注解定义</td>\n                    <td>@PrivacyMethodProxy, @PrivacyClassProxy</td>\n                </tr>\n                <tr>\n                    <td><strong>plugin-sentry</strong></td>\n                    <td>/plugin-sentry</td>\n                    <td>Gradle 插件和字节码转换</td>\n                    <td>PrivacySentryPlugin, Transform 类</td>\n                </tr>\n                <tr>\n                    <td><strong>hook-sentry</strong></td>\n                    <td>/hook-sentry</td>\n                    <td>运行时 SDK 和日志收集</td>\n                    <td>PrivacySentry, 缓存管理器</td>\n                </tr>\n                <tr>\n                    <td><strong>privacy-proxy</strong></td>\n                    <td>/privacy-proxy</td>\n                    <td>预置的拦截实现</td>\n                    <td>PrivacyProxyCall, 各种 Proxy 类</td>\n                </tr>\n                <tr>\n                    <td><strong>privacy-replace</strong></td>\n                    <td>/privacy-replace</td>\n                    <td>类替换功能（已废弃）</td>\n                    <td>-</td>\n                </tr>\n            </table>\n        </section>\n\n        <section id=\"part2\">\n            <h2>第二部分：注解层详细分析</h2>\n\n            <h3>2.1 核心注解系统</h3>\n            <p><strong>文件位置</strong>: <code>privacy-annotation/src/main/java/com/yl/lib/privacy_annotation/</code></p>\n\n            <h4>2.1.1 @PrivacyMethodProxy - 方法代理注解</h4>\n            <pre><code>@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.CLASS)\npublic @interface PrivacyMethodProxy {\n    Class originalClass();              // 原始类\n    String originalMethod() default \"\"; // 原始方法名\n    int originalOpcode() default MethodInvokeOpcode.INVOKESTATIC;\n    boolean ignoreClass() default false;\n}</code></pre>\n\n            <div class=\"info-box\">\n                <strong>用途</strong>: 标记需要代理的方法。编译期插件通过该注解收集需要拦截的方法列表。\n            </div>\n\n            <h4>关键字段说明</h4>\n            <ul>\n                <li><code>originalClass</code>: 要拦截的目标类</li>\n                <li><code>originalMethod</code>: 要拦截的目标方法名</li>\n                <li><code>originalOpcode</code>: 调用方式（静态/虚实例/接口等）</li>\n                <li><code>ignoreClass</code>: 允许只按方法名和签名匹配</li>\n            </ul>\n\n            <h4>2.1.2 MethodInvokeOpcode 定义</h4>\n            <table>\n                <tr>\n                    <th>Opcode</th>\n                    <th>值</th>\n                    <th>含义</th>\n                    <th>使用场景</th>\n                </tr>\n                <tr>\n                    <td><code>INVOKEVIRTUAL</code></td>\n                    <td>182</td>\n                    <td>调用实例方法</td>\n                    <td>普通实例方法</td>\n                </tr>\n                <tr>\n                    <td><code>INVOKESPECIAL</code></td>\n                    <td>183</td>\n                    <td>调用特殊方法</td>\n                    <td>私有方法、构造函数</td>\n                </tr>\n                <tr>\n                    <td><code>INVOKESTATIC</code></td>\n                    <td>184</td>\n                    <td>调用静态方法</td>\n                    <td>静态方法</td>\n                </tr>\n                <tr>\n                    <td><code>INVOKEINTERFACE</code></td>\n                    <td>185</td>\n                    <td>调用接口方法</td>\n                    <td>接口实现</td>\n                </tr>\n            </table>\n        </section>\n\n        <section id=\"part3\">\n            <h2>第三部分：插件层详细分析</h2>\n\n            <h3>3.1 Gradle 插件入口</h3>\n            <p><strong>文件</strong>: <code>PrivacySentryPlugin.kt</code></p>\n\n            <pre><code>class PrivacySentryPlugin : Plugin&lt;Project&gt; {\n    override fun apply(project: Project) {\n        // 1. 创建配置扩展点\n        var extension = project.extensions.create(\"privacy\", PrivacyExtension::class.java)\n\n        if (!extension.enablePrivacy) {\n            return  // 功能关闭时直接返回\n        }\n\n        // 2. 只对 App 插件生效\n        if (project.plugins.hasPlugin(AppPlugin::class.java)) {\n            // 3. 清空历史数据\n            HookMethodManager.MANAGER.clear()\n            HookFieldManager.MANAGER.clear()\n\n            // 4. 注册 Transform\n            registerTransform(project)\n\n            // 5. 设置 Manifest 和 Assets 处理任务\n            setupTasks(project)\n        }\n    }\n}</code></pre>\n\n            <h3>3.2 两阶段 Transform 架构</h3>\n            <div class=\"diagram\">\n编译期流程：\n┌──────────────────────────────────┐\n│  输入：所有 .class 文件和 Jar    │\n└──────────────┬───────────────────┘\n               │\n        ┌──────▼─────────────┐\n        │  第一阶段（预处理） │\n        │  Pre-Transform     │\n        └──────┬─────────────┘\n               │\n    ┌──────────┴──────────────┐\n    │                         │\n┌───▼────────────────┐   ┌───▼──────────────────┐\n│MethodProxy         │   │ ClassProxy           │\n│ CollectTransform   │   │ CollectTransform     │\n│ (收集方法拦截规则) │   │ (收集类替换规则)    │\n└───┬────────────────┘   └───┬──────────────────┘\n    │                         │\n    │ 结果写入：              │\n    │ HookMethodManager       │ ReplaceClassManager\n    │\n        ┌──────▼────────────────┐\n        │  第二阶段（执行替换）  │\n        │  Transform            │\n        └──────┬────────────────┘\n               │\n    ┌──────────┼──────────────┬──────────────┐\n    │          │              │              │\n┌───▼───┐ ┌───▼───┐ ┌───────▼──┐ ┌────────▼───┐\n│Method │ │Field  │ │ Class    │ │ Service    │\n│Hook   │ │Proxy  │ │ Proxy    │ │ Hook       │\n└───┬───┘ └───┬───┘ └───────┬──┘ └────────┬───┘\n    │         │            │             │\n    └─────────┴─��──────────┴─────────────┘\n               │\n        ┌──────▼──────────┐\n        │ FlushHookData   │\n        │ Transform       │\n        └────────┬────────┘\n                 │\n    ┌────────────▼──────────────┐\n    │ 输出：修改后的 .class 和  │\n    │ privacy_hook.json         │\n    └───────────────────────────┘\n            </div>\n\n            <h3>3.3 字节码替换原理</h3>\n            <p><strong>原始代码</strong>:</p>\n            <pre><code>ActivityManager manager = ...;\nList&lt;RunningTaskInfo&gt; tasks = manager.getRunningTasks(maxNum);</code></pre>\n\n            <p><strong>原始字节码</strong>:</p>\n            <pre><code>ALOAD 1              // 加载 manager 对象\nILOAD 2              // 加载 maxNum 参数\nINVOKEVIRTUAL ActivityManager.getRunningTasks</code></pre>\n\n            <p><strong>替换后的字节码</strong>:</p>\n            <pre><code>ALOAD 1              // 加载 manager 对象\nILOAD 2              // 加载 maxNum ��数\nINVOKESTATIC PrivacyProxyCall$Proxy.getRunningTasks</code></pre>\n        </section>\n\n        <section id=\"part4\">\n            <h2>第四部分：Hook 层详细分析</h2>\n\n            <h3>4.1 运行时 SDK 初始化</h3>\n            <p><strong>文件</strong>: <code>hook-sentry/src/main/java/com/yl/lib/sentry/hook/PrivacySentry.kt</code></p>\n\n            <div class=\"highlight-box\">\n                <strong>⚠️ 初始化时机</strong>: 建议在 <code>Application.attachBaseContext()</code> 中第一个调用\n            </div>\n\n            <pre><code>class MyApplication : Application() {\n    override fun attachBaseContext(base: Context?) {\n        super.attachBaseContext(base)\n\n        // 必须最先初始化\n        PrivacySentry.Privacy.init(\n            this,\n            PrivacySentryBuilder()\n                .enableFileResult(true)\n                .syncDebug(true)\n                .configWatchTime(30 * 60 * 1000)\n        )\n    }\n\n    override fun onCreate() {\n        super.onCreate()\n        // 隐私协议确认后调用\n        showPrivacyDialog {\n            PrivacySentry.Privacy.updatePrivacyShow()\n        }\n    }\n}</code></pre>\n\n            <h3>4.2 三层缓存架构</h3>\n            <div class=\"diagram\">\n┌───────────────────────────────────────────┐\n│ CachePrivacyManager（统一入口）           │\n└───────────────┬─────────────────────────────┘\n                │\n    ┌───────────┼───────────┬───────────┐\n    │           │           │           │\n    ▼           ▼           ▼           ▼\n┌─────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐\n│ Memory  │ │TimeLess  │ │Permanent │ │TimeLess  │\n│ Cache   │ │Memory    │ │ Disk     │ │ Disk     │\n│         │ │Cache     │ │ Cache    │ │ Cache    │\n└────┬────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘\n     │           │            │           │\n     └───────────┴────────────┴───────────┘\n                │\n     ┌──────────▼──────────┐\n     │ SharedPreferences   │\n     │ (磁盘持久化)       │\n     └─────────────────────┘\n            </div>\n\n            <h3>4.3 缓存类型和使用场景</h3>\n            <table>\n                <tr>\n                    <th>缓存类型</th>\n                    <th>生命周期</th>\n                    <th>使用场景</th>\n                    <th>实现类</th>\n                </tr>\n                <tr>\n                    <td><strong>内存缓存</strong></td>\n                    <td>进程级别</td>\n                    <td>IMEI、IMSI、MEID、Serial 等设备标识</td>\n                    <td>MemoryCache</td>\n                </tr>\n                <tr>\n                    <td><strong>时效内存缓存</strong></td>\n                    <td>时间限制</td>\n                    <td>位置信息、WiFi 信息</td>\n                    <td>TimeLessMemoryCache</td>\n                </tr>\n                <tr>\n                    <td><strong>永久磁盘缓存</strong></td>\n                    <td>持久化</td>\n                    <td>Android ID、设备名等不可变字段</td>\n                    <td>DiskCache</td>\n                </tr>\n                <tr>\n                    <td><strong>时效磁盘缓存</strong></td>\n                    <td>磁盘+时效</td>\n                    <td>需要定期刷新的敏感信息</td>\n                    <td>TimeLessDiskCache</td>\n                </tr>\n            </table>\n        </section>\n\n        <section id=\"part5\">\n            <h2>第五部分：代理层详细分析</h2>\n\n            <h3>5.1 支持的敏感 API 类别</h3>\n            <table>\n                <tr>\n                    <th>类别</th>\n                    <th>API 示例</th>\n                    <th>��截方式</th>\n                </tr>\n                <tr>\n                    <td><strong>任务管理</strong></td>\n                    <td>ActivityManager.getRunningTasks()</td>\n                    <td>返回空列表/代理</td>\n                </tr>\n                <tr>\n                    <td><strong>剪贴板</strong></td>\n                    <td>ClipboardManager.getPrimaryClip()</td>\n                    <td>代理访问</td>\n                </tr>\n                <tr>\n                    <td><strong>蓝牙</strong></td>\n                    <td>BluetoothAdapter.getAddress()</td>\n                    <td>代理访问</td>\n                </tr>\n                <tr>\n                    <td><strong>WiFi</strong></td>\n                    <td>WifiManager.getConnectionInfo()</td>\n                    <td>代理访问</td>\n                </tr>\n                <tr>\n                    <td><strong>位置</strong></td>\n                    <td>LocationManager.getLastKnownLocation()</td>\n                    <td>缓存+代理</td>\n                </tr>\n                <tr>\n                    <td><strong>设备标识</strong></td>\n                    <td>Build.getSerial()</td>\n                    <td>缓存+代理</td>\n                </tr>\n                <tr>\n                    <td><strong>应用列表</strong></td>\n                    <td>PackageManager.getInstalledPackages()</td>\n                    <td>返回空列表</td>\n                </tr>\n                <tr>\n                    <td><strong>通话信息</strong></td>\n                    <td>TelephonyManager.getDeviceId()</td>\n                    <td>缓存+代理</td>\n                </tr>\n                <tr>\n                    <td><strong>传感器</strong></td>\n                    <td>SensorManager.registerListener()</td>\n                    <td>记录日志</td>\n                </tr>\n                <tr>\n                    <td><strong>权限</strong></td>\n                    <td>requestPermissions()</td>\n                    <td>记录日志</td>\n                </tr>\n            </table>\n\n            <h3>5.2 代理实现示例</h3>\n            <pre><code>@PrivacyClassProxy\nobject PrivacyProxyCall {\n    @PrivacyMethodProxy(\n        originalClass = ActivityManager::class,\n        originalMethod = \"getRunningTasks\",\n        originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n    )\n    @JvmStatic\n    fun getRunningTasks(\n        manager: ActivityManager,\n        maxNum: Int\n    ): List&lt;RunningTaskInfo&gt; {\n        doFilePrinter(\"getRunningTasks\", \"当前运行中的任务\")\n\n        // 核心逻辑：根据隐私协议状态决定返回值\n        if (PrivacySentry.Privacy.inDangerousState()) {\n            return emptyList()  // 危险状态返回空\n        }\n\n        return manager.getRunningTasks(maxNum)\n    }\n}</code></pre>\n        </section>\n\n        <section id=\"part6\">\n            <h2>第六部分：完整数据流分析</h2>\n\n            <h3>6.1 从注解定义到字节码替换的完整流程</h3>\n            <div class=\"diagram\">\n开发阶段\n────────────────────────────────\n│\n1️⃣ 开发者编写代理方法\n   ├─ 使用 @PrivacyClassProxy 标注类\n   ├─ 使用 @PrivacyMethodProxy 标注方法\n   └─ 编译生成 class 文件（带注解元数据）\n        │\n        ▼\n编译期间\n────────────────────────────────\n│\n2️⃣ Gradle 执行 PrivacySentryPlugin\n   ├─ 清空历史 Manager\n   └─ 注册 Transform 任务\n        │\n        ▼\n3️⃣ 第一阶段：预处理 (Pre-Transform)\n   ├─ MethodProxyCollectTransform\n   │  ├─ 扫描所有 class 文件\n   │  ├─ 找到 @PrivacyClassProxy 的类\n   │  ├─ 提取 @PrivacyMethodProxy 注解信息\n   │  └─ 存储到 HookMethodManager\n   │\n   └─ ClassProxyCollectTransform\n      └─ 存储到 ReplaceClassManager\n        │\n        ▼\n4️⃣ 第二阶段：执行替换 (Transform)\n   ├─ MethodHookTransform\n   │  ├─ 遍历应用代码中的所有方法调用\n   │  ├─ 在 HookMethodManager 中查询\n   │  ├─ 修改字节码调用\n   │  └─ 记录到 HookedDataManger\n   │\n   └─ FlushHookDataTransform\n      └─ 生成 privacy_hook.json\n        │\n        ▼\n运行期间\n────────────────────────────────\n│\n5️⃣ 应用启动 → SDK 初始化\n   └─ 用户同意隐私协议\n      └─ 业务代码调用敏感 API\n         └─ 执行代理方法\n            └─ 记录日志并输出\n            </div>\n        </section>\n\n        <section id=\"part7\">\n            <h2>第七部分：关键交互关系</h2>\n\n            <h3>7.1 模块间的依赖关系</h3>\n            <div class=\"diagram\">\nprivacy-annotation (底层)\n        ↑\n        │ 依赖（注解定义）\n        │\nplugin-sentry ◄──── Booster 框架\n        │            ASM 库\n        │ 生成\n        ▼\nprivacy_hook.json\n        │\n        ▼ 加载\n    应用 APK\n        │\n        ├─ 包含修改后的 bytecode\n        └─ 包含 privacy_hook.json\n        │\n        ▼\nhook-sentry (运行时)\n        │ 依赖\n        ├─ privacy-annotation\n        └─ privacy-proxy\n            </div>\n        </section>\n\n        <section id=\"part8\">\n            <h2>第八部分：高级特性</h2>\n\n            <h3>8.1 反射 Hook</h3>\n            <p>支持拦截通过反射方式调用的敏感方法：</p>\n            <pre><code>privacy {\n    hookReflex = true\n    reflexMap = [\n        \"com.android.id.impl.IdProviderImpl\": [\n            \"getOAID\",   // 小米设备的广告 ID\n            \"getAAID\",\n            \"getVAID\"\n        ]\n    ]\n}</code></pre>\n\n            <h3>8.2 多进程支持</h3>\n            <p>自动为不同进程生成独立的日志文件：</p>\n            <pre><code>// 结果文件位置\n/storage/emulated/0/Android/data/{packageName}/files/privacy/\n├─ privacy_result.xls          (主进程)\n├─ com.example.service_result.xls  (Service 进程)\n└─ com.example.worker_result.xls   (其他进程)</code></pre>\n\n            <h3>8.3 粘性数据</h3>\n            <div class=\"info-box\">\n                <strong>粘性数据 (Sticky Data)</strong>: 处理 SDK 初始化晚于敏感 API 调用的场景，确保不遗漏任何调用记录。\n            </div>\n\n            <h3>8.4 黑名单配置</h3>\n            <pre><code>privacy {\n    blackList = [\n        \"com.loc\",              // 高德地图（ASM 冲突）\n        \"com.amap.api\",\n        \"io.openinstall.sdk\"\n    ]\n}</code></pre>\n        </section>\n\n        <section id=\"part9\">\n            <h2>第九部分：生成的产物分析</h2>\n\n            <h3>9.1 privacy_hook.json 结构</h3>\n            <pre><code>{\n    \"hookServiceList\": [\n        \"com.example.TestService\"\n    ],\n\n    \"replaceMethodMap\": {\n        \"android.app.ActivityManager.getRunningAppProcesses\": {\n            \"count\": 3,\n            \"originMethodList\": [...]\n        }\n    }\n}</code></pre>\n\n            <h3>9.2 Excel 输出文件</h3>\n            <p><strong>文件位置</strong>: <code>/storage/emulated/0/Android/data/{packageName}/files/privacy/</code></p>\n\n            <h4>Sheet 1：隐私合规明细</h4>\n            <table>\n                <tr>\n                    <th>调用时间</th>\n                    <th>别名</th>\n                    <th>函数名</th>\n                    <th>调用堆栈</th>\n                </tr>\n                <tr>\n                    <td>2024-12-30 10:25:15</td>\n                    <td>当前运行中的任务</td>\n                    <td>getRunningTasks</td>\n                    <td>com.example.MainActivity.onCreate() ...</td>\n                </tr>\n            </table>\n\n            <h4>Sheet 2：调用次数统计</h4>\n            <table>\n                <tr>\n                    <th>别名</th>\n                    <th>函数名</th>\n                    <th>调用堆栈</th>\n                    <th>调用次数</th>\n                </tr>\n                <tr>\n                    <td>当前运行中的任务</td>\n                    <td>getRunningTasks</td>\n                    <td>com.example.MainActivity.onCreate()</td>\n                    <td>3</td>\n                </tr>\n            </table>\n        </section>\n\n        <section id=\"part10\">\n            <h2>第十部分：完整工作流程示例</h2>\n\n            <h3>示例：拦截 Build.getSerial() 调用</h3>\n\n            <h4>步骤 1：定义代理方法</h4>\n            <pre><code>@PrivacyClassProxy\nobject PrivacyProxyCall {\n    @PrivacyMethodProxy(\n        originalClass = android.os.Build::class,\n        originalMethod = \"getSerial\",\n        originalOpcode = MethodInvokeOpcode.INVOKESTATIC\n    )\n    @JvmStatic\n    fun getSerial(): String? {\n        doFilePrinter(\"getSerial\", \"读取Serial\")\n\n        if (PrivacySentry.Privacy.inDangerousState()) {\n            return \"\"\n        }\n\n        return Build.getSerial()\n    }\n}</code></pre>\n\n            <h4>步骤 2：编译期收集</h4>\n            <p><code>MethodProxyCollectTransform</code> 扫描并收集代理方法信息</p>\n\n            <h4>步骤 3：编译期替换</h4>\n            <p><code>MethodHookTransform</code> 修改字节码调用</p>\n\n            <h4>步骤 4：运行时执行</h4>\n            <pre><code>// 1. SDK 初始化\nPrivacySentry.Privacy.init(application, builder)\n\n// 2. 用户同意隐私协议\nPrivacySentry.Privacy.updatePrivacyShow()\n\n// 3. 业务代码调用\nval serial = Build.getSerial()  // 实际调用代理方法</code></pre>\n        </section>\n\n        <section id=\"part11\">\n            <h2>第十一部分：架构优势和设计模式</h2>\n\n            <h3>11.1 采用的设计模式</h3>\n            <table>\n                <tr>\n                    <th>模式</th>\n                    <th>位置</th>\n                    <th>用途</th>\n                </tr>\n                <tr>\n                    <td><strong>代理模式</strong></td>\n                    <td>privacy-proxy</td>\n                    <td>代理敏感 API 调用</td>\n                </tr>\n                <tr>\n                    <td><strong>工厂模式</strong></td>\n                    <td>CachePrivacyManager</td>\n                    <td>创建不同类型的缓存</td>\n                </tr>\n                <tr>\n                    <td><strong>单例模式</strong></td>\n                    <td>Manager 对象</td>\n                    <td>全局唯一的管理器</td>\n                </tr>\n                <tr>\n                    <td><strong>观察者模式</strong></td>\n                    <td>PrivacyDataManager</td>\n                    <td>LiveData 通知数据变化</td>\n                </tr>\n                <tr>\n                    <td><strong>策略模式</strong></td>\n                    <td>BasePrinter</td>\n                    <td>不同的输出策略</td>\n                </tr>\n            </table>\n\n            <h3>11.2 关键架构优势</h3>\n            <div class=\"success-box\">\n                <h4>✅ 核心优势</h4>\n                <ul>\n                    <li><strong>编译期处理</strong>：相比 Xposed 不需要 Root，零运行时 overhead</li>\n                    <li><strong>完整方案</strong>：识别 → 拦截 → 记录 → 报告的完整链路</li>\n                    <li><strong>灵活扩展</strong>：支持自定义代理、黑名单、反射拦截</li>\n                    <li><strong>高效缓存</strong>：三层缓存策略满足不同场景</li>\n                    <li><strong>多进程支持</strong>：自动处理多进程数据隔离</li>\n                </ul>\n            </div>\n        </section>\n\n        <section id=\"part12\">\n            <h2>第十二部分：使用建议和最佳实践</h2>\n\n            <h3>12.1 集成步骤</h3>\n\n            <h4>1. 在根 build.gradle 中添加插件依赖</h4>\n            <pre><code>buildscript {\n    dependencies {\n        classpath 'com.github.allenymt.PrivacySentry:plugin-sentry:1.3.7_v820_beta4'\n    }\n}\n\nallprojects {\n    repositories {\n        maven { url 'https://jitpack.io' }\n    }\n}</code></pre>\n\n            <h4>2. 在 App build.gradle 中应用插件</h4>\n            <pre><code>apply plugin: 'privacy-sentry-plugin'\n\ndependencies {\n    implementation \"com.github.allenymt.PrivacySentry:hook-sentry:1.3.7_v820_beta4\"\n    implementation \"com.github.allenymt.PrivacySentry:privacy-annotation:1.3.7_v820_beta4\"\n    implementation \"com.github.allenymt.PrivacySentry:privacy-proxy:1.3.7_v820_beta4\"\n}\n\nprivacy {\n    enablePrivacy = true\n    blackList = []\n}</code></pre>\n\n            <h4>3. 初始化 SDK</h4>\n            <pre><code>class MyApplication : Application() {\n    override fun attachBaseContext(base: Context?) {\n        super.attachBaseContext(base)\n\n        PrivacySentry.Privacy.init(\n            this,\n            PrivacySentryBuilder()\n                .syncDebug(true)\n                .enableFileResult(true)\n                .configWatchTime(30 * 60 * 1000)\n        )\n    }\n}</code></pre>\n\n            <h3>12.2 调试技巧</h3>\n            <ul>\n                <li><strong>查看 Logcat</strong>: <code>adb logcat | grep \"PrivacyOfficer\"</code></li>\n                <li><strong>拉取文件</strong>: <code>adb pull /storage/emulated/0/Android/data/{packageName}/files/privacy/</code></li>\n                <li><strong>查看配置</strong>: <code>cat privacy_hook.json | jq</code></li>\n            </ul>\n\n            <h3>12.3 性能考量</h3>\n            <table>\n                <tr>\n                    <th>指标</th>\n                    <th>影响</th>\n                </tr>\n                <tr>\n                    <td>编译时间</td>\n                    <td>增加 &lt; 2 秒</td>\n                </tr>\n                <tr>\n                    <td>APK 包体积</td>\n                    <td>增加 ~200KB</td>\n                </tr>\n                <tr>\n                    <td>运行时性能</td>\n                    <td>零额外开销</td>\n                </tr>\n                <tr>\n                    <td>内存占用</td>\n                    <td>缓存数据占用，可定期清理</td>\n                </tr>\n            </table>\n\n            <h3>12.4 常见问题</h3>\n            <div class=\"highlight-box\">\n                <h4>Q: 为什么某些敏感 API 调用没有被拦截？</h4>\n                <p>A: 检查以下几点：</p>\n                <ul>\n                    <li>是否添加了代理实现</li>\n                    <li>检查黑名单配置</li>\n                    <li>检查是否同意了隐私协议</li>\n                    <li>查看 privacy_hook.json 是否包含该 API</li>\n                </ul>\n            </div>\n\n            <div class=\"highlight-box\">\n                <h4>Q: 为什么应用闪退？</h4>\n                <p>A: 可能原因：</p>\n                <ul>\n                    <li>privacy-proxy 中的代理实现有 bug</li>\n                    <li>ASM 库版本冲突（特别是高德地图）</li>\n                    <li>尝试添加到黑名单</li>\n                </ul>\n            </div>\n        </section>\n\n        <section>\n            <h2>总结</h2>\n            <div class=\"success-box\">\n                <p>PrivacySentry 是一套<strong>设计精妙的隐私合规解决方案</strong>，通过以下特点提供完整的隐私检测能力：</p>\n                <ul>\n                    <li><span class=\"badge badge-success\">✅</span> 四层架构 - 从注解定义到运行时拦截的完整链路</li>\n                    <li><span class=\"badge badge-success\">✅</span> 两阶段 Transform - 先收集再替换，模块化清晰</li>\n                    <li><span class=\"badge badge-success\">✅</span> 智能缓存 - 多种缓存策略满足不同场景</li>\n                    <li><span class=\"badge badge-success\">✅</span> 完整日志 - Excel 报表化的统计分析</li>\n                    <li><span class=\"badge badge-success\">✅</span> 隐私协议状态管理 - 根据用户同意状态动态返回数据</li>\n                    <li><span class=\"badge badge-success\">✅</span> 多进程支持 - 自动处理多进程的数据隔离</li>\n                </ul>\n                <p><strong>关键数据流</strong>：注解 → 编译期收集 → 字节码替换 → 运行时拦截 → 日志收集 → Excel 输出</p>\n            </div>\n        </section>\n    </div>\n\n    <footer>\n        <div class=\"container\">\n            <p><strong>文档版本</strong>: v1.0</p>\n            <p><strong>最后更新</strong>: 2024-12-30</p>\n            <p><strong>项目版本</strong>: PrivacySentry 1.3.7_v820_beta4</p>\n        </div>\n    </footer>\n\n    <div class=\"scroll-top\" id=\"scrollTop\" onclick=\"scrollToTop()\">\n        ↑\n    </div>\n\n    <script>\n        // Scroll to top button\n        window.addEventListener('scroll', function() {\n            const scrollTop = document.getElementById('scrollTop');\n            if (window.pageYOffset > 300) {\n                scrollTop.classList.add('visible');\n            } else {\n                scrollTop.classList.remove('visible');\n            }\n        });\n\n        function scrollToTop() {\n            window.scrollTo({\n                top: 0,\n                behavior: 'smooth'\n            });\n        }\n\n        // Smooth scroll for anchor links\n        document.querySelectorAll('a[href^=\"#\"]').forEach(anchor => {\n            anchor.addEventListener('click', function (e) {\n                e.preventDefault();\n                const target = document.querySelector(this.getAttribute('href'));\n                if (target) {\n                    target.scrollIntoView({\n                        behavior: 'smooth',\n                        block: 'start'\n                    });\n                }\n            });\n        });\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "docs/architecture.md",
    "content": "# PrivacySentry 架构深度分析\n\n> Android 隐私合规检测工具的完整技术解析\n\n## 目录\n\n- [执行摘要](#执行摘要)\n- [第一部分：架构总体设计](#第一部分架构总体设计)\n- [第二部分：注解层详细分析](#第二部分注解层详细分析)\n- [第三部分：插件层详细分析](#第三部分插件层详细分析)\n- [第四部分：Hook 层详细分析](#第四部分hook-层详细分析)\n- [第五部分：代理层详细分析](#第五部分代理层详细分析)\n- [第六部分：完整数据流分析](#第六部分完整数据流分析)\n- [第七部分：关键交互关系](#第七部分关键交互关系)\n- [第八部分：高级特性](#第八部分高级特性)\n- [第九部分：生成的产物分析](#第九部分生成的产物分析)\n- [第十部分：完整工作流程示例](#第十部分完整工作流程示例)\n- [第十一部分：架构优势和设计模式](#第十一部分架构优势和设计模式)\n- [第十二部分：使用建议和最佳实践](#第十二部分使用建议和最佳实践)\n\n---\n\n## 执行摘要\n\nPrivacySentry 是一套完整的 Android 隐私合规检测解决方案，采用**编译期注解 + 字节码插桩 + 运行时 Hook** 的三层架构设计。总共包含 67 个 Kotlin/Java 文件，通过 ASM 和 Booster 框架在编译期对敏感 API 调用进行拦截和代理，运行时记录完整的隐私合规数据。\n\n### 核心技术栈\n\n- **Gradle Plugin**: 基于 AGP 8.0+\n- **字节码操作**: ASM 9.1\n- **Transform 框架**: Booster\n- **语言**: Kotlin 1.8.10 + Java 8\n- **最低支持**: Android API 19\n\n---\n\n## 第一部分：架构总体设计\n\n### 1.1 四层架构模型\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│  4. 代理层 (privacy-proxy)                                  │\n│  - 预置的 API 拦截实现                                      │\n│  - 使用注解声明拦截规则                                    │\n└─────────────────────────────────────────────────────────────┘\n                           ↑\n┌─────────────────────────────────────────────────────────────┐\n│  3. Hook 层 (hook-sentry)                                   │\n│  - 运行时 SDK 初始化和管理                                  │\n│  - 缓存机制（内存、磁盘）                                  │\n│  - 日志收集和文件输出                                      │\n└─────────────────────────────────────────────────────────────┘\n                           ↑\n┌─────────────────────────────────────────────────────────────┐\n│  2. 插件层 (plugin-sentry)                                  │\n│  - Gradle 编译期 Transform 执行                             │\n│  - ASM 字节码操作和修改                                     │\n│  - Booster 框架集成                                        │\n└─────────────────────────────────────────────────────────────┘\n                           ↑\n┌─────────────────────────────────────────────────────────────┐\n│  1. 注解层 (privacy-annotation)                             │\n│  - 编译期注解定义                                          │\n│  - 运行时不可见 (@Retention(CLASS))                        │\n└─────────────────────────────────────────────────────────────┘\n```\n\n### 1.2 项目模块说明\n\n| 模块 | 路径 | 职责 | 关键类 |\n|------|------|------|--------|\n| **privacy-annotation** | `/privacy-annotation` | 注解定义 | `@PrivacyMethodProxy`, `@PrivacyClassProxy` |\n| **plugin-sentry** | `/plugin-sentry` | Gradle 插件和字节码转换 | `PrivacySentryPlugin`, Transform 类 |\n| **hook-sentry** | `/hook-sentry` | 运行时 SDK 和日志收集 | `PrivacySentry`, 缓存管理器 |\n| **privacy-proxy** | `/privacy-proxy` | 预置的拦截实现 | `PrivacyProxyCall`, 各种 Proxy 类 |\n| **privacy-replace** | `/privacy-replace` | 类替换功能（已废弃） | - |\n| **app** | `/app` | 示例应用 | - |\n\n---\n\n## 第二部分：注解层详细分析\n\n### 2.1 核心注解系统\n\n**文件位置**: `privacy-annotation/src/main/java/com/yl/lib/privacy_annotation/`\n\n#### 2.1.1 `@PrivacyMethodProxy` - 方法代理注解\n\n```java\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.CLASS)\npublic @interface PrivacyMethodProxy {\n    Class originalClass();              // 原始类\n    String originalMethod() default \"\"; // 原始方法名\n    int originalOpcode() default MethodInvokeOpcode.INVOKESTATIC;  // 调用方式\n    boolean ignoreClass() default false; // 是否忽略类名\n}\n```\n\n**用途**: 标记需要代理的方法。编译期插件通过该注解收集需要拦截的方法列表。\n\n**关键字段说明**:\n- `originalClass`: 要拦截的目标类\n- `originalMethod`: 要拦截的目标方法名\n- `originalOpcode`: 调用方式（静态/虚实例/接口等）\n- `ignoreClass`: 允许只按方法名和签名匹配，忽略类名（用于反射方法代理）\n\n**使用示例**:\n\n```kotlin\n@PrivacyMethodProxy(\n    originalClass = ActivityManager::class,\n    originalMethod = \"getRunningTasks\",\n    originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n)\n@JvmStatic\nfun getRunningTasks(manager: ActivityManager, maxNum: Int): List<RunningTaskInfo> {\n    // 代理实现\n}\n```\n\n#### 2.1.2 `@PrivacyClassProxy` - 类标记注解\n\n```java\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.CLASS)\npublic @interface PrivacyClassProxy { }\n```\n\n**用途**: 标记包含代理方法的类。告诉编译器该类需要被解析以提取 `@PrivacyMethodProxy` 标注的方法。\n\n#### 2.1.3 `@PrivacyFieldProxy` - 字段代理注解\n\n```java\n@Target(ElementType.FIELD)\n@Retention(RetentionPolicy.CLASS)\npublic @interface PrivacyFieldProxy {\n    Class originalClass();          // 原始类\n    String originalFieldName() default \"\"; // 原始字段名\n}\n```\n\n**用途**: 标记需要代理的字段（如 `Build.SERIAL`）。\n\n#### 2.1.4 `@PrivacyClassBlack` - 黑名单注解\n\n```java\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.CLASS)\npublic @interface PrivacyClassBlack { }\n```\n\n**用途**: 标记不需要拦截的类，跳过字节码修改。\n\n#### 2.1.5 MethodInvokeOpcode 定义\n\n| Opcode | 值 | 含义 | 使用场景 |\n|--------|-----|------|---------|\n| `INVOKEVIRTUAL` | 182 | 调用实例方法 | 普通实例方法 |\n| `INVOKESPECIAL` | 183 | 调用特殊方法 | 私有方法、构造函数 |\n| `INVOKESTATIC` | 184 | 调用静态方法 | 静态方法 |\n| `INVOKEINTERFACE` | 185 | 调用接口方法 | 接口实现 |\n| `INVOKEDYNAMIC` | 186 | 动态方法调用 | Lambda 表达式 |\n\n---\n\n## 第三部分：插件层详细分析\n\n### 3.1 Gradle 插件入口\n\n**文件**: `plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/PrivacySentryPlugin.kt`\n\n```kotlin\nclass PrivacySentryPlugin : Plugin<Project> {\n    override fun apply(project: Project) {\n        // 1. 创建配置扩展点\n        var extension = project.extensions.create(\"privacy\", PrivacyExtension::class.java)\n\n        if (!extension.enablePrivacy) {\n            return  // 功能关闭时直接返回\n        }\n\n        // 2. 只对 App 插件生效\n        if (project.plugins.hasPlugin(AppPlugin::class.java)) {\n            // 3. 清空历史数据\n            HookMethodManager.MANAGER.clear()\n            HookFieldManager.MANAGER.clear()\n            ReplaceClassManager.MANAGER.clear()\n\n            // 4. 注册 Transform\n            registerTransform(project)\n\n            // 5. 设置 Manifest 和 Assets 处理任务\n            setupTasks(project)\n        }\n    }\n}\n```\n\n### 3.2 Transform 执行流程\n\n#### 3.2.1 两阶段 Transform 架构\n\n```\n编译期流程：\n┌──────────────────────────────────┐\n│  输入：所有 .class 文件和 Jar    │\n└──────────────┬───────────────────┘\n               │\n        ┌──────▼─────────────┐\n        │  第一阶段（预处理） │\n        │  Pre-Transform     │\n        └──────┬─────────────┘\n               │\n    ┌──────────┴──────────────┐\n    │                         │\n┌───▼────────────────┐   ┌───▼──────────────────┐\n│MethodProxy         │   │ ClassProxy           │\n│ CollectTransform   │   │ CollectTransform     │\n│ (收集方法拦截规则) │   │ (收集类替换规则)    │\n└───┬────────────────┘   └───┬──────────────────┘\n    │                         │\n    │ 结果写入：            │\n    │ HookMethodManager     │ ReplaceClassManager\n    │ HookFieldManager      │\n    │\n        ┌──────▼────────────────┐\n        │  第二阶段（执行替换）  │\n        │  Transform            │\n        └──────┬────────────────┘\n               │\n    ┌──────────┼──────────────┬──────────────┐\n    │          │              │              │\n┌───▼───┐ ┌───▼───┐ ┌───────▼──┐ ┌────────▼───┐\n│Method │ │Field  │ │ Class    │ │ Service    │\n│Hook   │ │Proxy  │ │ Proxy    │ │ Hook       │\n│       │ │       │ │          │ │            │\n└───┬───┘ └───┬───┘ └───────┬──┘ └────────┬───┘\n    │         │            │             │\n    └─────────┴────────────┴─────────────┘\n               │\n        ┌──────▼──────────┐\n        │ FlushHookData   │\n        │ Transform       │\n        │ (生成hook配置)  │\n        └────────┬────────┘\n                 │\n    ┌────────────▼──────────────┐\n    │ 输出：修改后的 .class 和  │\n    │ privacy_hook.json         │\n    └───────────────────────────┘\n```\n\n### 3.3 第一阶段：收集拦截规则\n\n#### MethodProxyCollectTransform\n\n**职责**: 扫描所有带 `@PrivacyClassProxy` 的类，收集 `@PrivacyMethodProxy` 标注的代理方法\n\n**核心逻辑**:\n\n```kotlin\nclass MethodProxyCollectTransform : AbsClassTransformer() {\n    override fun transform(\n        project: Project,\n        privacyExtension: PrivacyExtension,\n        context: TransformContext,\n        klass: ClassNode\n    ): ClassNode {\n        // 1. 过滤只有 @PrivacyClassProxy 注解的类\n        klass.invisibleAnnotations?.find {\n            it.desc.privacyClassProxy()\n        } ?: return klass\n\n        // 2. 收集方法\n        klass.methods.filter { methodNode ->\n            methodNode.invisibleAnnotations?.find {\n                it.desc.privacyMethodProxy()\n            } != null\n        }.forEach { methodNode ->\n            // 3. 提取注解信息\n            val hookMethodItem = HookMethodItem(\n                proxyClassName = klass.formatName(),\n                proxyMethodName = methodNode.name,\n                proxyMethodDesc = methodNode.desc\n            )\n\n            // 4. 获取目标方法信息\n            val annotationNode = methodNode.invisibleAnnotations\n                ?.find { it.desc.privacyMethodProxy() }\n\n            hookMethodItem.originClassName =\n                annotationNode?.privacyGetValue<Type>(\"originalClass\")\n            hookMethodItem.originMethodName =\n                annotationNode?.privacyGetValue<String>(\"originalMethod\")\n            hookMethodItem.originMethodAccess =\n                annotationNode?.privacyGetValue<Int>(\"originalOpcode\")\n\n            // 5. 处理方法描述符\n            if (hookMethodItem.originMethodAccess == INVOKESTATIC) {\n                // 静态方法：签名相同\n                hookMethodItem.originMethodDesc = hookMethodItem.proxyMethodDesc\n            } else {\n                // 实例方法：需要移除第一个参数（this 对象）\n                hookMethodItem.originMethodDesc =\n                    hookMethodItem.proxyMethodDesc.replaceFirst(\n                        \"L${originClassName};\", \"\"\n                    )\n            }\n\n            // 6. 存储到全局管理器\n            HookMethodManager.MANAGER.appendHookMethod(hookMethodItem)\n        }\n\n        return klass\n    }\n}\n```\n\n**数据结构**:\n\n```kotlin\ndata class HookMethodItem(\n    val proxyClassName: String,           // 代理类名\n    val proxyMethodName: String,          // 代理方法名\n    val proxyMethodDesc: String,          // 代理方法签名\n    var originClassName: String = \"\",     // 目标类名\n    var originMethodName: String = \"\",    // 目标方法名\n    var originMethodDesc: String = \"\",    // 目标方法签名\n    var originMethodAccess: Int = 0,      // 目标方法调用方式\n    var ignoreClass: Boolean = false      // 是否忽略类名\n)\n```\n\n### 3.4 第二阶段：执行字节码替换\n\n#### MethodHookTransform\n\n**职责**: 遍历所有 class 文件，将原始方法调用替换为代理方法调用\n\n**核心逻辑**:\n\n```kotlin\nclass MethodHookTransform : BaseHookTransform() {\n    override fun transform(\n        project: Project,\n        privacyExtension: PrivacyExtension,\n        context: TransformContext,\n        klass: ClassNode\n    ): ClassNode {\n        klass.methods?.forEach { methodNode ->\n            var bLdcHookMethod = false\n\n            // 遍历方法内的所有指令\n            methodNode.instructions?.iterator()?.asSequence()?.forEach { node ->\n                if (node is MethodInsnNode) {\n                    // 1. 查询是否需要拦截该方法\n                    val methodItem = HookMethodManager.MANAGER.findHookItemByName(\n                        node.name,\n                        node.owner,\n                        node.desc,\n                        node.opcode\n                    )\n\n                    if (methodItem != null && shouldHook(...)) {\n                        // 2. 记录被替换的方法调用\n                        HookedDataManger.MANAGER.addReplaceMethodItem(\n                            ReplaceMethodItem(\n                                originClassName = node.owner,\n                                originMethodName = node.name\n                            )\n                        )\n\n                        // 3. 修改方法调用指令\n                        node.opcode = INVOKESTATIC      // 改为静态调用\n                        node.owner = methodItem.proxyClassName\n                        node.name = methodItem.proxyMethodName\n                        node.desc = methodItem.proxyMethodDesc\n                        node.itf = false\n                    }\n                } else if (node is LdcInsnNode) {\n                    // 处理反射调用（需要 hookReflex = true）\n                    if (node.cst is String) {\n                        bLdcHookMethod = HookMethodManager.MANAGER\n                            .findByClsOrMethod(node.cst as String)\n                    }\n                }\n            }\n        }\n        return klass\n    }\n}\n```\n\n**字节码替换原理**:\n\n原始代码:\n```java\nActivityManager manager = ...;\nList<RunningTaskInfo> tasks = manager.getRunningTasks(maxNum);\n```\n\n原始字节码:\n```\nALOAD 1              // 加载 manager 对象\nILOAD 2              // 加载 maxNum 参数\nINVOKEVIRTUAL ActivityManager.getRunningTasks\n```\n\n替换后的字节码:\n```\nALOAD 1              // 加载 manager 对象\nILOAD 2              // 加载 maxNum 参数\nINVOKESTATIC PrivacyProxyCall$Proxy.getRunningTasks\n```\n\n### 3.5 插件配置\n\n**文件**: `plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/extension/PrivacyExtension.kt`\n\n```gradle\nprivacy {\n    // 黑名单：指定包名不进行字节码修改\n    blackList = []\n\n    // 总开关\n    enablePrivacy = true\n\n    // 是否 hook 反射方法\n    hookReflex = false\n\n    // 反射拦截配置（用于获取小米设备的 OAID 等）\n    reflexMap = [\n        \"com.android.id.impl.IdProviderImpl\": [\"getOAID\", \"getAAID\", \"getVAID\"]\n    ]\n\n    // 已废弃功能\n    hookConstructor = false\n    hookField = false\n}\n```\n\n---\n\n## 第四部分：Hook 层详细分析\n\n### 4.1 运行时 SDK 初始化\n\n**文件**: `hook-sentry/src/main/java/com/yl/lib/sentry/hook/PrivacySentry.kt`\n\n```kotlin\nclass PrivacySentry {\n    object Privacy {\n        @Volatile\n        private var mBuilder: PrivacySentryBuilder? = null\n        private val bInit = AtomicBoolean(false)\n        private var bShowPrivacy: AtomicBoolean? = null\n\n        fun init(ctx: Application, builder: PrivacySentryBuilder?) {\n            if (bInit.compareAndSet(false, true)) {\n                mBuilder = builder\n                initInner(ctx)\n            }\n        }\n\n        private fun initInner(ctx: Application) {\n            this.ctx = ctx\n\n            // 启动文件监控\n            if (mBuilder?.isEnableFileResult() == true) {\n                mBuilder?.getWatchTime()?.let { watchTime ->\n                    Handler(Looper.getMainLooper()).postDelayed({\n                        stop()  // 超时停止写入\n                    }, watchTime)\n                }\n            }\n\n            // 添加文件输出打印器\n            mBuilder?.addPrinter(defaultFilePrinter(ctx, mBuilder))\n        }\n\n        fun updatePrivacyShow() {\n            // 用户同意隐私协议，需要显式调用\n            bShowPrivacy?.compareAndSet(false, true)\n            diskCache.put(\"show_privacy_dialog\", \"true\")\n        }\n\n        fun hasShowPrivacy(): Boolean {\n            // 检查隐私协议是否已显示\n        }\n\n        fun inDangerousState(): Boolean {\n            // true: 未同意隐私协议（危险状态）\n            // 在危险状态下，返回空数据给调用者\n            return !hasShowPrivacy()\n        }\n    }\n}\n```\n\n**初始化时机**: 建议在 `Application.attachBaseContext()` 中第一个调用\n\n```kotlin\nclass MyApplication : Application() {\n    override fun attachBaseContext(base: Context?) {\n        super.attachBaseContext(base)\n\n        // 必须最先初始化\n        PrivacySentry.Privacy.init(\n            this,\n            PrivacySentryBuilder()\n                .enableFileResult(true)\n                .syncDebug(true)\n                .configWatchTime(30 * 60 * 1000)\n        )\n    }\n\n    override fun onCreate() {\n        super.onCreate()\n        // ... 其他初始化\n\n        // 隐私协议确认后调用\n        showPrivacyDialog {\n            PrivacySentry.Privacy.updatePrivacyShow()\n        }\n    }\n}\n```\n\n### 4.2 缓存机制详解\n\n#### 4.2.1 三层缓存架构\n\n```\n┌───────────────────────────────────────────┐\n│ CachePrivacyManager（统一入口）           │\n└───────────────┬─────────────────────────────┘\n                │\n    ┌───────────┼───────────┬───────────┬───────────┐\n    │           │           │           │           │\n    ▼           ▼           ▼           ▼           ▼\n┌─────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐\n│ Memory  │ │TimeLess  │ │Permanent │ │TimeLess  │\n│ Cache   │ │Memory    │ │ Disk     │ │ Disk     │\n│         │ │Cache     │ │ Cache    │ │ Cache    │\n└────┬────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘\n     │           │            │           │\n     └───────────┴────────────┴───────────┘\n                │\n     ┌──────────▼──────────┐\n     │ SharedPreferences   │\n     │ (磁盘持久化)       │\n     └─────────────────────┘\n```\n\n#### 4.2.2 缓存类型和使用场景\n\n| 缓存类型 | 生命周期 | 使用场景 | 实现类 |\n|---------|---------|---------|--------|\n| **内存缓存** | 进程级别 | IMEI、IMSI、MEID、Serial 等设备标识 | `MemoryCache` |\n| **时效内存缓存** | 时间限制 | 位置信息、WiFi 信息 | `TimeLessMemoryCache` |\n| **永久磁盘缓存** | 持久化 | Android ID、设备名等不可变字段 | `DiskCache` |\n| **时效磁盘缓存** | 磁盘+时效 | 需要定期刷新的敏感信息 | `TimeLessDiskCache` |\n\n**API 示例**:\n\n```kotlin\nclass CachePrivacyManager {\n    object Manager {\n        // 1. 内存缓存\n        fun <T> loadWithMemoryCache(\n            key: String,\n            defaultValue: T,\n            getValue: () -> T\n        ): T\n\n        // 2. 时效内存缓存\n        fun <T> loadWithTimeMemoryCache(\n            key: String,\n            duration: Long = 0,\n            getValue: () -> T\n        ): T\n\n        // 3. 永久磁盘缓存\n        fun loadWithDiskCache(\n            key: String,\n            getValue: () -> String\n        ): String\n\n        // 4. 时效磁盘缓存\n        fun loadWithTimeDiskCache(\n            key: String,\n            duration: Long = 30 * MINUTE,\n            getValue: () -> String\n        ): String\n    }\n}\n```\n\n#### 4.2.3 缓存实现细节\n\n**MemoryCache** - 无竞争条件的内存存储:\n\n```kotlin\nclass MemoryCache<T> : BasePrivacyCache<T> {\n    private var paramMap: ConcurrentHashMap<String, T> = ConcurrentHashMap()\n\n    override fun get(key: String, default: T): Pair<Boolean, T?> {\n        return if (paramMap.containsKey(key)) {\n            Pair(true, paramMap[key])  // 第一个元素 = 是否命中\n        } else {\n            Pair(false, null)\n        }\n    }\n\n    override fun put(key: String, value: T) {\n        paramMap[key] = value\n    }\n}\n```\n\n**DiskCache** - 两层缓存减少 I/O:\n\n```kotlin\nclass DiskCache : BasePrivacyCache<String> {\n    // 内存缓存层：避免频繁读 SharedPreferences\n    private var paramMap: ConcurrentHashMap<String, String> = ConcurrentHashMap()\n\n    override fun get(key: String, default: String): Pair<Boolean, String?> {\n        // 1. 先查内存缓存\n        if (paramMap.containsKey(key)) {\n            return Pair(true, paramMap[key])\n        }\n\n        // 2. 再查 SharedPreferences\n        val cacheResult = CacheUtils.Utils.loadFromSp(key, default)\n        if (cacheResult.first) {\n            paramMap[key] = cacheResult.second!!  // 缓存到内存\n        }\n        return cacheResult\n    }\n\n    override fun put(key: String, value: String) {\n        paramMap[key] = value\n        CacheUtils.Utils.saveToSp(key, value)  // 同时写入磁盘\n    }\n}\n```\n\n### 4.3 日志收集和输出\n\n#### 4.3.1 日志数据流\n\n```\n运行时敏感 API 调用\n        │\n        ▼\n┌──────────────────────────┐\n│ doFilePrinter()          │\n│ (PrivacyProxyUtil)       │\n└──────────┬───────────────┘\n           │\n   ┌───────▼──────────┐\n   │ 构建 PrivacyFun  │\n   │ Bean (调用信息)  │\n   └───────┬──────────┘\n           │\n   ┌───────▼──────────────────┐\n   │ 判断 SDK 初始化状态      │\n   └───────┬──────────┬───────┘\n           │          │\n       已初始化   未初始化\n           │          │\n           │      ┌───▼──────────┐\n           │      │ 粘性数据保存 │\n           │      │ (粘性队列)   │\n           │      └──────────────┘\n           │\n   ┌───────▼──────────────────┐\n   │ PrivacyDataManager       │\n   │ 管理数据列表             │\n   └───────┬──────────────────┘\n           │\n   ┌───────▼──────────────────┐\n   │ BasePrinter 列表         │\n   │ (日志 + 文件输出)        │\n   └───────┬──────────────────┘\n           │\n   ┌───────┴────────┬──────────────┐\n   │                │              │\n   ▼                ▼              ▼\nDefaultLogPrint  DefaultFilePrint  ...\n(Logcat输出)    (Excel文件输出)\n```\n\n#### 4.3.2 数据模型\n\n```kotlin\nclass PrivacyFunBean(\n    val funAlias: String,           // 函数别名（描述）\n    val funName: String,            // 函数名\n    val msg: String,                // 调用堆栈\n    var count: Int = 1              // 调用次数（用于聚合）\n) {\n    var appendTime: Long = System.currentTimeMillis()  // 记录时间\n\n    fun buildStackTrace(): String {\n        // 构建堆栈信息用于聚合\n    }\n\n    fun addSelf() {\n        count++  // 计数累加\n    }\n}\n```\n\n---\n\n## 第五部分：代理层详细分析\n\n### 5.1 预置拦截实现\n\n**文件位置**: `privacy-proxy/src/main/java/com/yl/lib/privacy_proxy/`\n\n#### 5.1.1 支持的敏感 API 类别\n\n| 类别 | API 示例 | 拦截方式 | 文件 |\n|------|---------|---------|------|\n| **任务管理** | `ActivityManager.getRunningTasks()` | 返回空列表/代理 | `PrivacyProxyCall.kt` |\n| | `ActivityManager.getRecentTasks()` | 返回空列表/代理 | |\n| **剪贴板** | `ClipboardManager.getPrimaryClip()` | 代理访问 | `PrivacyProxyCall.kt` |\n| **蓝牙** | `BluetoothAdapter.getAddress()` | 代理访问 | `PrivacyProxyCall.kt` |\n| **WiFi** | `WifiManager.getConnectionInfo()` | 代理访问 | `PrivacyProxyCall.kt` |\n| | `WifiManager.getScanResults()` | 返回空列表 | |\n| **位置** | `LocationManager.getLastKnownLocation()` | 缓存+代理 | `PrivacyProxyCall.kt` |\n| **设备标识** | `Build.getSerial()` | 缓存+代理 | `PrivacyProxyCall.kt` |\n| | `Settings.Secure.getAndroidId()` | 缓存+代理 | |\n| **应用列表** | `PackageManager.getInstalledPackages()` | 返回空列表 | `PrivacyProxyCall.kt` |\n| **通话信息** | `TelephonyManager.getDeviceId()` | 缓存+代理 | `PrivacyTelephonyProxy.kt` |\n| | `TelephonyManager.getIMSI()` | 缓存+代理 | |\n| **内容提供者** | `ContentResolver.query()` | 记录日志 | `PrivacyProxyResolver.kt` |\n| **传感器** | `SensorManager.registerListener()` | 记录日志 | `PrivacySensorProxy.kt` |\n| **权限** | `requestPermissions()` | 记录日志 | `PrivacyPermissionProxy.kt` |\n\n#### 5.1.2 具体实现示例\n\n```kotlin\n@PrivacyClassProxy\nobject PrivacyProxyCall {\n    @PrivacyMethodProxy(\n        originalClass = ActivityManager::class,\n        originalMethod = \"getRunningTasks\",\n        originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n    )\n    @JvmStatic\n    fun getRunningTasks(\n        manager: ActivityManager,\n        maxNum: Int\n    ): List<ActivityManager.RunningTaskInfo?>? {\n        doFilePrinter(\"getRunningTasks\", \"当前运行中的任务\")\n\n        // 核心逻辑：根据隐私协议状态决定返回值\n        if (PrivacySentry.Privacy.inDangerousState()) {\n            return emptyList()  // 危险状态返回空\n        }\n\n        return manager.getRunningTasks(maxNum)  // 正常状态返回真实数据\n    }\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    @PrivacyMethodProxy(\n        originalClass = android.os.Build::class,\n        originalMethod = \"getSerial\",\n        originalOpcode = MethodInvokeOpcode.INVOKESTATIC\n    )\n    @JvmStatic\n    fun getSerial(): String? {\n        var result = \"\"\n        try {\n            doFilePrinter(\"getSerial\", \"读取Serial\")\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                return \"\"\n            }\n            result = Build.getSerial()\n        } catch (e: Exception) {\n            e.printStackTrace()\n        }\n        return result\n    }\n}\n```\n\n---\n\n## 第六部分：完整数据流分析\n\n### 6.1 从注解定义到字节码替换的完整流程\n\n```\n开发阶段\n────────────────────────────────\n│\n1️⃣ 开发者编写代理方法\n   ├─ 使用 @PrivacyClassProxy 标注类\n   ├─ 使用 @PrivacyMethodProxy 标注方法\n   └─ 编译生成 class 文件（带注解元数据）\n        │\n        ▼\n编译期间\n────────────────────────────────\n│\n2️⃣ Gradle 执行 PrivacySentryPlugin\n   ├─ 清空历史 Manager\n   └─ 注册 Transform 任务\n        │\n        ▼\n3️⃣ 第一阶段：预处理 (Pre-Transform)\n   ├─ MethodProxyCollectTransform\n   │  ├─ 扫描所有 class 文件\n   │  ├─ 找到 @PrivacyClassProxy 的类\n   │  ├─ 提取 @PrivacyMethodProxy 注解信息\n   │  ├─ 解析代理方法的签名\n   │  └─ 存储到 HookMethodManager\n   │\n   └─ ClassProxyCollectTransform\n      ├─ 找到 @PrivacyClassReplace 的类\n      └─ 存储到 ReplaceClassManager\n        │\n        ▼\n4️⃣ 第二阶段：执行替换 (Transform)\n   ├─ MethodHookTransform\n   │  ├─ 遍历应用代码中的所有方法调用\n   │  ├─ 在 HookMethodManager 中查询是否需要拦截\n   │  ├─ 如果需要，修改字节码：\n   │  │  ├─ 修改调用的目标类（从原类改为代理类）\n   │  │  ├─ 修改调用的方法（从原方法改为代理方法）\n   │  │  ├─ 修改调用方式（改为 INVOKESTATIC）\n   │  │  └─ 修改方法签名\n   │  └─ 记录到 HookedDataManger\n   │\n   └─ FlushHookDataTransform\n      └─ 生成 privacy_hook.json\n        │\n        ▼\n5️⃣ 输出产物\n   ├─ 修改后的 .class 文件\n   ├─ 修改后的 .jar/.aar 文件\n   └─ privacy_hook.json (hook 配置清单)\n\n运行期间\n────────────────────────────────\n│\n6️⃣ 应用启动\n   ├─ Application.attachBaseContext()\n   │  └─ PrivacySentry.Privacy.init(...)  ⚠️ 必须最先调用\n   │\n   └─ Application.onCreate()\n      └─ 其他初始化...\n        │\n        ▼\n7️⃣ 用户行为：同意隐私协议\n   └─ PrivacySentry.Privacy.updatePrivacyShow()\n      ├─ 设置 bShowPrivacy = true\n      └─ 写入磁盘缓存\n        │\n        ▼\n8️⃣ 业务代码调用敏感 API\n   例如：\n   val tasks = activityManager.getRunningTasks(10)\n\n   字节码执行流程：\n   ├─ ALOAD (加载对象)\n   ├─ ICONST (加载参数)\n   ├─ INVOKESTATIC (调用代理方法！)\n   │  └─ PrivacyProxyCall$Proxy.getRunningTasks()\n   │     ├─ doFilePrinter() - 记录日志\n   │     ├─ inDangerousState()? - 检查协议状态\n   │     │  ├─ true: 返回 emptyList()\n   │     │  └─ false: 调用真实方法\n   │     └─ return result\n   └─ ASTORE (存储结果)\n        │\n        ▼\n9️⃣ 数据收集和输出\n   ├─ PrivacyProxyUtil.doFilePrinter()\n   ├─ PrivacyDataManager.addData()\n   ├─ BasePrinter.filePrint()\n   │  ├─ DefaultLogPrint: logcat 输出\n   │  └─ DefaultFilePrint: Excel 文件输出\n   └─ 结果保存到\n      /storage/emulated/0/Android/data/packageName/files/privacy/\n```\n\n---\n\n## 第七部分：关键交互关系\n\n### 7.1 模块间的依赖关系\n\n```\nprivacy-annotation (底层)\n        ↑\n        │ 依赖（注解定义）\n        │\nplugin-sentry ◄──── Booster 框架\n        │            ASM 库\n        │ 生成\n        ▼\nprivacy_hook.json\n        │\n        ├─ 记录 hook 的方法列表\n        ├─ 记录 hook 的类列表\n        └─ 记录 hook 的 Service 列表\n        │\n        ▼ 加载\n    应用 APK\n        │\n        ├─ 包含修改后的 bytecode\n        └─ 包含 privacy_hook.json\n        │\n        ▼\nhook-sentry (运行时)\n        │ 依赖\n        ├─ privacy-annotation (获取注解常数)\n        └─ privacy-proxy (预���实现)\n```\n\n---\n\n## 第八部分：高级特性\n\n### 8.1 反射 Hook\n\n支持拦截通过反射方式调用的敏感方法：\n\n```kotlin\n// 编译期配置\nprivacy {\n    hookReflex = true\n    reflexMap = [\n        \"com.android.id.impl.IdProviderImpl\": [\n            \"getOAID\",   // 小米设备的广告 ID\n            \"getAAID\",\n            \"getVAID\"\n        ]\n    ]\n}\n```\n\n### 8.2 多进程支持\n\n```kotlin\n// 自动为不同进程添加进程名前缀\nfun getResultFileName(): String? {\n    return if (isMainProcess()) {\n        resultFileName\n    } else {\n        val processName = getProcessName()\n        \"${processName}_$resultFileName\"\n    }\n}\n```\n\n### 8.3 粘性数据 (Sticky Data)\n\n处理 SDK 初始化晚于敏感 API 调用的场景：\n\n```kotlin\nPrivacyProxyUtil.doFilePrinter() {\n    if (!PrivacySentry.Privacy.hasInit()) {\n        // 保存到粘性队列\n        PrivacyDataManager.Manager.addStickData(bean)\n    }\n}\n```\n\n### 8.4 黑名单配置\n\n```gradle\nprivacy {\n    // 指定包名不进行字节码修改\n    blackList = [\n        \"com.loc\",              // 高德地图（ASM 冲突）\n        \"com.amap.api\",\n        \"io.openinstall.sdk\"\n    ]\n}\n```\n\n---\n\n## 第九部分：生成的产物分析\n\n### 9.1 privacy_hook.json 结构\n\n```json\n{\n    \"hookServiceList\": [\n        \"com.example.TestService\"\n    ],\n\n    \"replaceMethodMap\": {\n        \"android.app.ActivityManager.getRunningAppProcesses\": {\n            \"count\": 3,\n            \"originMethodList\": [\n                {\n                    \"originClassName\": \"com.example.MainActivity\",\n                    \"originMethodName\": \"getRunningAppProcesses\"\n                }\n            ]\n        }\n    }\n}\n```\n\n### 9.2 Excel 输出文件\n\n**文件位置**: `/storage/emulated/0/Android/data/{packageName}/files/privacy/{processName_}privacy_result.xls`\n\n**Sheet 1：隐私合规明细**\n\n| 调用时间(倒序排序) | 别名 | 函数名 | 调用堆栈 |\n|-------|------|--------|--------|\n| 2024-12-30 10:25:15 | 当前运行中的任务 | getRunningTasks | com.example.MainActivity.onCreate() ... |\n| 2024-12-30 10:25:14 | 读取Serial | getSerial | com.example.utils.Utils.getDeviceId() ... |\n\n**Sheet 2：调用次数统计**\n\n| 别名 | 函数名 | 调用堆栈 | 调用次数 |\n|------|--------|--------|---------|\n| 当前运行中的任务 | getRunningTasks | com.example.MainActivity.onCreate() | 3 |\n| 读取Serial | getSerial | com.example.utils.Utils.getDeviceId() | 5 |\n\n---\n\n## 第十部分：完整工作流程示例\n\n### 示例：拦截 Build.getSerial() 调用\n\n#### 步骤 1：定义代理方法\n\n```kotlin\n@PrivacyClassProxy\nobject PrivacyProxyCall {\n    @PrivacyMethodProxy(\n        originalClass = android.os.Build::class,\n        originalMethod = \"getSerial\",\n        originalOpcode = MethodInvokeOpcode.INVOKESTATIC\n    )\n    @JvmStatic\n    fun getSerial(): String? {\n        doFilePrinter(\"getSerial\", \"读取Serial\")\n\n        if (PrivacySentry.Privacy.inDangerousState()) {\n            return \"\"  // 危险状态返回空字符串\n        }\n\n        return Build.getSerial()\n    }\n}\n```\n\n#### 步骤 2：编译期收集\n\n`MethodProxyCollectTransform` 扫描并收集：\n\n```\n找到: @PrivacyClassProxy 修饰的类\n  └─ 提取所有 @PrivacyMethodProxy 方法\n     └─ 存储到: HookMethodManager.MANAGER\n```\n\n#### 步骤 3：编译期替换\n\n`MethodHookTransform` 修改字节码：\n\n原始字节码:\n```\nINVOKESTATIC Build.getSerial ()Ljava/lang/String;\n```\n\n替换后:\n```\nINVOKESTATIC PrivacyProxyCall$Proxy.getSerial ()Ljava/lang/String;\n```\n\n#### 步骤 4：运行时执行\n\n```kotlin\n// 1. SDK 初始化\nPrivacySentry.Privacy.init(application, builder)\n\n// 2. 用户同意隐私协议\nPrivacySentry.Privacy.updatePrivacyShow()\n\n// 3. 业务代码调用\nval serial = Build.getSerial()  // 实际调用代理方法\n```\n\n---\n\n## 第十一部分：架构优势和设计模式\n\n### 11.1 采用的设计模式\n\n| 模式 | 位置 | 用途 |\n|------|------|------|\n| **代理模式** | privacy-proxy | 代理敏感 API 调用 |\n| **工厂模式** | CachePrivacyManager | 创建不同类型的缓存 |\n| **单例模式** | Manager 对象 | 全局唯一的管理器 |\n| **观察者模式** | PrivacyDataManager | LiveData 通知数据变化 |\n| **策略模式** | BasePrinter | 不同的输出策略 |\n| **装饰模式** | Booster Transformer | 链式处理字节码 |\n| **模板方法模式** | AbsClassTransformer | Transform 框架模板 |\n\n### 11.2 关键架构优势\n\n1. **编译期处理 vs 运行时 Hook**\n   - 相比 Xposed，不需要 Root\n   - 相比 Lint 扫描，能获取运行时的调用时机和次数\n   - 零运行时 overhead（字节码已修改）\n\n2. **完整的隐私合规方案**\n   - 识别：通过注解和字节码扫描\n   - 拦截：字节码替换\n   - 记录：完整的堆栈和时间戳\n   - 报告：Excel 统计\n\n3. **灵活的扩展性**\n   - 支持自定义代理实现\n   - 支持黑名单配置\n   - 支持反射方法拦截\n\n4. **三层缓存的高效性**\n   - 内存缓存：最快\n   - 时效缓存：防止频繁读取\n   - 磁盘缓存：程序重启保留\n\n---\n\n## 第十二部分：使用建议和最佳实践\n\n### 12.1 集成步骤\n\n**1. 在根 build.gradle 中添加插件依赖**\n\n```gradle\nbuildscript {\n    dependencies {\n        classpath 'com.github.allenymt.PrivacySentry:plugin-sentry:1.3.7_v820_beta4'\n    }\n}\n\nallprojects {\n    repositories {\n        maven { url 'https://jitpack.io' }\n    }\n}\n```\n\n**2. 在 App build.gradle 中应用插件和库**\n\n```gradle\napply plugin: 'privacy-sentry-plugin'\n\ndependencies {\n    implementation \"com.github.allenymt.PrivacySentry:hook-sentry:1.3.7_v820_beta4\"\n    implementation \"com.github.allenymt.PrivacySentry:privacy-annotation:1.3.7_v820_beta4\"\n    implementation \"com.github.allenymt.PrivacySentry:privacy-proxy:1.3.7_v820_beta4\"\n}\n\nprivacy {\n    enablePrivacy = true\n    blackList = []\n}\n```\n\n**3. 在 Application 中初始化 SDK**\n\n```kotlin\nclass MyApplication : Application() {\n    override fun attachBaseContext(base: Context?) {\n        super.attachBaseContext(base)\n\n        PrivacySentry.Privacy.init(\n            this,\n            PrivacySentryBuilder()\n                .syncDebug(true)      // 开启 logcat\n                .enableFileResult(true)  // 开启文件输出\n                .configWatchTime(30 * 60 * 1000)\n        )\n    }\n}\n```\n\n**4. 用户同意隐私协议后调用**\n\n```kotlin\nshowPrivacyDialog {\n    PrivacySentry.Privacy.updatePrivacyShow()\n}\n```\n\n### 12.2 调试技巧\n\n**1. 查看 Logcat 日志**\n\n```bash\nadb logcat | grep \"PrivacyOfficer\"\n```\n\n**2. 拉取生成的 Excel 文件**\n\n```bash\nadb pull /storage/emulated/0/Android/data/{packageName}/files/privacy/\n```\n\n**3. 查看静态扫描报告**\n\n```bash\ncat privacy_hook.json | jq .replaceMethodMap | less\n```\n\n### 12.3 性能考量\n\n- **编译时间增加**: 新增两个 Transform 阶段，但通常 < 2 秒\n- **APK 包体积**: 增加 ~200KB（主要是 privacy-proxy 代码）\n- **运行时性能**: 零额外开销（字节码已修改）\n- **内存占用**: 缓存数据占用，可通过 watchTime 定期清理\n\n### 12.4 常见问题\n\n**Q: 为什么某些敏感 API 调用没有被拦截？**\n\nA: 检查以下几点：\n1. 是否添加了代理实现\n2. 检查黑名单配置\n3. 检查是否同意了隐私协议\n4. 查看 privacy_hook.json 是否包含该 API\n\n**Q: 为什么应用闪退？**\n\nA: 可能原因：\n1. privacy-proxy 中的代��实现有 bug\n2. ASM 库版本冲突（特别是高德地图）\n3. 尝试添加到黑名单\n\n**Q: 如何自定义拦截？**\n\nA: 创建新的 `@PrivacyClassProxy` 类，按照 privacy-proxy 的格式实现。\n\n---\n\n## 总结\n\nPrivacySentry 是一套**设计精妙的隐私合规解决方案**，通过以下特点提供完整的隐私检测能力：\n\n✅ **四层架构** - 从注解定义到运行时拦截的完整链路\n✅ **两阶段 Transform** - 先收集再替换，模块化清晰\n✅ **智能缓存** - 多种缓存策略满足不同场景\n✅ **完整日志** - Excel 报表化的统计分析\n✅ **隐私协议状态管理** - 根据用户同意状态动态返回数据\n✅ **多进程支持** - 自动处理多进程的数据隔离\n\n**关键数据流**：注解 → 编译期收集 → 字节码替换 → 运行时拦截 → 日志收集 → Excel 输出\n\n---\n\n**文档版本**: v1.0\n**最后更新**: 2024-12-30\n**项目版本**: PrivacySentry 1.3.7_v820_beta4\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Nov 15 17:09:33 CST 2021\ndistributionBase=GRADLE_USER_HOME\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.2-bin.zip\ndistributionPath=wrapper/dists\nzipStorePath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app\"s APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n# Automatically convert third-party libraries to use AndroidX\nandroid.enableJetifier=true\n# Kotlin code style for this project: \"official\" or \"obsolete\":\nkotlin.code.style=official"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif [ \"$cygwin\" = \"true\" -o \"$msys\" = \"true\" ] ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=`expr $i + 1`\n    done\n    case $i in\n        0) set -- ;;\n        1) set -- \"$args0\" ;;\n        2) set -- \"$args0\" \"$args1\" ;;\n        3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=`save \"$@\"`\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n\r\n@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto execute\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "hook-sentry/.gitignore",
    "content": "/build"
  },
  {
    "path": "hook-sentry/build.gradle",
    "content": "apply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\nandroid {\n    compileSdkVersion 30\n    buildToolsVersion \"30.0.3\"\n    namespace \"com.yl.lib.sentry.hook\"\n    defaultConfig {\n        minSdkVersion 19\n        targetSdkVersion 30\n        versionCode 1\n        versionName \"1.0\"\n\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n\n    buildTypes {\n        debug {\n            debuggable true\n        }\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    kotlinOptions {\n        jvmTarget = '1.8'\n    }\n    testOptions {\n        unitTests.returnDefaultValues = true\n    }\n}\n\ndependencies {\n\n    implementation 'androidx.core:core-ktx:1.3.2'\n    implementation(\"net.sourceforge.jexcelapi:jxl:2.6.12\") {\n        exclude module: 'log4j'\n    }\n    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'\n    implementation 'com.google.android.material:material:1.1.0'\n    testImplementation 'junit:junit:4.+'\n    androidTestImplementation 'androidx.test.ext:junit:1.1.2'\n    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'\n}\n\n//apply plugin: 'com.github.dcendents.android-maven'\napply from: '../publish.gradle'  // Changed from 'maven' to 'maven-publish'\n"
  },
  {
    "path": "hook-sentry/gradle.properties",
    "content": "ARTIFACT_ID=hook-sentry"
  },
  {
    "path": "hook-sentry/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile"
  },
  {
    "path": "hook-sentry/src/androidTest/java/com/yl/lib/hook_sentry/ExampleInstrumentedTest.kt",
    "content": "package com.yl.lib.hook_sentry\n\nimport androidx.test.platform.app.InstrumentationRegistry\nimport androidx.test.ext.junit.runners.AndroidJUnit4\n\nimport org.junit.Test\nimport org.junit.runner.RunWith\n\nimport org.junit.Assert.*\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * See [testing documentation](http://d.android.com/tools/testing).\n */\n@RunWith(AndroidJUnit4::class)\nclass ExampleInstrumentedTest {\n    @Test\n    fun useAppContext() {\n        // Context of the app under test.\n        val appContext = InstrumentationRegistry.getInstrumentation().targetContext\n        assertEquals(\"com.yl.lib.hook_sentry\", appContext.packageName)\n    }\n}"
  },
  {
    "path": "hook-sentry/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n</manifest>"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/PrivacySentry.kt",
    "content": "package com.yl.lib.sentry.hook\n\nimport android.app.Application\nimport android.content.Context\nimport android.os.Handler\nimport android.os.Looper\nimport com.yl.lib.sentry.hook.cache.DiskCache\nimport com.yl.lib.sentry.hook.printer.BaseFilePrinter\nimport com.yl.lib.sentry.hook.printer.BasePrinter\nimport com.yl.lib.sentry.hook.printer.DefaultFilePrint\nimport com.yl.lib.sentry.hook.printer.PrintCallBack\nimport com.yl.lib.sentry.hook.util.PrivacyLog\nimport com.yl.lib.sentry.hook.util.PrivacyUtil\nimport com.yl.lib.sentry.hook.util.PrivacyUtil.Util.getApplicationByReflect\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.GlobalScope\nimport kotlinx.coroutines.launch\nimport java.io.File\nimport java.util.concurrent.atomic.AtomicBoolean\n\n/**\n * @author yulun\n * @sinice 2021-09-24 14:33\n */\nclass PrivacySentry {\n    object Privacy {\n        @Volatile\n        private var mBuilder: PrivacySentryBuilder? = PrivacySentryBuilder()\n        private val bInit = AtomicBoolean(false)\n        private val bFilePrintFinish = AtomicBoolean(false)\n        private var bShowPrivacy: AtomicBoolean? = null\n        private var ctx: Application? = null\n        private val diskCache: DiskCache by lazy {\n            DiskCache()\n        }\n\n        /**\n         *  transform简单初始化，需要搭配插件使用\n         */\n        fun initTransform(ctx: Application) {\n            var builder = PrivacySentryBuilder()\n            init(ctx, builder)\n        }\n\n        /**\n         *  完整版初始化\n         */\n        fun init(\n            ctx: Application, builder: PrivacySentryBuilder?\n        ) {\n            if (bInit.compareAndSet(false, true)) {\n                mBuilder = builder\n                initInner(ctx)\n            }\n        }\n\n        private fun initInner(ctx: Application) {\n            PrivacyLog.i(\"call initInner\")\n            this.ctx = ctx\n            if (mBuilder?.isEnableFileResult() == true || mBuilder?.debug == true) {\n                if (mBuilder?.isEnableFileResult() == true) {\n                    mBuilder?.getWatchTime()?.let {\n                        PrivacyLog.i(\"delay stop watch $it\")\n                        var handler = Handler(Looper.getMainLooper())\n                        handler.postDelayed({\n                            stop()\n                        }, it)\n                    }\n                }\n                mBuilder?.addPrinter(defaultFilePrinter(ctx, mBuilder))\n            }\n        }\n\n        fun hasInit(): Boolean {\n            return bInit.get()\n        }\n\n        /**\n         * 停止文件写入\n         */\n        fun stop() {\n            if (!isFilePrintFinish()) {\n                PrivacyLog.i(\"call stopWatch\")\n                var filePrinterList =\n                    mBuilder?.getPrinterList()?.filterIsInstance<BaseFilePrinter>()\n                var printerSize = filePrinterList?.size ?: 0\n                mBuilder?.getPrinterList()?.filterIsInstance<BaseFilePrinter>()?.forEach {\n                    // 强制写入文件\n                    GlobalScope.launch(Dispatchers.IO) {\n                        it.flushToFile()\n                        printerSize--\n                        if (printerSize == 0) {\n                            bFilePrintFinish.set(true)\n                        }\n                    }\n                    // 结果回调\n                    mBuilder?.getResultCallBack()?.onResultCallBack(it.resultFileName)\n                }\n            }\n\n        }\n\n        /**\n         * 记录展示隐私协议，调用时机一般为 隐私协议点击确定的时候，必须调用\n         */\n        fun updatePrivacyShow() {\n            if (bShowPrivacy?.get() == true) {\n                return\n            }\n            PrivacyLog.i(\"call updatePrivacyShow\")\n            if (bShowPrivacy == null) {\n                bShowPrivacy = AtomicBoolean(true)\n            } else {\n                bShowPrivacy?.compareAndSet(false, true)\n            }\n            diskCache.put(\"show_privacy_dialog\", \"true\")\n            mBuilder?.getPrinterList()?.filterIsInstance<BaseFilePrinter>()\n                ?.forEach { it.appendData(\"点击隐私协议确认\", \"点击隐私协议确认\", \"点击隐私协议确认\") }\n        }\n\n        fun hasShowPrivacy(): Boolean {\n            if (bShowPrivacy == null) {\n                // getContext() = null 代表什么？\n                // privacy还未初始化，而且是在attachBaseContext里调用\n                if (getContext() == null) {\n                    // 这里返回ture，是尽量不影响三方SDK的使用\n                    return true\n                } else {\n                    bShowPrivacy =\n                        AtomicBoolean(\n                            diskCache.get(\n                                \"show_privacy_dialog\",\n                                \"false\"\n                            ).second == \"true\"\n                        )\n\n                }\n            }\n            return bShowPrivacy?.get() ?: false\n        }\n\n        fun isDebug(): Boolean {\n            return mBuilder?.debug ?: true\n        }\n\n        fun getContext(): Application? {\n            return ctx ?: getApplicationByReflect() ?: null\n        }\n\n        fun getBuilder(): PrivacySentryBuilder? {\n            return mBuilder ?: null\n        }\n\n        fun inDangerousState(): Boolean {\n//            if (getBuilder()?.isVisitorModel() == true) {\n//                return true\n//            }\n            return !hasShowPrivacy()\n        }\n\n        /**\n         * 当前写入文件任务是否结束\n         * @return Boolean\n         */\n        fun isFilePrintFinish(): Boolean {\n            return bFilePrintFinish.get()\n        }\n\n        /**\n         * 关闭游客模式\n         */\n        @Deprecated(\"弃用\")\n        fun closeVisitorModel() {\n            mBuilder?.configVisitorModel(false)\n        }\n\n        /**\n         * 打开游客模式\n         */\n        @Deprecated(\"弃用\")\n        fun openVisitorModel() {\n            mBuilder?.configVisitorModel(true)\n        }\n\n\n        private fun defaultFilePrinter(\n            ctx: Context,\n            builder: PrivacySentryBuilder?\n        ): List<BasePrinter> {\n            var fileName = builder?.getResultFileName() ?: \"privacy_result_${\n                PrivacyUtil.Util.formatTime(\n                    System.currentTimeMillis()\n                )\n            }\"\n            PrivacyLog.i(\"print fileName is $fileName\")\n            return listOf(\n                DefaultFilePrint(\n                    \"${ctx.getExternalFilesDir(null)}${File.separator}privacy${File.separator}$fileName.xls\",\n                    printCallBack = object : PrintCallBack {\n                        override fun checkPrivacyShow(): Boolean {\n                            return hasShowPrivacy()\n                        }\n\n                        override fun stopWatch() {\n                            PrivacyLog.i(\"stopWatch\")\n                            Privacy.stop()\n                        }\n                    }, watchTime = builder?.getWatchTime()\n                )\n            )\n        }\n\n    }\n}\n\n/**\n * 检测结果回调，业务方自行处理\n */\npublic interface PrivacyResultCallBack {\n    fun onResultCallBack(filePath: String)\n}\n"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/PrivacySentryBuilder.kt",
    "content": "package com.yl.lib.sentry.hook\n\nimport com.yl.lib.sentry.hook.printer.BasePrinter\nimport com.yl.lib.sentry.hook.printer.DefaultLogPrint\nimport com.yl.lib.sentry.hook.util.MainProcessUtil\n\n/**\n * @author yulun\n * @sinice 2021-09-24 15:07\n */\nclass PrivacySentryBuilder {\n\n    // 默认需要关闭\n    @Volatile\n    var debug: Boolean = false\n\n    //日志输出 和 文件输出\n    private var mPrinterList: ArrayList<BasePrinter>? = null\n\n    // 默认的监听时间\n    private var watchTime: Long = 3 * 60 * 1000\n\n    // 结束回调\n    private var privacyResultCallBack: PrivacyResultCallBack? = null\n\n    // 输出的文件名\n    private var resultFileName: String? = null\n\n    // 是否激活输入日志到文件\n    private var enableFileResult: Boolean = true\n\n    // 游客模式，拦截所有敏感方法，默认关闭\n    @Deprecated(\"弃用\")\n    @Volatile\n    private var visitorModel: Boolean = false\n\n    // 可以拦截读取系统剪贴板\n    @Volatile\n    private var enableReadClipBoard: Boolean = true\n\n    constructor() {\n        addPrinter(DefaultLogPrint())\n    }\n\n    fun getPrinterList(): ArrayList<BasePrinter>? {\n        return mPrinterList\n    }\n\n    fun getWatchTime(): Long? {\n        return watchTime\n    }\n\n    fun getResultCallBack(): PrivacyResultCallBack? {\n        return privacyResultCallBack\n    }\n\n    fun getResultFileName(): String? {\n        // 这里可能是多进程\n        return if (MainProcessUtil.MainProcessChecker.isMainProcess(PrivacySentry.Privacy.getContext())) {\n            resultFileName\n        } else {\n            var processName = PrivacySentry.Privacy.getContext()?.let {\n                MainProcessUtil.MainProcessChecker.getProcessName(PrivacySentry.Privacy.getContext()!!)\n            } ?: \"\"\n            \"${processName}_$resultFileName\"\n        }\n    }\n\n    fun addPrinter(basePrinter: BasePrinter): PrivacySentryBuilder {\n        if (mPrinterList == null) {\n            mPrinterList = ArrayList()\n        }\n        mPrinterList?.add(basePrinter)\n        return this\n    }\n\n    fun addPrinter(basePrinter: List<BasePrinter>): PrivacySentryBuilder {\n        if (mPrinterList == null) {\n            mPrinterList = ArrayList()\n        }\n        mPrinterList?.addAll(basePrinter)\n        return this\n    }\n\n    fun syncDebug(debug: Boolean): PrivacySentryBuilder {\n        this.debug = debug\n        return this\n    }\n\n    fun configWatchTime(watchTime: Long): PrivacySentryBuilder {\n        this.watchTime = watchTime\n        return this\n    }\n\n    fun configResultCallBack(privacyResultCallBack: PrivacyResultCallBack?): PrivacySentryBuilder {\n        this.privacyResultCallBack = privacyResultCallBack\n        return this\n    }\n\n    fun configResultFileName(resultFileName: String): PrivacySentryBuilder {\n        this.resultFileName = resultFileName\n        return this\n    }\n\n    @Deprecated(\"弃用\")\n    fun configVisitorModel(visitorModel: Boolean): PrivacySentryBuilder {\n        this.visitorModel = visitorModel\n        return this\n    }\n\n    @Deprecated(\"弃用\")\n    fun isVisitorModel(): Boolean {\n        return visitorModel\n    }\n\n    fun enableFileResult(enableFileResult: Boolean): PrivacySentryBuilder {\n        this.enableFileResult = enableFileResult\n        return this\n    }\n\n    fun isEnableFileResult(): Boolean {\n        return enableFileResult\n    }\n\n    fun enableReadClipBoard(enableReadClipBoard: Boolean): PrivacySentryBuilder {\n        this.enableReadClipBoard = enableReadClipBoard\n        return this\n    }\n\n    fun isEnableReadClipBoard(): Boolean {\n        return enableReadClipBoard\n    }\n\n}\n"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/cache/BasePrivacyCache.kt",
    "content": "package com.yl.lib.sentry.hook.cache\n\n/**\n * @author yulun\n * @since 2022-10-17 11:32\n */\nabstract class BasePrivacyCache<T> {\n    var cacheType: PrivacyCacheType = PrivacyCacheType.MEMORY\n\n    constructor(cacheType: PrivacyCacheType) {\n        this.cacheType = cacheType\n    }\n\n    abstract fun get(key: String, default: T): Pair<Boolean,T?>\n\n    abstract fun put(key: String, value: T)\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/cache/CachePrivacyManager.kt",
    "content": "package com.yl.lib.sentry.hook.cache\n\nimport android.location.Location\nimport android.text.TextUtils\nimport com.yl.lib.sentry.hook.util.PrivacyProxyUtil\nimport java.io.File\n\n/**\n * @author yulun\n * @since 2022-10-18 10:39\n */\nclass CachePrivacyManager {\n    object Manager {\n        private val dickCache: DiskCache by lazy {\n            DiskCache()\n        }\n\n        // 不同字段可能对时间的要求不一样\n        private val timeDiskCache: TimeLessDiskCache by lazy {\n            TimeLessDiskCache()\n        }\n\n        private val memoryCache: MemoryCache<Any> by lazy {\n            MemoryCache<Any>()\n        }\n\n        private val timeMemoryCache: TimeLessMemoryCache<Any> by lazy {\n            TimeLessMemoryCache<Any>()\n        }\n\n        fun <T> loadWithMemoryCache(\n            key: String,\n            methodDocumentDesc: String,\n            defaultValue: T,\n            getValue: () -> T\n        ): T {\n            var result = getCacheParam(key, defaultValue, PrivacyCacheType.MEMORY)\n            return handleData(\n                key,\n                methodDocumentDesc,\n                defaultValue,\n                getValue,\n                result,\n                PrivacyCacheType.MEMORY\n            )\n        }\n\n        fun <T> loadWithTimeMemoryCache(\n            key: String,\n            methodDocumentDesc: String,\n            defaultValue: T,\n            duration: Long = 0,\n            getValue: () -> T\n        ): T {\n            var result = getCacheParam(key, defaultValue, PrivacyCacheType.TIMELINESS_MEMORY)\n            return handleData(\n                key,\n                methodDocumentDesc,\n                defaultValue,\n                getValue,\n                result,\n                PrivacyCacheType.TIMELINESS_MEMORY,\n                duration\n            )\n        }\n\n        fun loadWithTimeDiskCache(\n            key: String,\n            methodDocumentDesc: String,\n            defaultValue: String,\n            duration: Long = CacheUtils.Utils.MINUTE * 30,\n            getValue: () -> String\n        ): String {\n            var result = getCacheParam(\n                key,\n                defaultValue,\n                PrivacyCacheType.TIMELINESS_DISK\n            )\n            return handleData(\n                key,\n                methodDocumentDesc,\n                defaultValue,\n                getValue,\n                result,\n                PrivacyCacheType.TIMELINESS_DISK,\n                duration\n            )\n        }\n\n        fun loadWithDiskCache(\n            key: String,\n            methodDocumentDesc: String,\n            defaultValue: String,\n//            transform: ((value: T) -> T)? = null,\n            getValue: () -> String\n        ): String {\n            var result = getCacheParam(key, defaultValue, PrivacyCacheType.PERMANENT_DISK)\n            return handleData(\n                key,\n                methodDocumentDesc,\n                defaultValue,\n                getValue,\n                result,\n                PrivacyCacheType.PERMANENT_DISK\n            )\n        }\n\n\n\n        private fun <T> handleData(\n            key: String,\n            methodDocumentDesc: String,\n            defaultValue: T,\n            getValue: () -> T,\n            cacheResult: Pair<Boolean, T>,\n            cacheType: PrivacyCacheType,\n            duration: Long = 0\n        ): T {\n            if (cacheResult.first) {\n                PrivacyProxyUtil.Util.doFilePrinter(key, methodDocumentDesc, bCache = true)\n                return cacheResult.second\n            }\n            PrivacyProxyUtil.Util.doFilePrinter(key, methodDocumentDesc)\n            var value: T? = null\n            try {\n                value = getValue()\n            } catch (e: Throwable) {\n                e.printStackTrace()\n                throw e\n            } finally {\n                putCacheParam(value ?: defaultValue, key, cacheType, duration)\n            }\n            return value ?: defaultValue\n        }\n\n\n        /**\n         * 获取该进程内已经缓存的静态字段\n         * @param defaultValue T\n         * @param key String\n         * @return T\n         */\n        private fun <T> getCacheParam(\n            key: String,\n            defaultValue: T,\n            cacheType: PrivacyCacheType\n        ): Pair<Boolean, T> {\n            var cacheValue = when (cacheType) {\n                PrivacyCacheType.MEMORY -> memoryCache.get(key, defaultValue as Any)\n                PrivacyCacheType.TIMELINESS_MEMORY -> timeMemoryCache.get(\n                    key,\n                    defaultValue as Any\n                )\n                PrivacyCacheType.PERMANENT_DISK -> dickCache.get(key, defaultValue.toString())\n                PrivacyCacheType.TIMELINESS_DISK -> timeDiskCache.get(key, defaultValue.toString())\n            }\n            return if (cacheValue.first) {\n                Pair(true, cacheValue.second as T)\n            } else {\n                var value = cacheValue.second\n                if (isEmpty(value)) {\n                    value = defaultValue\n                }\n                Pair(false, value as T)\n            }\n        }\n\n        /**\n         * 设置字段\n         * @param value T\n         * @param key String\n         */\n        private fun <T> putCacheParam(\n            value: T,\n            key: String,\n            cacheType: PrivacyCacheType,\n            duration: Long = 0\n        ) {\n            value?.also {\n                when (cacheType) {\n                    PrivacyCacheType.MEMORY -> memoryCache.put(key, value)\n                    PrivacyCacheType.TIMELINESS_MEMORY -> timeMemoryCache.put(\n                        key,\n                        value as Any,\n                        duration\n                    )\n                    PrivacyCacheType.PERMANENT_DISK -> dickCache.put(key, value.toString())\n                    PrivacyCacheType.TIMELINESS_DISK -> timeDiskCache.put(key, value.toString(),duration)\n                }\n            }\n        }\n\n        private fun isEmpty(value: Any?): Boolean {\n            if (value == null) {\n                return true\n            } else if (value is String && TextUtils.isEmpty(value)) {\n                return true\n            } else if (value is List<*> && value.isEmpty()) {\n                return true\n            } else if (value is Map<*, *> && value.isEmpty()) {\n                return true\n            } else if (value is File && value.absolutePath.equals(\"/\")) {\n                return true\n            } else if (value is Location && (value.latitude == 0.0 || value.longitude == 0.0)) {\n                return true\n            }\n            return false\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/cache/CacheUtils.kt",
    "content": "package com.yl.lib.sentry.hook.cache\n\nimport android.content.Context.MODE_PRIVATE\nimport android.content.SharedPreferences\nimport android.text.TextUtils\nimport com.yl.lib.sentry.hook.PrivacySentry\n\n/**\n * @author yulun\n * @since 2022-10-17 14:47\n * 封装部分通用函数\n */\nclass CacheUtils {\n    object Utils {\n        // 带有时间属性的缓存格式\n        // 0-12位 xxx 13-？有效期，单位毫秒 |分隔符 实际值\n        private const val separator: String = \"|\"\n\n        const val MINUTE = 60 * 1000L\n        const val HOUR = MINUTE * 60\n        const val DAY = HOUR * 24\n        const val EMPTY = \"|PrivacyEmpty|\"\n\n        /**\n         * 当前值是否在有效期\n         * @param value String\n         * @return Boolean\n         */\n        fun isValid(value: String): Boolean {\n            if (!isPrivacyTimeData(value)) {\n                return false\n            }\n            try {\n                val starTime = value.substring(0, 13)\n                val validTime = value.substring(13, value.indexOf(separator))\n                return System.currentTimeMillis() - starTime.toLong() < validTime.toLong()\n            } catch (e: Exception) {\n                e.printStackTrace()\n            } catch (e: Exception) {\n                throw e\n            }\n            return false\n        }\n\n        fun parseValue(value: String, default: String): String {\n            if (TextUtils.isEmpty(value)) {\n                return default\n            }\n            if (!isPrivacyTimeData(value)) {\n                return value\n            }\n            return value.substring(value.indexOf(separator) + 1, value.length)\n        }\n\n        /**\n         *\n         * @param value String 实际的值\n         * @param validTime Long 单位ms\n         */\n        fun buildTimeValue(value: String, validTime: Long): String {\n            return \"${System.currentTimeMillis()}$validTime$separator$value\"\n        }\n\n        private fun isPrivacyTimeData(value: String): Boolean {\n            return value != null && value.length > 15 && value.indexOf(separator) > 13\n        }\n\n        fun saveToSp(key: String, value: String) {\n            getSp()?.edit()?.putString(key, value)?.apply()\n        }\n\n        fun loadFromSp(key: String, defaultValue: String): Pair<Boolean, Any?> {\n            if (getSp() == null) {\n                return Pair(false, defaultValue)\n            }\n            var result = getSp()?.getString(key, EMPTY)\n\n            var success = false\n            if (EMPTY == result) {\n                result = defaultValue\n                success = false\n            } else {\n                success = true\n            }\n            return Pair(success, result)\n        }\n\n        fun clearData(key: String) {\n            getSp()?.edit()?.remove(key)?.apply()\n        }\n\n        private var sp: SharedPreferences? = null\n        private fun getSp(): SharedPreferences? {\n            if (sp != null) {\n                return sp\n            }\n            return PrivacySentry.Privacy.getContext()?.getSharedPreferences(\"sentry\", MODE_PRIVATE)\n        }\n    }\n\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/cache/DiskCache.kt",
    "content": "package com.yl.lib.sentry.hook.cache\n\nimport java.util.concurrent.ConcurrentHashMap\n\n/**\n * @author yulun\n * @since 2022-10-17 16:56\n */\nclass DiskCache : BasePrivacyCache<String>(PrivacyCacheType.PERMANENT_DISK) {\n\n    // 加个内存级别，避免频繁读sp\n    private var paramMap: ConcurrentHashMap<String, String> = ConcurrentHashMap()\n\n\n    override fun get(key: String, default: String): Pair<Boolean, String?> {\n        if (paramMap.containsKey(key)) {\n            return Pair(true, paramMap[key] as String)\n        }\n\n        // 读操作可以频繁，文件io只会触发一次\n        var cacheResult: Pair<Boolean, String?> =\n            CacheUtils.Utils.loadFromSp(key, default) as Pair<Boolean,String?>\n        if (cacheResult.first) {\n            paramMap[key] = cacheResult.second!!\n        }\n        return cacheResult\n    }\n\n\n    // TODO 如何优化，避免频繁写入sp\n    override fun put(key: String, value: String) {\n        paramMap[key] = value\n        CacheUtils.Utils.saveToSp(key, value)\n    }\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/cache/MemoryCache.kt",
    "content": "package com.yl.lib.sentry.hook.cache\n\nimport java.util.concurrent.ConcurrentHashMap\n\n/**\n * @author yulun\n * @since 2022-10-17 11:39\n */\nclass MemoryCache<T> : BasePrivacyCache<T>(PrivacyCacheType.MEMORY) {\n\n    //部分字段只需要读取一次\n    // 部分SDK在子线程读取，需要声明可见性\n    private var paramMap: ConcurrentHashMap<String, T> = ConcurrentHashMap()\n\n    override fun get(key: String, default: T): Pair<Boolean, T?> {\n        return if (paramMap.containsKey(key)) {\n            Pair(true, paramMap[key] as? T ?: default)\n        } else {\n            Pair(false, null)\n        }\n    }\n\n    override fun put(key: String, value: T) {\n        paramMap[key] = value\n    }\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/cache/PrivacyCacheType.kt",
    "content": "package com.yl.lib.sentry.hook.cache\n\n/**\n * @author yulun\n * @since 2022-10-14 17:55\n */\nenum class PrivacyCacheType {\n    /**\n     * 内存缓存\n     */\n    MEMORY,\n\n    /**\n     * 内存 with 时间\n     */\n    TIMELINESS_MEMORY,\n\n    /**\n     * 磁盘，带有过期时间\n     */\n    TIMELINESS_DISK,\n\n    /**\n     * 磁盘，永久(app缓存不被删，就一直在)\n     */\n    PERMANENT_DISK\n\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/cache/TimeLessDiskCache.kt",
    "content": "package com.yl.lib.sentry.hook.cache\n\nimport android.text.TextUtils\nimport java.util.concurrent.ConcurrentHashMap\n\n/**\n * @author yulun\n * @since 2022-10-17 11:46\n *\n */\nclass TimeLessDiskCache : BasePrivacyCache<String>(PrivacyCacheType.TIMELINESS_DISK) {\n    // 加个内存级别，避免频繁读sp\n    private var paramMap: ConcurrentHashMap<String, String> = ConcurrentHashMap()\n\n    override fun get(key: String, default: String): Pair<Boolean, String?> {\n        var value: String = if (paramMap.containsKey(key)) {\n            paramMap[key] ?: default\n        } else {\n            var cache = CacheUtils.Utils.loadFromSp(key, \"\")\n            if (cache.first) {\n                cache.second?.toString() ?: default\n            } else {\n                cache.second?.toString() ?: default\n            }\n        }\n\n        value?.let {\n            return if (CacheUtils.Utils.isValid(it)) {\n                Pair(true, CacheUtils.Utils.parseValue(it, default))\n            } else {\n                CacheUtils.Utils.clearData(key)\n                Pair(false, default)\n            }\n        }\n        return Pair(false, default)\n    }\n\n    override fun put(key: String, value: String) {\n        put(key, value, 0)\n    }\n\n\n    fun put(key: String, value: String, duration: Long) {\n        if (TextUtils.isEmpty(key) || value == null) {\n            return\n        }\n        var formatValue = CacheUtils.Utils.buildTimeValue(value, duration)\n        paramMap[key] = formatValue\n        CacheUtils.Utils.saveToSp(\n            key,\n            formatValue\n        )\n    }\n\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/cache/TimeLessMemoryCache.kt",
    "content": "package com.yl.lib.sentry.hook.cache\n\nimport android.text.TextUtils\nimport java.util.concurrent.ConcurrentHashMap\n\n/**\n * @author yulun\n * @since 2022-10-17 11:46\n *\n */\nclass TimeLessMemoryCache<T> : BasePrivacyCache<T>(PrivacyCacheType.TIMELINESS_DISK) {\n    // 加个内存级别，避免频繁读sp\n    private var paramMap: ConcurrentHashMap<String, T> = ConcurrentHashMap()\n\n    private var timeMap: ConcurrentHashMap<String, Long> = ConcurrentHashMap()\n\n    override fun get(key: String, default: T): Pair<Boolean, T?> {\n        var value: T? = if (paramMap.containsKey(key)) {\n            paramMap[key] ?: default\n        } else {\n            null\n        }\n\n        if (value == null) {\n            return  Pair(false, default)\n        }\n\n        return value.let {\n            if (System.currentTimeMillis() < timeMap[key]!!) {\n                Pair(true, value)\n            } else {\n                paramMap.remove(key)\n                timeMap.remove(key)\n                Pair(false, default)\n            }\n        }\n    }\n\n    override fun put(key: String, value: T) {\n        put(key, value, 0)\n    }\n\n    fun put(key: String, value: T, duration: Long) {\n        if (TextUtils.isEmpty(key) || value == null) {\n            return\n        }\n        paramMap[key] = value\n        timeMap[key] = System.currentTimeMillis() + duration\n    }\n\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/excel/ExcelBuildDataListener.kt",
    "content": "package com.yl.lib.sentry.hook.excel\n\nimport com.yl.lib.sentry.hook.printer.PrivacyFunBean\n\n/**\n * @author yulun\n * @sinice 2021-11-25 14:28\n */\ninterface ExcelBuildDataListener {\n    fun buildData(sheetIndex: Int, privacyFunBean: PrivacyFunBean): List<String>\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/excel/ExcelUtil.kt",
    "content": "package com.yl.lib.sentry.hook.excel\n\nimport com.yl.lib.sentry.hook.printer.PrivacyFunBean\nimport com.yl.lib.sentry.hook.util.PrivacyLog\nimport jxl.Workbook\nimport jxl.WorkbookSettings\nimport jxl.format.Alignment\nimport jxl.format.Border\nimport jxl.format.BorderLineStyle\nimport jxl.format.Colour\nimport jxl.write.*\nimport java.io.File\nimport java.io.FileInputStream\nimport java.io.IOException\nimport java.io.InputStream\n\n\n/**\n * @author yulun\n * @sinice 2021-11-19 15:14\n */\nclass ExcelUtil {\n    object instance {\n        private var arial14font: WritableFont? = null\n\n        private var arial14format: WritableCellFormat? = null\n        private var arial10font: WritableFont? = null\n        private var arial10format: WritableCellFormat? = null\n        private var arial12font: WritableFont? = null\n        private var arial12format: WritableCellFormat? = null\n        private const val UTF8_ENCODING = \"UTF-8\"\n\n\n        /**\n         * 单元格的格式设置 字体大小 颜色 对齐方式、背景颜色等...\n         */\n        private fun format() {\n            try {\n                arial14font = WritableFont(WritableFont.ARIAL, 14, WritableFont.BOLD)\n                arial14font!!.colour = Colour.LIGHT_BLUE\n                arial14format = WritableCellFormat(arial14font)\n                arial14format!!.alignment = Alignment.CENTRE\n                arial14format!!.setBorder(Border.ALL, BorderLineStyle.THIN)\n                arial14format!!.setBackground(Colour.VERY_LIGHT_YELLOW)\n                arial10font = WritableFont(WritableFont.ARIAL, 10, WritableFont.BOLD)\n                arial10format = WritableCellFormat(arial10font)\n                arial10format!!.alignment = Alignment.CENTRE\n                arial10format!!.setBorder(Border.ALL, BorderLineStyle.THIN)\n                arial10format!!.setBackground(Colour.GRAY_25)\n                arial12font = WritableFont(WritableFont.ARIAL, 10)\n                arial12format = WritableCellFormat(arial12font)\n                //对齐格式\n                arial10format!!.alignment = Alignment.CENTRE\n                //设置边框\n                arial12format!!.setBorder(Border.ALL, BorderLineStyle.THIN)\n            } catch (e: WriteException) {\n                e.printStackTrace()\n            }\n        }\n\n        fun checkDelOldFile(filePath: String){\n            try {\n                val file = File(filePath)\n                if (file.exists()) {\n                    file.delete()\n                    PrivacyLog.i(\"del old file  name is $filePath\")\n                }\n            }catch (e:java.lang.Exception){\n                e.printStackTrace()\n            }\n        }\n        /**\n         * 初始化Excel表格\n         *\n         * @param filePath  存放excel文件的路径（path/demo.xls）\n         * @param sheetName Excel表格的表名\n         * @param colName   excel中包含的列名（可以有多个）\n         */\n        fun initExcel(\n            filePath: String,\n            sheetName: List<String>,\n            colName: List<Array<String>>,\n            sheetIndex: List<Int>\n        ) {\n            format()\n            var workbook: WritableWorkbook? = null\n            try {\n                val file = File(filePath)\n                if (file.exists()) {\n                    file.deleteOnExit()\n                }\n                if (!file.parentFile.exists()) {\n                    file.parentFile.mkdirs()\n                }\n                file.createNewFile()\n                workbook = Workbook.createWorkbook(file)\n                for (index in sheetName.indices) {\n                    //设置表格的名字\n                    val sheet = workbook.createSheet(sheetName[index], sheetIndex[index])\n                    //创建标题栏\n                    sheet.addCell(Label(0, 0, filePath, arial14format) as WritableCell)\n                    var currentColName = colName[index]\n                    for (col in currentColName.indices) {\n                        sheet.addCell(Label(col, 0, currentColName[col], arial10format))\n                    }\n                    //设置行高\n                    sheet.setRowView(0, 340)\n                }\n                workbook.write()\n                PrivacyLog.e(\"initExcel success\")\n            } catch (e: Exception) {\n                PrivacyLog.e(\"initExcel fail\")\n                e.printStackTrace()\n            } finally {\n                if (workbook != null) {\n                    try {\n                        workbook.close()\n                    } catch (e: Exception) {\n                        e.printStackTrace()\n                    }\n                }\n            }\n        }\n\n        /**\n         *\n         */\n        fun writeObjListToExcel(\n            objList: List<PrivacyFunBean>?,\n            fileName: String?,\n            sheetIndex: Int,\n            buildDataListener: ExcelBuildDataListener\n        ) {\n            if (objList != null && objList.isNotEmpty()) {\n                var writebook: WritableWorkbook? = null\n                var `in`: InputStream? = null\n                try {\n                    val setEncode = WorkbookSettings()\n                    setEncode.encoding = UTF8_ENCODING\n                    `in` = FileInputStream(File(fileName))\n                    val workbook = Workbook.getWorkbook(`in`)\n                    writebook = Workbook.createWorkbook(File(fileName), workbook)\n                    val sheet = writebook.getSheet(sheetIndex)\n                    for (j in objList.indices) {\n                        val privacyFunBean = objList[j] as PrivacyFunBean\n                        val list = buildDataListener.buildData(sheetIndex, privacyFunBean)\n                        for (i in list.indices) {\n                            sheet.addCell(Label(i, j + 1, list[i], arial12format))\n                            if (list[i]!!.length <= 4) {\n                                //设置列宽\n                                sheet.setColumnView(i, list[i]!!.length + 8)\n                            } else {\n                                //设置列宽\n                                sheet.setColumnView(i, list[i]!!.length + 5)\n                            }\n                        }\n                        //设置行高\n                        sheet.setRowView(j + 1, 500)\n                    }\n                    writebook.write()\n                    workbook.close()\n                    PrivacyLog.e(\"导出Excel success file : $fileName\")\n                    PrivacyLog.e(\"可执行  adb pull $fileName\")\n                } catch (e: Exception) {\n                    PrivacyLog.e(\"导出Excel fail\")\n                    e.printStackTrace()\n                } finally {\n                    if (writebook != null) {\n                        try {\n                            writebook.close()\n                        } catch (e: Exception) {\n                            e.printStackTrace()\n                        }\n                    }\n                    if (`in` != null) {\n                        try {\n                            `in`.close()\n                        } catch (e: IOException) {\n                            e.printStackTrace()\n                        }\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/printer/BaseFilePrinter.kt",
    "content": "package com.yl.lib.sentry.hook.printer\n\nimport com.yl.lib.sentry.hook.util.PrivacyLog\n\n/**\n * @author yulun\n * @sinice 2021-11-22 14:26\n */\nabstract class BaseFilePrinter : BasePrinter {\n\n    val printCallBack: PrintCallBack\n    val resultFileName:String\n\n    constructor(printCallBack: PrintCallBack,resultFileName:String) {\n        this.printCallBack = printCallBack\n        this.resultFileName = resultFileName\n    }\n\n    final override fun filePrint(funName: String, funAlias: String, msg: String) {\n        if (!printCallBack.checkPrivacyShow()) {\n            PrivacyLog.e(\"check!!! 还未展示隐私协议，Illegal print\")\n        }\n        appendData(funName, funAlias, msg)\n    }\n\n    abstract fun flushToFile()\n\n    abstract fun appendData(funName: String, funAlias: String, msg: String)\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/printer/BasePrinter.kt",
    "content": "package com.yl.lib.sentry.hook.printer\n\n/**\n * @author yulun\n * @sinice 2021-09-24 15:43\n */\nopen class BasePrinter {\n\n    constructor()\n\n    open fun logPrint(msg:String){}\n\n    open fun filePrint(funName:String, funAlias:String, msg:String){}\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/printer/DefaultFilePrint.kt",
    "content": "package com.yl.lib.sentry.hook.printer\n\nimport com.yl.lib.sentry.hook.PrivacySentry\nimport com.yl.lib.sentry.hook.excel.ExcelBuildDataListener\nimport com.yl.lib.sentry.hook.excel.ExcelUtil\nimport com.yl.lib.sentry.hook.util.PrivacyLog\nimport com.yl.lib.sentry.hook.watcher.DelayTimeWatcher\nimport com.yl.lib.sentry.hook.watcher.PrivacyDataManager\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.GlobalScope\nimport kotlinx.coroutines.launch\n\n/**\n * @author yulun\n * @sinice 2021-09-24 15:47\n * 为了可以更直观的查看统计结果，默认采用excel文件形式输出\n */\nclass DefaultFilePrint : BaseFilePrinter {\n\n    // 隐私函数调用 堆栈跟踪\n    private val titlePrivacyLegal = arrayOf(\"调用时间(倒序排序)\", \"别名\", \"函数名\", \"调用堆栈\")\n    private val sheetPrivacyLegal = 0\n\n    // 隐私函数调用次数聚合\n    private val titlePrivacyCount = arrayOf(\"别名\", \"函数名\", \"调用堆栈\", \"调用次数\")\n    private val sheetPrivacyCount = 1\n\n    @Volatile\n    private var hasInit = false\n\n    constructor(\n        fileName: String,\n        printCallBack: PrintCallBack,\n        watchTime: Long?\n    ) : super(printCallBack, fileName) {\n        PrivacyLog.i(\"file name is $fileName\")\n        if (PrivacySentry.Privacy.getBuilder()?.isEnableFileResult() == true) {\n            GlobalScope.launch(Dispatchers.IO) {\n                ExcelUtil.instance.checkDelOldFile(fileName)\n            }\n        }\n\n        DelayTimeWatcher(watchTime ?: 60 * 60 * 1000, Runnable {\n            GlobalScope.launch(Dispatchers.IO) {\n                flushToFile()\n            }\n        })\n    }\n\n    override fun logPrint(msg: String) {\n    }\n\n    override fun flushToFile() {\n        assert(resultFileName != null)\n        if (PrivacyDataManager.Manager.isEmpty())\n            return\n        if (PrivacySentry.Privacy.getBuilder()?.isEnableFileResult() == false) {\n            PrivacyLog.e(\"disable print file\")\n            return\n        }\n        if (PrivacySentry.Privacy.isFilePrintFinish()) {\n            PrivacyLog.e(\"print file finished,so fail to print file\")\n            return\n        }\n\n        if (!hasInit) {\n            hasInit = true\n            ExcelUtil.instance.initExcel(\n                resultFileName,\n                arrayListOf(\"隐私合规\", \"调用次数\"),\n                arrayListOf(titlePrivacyLegal, titlePrivacyCount),\n                arrayListOf(sheetPrivacyLegal, sheetPrivacyCount)\n            )\n        }\n        var newFunBeanList = ArrayList<PrivacyFunBean>()\n        newFunBeanList.addAll(PrivacyDataManager.Manager.getFunBeanList())\n        flushSheetPrivacyLegal(newFunBeanList)\n        flushSheetPrivacyCount(newFunBeanList)\n        newFunBeanList.clear()\n    }\n\n    override fun appendData(funName: String, funAlias: String, msg: String) {\n        if (funName == null || funAlias == null)\n            return\n        PrivacyDataManager.Manager.addData(PrivacyFunBean(funAlias, funName, msg, 1))\n    }\n\n    private fun flushSheetPrivacyCount(funBeanList: ArrayList<PrivacyFunBean>) {\n        try {\n            var privacyFunBeanMap: HashMap<String, PrivacyFunBean> = HashMap()\n            PrivacyLog.e(\"call flushSheetPrivacyCount\")\n            funBeanList.filter { !it.funName.equals(\"点击隐私协议确认\") }.forEach {\n                if (privacyFunBeanMap[it.buildStackTrace()] == null) {\n                    privacyFunBeanMap[it.buildStackTrace()] = it\n                } else {\n                    privacyFunBeanMap[it.buildStackTrace()]?.addSelf()\n                }\n            }\n            ExcelUtil.instance.writeObjListToExcel(\n                privacyFunBeanMap?.map { it.value },\n                resultFileName,\n                sheetPrivacyCount, object : ExcelBuildDataListener {\n                    override fun buildData(\n                        sheetIndex: Int,\n                        privacyFunBean: PrivacyFunBean\n                    ): List<String> {\n                        return listOf(\n                            privacyFunBean.funAlias.toString(),\n                            privacyFunBean.funName.toString(),\n                            privacyFunBean.buildStackTrace(),\n                            privacyFunBean.count.toString()\n                        )\n                    }\n                }\n            )\n        } catch (e: java.lang.Exception) {\n            e.printStackTrace()\n        }\n\n    }\n\n    private fun flushSheetPrivacyLegal(funBeanList: ArrayList<PrivacyFunBean>) {\n        try {\n            PrivacyLog.e(\"call flushSheetPrivacyLegal\")\n            ExcelUtil.instance.writeObjListToExcel(\n                funBeanList,\n                resultFileName,\n                sheetPrivacyLegal,\n                object : ExcelBuildDataListener {\n                    override fun buildData(\n                        sheetIndex: Int,\n                        privacyFunBean: PrivacyFunBean\n                    ): List<String> {\n                        return listOf(\n                            privacyFunBean.appendTime.toString(),\n                            privacyFunBean.funAlias.toString(),\n                            privacyFunBean.funName.toString(),\n                            privacyFunBean.buildStackTrace()\n                        )\n                    }\n\n                })\n        } catch (e: java.lang.Exception) {\n            e.printStackTrace()\n        }\n    }\n}\n"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/printer/DefaultLogPrint.kt",
    "content": "package com.yl.lib.sentry.hook.printer\n\nimport com.yl.lib.sentry.hook.util.PrivacyLog\n\n\n/**\n * @author yulun\n * @sinice 2021-09-24 15:46\n */\nclass DefaultLogPrint : BasePrinter() {\n    override fun logPrint(msg: String) {\n        PrivacyLog.i(\"msg : $msg\")\n    }\n\n    override fun filePrint(funName: String, funAlias: String, msg: String) {\n        logPrint(\"$funName-$funAlias-$msg\")\n    }\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/printer/PrintCallBack.kt",
    "content": "package com.yl.lib.sentry.hook.printer\n\n/**\n * @author yulun\n * @sinice 2021-11-22 14:20\n */\ninterface PrintCallBack {\n    fun checkPrivacyShow():Boolean\n\n    fun stopWatch()\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/printer/PrivacyFunBean.kt",
    "content": "package com.yl.lib.sentry.hook.printer\n\nimport com.yl.lib.sentry.hook.util.PrivacyUtil\n\n/**\n * @author yulun\n * @sinice 2021-11-19 15:24\n * 写入文件记录的单条记录\n */\nclass PrivacyFunBean {\n\n    // 记录生成的时间\n    var appendTime: String? = null\n\n    /**\n     * 类似于我们正常理解中的别名，比如imsi在系统里的函数名并不是imsi\n     */\n    var funAlias: String? = null\n\n    /**\n     * 实际的函数名\n     */\n    var funName: String? = null\n\n    /**\n     * 调用的堆栈\n     */\n    var stackTraces: String? = null\n\n    /**\n     * 调用次数，同个堆栈可能调用多次，这个也存在合规风险\n     */\n    var count = 0\n\n\n    constructor(alias: String?, funName: String?, stackTrace: String?, count: Int) {\n        appendTime = PrivacyUtil.Util.formatTime(System.currentTimeMillis(), \"MM-dd HH:mm:ss.SSS\")\n        this.funAlias = alias\n        this.funName = funName\n        this.stackTraces = trimTrace(stackTrace)\n        this.count = count\n    }\n\n    fun addSelf() {\n        count++\n    }\n\n    fun buildStackTrace(): String {\n        if (stackTraces == null || stackTraces?.isEmpty() != false) {\n            return \"\"\n        }\n        return stackTraces ?: \"\"\n    }\n\n    // 裁剪掉部分冗余重复的trace\n    private fun trimTrace(stackStrace: String?): String? {\n        if (stackStrace == null || \"\" == stackStrace)\n            return \"\"\n        var sArray = stackStrace?.split(\"\\n\")\n        var delIndex = sArray?.indexOfFirst { it.contains(\"java.lang.reflect.Proxy.invoke\") }\n        if (delIndex != null && delIndex <= 0) {\n            return stackStrace\n        }\n        return sArray?.subList(delIndex!!+1,sArray.size)?.joinToString(separator = \"\\n\")\n    }\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/util/MainProcessUtil.kt",
    "content": "package com.yl.lib.sentry.hook.util\n\nimport android.app.Application\nimport android.content.Context\nimport android.os.Build\nimport android.text.TextUtils\n\n/**\n * @author yulun\n * @sinice 2021-09-24 14:54\n * 主进程判断代码，绕过getRunningAppProcesses\n */\nclass MainProcessUtil {\n    object MainProcessChecker {\n        private var currentProcessName = \"\"\n\n        /**\n         * 是否主进程\n         */\n        fun isMainProcess(context: Context?): Boolean {\n            if (context == null) {\n                PrivacyLog.e(\"======> isMainProcess context == null\")\n                return false\n            }\n            if (TextUtils.isEmpty(currentProcessName)) {\n                currentProcessName = getProcessName(context)\n            }\n            return context.packageName == currentProcessName\n        }\n\n        /**\n         * 当前进程名\n         */\n        fun getProcessName(context: Context): String {\n            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n                // 9.0开始直接读\n                Application.getProcessName()\n            } else {\n                // 9.0以下反射拿\n                getProcessNameByReflect(context)\n            }\n        }\n\n        // 以下代码 替代 getRunningProcessName\n        private fun getProcessNameByReflect(context: Context): String {\n            val activityThread = getActivityThread(context)\n            if (activityThread != null) {\n                try {\n                    val method =\n                        activityThread.javaClass.getMethod(\"currentProcessName\")\n                    method.isAccessible = true\n                    return method.invoke(activityThread) as String\n                } catch (e: Exception) {\n                    e.printStackTrace()\n                }\n            }\n            return \"\"\n        }\n\n        private fun getActivityThread(context: Context): Any? {\n            var activityThread = getActivityThreadInActivityThreadStaticField()\n            if (activityThread != null) return activityThread\n            activityThread = getActivityThreadInActivityThreadStaticMethod()\n            return activityThread ?: getActivityThreadInLoadedApkField(context)\n        }\n\n        private fun getActivityThreadInActivityThreadStaticField(): Any? {\n            return try {\n                val activityThreadClass = Class.forName(\"android.app.ActivityThread\")\n                val sCurrentActivityThreadField =\n                    activityThreadClass.getDeclaredField(\"sCurrentActivityThread\")\n                sCurrentActivityThreadField.isAccessible = true\n                sCurrentActivityThreadField[null]\n            } catch (e: Exception) {\n                PrivacyLog.e(\"getActivityThreadInActivityThreadStaticField: \" + e.message)\n                null\n            }\n        }\n\n        private fun getActivityThreadInActivityThreadStaticMethod(): Any? {\n            return try {\n                val activityThreadClass = Class.forName(\"android.app.ActivityThread\")\n                activityThreadClass.getMethod(\"currentActivityThread\").invoke(null)\n            } catch (e: Exception) {\n                PrivacyLog.e(\"getActivityThreadInActivityThreadStaticMethod: \" + e.message)\n                null\n            }\n        }\n\n        private fun getActivityThreadInLoadedApkField(context: Context): Any? {\n            return try {\n                val mLoadedApkField = Application::class.java.getDeclaredField(\"mLoadedApk\")\n                mLoadedApkField.isAccessible = true\n                val mLoadedApk = mLoadedApkField[context]\n                val mActivityThreadField = mLoadedApk.javaClass.getDeclaredField(\"mActivityThread\")\n                mActivityThreadField.isAccessible = true\n                mActivityThreadField[mLoadedApk]\n            } catch (e: Exception) {\n                PrivacyLog.e(\"getActivityThreadInLoadedApkField: \" + e.message)\n                null\n            }\n        }\n    }\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/util/PrivacyClipBoardManager.kt",
    "content": "package com.yl.lib.sentry.hook.util\n\nimport androidx.annotation.Keep\nimport com.yl.lib.sentry.hook.PrivacySentry\nimport com.yl.lib.sentry.hook.cache.DiskCache\n\n/**\n * @author yulun\n * @since 2022-11-02 15:28\n */\n@Keep\nclass PrivacyClipBoardManager {\n    @Keep\n    companion object {\n\n        private val diskCache by lazy {\n            DiskCache()\n        }\n        var bReadClipboardEnable: Boolean? = null\n\n        /**\n         * 打开 读取系统剪贴板\n         */\n        fun openReadClipboard() {\n            PrivacySentry.Privacy.getBuilder()?.enableReadClipBoard(true)\n            syncReadClipboardEnable(true)\n        }\n\n        /**\n         * 关闭 读取系统剪贴板\n         */\n        fun closeReadClipboard() {\n            PrivacySentry.Privacy.getBuilder()?.enableReadClipBoard(false)\n            syncReadClipboardEnable(false)\n        }\n\n        /**\n         * 当前读取系统剪贴板是否开启，默认true\n         * @return Boolean\n         */\n        fun isReadClipboardEnable(): Boolean {\n            if (bReadClipboardEnable == null) {\n                var strEnable = diskCache.get(\"isReadClipboardEnable\", \"true\")?.second\n                bReadClipboardEnable = strEnable?.toBoolean() ?: true\n            }\n            return (PrivacySentry.Privacy.getBuilder()?.isEnableReadClipBoard()\n                ?: true) && (bReadClipboardEnable ?: true)\n        }\n\n        private fun syncReadClipboardEnable(bEnable: Boolean) {\n            if (bEnable != bReadClipboardEnable) {\n                bReadClipboardEnable = bEnable\n                diskCache.put(\"isReadClipboardEnable\", bEnable.toString())\n            }\n        }\n    }\n\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/util/PrivacyLog.kt",
    "content": "package com.yl.lib.sentry.hook.util\n\nimport com.yl.lib.sentry.hook.PrivacySentry\n\n\n/**\n * @author yulun\n * @sinice 2021-06-10 15:09\n */\nclass PrivacyLog {\n    companion object Log {\n        private const val TAG = \"PrivacyOfficer\"\n\n        fun e(msg: String) {\n            if (PrivacySentry.Privacy.isDebug() || PrivacySentry.Privacy.inDangerousState()) {\n                android.util.Log.e(TAG, msg)\n            }\n        }\n\n        fun w(msg: String) {\n            if (PrivacySentry.Privacy.isDebug() || PrivacySentry.Privacy.inDangerousState()) {\n                android.util.Log.w(TAG, msg)\n            }\n        }\n\n        fun i(msg: String) {\n            if (PrivacySentry.Privacy.isDebug() || PrivacySentry.Privacy.inDangerousState()) {\n                android.util.Log.i(TAG, msg)\n            }\n        }\n    }\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/util/PrivacyProxyUtil.kt",
    "content": "package com.yl.lib.sentry.hook.util\n\nimport android.content.pm.PackageManager\nimport com.yl.lib.sentry.hook.PrivacySentry\nimport com.yl.lib.sentry.hook.printer.PrivacyFunBean\nimport com.yl.lib.sentry.hook.watcher.PrivacyDataManager\n\n/**\n * @author yulun\n * @since 2022-01-13 17:58\n */\nclass PrivacyProxyUtil {\n    object Util {\n        fun doFilePrinter(\n            funName: String,\n            methodDocumentDesc: String = \"\",\n            args: String? = \"\",\n            bCache: Boolean = false\n        ) {\n            var funName = funName + \"-\\n线程名: ${Thread.currentThread().name}\"\n            var funAlias =\n                (if (bCache) \"命中缓存--\" else \"\") + methodDocumentDesc + if (args?.isNotEmpty() == true) \"--参数: $args\" else \"\"\n            var msg = PrivacyUtil.Util.getStackTrace()\n\n            // 这里不再拦截，交给printer自己拦截\n            if (!PrivacySentry.Privacy.hasInit()) {\n                PrivacyDataManager.Manager.addStickData(PrivacyFunBean(funName, funAlias, msg, 1))\n            }\n\n            PrivacySentry.Privacy.getBuilder()?.getPrinterList()?.forEach {\n                it.filePrint(\n                    funName,\n                    funAlias,\n                    msg\n                )\n            }\n        }\n\n        /**\n         * 检查运行时权限\n         * @param permission String\n         * @return Boolean\n         */\n        fun checkPermission(permission: String): Boolean {\n            val localPackageManager: PackageManager? =\n                PrivacySentry.Privacy.getContext()?.packageManager\n            return localPackageManager?.checkPermission(\n                permission,\n                PrivacySentry.Privacy.getContext()?.packageName ?: \"\"\n            ) == PackageManager.PERMISSION_GRANTED\n        }\n    }\n\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/util/PrivacyUtil.kt",
    "content": "package com.yl.lib.sentry.hook.util\n\nimport android.app.Application\nimport android.location.Location\nimport android.location.LocationManager.GPS_PROVIDER\nimport android.text.TextUtils\nimport android.util.Log\nimport java.io.ByteArrayOutputStream\nimport java.io.InputStream\nimport java.text.MessageFormat\nimport java.text.SimpleDateFormat\nimport java.util.*\n\n/**\n * @author yulun\n * @sinice 2021-09-24 15:33\n */\nclass PrivacyUtil {\n    object Util {\n        fun getStackTrace(): String {\n            val st = Thread.currentThread().stackTrace\n            val sbf = StringBuilder()\n            for (e in st) {\n                if (e.methodName.equals(\"getThreadStackTrace\") || e.methodName.equals(\"getStackTrace\")) {\n                    continue\n                }\n                if (e.className.contains(\"PrivacyProxy\")\n                    || e.className.contains(\"PrivacySensorProxy\")\n                ) {\n                    continue\n                }\n                if (sbf.isNotEmpty()) {\n                    sbf.append(\" <- \")\n                    sbf.append(System.getProperty(\"line.separator\"))\n                }\n                sbf.append(\n                    MessageFormat.format(\n                        \"{0}.{1}() {2}\", e.className, e.methodName, e.lineNumber\n                    )\n                )\n            }\n            return sbf.toString()\n        }\n\n        fun formatTime(time: Long, formatStr: String? = \"yy-MM-dd_HH-mm-ss.SSS\"): String {\n            val sdr = SimpleDateFormat(formatStr, Locale.CHINA)\n            return sdr.format(time)\n        }\n\n\n        private fun convertStreamToByte(inputStream: InputStream?): ByteArray? {\n            if (inputStream == null) {\n                return null\n            }\n            var bos: ByteArrayOutputStream? = null\n            try {\n                bos = ByteArrayOutputStream()\n                val buffer = ByteArray(2 * 1024)\n                var read = -1\n                while (inputStream.read(buffer)?.also { read = it } != -1) {\n                    bos.write(buffer, 0, read)\n                }\n                return bos.toByteArray()\n            } catch (e: java.lang.Exception) {\n                Log.e(\"error:\", e.toString())\n            } finally {\n                if (bos != null) {\n                    try {\n                        bos.close()\n                    } catch (e2: java.lang.Exception) {\n                    }\n                }\n            }\n            return null\n        }\n\n        fun convertStreamToString(inputStream: InputStream?): String? {\n            var result: String? = \"\"\n            val data: ByteArray? = convertStreamToByte(inputStream)\n            if (data != null) {\n                result = String(data)\n            }\n            return result\n        }\n\n        fun formatLocation(location: Location?): String {\n            if (location == null) {\n                return \"\"\n            }\n            return \"${location?.provider},${location?.latitude},${location?.longitude},${location?.altitude},${location?.accuracy},${location?.speed},${location?.bearing}\"\n        }\n\n        fun formatLocation(locationInfo: String): Location? {\n            if (TextUtils.isEmpty(locationInfo)) {\n                return null\n            }\n            var location :Location? = null\n            try{\n                val infoArray: Array<String> = locationInfo.split(\",\").toTypedArray()\n                if (infoArray.size > 1) {\n                    location = Location(infoArray[0])\n                    location.latitude = infoArray[1].toDouble()\n                    location.longitude = infoArray[2].toDouble()\n                    location.altitude = infoArray[3].toDouble()\n                    location.accuracy = infoArray[4].toFloat()\n                    location.speed = infoArray[5].toFloat()\n                    location.bearing = infoArray[6].toFloat()\n                }\n            }catch (e:Exception){\n                e.printStackTrace()\n            }\n            return location\n        }\n\n        fun getApplicationByReflect(): Application? {\n            return getContextByActivityThread()\n        }\n\n        private fun getContextByActivityThread(): Application? {\n            try {\n                var activityThread = getActivityThreadInActivityThreadStaticField()\n                if (activityThread == null) activityThread =\n                    getActivityThreadInActivityThreadStaticMethod()\n                val declaredField = activityThread?.javaClass?.getDeclaredField(\"mInitialApplication\")\n                declaredField?.isAccessible = true\n                val `object` = declaredField?.get(activityThread)\n                if (`object` is Application) {\n                    return `object`\n                }\n            } catch (e: Throwable) {\n                e.printStackTrace()\n            }\n            return null\n        }\n\n\n        private fun getActivityThreadInActivityThreadStaticField(): Any? {\n            return try {\n                val activityThreadClass = Class.forName(\"android.app.ActivityThread\")\n                val activityThreadField =\n                    activityThreadClass.getDeclaredField(\"sCurrentActivityThread\")\n                activityThreadField.isAccessible = true\n                activityThreadField[null]\n            } catch (e: Exception) {\n                e.printStackTrace()\n                null\n            }\n        }\n\n        private fun getActivityThreadInActivityThreadStaticMethod(): Any? {\n            return try {\n                val activityThreadClass = Class.forName(\"android.app.ActivityThread\")\n                activityThreadClass.getMethod(\"currentActivityThread\").invoke(null)\n            } catch (e: Exception) {\n               e.printStackTrace()\n                null\n            }\n        }\n\n    }\n\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/util/ReflectUtils.kt",
    "content": "package com.yl.lib.sentry.hook.util\n\nimport java.lang.reflect.Method\n\n/**\n * @author yulun\n * @since 2022-11-10 15:06\n * https://juejin.cn/post/7018030594156134408 会触发反射数组长度的错误\n */\nclass ReflectUtils {\n    object Utils {\n        fun <T> invokeSuperMethod(\n            obj: Any,\n            name: String,\n            types: Array<Class<*>>,\n            args: Array<Any?>\n        ): T? {\n            try {\n                val method: Method? = getMethod(obj.javaClass.superclass, name, types)\n                if (null != method) {\n                    method.isAccessible = true\n                    return method.invoke(obj, *args) as T\n                }\n            } catch (t: Throwable) {\n                t.printStackTrace()\n            }\n            return null\n        }\n\n        private fun getMethod(klass: Class<*>, name: String, types: Array<Class<*>>): Method? {\n            return try {\n                klass.getDeclaredMethod(name, *types)\n            } catch (e: NoSuchMethodException) {\n                val parent = klass.superclass ?: return null\n                getMethod(parent, name, types)\n            }\n        }\n\n        fun <T> invokeMethod(obj: Any, name: String?, types: Array<Class<*>>, args: Array<Any?>): T? {\n            try {\n                val method = getMethod(obj.javaClass, name!!, types)\n                if (null != method) {\n                    method.isAccessible = true\n                    return method.invoke(obj, *args) as T\n                }\n            } catch (t: Throwable) {\n                t.printStackTrace()\n            }\n            return null\n        }\n    }\n\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/watcher/DelayTimeWatcher.kt",
    "content": "package com.yl.lib.sentry.hook.watcher\n\nimport android.os.CountDownTimer\nimport android.os.Handler\nimport android.os.Looper\nimport com.yl.lib.sentry.hook.util.PrivacyLog\n\n/**\n * @author yulun\n * @sinice 2021-12-01 17:32\n * 分段延时触发辅助类\n */\nclass DelayTimeWatcher {\n    private var watchTime: Long? = null//ms\n    private var callBack: Runnable? = null\n    private val minDelayTime: Long = 60 * 1000 // 一分钟写一次\n    private var countDownTimer: CountDownTimer? = null\n\n    constructor(watchTime: Long, callBack: Runnable) {\n        this.watchTime = watchTime + minDelayTime\n        this.callBack = callBack\n\n        if (Looper.myLooper() != Looper.getMainLooper()) {\n            // 子线程\n            Handler(Looper.getMainLooper()).post {\n                initCountDownTimer()\n            }\n        } else {\n            initCountDownTimer()\n        }\n\n    }\n\n    private fun initCountDownTimer() {\n        countDownTimer = object : CountDownTimer(watchTime!!, minDelayTime) {\n            override fun onTick(millisUntilFinished: Long) {\n                PrivacyLog.i(\"DelayTimeWatcher onTick $millisUntilFinished\")\n                callBack?.run()\n            }\n\n            override fun onFinish() {\n                PrivacyLog.i(\"DelayTimeWatcher onFinish\")\n                callBack?.run()\n            }\n        }\n        start()\n    }\n\n    fun start() {\n        quit()\n        countDownTimer?.start()\n    }\n\n    fun quit() {\n        countDownTimer?.cancel()\n    }\n\n}"
  },
  {
    "path": "hook-sentry/src/main/java/com/yl/lib/sentry/hook/watcher/PrivacyDataManager.kt",
    "content": "package com.yl.lib.sentry.hook.watcher\n\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.MutableLiveData\nimport androidx.lifecycle.Observer\nimport com.yl.lib.sentry.hook.printer.PrivacyFunBean\nimport java.util.concurrent.CopyOnWriteArrayList\n\n/**\n * @author yulun\n * @since 2022-07-05 16:26\n * 实时hook数据 管理中心，负责分发\n */\nclass PrivacyDataManager {\n    object Manager {\n        private var privacyFunBeanList: CopyOnWriteArrayList<PrivacyFunBean> =\n            CopyOnWriteArrayList()\n\n        private var liveItemPrivacy: MutableLiveData<PrivacyFunBean> = MutableLiveData()\n\n        private var stickFunBeanList: CopyOnWriteArrayList<PrivacyFunBean> = CopyOnWriteArrayList()\n        fun addData(bean: PrivacyFunBean) {\n            assert(bean != null)\n            privacyFunBeanList.add(bean)\n            liveItemPrivacy.postValue(bean)\n        }\n\n        fun addStickData(bean: PrivacyFunBean) {\n            assert(bean != null)\n            stickFunBeanList.add(bean)\n        }\n\n        fun getFunBeanList(): CopyOnWriteArrayList<PrivacyFunBean> {\n            if (stickFunBeanList.isNotEmpty()) {\n                privacyFunBeanList.addAll(0,stickFunBeanList)\n                stickFunBeanList.clear()\n            }\n            return privacyFunBeanList\n        }\n\n        fun isEmpty(): Boolean {\n            return privacyFunBeanList.isEmpty()\n        }\n\n\n        fun observerItem(lifecycleOwner: LifecycleOwner, observer: Observer<PrivacyFunBean>) {\n            liveItemPrivacy.observe(lifecycleOwner, observer)\n        }\n    }\n}"
  },
  {
    "path": "hook-sentry/src/test/java/com/yl/lib/hook_sentry/ExampleUnitTest.kt",
    "content": "package com.yl.lib.hook_sentry\n\nimport com.yl.lib.sentry.hook.cache.DiskCache\nimport com.yl.lib.sentry.hook.cache.MemoryCache\nimport com.yl.lib.sentry.hook.cache.TimeLessMemoryCache\nimport com.yl.lib.sentry.hook.cache.TimeLessDiskCache\nimport org.junit.Assert.assertEquals\nimport org.junit.Test\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * See [testing documentation](http://d.android.com/tools/testing).\n */\nclass ExampleUnitTest {\n    @Test\n    fun addition_isCorrect() {\n        assertEquals(4, 2 + 2)\n    }\n\n    @Test\n    fun testDiskCache() {\n        var diskCache = DiskCache()\n        diskCache.put(\"key1\", \"value1\")\n        var result = diskCache.get(\"key1\", \"default\")\n        assertEquals(true, result.first)\n        assertEquals(\"value1\", result.second)\n    }\n\n    @Test\n    fun testMemoryCache() {\n        var memoryCache = MemoryCache<Any>()\n        memoryCache.put(\"key1\", \"value1\")\n        var result = memoryCache.get(\"key1\", \"default\")\n        assertEquals(true, result.first)\n        assertEquals(\"value1\", result.second)\n    }\n\n    @Test\n    fun testTimeMemoryCache() {\n        var memoryCache = TimeLessMemoryCache<Any>()\n        memoryCache.put(\"key1\", \"value1\", 1000 * 1)\n        Thread.sleep(1000 * 2)\n        var result = memoryCache.get(\"key1\", \"default\")\n        assertEquals(false, result.first)\n        assertEquals(\"default\", result.second)\n    }\n\n    @Test\n    fun testTimeDiskCache() {\n        var timeDiskCache = TimeLessDiskCache()\n        timeDiskCache.put(\"key1\", \"value1\",1000 * 1)\n        Thread.sleep(1000 * 2)\n        var result = timeDiskCache.get(\"key1\", \"default\")\n        assertEquals(false, result.first)\n        assertEquals(\"default\", result.second)\n\n        timeDiskCache.put(\"key2\", \"value2\",1000 * 2)\n        var result2 = timeDiskCache.get(\"key2\", \"default\")\n        assertEquals(true, result2.first)\n        assertEquals(\"value2\", result2.second)\n    }\n}"
  },
  {
    "path": "hook-sentry/~/.m2/repository/com/yl/lib/privacy/hook-sentry/0.0.1-SNAPSHOT/maven-metadata-remote.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<metadata modelVersion=\"1.1.0\">\n  <groupId>com.yl.lib.privacy</groupId>\n  <artifactId>hook-sentry</artifactId>\n  <version>0.0.1-SNAPSHOT</version>\n  <versioning>\n    <snapshot>\n      <timestamp>20220106.092704</timestamp>\n      <buildNumber>1</buildNumber>\n    </snapshot>\n    <lastUpdated>20220106092704</lastUpdated>\n    <snapshotVersions>\n      <snapshotVersion>\n        <extension>aar</extension>\n        <value>0.0.1-20220106.092704-1</value>\n        <updated>20220106092704</updated>\n      </snapshotVersion>\n      <snapshotVersion>\n        <extension>pom</extension>\n        <value>0.0.1-20220106.092704-1</value>\n        <updated>20220106092704</updated>\n      </snapshotVersion>\n    </snapshotVersions>\n  </versioning>\n</metadata>\n"
  },
  {
    "path": "hook-sentry/~/.m2/repository/com/yl/lib/privacy/hook-sentry/0.0.1-SNAPSHOT/resolver-status.properties",
    "content": "#NOTE: This is an internal implementation file, its format can be changed without prior notice.\n#Thu Jan 06 17:27:04 CST 2022\nmaven-metadata-remote.xml.lastUpdated=1641461224244\n"
  },
  {
    "path": "hook-sentry/~/.m2/repository/com/yl/lib/privacy/hook-sentry/maven-metadata-remote.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<metadata>\n  <groupId>com.yl.lib.privacy</groupId>\n  <artifactId>hook-sentry</artifactId>\n  <versioning>\n    <versions>\n      <version>0.0.1-SNAPSHOT</version>\n    </versions>\n    <lastUpdated>20220106092704</lastUpdated>\n  </versioning>\n</metadata>\n"
  },
  {
    "path": "hook-sentry/~/.m2/repository/com/yl/lib/privacy/hook-sentry/resolver-status.properties",
    "content": "#NOTE: This is an internal implementation file, its format can be changed without prior notice.\n#Thu Jan 06 17:27:04 CST 2022\nmaven-metadata-remote.xml.lastUpdated=1641461224261\n"
  },
  {
    "path": "plugin-sentry/.gitignore",
    "content": "/build\n/plugins\n/~/.m2\n/~"
  },
  {
    "path": "plugin-sentry/build.gradle",
    "content": "apply plugin: 'kotlin'\napply plugin: 'kotlin-kapt'\napply plugin: 'java'\napply plugin: 'groovy'\n//apply plugin: 'maven-publish'  // Changed from 'maven' to 'maven-publish'\napply from: '../publish.gradle'  // Changed from 'maven' to 'maven-publish'\n\nsourceCompatibility = JavaVersion.VERSION_17\ntargetCompatibility = JavaVersion.VERSION_17\n\ncompileKotlin {\n    kotlinOptions.jvmTarget = JavaVersion.VERSION_17\n}\n\ndependencies {\n    compileOnly gradleApi()//gradle sdk\n    compileOnly localGroovy()\n    implementation project(path: ':privacy-annotation')\n    compileOnly 'com.android.tools.build:gradle:8.0.0'\n\n    def booster_version = '5.1.0'\n    // Booster V7.1\n    implementation \"com.didiglobal.booster:booster-api:$booster_version\"\n    implementation \"com.didiglobal.booster:booster-transform-asm:$booster_version\"\n\n\n    implementation \"com.alibaba:fastjson:1.1.68.android\"\n\n    // 如果需要放开上传任务，再打开\n//    implementation 'org.apache.httpcomponents:httpcore:4.4.13'\n//    implementation 'org.apache.httpcomponents:httpmime:4.5.12'\n//    implementation 'org.apache.httpcomponents:httpclient:4.5.12'\n}\n\n//if (rootProject.ext.build.local_debug) {\n//    publishing {\n//        publications {\n//            maven(MavenPublication) {\n//                from components.java\n//            }\n//        }\n//        repositories {\n//            maven {\n//                url = uri('plugins')\n//            }\n//        }\n//    }\n//}\n\n\n"
  },
  {
    "path": "plugin-sentry/gradle.properties",
    "content": "ARTIFACT_ID=plugin-sentry"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/PrivacySentryPlugin.kt",
    "content": "package com.yl.lib.plugin.sentry\n\nimport com.android.build.api.artifact.ScopedArtifact\nimport com.android.build.api.variant.AndroidComponentsExtension\nimport com.android.build.api.variant.ScopedArtifacts\nimport com.android.build.gradle.AppExtension\nimport com.android.build.gradle.AppPlugin\nimport com.android.build.gradle.BaseExtension\nimport com.android.build.gradle.LibraryExtension\nimport com.android.build.gradle.api.BaseVariant\nimport com.didiglobal.booster.gradle.getAndroid\nimport com.didiglobal.booster.kotlinx.capitalized\nimport com.didiglobal.booster.task.spi.VariantProcessor\nimport com.yl.lib.plugin.sentry.extension.PrivacyExtension\nimport com.yl.lib.plugin.sentry.transform.booster.classtransform.collect.ClassProxyCollectTransform\nimport com.yl.lib.plugin.sentry.transform.booster.classtransform.collect.MethodProxyCollectTransform\nimport com.yl.lib.plugin.sentry.transform.booster.classtransform.hook.ClassProxyTransform\nimport com.yl.lib.plugin.sentry.transform.booster.classtransform.hook.FieldProxyTransform\nimport com.yl.lib.plugin.sentry.transform.booster.classtransform.hook.FlushHookDataTransform\nimport com.yl.lib.plugin.sentry.transform.booster.classtransform.hook.MethodHookTransform\nimport com.yl.lib.plugin.sentry.transform.booster.classtransform.hook.ServiceHookTransform\nimport com.yl.lib.plugin.sentry.transform.booster.processor.PrivacyAssetsProcessor\nimport com.yl.lib.plugin.sentry.transform.booster.processor.PrivacyManifestProcessor\nimport com.yl.lib.plugin.sentry.transform.booster.transformer.PrivacyBaseTransformer\nimport com.yl.lib.plugin.sentry.transform.manager.HookFieldManager\nimport com.yl.lib.plugin.sentry.transform.manager.HookMethodManager\nimport com.yl.lib.plugin.sentry.transform.manager.ReplaceClassManager\nimport com.yl.lib.plugin.sentry.util.PrivacyPluginUtil\nimport org.gradle.api.Plugin\nimport org.gradle.api.Project\n\n/**\n * @author yulun\n * @sinice 2021-12-13 17:05\n */\nclass PrivacySentryPlugin : Plugin<Project> {\n    override fun apply(project: Project) {\n\n        var extension = project.extensions.create(\"privacy\", PrivacyExtension::class.java)\n        if (!extension.enablePrivacy) {\n            return\n        }\n        PrivacyPluginUtil.privacyPluginUtil.logger = project.logger\n        when {\n            project.plugins.hasPlugin(AppPlugin::class.java)  -> {\n                HookFieldManager.MANAGER.clear()\n                HookMethodManager.MANAGER.clear()\n                ReplaceClassManager.MANAGER.clear()\n                registerTransform(project)\n                setupTasks(project)\n            }\n        }\n    }\n\n    private fun setupTasks(project: Project) {\n        val processors = listOf(  PrivacyAssetsProcessor(project),\n                PrivacyManifestProcessor(project))\n\n        project.setup(processors)\n\n        if (project.state.executed) {\n            project.legacySetup(processors)\n        } else {\n            project.afterEvaluate {\n                project.legacySetup(processors)\n            }\n        }\n    }\n\n    private fun Project.setup(processors: List<VariantProcessor>) {\n        val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)\n        androidComponents.beforeVariants { variantBuilder ->\n            processors.forEach { processor ->\n                processor.beforeProcess(variantBuilder)\n            }\n        }\n        androidComponents.onVariants { variant ->\n            processors.forEach { processor ->\n                processor.process(variant)\n            }\n        }\n    }\n\n    private fun Project.legacySetup(processors: List<VariantProcessor>) {\n        val android = project.getAndroid<BaseExtension>()\n        when (android) {\n            is AppExtension -> android.applicationVariants\n            is LibraryExtension -> android.libraryVariants\n            else -> emptyList<BaseVariant>()\n        }.takeIf<Collection<BaseVariant>>(Collection<BaseVariant>::isNotEmpty)?.let { variants ->\n            variants.forEach { variant ->\n                processors.forEach { processor ->\n                    processor.process(variant)\n                }\n            }\n        }\n    }\n\n    private fun registerTransform(project: Project) {\n        val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)\n        androidComponents.onVariants { variant ->\n            val transform = project.tasks.register(\n                \"transform${variant.name.capitalized()}ClassesWithBooster\",\n                PrivacyTransformTask::class.java\n            ) {\n                it.preTransformers = listOf(\n                    PrivacyBaseTransformer(\n                         listOf(\n                            MethodProxyCollectTransform(),\n                            ClassProxyCollectTransform()\n                        )\n                    )\n                )\n                it.transformers = listOf(\n                    PrivacyBaseTransformer(\n                        listOf(\n                            MethodHookTransform(),\n                            FieldProxyTransform(),\n                            ClassProxyTransform(),\n                            ServiceHookTransform(),\n                            FlushHookDataTransform()\n                        )\n                    )\n                )\n                it.variant = variant\n                it.applicationId = variant.namespace.get()\n                it.bootClasspath = androidComponents.sdkComponents.bootClasspath\n            }\n            variant.artifacts.forScope(ScopedArtifacts.Scope.ALL)\n                .use(transform).toTransform(\n                    ScopedArtifact.CLASSES,\n                    PrivacyTransformTask::allJars,\n                    PrivacyTransformTask::allDirectories,\n                    PrivacyTransformTask::output\n                )\n        }\n    }\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/PrivacyTransformTask.kt",
    "content": "package com.yl.lib.plugin.sentry\n\nimport com.android.build.api.variant.Variant\nimport com.didiglobal.booster.kotlinx.NCPU\nimport com.didiglobal.booster.kotlinx.search\nimport com.didiglobal.booster.kotlinx.touch\nimport com.didiglobal.booster.transform.AbstractTransformContext\nimport com.didiglobal.booster.transform.Transformer\nimport com.didiglobal.booster.transform.artifactManager\nimport com.didiglobal.booster.transform.util.CompositeCollector\nimport com.didiglobal.booster.transform.util.collect\nimport com.google.common.collect.Sets\nimport com.yl.lib.plugin.sentry.extension.PrivacyExtension\nimport com.yl.lib.plugin.sentry.transform.PrivacyTransformInvocation\nimport org.apache.commons.compress.archivers.jar.JarArchiveEntry\nimport org.apache.commons.compress.archivers.jar.JarArchiveOutputStream\nimport org.apache.commons.compress.archivers.zip.ParallelScatterZipCreator\nimport org.apache.commons.compress.archivers.zip.ZipArchiveEntry\nimport org.apache.commons.compress.parallel.InputStreamSupplier\nimport org.gradle.api.DefaultTask\nimport org.gradle.api.file.Directory\nimport org.gradle.api.file.RegularFile\nimport org.gradle.api.file.RegularFileProperty\nimport org.gradle.api.provider.ListProperty\nimport org.gradle.api.provider.Provider\nimport org.gradle.api.tasks.Input\nimport org.gradle.api.tasks.InputFiles\nimport org.gradle.api.tasks.Internal\nimport org.gradle.api.tasks.OutputFile\nimport org.gradle.api.tasks.TaskAction\nimport java.io.File\nimport java.io.IOException\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Executors\nimport java.util.concurrent.LinkedBlockingQueue\nimport java.util.concurrent.ThreadPoolExecutor\nimport java.util.concurrent.TimeUnit\nimport java.util.concurrent.atomic.AtomicInteger\nimport java.util.zip.ZipEntry\nimport java.util.zip.ZipInputStream\n\n/**\n * @author yulun\n * @since 2025-04-24 14:56\n */\nabstract class PrivacyTransformTask : DefaultTask() {\n    @get:Input\n    abstract var applicationId: String\n\n    @get:Internal\n    abstract var preTransformers: Collection<Transformer>\n\n    @get:Internal\n    abstract var transformers: Collection<Transformer>\n\n    @get:Internal\n    abstract var variant: Variant\n\n    @get:Internal\n    abstract var bootClasspath: Provider<List<RegularFile>>\n\n    @get:InputFiles\n    abstract val allJars: ListProperty<RegularFile>\n\n    @get:InputFiles\n    abstract val allDirectories: ListProperty<Directory>\n\n    @get:OutputFile\n    abstract val output: RegularFileProperty\n\n    private val entries = Sets.newConcurrentHashSet<String>()\n\n    @TaskAction\n    fun taskAction() {\n        val context = object : PrivacyTransformInvocation(\n            applicationId,\n            variant.name,\n            bootClasspath.get().map(RegularFile::getAsFile),\n            compileClasspath,\n            compileClasspath,\n            project = project,\n            extension = project.extensions.getByType(PrivacyExtension::class.java)\n        ) {\n            override val projectDir = project.projectDir\n            override val artifacts = variant.artifactManager\n        }\n        val executor = Executors.newFixedThreadPool(NCPU)\n        project.logger.info(\"preTransformers size ${preTransformers.size}\")\n        try {\n            if (preTransformers.isNotEmpty()) {\n                doTransformers(preTransformers, executor, context)\n            }\n            entries.clear()\n            if (transformers.isNotEmpty()){\n                doTransformers(transformers, executor, context)\n            }\n            project.logger.info(\"PrivacyTransformTask output is ${output.get().asFile.absolutePath}\")\n        } finally {\n            executor.shutdown()\n            executor.awaitTermination(1L, TimeUnit.HOURS)\n        }\n\n    }\n\n    private fun doTransformers(\n        _transformers: Collection<Transformer>,\n        executor: ExecutorService,\n        context: AbstractTransformContext\n    ) {\n        try {\n            _transformers.map {\n                executor.submit {\n                    project.logger.info(\"onPreTransform\")\n                    it.onPreTransform(context)\n                }\n            }.forEach {\n                it.get()\n            }\n\n            compileClasspath.map { input ->\n                executor.submit {\n                    input.takeIf {\n                        it.collect(CompositeCollector(context.collectors)).isNotEmpty()\n                    }\n                }\n            }.forEach {\n                it.get()\n            }\n            project.logger.info(\"输出的内容位置 : ${output.get().asFile.absolutePath}\")\n            JarArchiveOutputStream(\n                output.get().asFile.touch().outputStream().buffered()\n            ).use { jos ->\n                val creator = ParallelScatterZipCreator(\n                    ThreadPoolExecutor(\n                        NCPU,\n                        NCPU,\n                        0L,\n                        TimeUnit.MILLISECONDS,\n                        LinkedBlockingQueue<Runnable>(),\n                        Executors.defaultThreadFactory()\n                    ) { runnable, _ ->\n                        runnable.run()\n                    }\n                )\n                project.logger.info(\"开始处理 compileClasspath，大小: ${compileClasspath.size}\")\n                compileClasspath.map {\n                    executor.submit {\n                        it.transform(\"\", creator) { bytecode ->\n                            _transformers.fold(bytecode) { bytes, transformer ->\n                                transformer.transform(context, bytes)\n                            }\n                        }\n                    }\n                }.forEach {\n                    it.get()\n                }\n                creator.writeTo(jos)\n            }\n\n            _transformers.map {\n                executor.submit {\n                    it.onPostTransform(context)\n                }\n            }.forEach {\n                it.get()\n            }\n        } finally {\n        }\n    }\n\n    private val compileClasspath: Collection<File>\n        get() = (allJars.get() + allDirectories.get()).map {\n            it.asFile\n        }\n\n\n    /**\n     * Transform this file or directory to the output by the specified transformer\n     *\n     * @param transformer The byte data transformer\n     */\n    fun File.transform(\n        prefix: String,\n        creator: ParallelScatterZipCreator,\n        transformer: (ByteArray) -> ByteArray = { it -> it }\n    ) {\n        when {\n            isDirectory -> {\n                this.toURI().let { base ->\n                    this.search {\n                        it.extension.lowercase() == \"class\"\n                    }.parallelStream().forEach {\n                        it.transform(creator, base.relativize(it.toURI()).path, transformer)\n                    }\n                }\n            }\n\n            isFile -> when (extension.lowercase()) {\n                \"jar\" -> ZipInputStream(this.inputStream()).use {\n                    it.transform(\n                        creator,\n                        ::JarArchiveEntry,\n                        transformer\n                    )\n                }\n\n                \"class\" -> transform(creator, \"$prefix/$name\".substring(1), transformer)\n                else -> println(\"Not transform file $path\")\n            }\n\n            else -> throw IOException(\"Unexpected file: ${this.canonicalPath}\")\n        }\n    }\n\n    fun File.transform(\n        creator: ParallelScatterZipCreator,\n        name: String,\n        transformer: (ByteArray) -> ByteArray\n    ) {\n        if (entries.contains(name)) {\n            return\n        }\n        this.inputStream().use {\n            val inputStreamSupplier = {\n                transformer(readBytes()).inputStream()\n            }\n            val jarArchiveEntry = JarArchiveEntry(name).apply {\n                method = JarArchiveEntry.DEFLATED\n            }\n            creator.addArchiveEntry(jarArchiveEntry, inputStreamSupplier)\n        }\n        entries.add(name)\n    }\n\n    fun ZipInputStream.transform(\n        creator: ParallelScatterZipCreator,\n        entryFactory: (ZipEntry) -> ZipArchiveEntry = ::ZipArchiveEntry,\n        transformer: (ByteArray) -> ByteArray\n    ) {\n        while (true) {\n            val next = nextEntry ?: break\n            val entry = next.takeIf(::isValidate) ?: continue\n            if (!entries.contains(entry.name)) {\n                entries.add(entry.name)\n                val zae = entryFactory(entry)\n                val data = readBytes()\n                val stream = InputStreamSupplier {\n                    if (entry.isDirectory) {\n                        data.inputStream()\n                    } else {\n                        transformer(data).inputStream()\n                    }\n                }\n                creator.addArchiveEntry(zae, stream)\n            }\n        }\n    }\n\n\n    private fun isValidate(entry: ZipEntry): Boolean {\n        return (entry.isDirectory || entry.name.endsWith(\".class\")) && !entry.name.startsWith(\"META-INF/\")\n    }\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/extension/PrivacyExtension.kt",
    "content": "package com.yl.lib.plugin.sentry.extension\n\n/**\n * @author yulun\n * @sinice 2021-12-13 17:28\n */\nopen class PrivacyExtension {\n\n    var enablePrivacy = true\n\n    // 不修改的黑名单，首先是包括自己\n    var blackList: Set<String>? = null\n\n    // hook变量\n    @Deprecated(\"后续准备放弃，几乎没有业务场景\")\n    var hookField : Boolean = false\n\n    // 记录所有被代理的方法名+类名,将以单行的形式被写入到文件中\n    // 空=不写入\n    var replaceFileName :String? = \"privacy_hook.json\"\n\n    // 开启hook反射方法，默认为false\n    var hookReflex: Boolean = false\n    var reflexMap: Map<String, List<String>>? = null\n\n    // 开启hook构造函数，默认为false\n    @Deprecated(\"放弃维护\")\n    var hookConstructor: Boolean = false\n\n    @Deprecated(\"放弃维护\")\n    var enableProcessManifest : Boolean = false\n    // hook Service的部分代码，修复在MIUI上的自启动问题\n    // 部分Service把自己的Priority设置为1000，这里开启代理功能，可以代理成0\n    @Deprecated(\"放弃维护\")\n    var enableReplacePriority = false\n    @Deprecated(\"放弃维护\")\n    var replacePriority = 0\n\n    // 支持关闭Service的Export功能，默认为false，注意部分厂商通道之类的push，不能关闭\n    @Deprecated(\"放弃维护\")\n    var enableCloseServiceExport = false\n    // Export白名单Service\n    @Deprecated(\"放弃维护\")\n    var serviceExportPkgWhiteList: Set<String>? = null\n    // hook Service的startCommand方法，修复在MIUI上的自启动问题\n    @Deprecated(\"放弃维护\")\n    var enableHookServiceStartCommand = false\n}\n"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/transform/PrivacyTransformContext.kt",
    "content": "package com.yl.lib.plugin.sentry.transform\n\nimport com.yl.lib.plugin.sentry.extension.PrivacyExtension\nimport org.gradle.api.Project\n\n/**\n * @author yulun\n * @since 2023-08-08 19:34\n */\ninterface PrivacyTransformContext {\n    fun project(): Project\n\n    fun privacyExtension(): PrivacyExtension\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/transform/PrivacyTransformInvocation.kt",
    "content": "package com.yl.lib.plugin.sentry.transform\n\nimport com.didiglobal.booster.transform.*\nimport com.yl.lib.plugin.sentry.extension.PrivacyExtension\nimport org.gradle.api.Project\nimport java.io.File\n\n/**\n * @author yulun\n * @since 2023-08-09 14:44\n */\nabstract class PrivacyTransformInvocation(\n    applicationId: String,\n    name: String,\n    bootClasspath: Collection<File>,\n    compileClasspath: Collection<File>,\n    runtimeClasspath: Collection<File>,\n    private val project: Project,\n    private val extension: PrivacyExtension,\n) : AbstractTransformContext(\n    applicationId,\n    name,\n    bootClasspath,\n    compileClasspath,\n    runtimeClasspath,\n), PrivacyTransformContext {\n\n\n    override fun project(): Project {\n        return project\n    }\n\n    override fun privacyExtension(): PrivacyExtension {\n        return extension\n    }\n\n\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/transform/booster/asmtransform/AbsClassTransformer.kt",
    "content": "package com.yl.lib.plugin.sentry.transform.booster.asmtransform\n\nimport com.didiglobal.booster.transform.TransformContext\nimport com.didiglobal.booster.transform.asm.ClassTransformer\nimport com.didiglobal.booster.transform.asm.className\nimport com.yl.lib.plugin.sentry.extension.PrivacyExtension\nimport com.yl.lib.plugin.sentry.transform.PrivacyTransformContext\nimport com.yl.lib.plugin.sentry.util.PrivacyPluginUtil\nimport org.gradle.api.Project\nimport org.objectweb.asm.tree.ClassNode\n\n/**\n * @author yulun\n * @since 2023-08-08 17:41\n * transform 基类\n */\nopen class AbsClassTransformer : ClassTransformer {\n\n    open fun ignoreClass(context: TransformContext, klass: ClassNode) : Boolean {\n        var  isBlack = klass.invisibleAnnotations?.find {\n            it.desc.equals(\"Lcom/yl/lib/privacy_annotation/PrivacyClassBlack;\")\n        }\n\n        if (isBlack != null) {\n            return true\n        }\n\n        if (context is PrivacyTransformContext) {\n            var extension = context.privacyExtension()\n            if (PrivacyPluginUtil.privacyPluginUtil.ignoreClass(\n                    klass.className,\n                    extension.blackList\n                )\n            ) {\n                return true\n            }\n        }\n        return false\n    }\n\n\n    final override fun transform(context: TransformContext, klass: ClassNode): ClassNode {\n        //过滤kotlin module-info\n        if (klass.className == \"module-info\") {\n            return klass\n        }\n\n        if (ignoreClass(context, klass)) {\n            return klass\n        }\n\n        if (context is PrivacyTransformContext) {\n            var project = context.project()\n            var extension = context.privacyExtension()\n            // 在黑白名单里不作处理\n            if (PrivacyPluginUtil.privacyPluginUtil.ignoreClass(\n                    klass.className,\n                    extension.blackList\n                )\n            ) {\n                return klass\n            }\n            transform(project, extension, context, klass)\n        }\n        return klass\n    }\n\n    open fun transform(\n        project: Project,\n        privacyExtension: PrivacyExtension,\n        context: TransformContext,\n        klass: ClassNode\n    ): ClassNode = klass\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/transform/booster/classtransform/collect/ClassProxyCollectTransform.kt",
    "content": "package com.yl.lib.plugin.sentry.transform.booster.classtransform.collect\n\nimport com.didiglobal.booster.transform.TransformContext\nimport com.yl.lib.plugin.sentry.extension.PrivacyExtension\nimport com.yl.lib.plugin.sentry.transform.booster.asmtransform.AbsClassTransformer\nimport com.yl.lib.plugin.sentry.transform.manager.ReplaceClassItem\nimport com.yl.lib.plugin.sentry.transform.manager.ReplaceClassManager\nimport com.yl.lib.plugin.sentry.util.formatName\nimport com.yl.lib.plugin.sentry.util.privacyClassReplace\nimport com.yl.lib.plugin.sentry.util.privacyGetValue\nimport org.gradle.api.Project\nimport org.objectweb.asm.Type\nimport org.objectweb.asm.tree.ClassNode\n\n/**\n * @author yulun\n * @since 2023-08-11 11:17\n * @see com.yl.lib.privacy_annotation.PrivacyClassReplace\n * 收集待代理的类\n */\nclass ClassProxyCollectTransform : AbsClassTransformer() {\n    override fun ignoreClass(context: TransformContext, klass: ClassNode): Boolean {\n        var ignore = super.ignoreClass(context, klass)\n        if (ignore) {\n            return true\n        }\n        klass.invisibleAnnotations?.find {\n            it.desc.privacyClassReplace()\n        } ?: return true\n\n        return false\n    }\n\n    override fun transform(\n        project: Project,\n        privacyExtension: PrivacyExtension,\n        context: TransformContext,\n        klass: ClassNode\n    ): ClassNode {\n        var annotationNode = klass.invisibleAnnotations?.find {\n            it.desc.privacyClassReplace()\n        }\n\n        var classSourceName = annotationNode?.privacyGetValue<Type>(\"originClass\").toString()\n        var item = ReplaceClassItem(\n            originClassName = classSourceName?.substring(1, classSourceName?.length?.minus(1) ?: 1) ?: \"\",\n            proxyClassName = klass.formatName()\n        )\n        ReplaceClassManager.MANAGER.appendHookItem(item)\n        project.logger.info(\"CollectClassAnnotationVisitor-ReplaceClassItem - ${item.toString()}\")\n        return klass\n    }\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/transform/booster/classtransform/collect/MethodProxyCollectTransform.kt",
    "content": "package com.yl.lib.plugin.sentry.transform.booster.classtransform.collect\n\nimport com.didiglobal.booster.transform.TransformContext\nimport com.yl.lib.plugin.sentry.extension.PrivacyExtension\nimport com.yl.lib.plugin.sentry.transform.booster.asmtransform.AbsClassTransformer\nimport com.yl.lib.plugin.sentry.transform.manager.HookFieldItem\nimport com.yl.lib.plugin.sentry.transform.manager.HookFieldManager\nimport com.yl.lib.plugin.sentry.transform.manager.HookMethodItem\nimport com.yl.lib.plugin.sentry.transform.manager.HookMethodManager\nimport com.yl.lib.plugin.sentry.util.*\nimport com.yl.lib.privacy_annotation.MethodInvokeOpcode\nimport org.gradle.api.Project\nimport org.objectweb.asm.Type\nimport org.objectweb.asm.tree.ClassNode\n\n/**\n * @author yulun\n * @since 2023-08-08 11:08\n * @see com.yl.lib.privacy_annotation.PrivacyMethodProxy\n * 解析和收集PrivacyMethodProxy注解的方法\n * @see com.yl.lib.privacy_annotation.PrivacyFieldProxy\n * 解析和收集PrivacyFieldProxy注解的变量\n */\nclass MethodProxyCollectTransform : AbsClassTransformer() {\n    override fun ignoreClass(context: TransformContext, klass: ClassNode): Boolean {\n        var ignore = super.ignoreClass(context, klass)\n        if (ignore) {\n            return true\n        }\n\n        klass.invisibleAnnotations?.find {\n            it.desc.privacyClassProxy()\n        } ?: return true\n\n        return false\n    }\n\n    override fun transform(\n        project: Project,\n        privacyExtension: PrivacyExtension,\n        context: TransformContext,\n        klass: ClassNode\n    ): ClassNode {\n        // 收集方法\n        klass.methods.filter { methodNode ->\n            methodNode.invisibleAnnotations?.find {\n                it.desc.privacyMethodProxy()\n            } != null\n        }.forEach { methodNode ->\n            var hookMethodItem = HookMethodItem(klass.formatName(), methodNode.name, methodNode.desc)\n\n            var annotationNode = methodNode.invisibleAnnotations?.find {\n                it.desc.privacyMethodProxy()\n            }\n\n            var classSourceName = annotationNode?.privacyGetValue<Type>(\"originalClass\").toString()\n            hookMethodItem.originClassName =\n                classSourceName.substring(1, classSourceName.length - 1)\n\n            hookMethodItem.ignoreClass = annotationNode?.privacyGetValue<Boolean>(\"ignoreClass\") == true\n\n            hookMethodItem.originMethodName = annotationNode?.privacyGetValue<String>(\"originalMethod\")\n\n            hookMethodItem.originMethodAccess = annotationNode?.privacyGetValue<Int>(\"originalOpcode\")\n\n\n            if (hookMethodItem.originMethodAccess == MethodInvokeOpcode.INVOKESTATIC) {\n                hookMethodItem.originMethodDesc = hookMethodItem.proxyMethodDesc\n            } else if (hookMethodItem.originMethodAccess == MethodInvokeOpcode.INVOKEVIRTUAL ||\n                hookMethodItem.originMethodAccess == MethodInvokeOpcode.INVOKEINTERFACE ||\n                hookMethodItem.originMethodAccess == MethodInvokeOpcode.INVOKESPECIAL\n            ) {\n                // 如果是调用实例方法，代理方法的描述会比原始方法多了一个实例，这里需要裁剪，方便做匹配 、、、\n                hookMethodItem.originMethodDesc =\n                    hookMethodItem.proxyMethodDesc.replaceFirst(\n                        \"L${hookMethodItem.originClassName};\",\n                        \"\"\n                    )\n            }\n            HookMethodManager.MANAGER.appendHookMethod(hookMethodItem)\n        }\n\n        // 收集变量\n        klass.fields.filter { fieldNode ->\n            fieldNode.invisibleAnnotations?.find {\n                it.desc.privacyFieldProxy()\n            } != null\n        }.forEach { fieldNode ->\n            var annotationNode = fieldNode.invisibleAnnotations?.find {\n                it.desc.privacyFieldProxy()\n            }\n\n            var classSourceName = annotationNode?.privacyGetValue<Type>(\"originalClass\").toString()\n            var item = HookFieldItem(\n                proxyClassName = klass.formatName(),\n                proxyFieldDesc =  fieldNode.desc,\n                proxyFieldName =  fieldNode.name,\n                originClassName = classSourceName?.substring(1, classSourceName.length - 1) ?: \"\",\n                originFieldName = annotationNode?.privacyGetValue<String>(\"originalFieldName\") ?: \"\"\n            )\n            HookFieldManager.MANAGER.appendHookField(item)\n            project.logger.info(\"CollectClassAnnotationVisitor-ReplaceClassItem - ${item.toString()}\")\n        }\n        return klass\n    }\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/transform/booster/classtransform/hook/BaseHookTransform.kt",
    "content": "package com.yl.lib.plugin.sentry.transform.booster.classtransform.hook\n\nimport com.didiglobal.booster.transform.TransformContext\nimport com.yl.lib.plugin.sentry.transform.booster.asmtransform.AbsClassTransformer\nimport com.yl.lib.plugin.sentry.transform.manager.HookFieldManager\nimport com.yl.lib.plugin.sentry.transform.manager.HookMethodManager\nimport com.yl.lib.plugin.sentry.transform.manager.ReplaceClassManager\nimport com.yl.lib.plugin.sentry.util.formatName\nimport com.yl.lib.plugin.sentry.util.privacyClassBlack\nimport com.yl.lib.plugin.sentry.util.privacyClassProxy\nimport com.yl.lib.plugin.sentry.util.privacyClassReplace\nimport org.objectweb.asm.tree.ClassNode\n\n/**\n * @author yulun\n * @since 2023-08-11 14:29\n */\nopen class BaseHookTransform : AbsClassTransformer() {\n    override fun ignoreClass(context: TransformContext, klass: ClassNode): Boolean {\n        var ignore = super.ignoreClass(context, klass)\n        if (!ignore) {\n            if (klass.invisibleAnnotations?.find {\n                    it.desc.privacyClassProxy() ||\n                            it.desc.privacyClassReplace() ||\n                            it.desc.privacyClassBlack()\n                } != null) {\n                return true\n            }\n\n            if (HookMethodManager.MANAGER.isProxyClass(klass.formatName()) ||\n                HookFieldManager.MANAGER.isProxyClass(klass.formatName()) ||\n                ReplaceClassManager.MANAGER.isProxyClass(klass.formatName())\n            ) {\n                return true\n            }\n        }\n        return ignore\n    }\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/transform/booster/classtransform/hook/ClassProxyTransform.kt",
    "content": "package com.yl.lib.plugin.sentry.transform.booster.classtransform.hook\n\nimport com.didiglobal.booster.transform.TransformContext\nimport com.yl.lib.plugin.sentry.extension.PrivacyExtension\nimport com.yl.lib.plugin.sentry.transform.manager.HookFieldManager\nimport com.yl.lib.plugin.sentry.transform.manager.ReplaceClassItem\nimport com.yl.lib.plugin.sentry.transform.manager.ReplaceClassManager\nimport org.gradle.api.Project\nimport org.objectweb.asm.Opcodes\nimport org.objectweb.asm.tree.*\n\n/**\n * @author yulun\n * @since 2023-08-08 10:55\n * 类代理，代理PrivacyClassReplace注解过的类\n * @see com.yl.lib.privacy_annotation.PrivacyClassReplace\n */\nclass ClassProxyTransform : BaseHookTransform() {\n\n    override fun transform(\n        project: Project,\n        privacyExtension: PrivacyExtension,\n        context: TransformContext,\n        klass: ClassNode\n    ): ClassNode {\n        if (!privacyExtension.hookConstructor) {\n            return super.transform(project, privacyExtension, context, klass)\n        }\n        klass.methods.forEach { methodNode ->\n            var proxyClassItem: ReplaceClassItem? = null\n            methodNode.instructions?.iterator()?.asSequence()?.forEach { node ->\n                if (node is TypeInsnNode) {\n                    if (node.opcode == Opcodes.NEW && ReplaceClassManager.MANAGER.contains(node.desc)) {\n                        proxyClassItem = ReplaceClassManager.MANAGER.findItemByName(node.desc)\n                        node.desc = proxyClassItem?.proxyClassName?.replace(\".\", \"/\")\n                    }\n                } else if (node is MethodInsnNode) {\n                    if (node.name == \"<init>\" && proxyClassItem != null && node.owner == proxyClassItem?.originClassName) {\n                        node.owner = proxyClassItem?.proxyClassName?.replace(\".\", \"/\")\n                        proxyClassItem = null\n                    }\n                }\n            }\n        }\n        return klass\n    }\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/transform/booster/classtransform/hook/FieldProxyTransform.kt",
    "content": "package com.yl.lib.plugin.sentry.transform.booster.classtransform.hook\n\nimport com.didiglobal.booster.transform.TransformContext\nimport com.yl.lib.plugin.sentry.extension.PrivacyExtension\nimport com.yl.lib.plugin.sentry.transform.manager.HookFieldManager\nimport com.yl.lib.plugin.sentry.transform.manager.HookMethodManager\nimport org.gradle.api.Project\nimport org.objectweb.asm.tree.ClassNode\nimport org.objectweb.asm.tree.FieldInsnNode\n\n/**\n * @author yulun\n * @since 2023-08-21 15:34\n * 代理PrivacyFieldProxy注解过的字段\n * @see com.yl.lib.privacy_annotation.PrivacyFieldProxy\n */\nclass FieldProxyTransform : BaseHookTransform() {\n    override fun transform(\n        project: Project,\n        privacyExtension: PrivacyExtension,\n        context: TransformContext,\n        klass: ClassNode\n    ): ClassNode {\n        if (!privacyExtension.hookField) {\n            return super.transform(project, privacyExtension, context, klass)\n        }\n        klass.methods.forEach { methodNode ->\n            methodNode.instructions?.iterator()?.asSequence()?.forEach { node ->\n                if (node is FieldInsnNode) {\n                    if (HookFieldManager.MANAGER.contains(\n                            fieldName = node.name,\n                            classOwnerName = node.owner,\n                            fieldDesc = node.desc\n                        )\n                    ) {\n                        var proxyFieldItem = HookFieldManager.MANAGER.findHookItemByName(\n                            fieldName = node.name,\n                            classOwnerName = node.owner,\n                            fieldDesc = node.desc\n                        )\n                        node.owner = proxyFieldItem?.proxyClassName?.replace(\".\", \"/\")\n                        node.name = proxyFieldItem?.proxyFieldName\n                    }\n                }\n            }\n        }\n        return klass\n    }\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/transform/booster/classtransform/hook/FlushHookDataTransform.kt",
    "content": "package com.yl.lib.plugin.sentry.transform.booster.classtransform.hook\n\nimport com.didiglobal.booster.transform.TransformContext\nimport com.yl.lib.plugin.sentry.util.PrivacyMoveAssetsUtil\nimport org.objectweb.asm.tree.ClassNode\n\n/**\n * @author yulun\n * @since 2023-08-29 11:22\n */\nclass FlushHookDataTransform : BaseHookTransform(){\n    override fun ignoreClass(context: TransformContext, klass: ClassNode): Boolean {\n        return true\n    }\n\n    override fun onPostTransform(context: TransformContext) {\n        super.onPostTransform(context)\n        PrivacyMoveAssetsUtil.Asset.doFlushProxyData()\n    }\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/transform/booster/classtransform/hook/MethodHookTransform.kt",
    "content": "package com.yl.lib.plugin.sentry.transform.booster.classtransform.hook\n\nimport com.didiglobal.booster.transform.TransformContext\nimport com.yl.lib.plugin.sentry.extension.PrivacyExtension\nimport com.yl.lib.plugin.sentry.transform.manager.HookMethodManager\nimport com.yl.lib.plugin.sentry.transform.manager.ReplaceMethodItem\nimport com.yl.lib.plugin.sentry.transform.manager.HookedDataManger\nimport com.yl.lib.plugin.sentry.util.formatName\nimport org.gradle.api.Project\nimport org.objectweb.asm.commons.AdviceAdapter\nimport org.objectweb.asm.tree.ClassNode\nimport org.objectweb.asm.tree.LdcInsnNode\nimport org.objectweb.asm.tree.MethodInsnNode\n\n/**\n * @author yulun\n * @since 2023-08-08 10:55\n * @see com.yl.lib.privacy_annotation.PrivacyMethodProxy\n * hook方法\n */\nclass MethodHookTransform : BaseHookTransform() {\n\n    override fun transform(\n        project: Project,\n        privacyExtension: PrivacyExtension,\n        context: TransformContext,\n        klass: ClassNode\n    ): ClassNode {\n        klass.methods?.forEach { methodNode ->\n            var bLdcHookMethod = false\n            methodNode.instructions?.iterator()?.asSequence()?.forEach { node ->\n                if (node is MethodInsnNode) {\n                    node.apply {\n                        var methodItem =\n                            HookMethodManager.MANAGER.findHookItemByName(\n                                node.name,\n                                node.owner,\n                                node.desc,\n                                node.opcode\n                            )\n                        if (methodItem != null && shouldHook(\n                                node.name,\n                                bLdcHookMethod,\n                                privacyExtension\n                            )\n                        ) {\n                            HookedDataManger.MANAGER.addReplaceMethodItem(\n                                ReplaceMethodItem(\n                                    klass.formatName(),\n                                    node.name,\n                                    owner.replace(\"/\", \".\"),\n                                    name\n                                )\n                            )\n\n                            node.opcode = AdviceAdapter.INVOKESTATIC\n                            node.owner = methodItem.proxyClassName.replace(\".\", \"/\")\n                            node.name = methodItem.proxyMethodName\n                            node.desc = methodItem.proxyMethodDesc\n                            node.itf = false\n                        }\n                    }\n                } else if (node is LdcInsnNode) {\n                    node.apply {\n                        if (cst is String && !bLdcHookMethod) {\n                            bLdcHookMethod =\n                                HookMethodManager.MANAGER.findByClsOrMethod(cst as String,privacyExtension.reflexMap)\n                        }\n                    }\n                }\n\n            }\n        }\n        return klass\n    }\n\n    private fun shouldHook(\n        methodName: String,\n        bLdcHookMethod: Boolean,\n        privacyExtension: PrivacyExtension\n    ): Boolean {\n        // 反射需要特殊处理下，避免hook所有的反射方法\n        return if (methodName == \"invoke\") {\n            bLdcHookMethod && privacyExtension.hookReflex\n        } else {\n            true\n        }\n    }\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/transform/booster/classtransform/hook/ServiceHookTransform.kt",
    "content": "package com.yl.lib.plugin.sentry.transform.booster.classtransform.hook\n\nimport com.didiglobal.booster.transform.TransformContext\nimport com.didiglobal.booster.transform.asm.isInterface\nimport com.yl.lib.plugin.sentry.extension.PrivacyExtension\nimport com.yl.lib.plugin.sentry.transform.manager.HookedDataManger\nimport com.yl.lib.plugin.sentry.util.PrivacyPluginUtil\nimport com.yl.lib.plugin.sentry.util.formatName\nimport com.yl.lib.plugin.sentry.util.formatSuperName\nimport org.gradle.api.Project\nimport org.objectweb.asm.Opcodes\nimport org.objectweb.asm.tree.ClassNode\nimport org.objectweb.asm.tree.InsnList\nimport org.objectweb.asm.tree.InsnNode\nimport org.objectweb.asm.tree.LdcInsnNode\n\n/**\n * @author yulun\n * @since 2023-08-08 10:55\n * 处理Service的onStartCommand方法，把返回值强行修改为\n */\nclass ServiceHookTransform : BaseHookTransform() {\n\n    override fun ignoreClass(context: TransformContext, klass: ClassNode): Boolean {\n        var ignore = super.ignoreClass(context, klass)\n        if (klass.isInterface) {\n            return true\n        }\n        if (!ignore) {\n            ignore = !PrivacyPluginUtil.privacyPluginUtil.isService(klass.formatName(), klass.formatSuperName())\n        }\n        return ignore\n    }\n\n    override fun transform(\n        project: Project,\n        privacyExtension: PrivacyExtension,\n        context: TransformContext,\n        klass: ClassNode\n    ): ClassNode {\n        if (!privacyExtension.enableHookServiceStartCommand){\n            return klass\n        }\n        HookedDataManger.MANAGER.addHookService(klass.formatName())\n        var onStartCommandMethod = klass.methods.find { it.name == \"onStartCommand\" }\n        if (onStartCommandMethod == null) {\n            val onStartCommand = klass.visitMethod(\n                Opcodes.ACC_PUBLIC,\n                \"onStartCommand\",\n                \"(Landroid/content/Intent;II)I\",\n                null,\n                null\n            )\n            onStartCommand.visitCode()\n            onStartCommand.visitInsn(Opcodes.ICONST_2)\n            onStartCommand.visitInsn(groovyjarjarasm.asm.Opcodes.IRETURN)\n            onStartCommand.visitMaxs(1, 1)\n            onStartCommand.visitEnd()\n        } else {\n            onStartCommandMethod.instructions.iterator().asSequence().forEach {\n                if (it is InsnNode) {\n                    if (it.opcode == Opcodes.IRETURN) {\n                        val newInstructions = InsnList()\n                        newInstructions.add(InsnNode(Opcodes.ICONST_2))\n                        newInstructions.add(InsnNode(Opcodes.IRETURN))\n                        onStartCommandMethod.instructions.insertBefore(it, newInstructions)\n                        onStartCommandMethod.instructions.remove(it)\n                    }\n                }\n            }\n        }\n        return klass\n    }\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/transform/booster/processor/PrivacyAssetsProcessor.kt",
    "content": "package com.yl.lib.plugin.sentry.transform.booster.processor\n\nimport com.android.build.gradle.api.ApplicationVariant\nimport com.android.build.gradle.api.BaseVariant\nimport com.didiglobal.booster.gradle.project\nimport com.didiglobal.booster.task.spi.VariantProcessor\nimport com.yl.lib.plugin.sentry.extension.PrivacyExtension\nimport com.yl.lib.plugin.sentry.util.PrivacyMoveAssetsUtil\nimport com.yl.lib.plugin.sentry.util.privacyPrintln\nimport org.gradle.api.Project\n\n/**\n * @author yulun\n * @since 2023-08-18 15:08\n */\nclass PrivacyAssetsProcessor(private val project: Project) : VariantProcessor {\n    override fun process(variant: BaseVariant) {\n        // privacy插件不支持library单独引用，只支持application引用\n        if (variant is ApplicationVariant) {\n            \"PrivacyAssetsProcessor ${variant.name}\".privacyPrintln()\n//            var variantName = variant.name.capitalize()\n//            var moveTask = variant.project.tasks.create(\n//                \"Privacy${variantName}AssetsTask\",\n//                PrivacyMoveAssetsTask::class.java\n//            )\n//           var findTask =  variant.project.tasks.findByName(\n//                variant.getTaskName(\"Privacy\", \"AssetsTask\")\n//            )\n//            \"PrivacyAssetsProcessor findTask  is $findTask\".privacyPrintln()\n//            \"PrivacyAssetsProcessor $variantName MoveAssetsTask is $moveTask\".privacyPrintln()\n            var privacyExtension = project.extensions.findByType(\n                PrivacyExtension::class.java\n            )\n            PrivacyMoveAssetsUtil.Asset.fileName = privacyExtension?.replaceFileName ?: \"\"\n            PrivacyMoveAssetsUtil.Asset.assetsPathList.add(variant.mergeAssetsProvider.get().outputDir.get().asFile.absolutePath)\n            PrivacyMoveAssetsUtil.Asset.buildDir = project.buildDir\n        }\n    }\n\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/transform/booster/processor/PrivacyManifestProcessor.kt",
    "content": "package com.yl.lib.plugin.sentry.transform.booster.processor\n\nimport com.android.build.api.variant.Variant\nimport com.didiglobal.booster.gradle.getTaskName\nimport com.didiglobal.booster.gradle.project\nimport com.didiglobal.booster.task.spi.VariantProcessor\nimport com.yl.lib.plugin.sentry.extension.PrivacyExtension\nimport com.yl.lib.plugin.sentry.transform.booster.task.PrivacyManifestTask\nimport com.yl.lib.plugin.sentry.util.privacyPrintln\nimport com.android.build.gradle.api.ApplicationVariant\nimport com.android.build.gradle.api.BaseVariant\nimport org.gradle.api.Project\n\n/**\n * @author yulun\n * @since 2023-08-21 17:56\n */\nclass PrivacyManifestProcessor(private val project: Project) : VariantProcessor {\n\n    override fun process(variant: Variant) {\n        if (variant is com.android.build.api.variant.ApplicationVariant) {\n            project.afterEvaluate {\n                project.tasks.findByName(\n                    variant.getTaskName(\"process\", \"Manifest\")\n                )?.let { manifestTask ->\n                    var extension = variant.project.extensions.findByType(\n                        PrivacyExtension::class.java\n                    )!!\n                    if (!extension.enableProcessManifest) {\n                        return@let\n                    }\n                    val taskName = \"update${variant.name.capitalize()}Manifest\"\n                    var privacyManifestProcessorTask =\n                        variant.project.tasks.create(taskName, PrivacyManifestTask::class.java) {\n                            it.variant = variant\n                            it.privacyExtension = extension\n                            it.outputs.upToDateWhen { false }\n                        }\n                    manifestTask.finalizedBy(privacyManifestProcessorTask)\n                }\n            }\n        } else {\n            \"${project.name}-不建议在Library Module下引入插件\".privacyPrintln()\n        }\n    }\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/transform/booster/task/PrivacyManifestTask.kt",
    "content": "package com.yl.lib.plugin.sentry.transform.booster.task\n\nimport com.android.SdkConstants\nimport com.android.build.api.artifact.SingleArtifact\nimport com.android.build.api.variant.ApplicationVariant\nimport com.android.utils.XmlUtils.parseUtfXmlFile\nimport com.didiglobal.booster.gradle.mergedManifests\nimport com.didiglobal.booster.kotlinx.search\nimport com.yl.lib.plugin.sentry.extension.PrivacyExtension\nimport com.yl.lib.plugin.sentry.util.PrivacyPluginUtil\nimport org.gradle.api.DefaultTask\nimport org.gradle.api.tasks.Internal\nimport org.gradle.api.tasks.TaskAction\nimport java.io.File\nimport javax.xml.transform.TransformerFactory\nimport javax.xml.transform.dom.DOMSource\n\n/**\n * @author yulun\n * @since 2022-11-17 14:04\n * 处理manifest文件，目前主要针对Service\n *  1. 关闭Service的Export\n *  2. 部分Service的priority设置为1000，可以强行替换\n */\nopen class PrivacyManifestTask : DefaultTask() {\n    @get:Internal\n    lateinit var variant: ApplicationVariant\n\n    @get:Internal\n    lateinit var privacyExtension: PrivacyExtension\n\n    @TaskAction\n    fun process() {\n        try {\n            variant.artifacts.get(SingleArtifact.MERGED_MANIFEST)\n                .get().asFile.let { manifestOutputFile ->\n                // 修改文件路径，将 merged_manifest 替换为 merged_manifests\n                val correctedManifestFile = File(\n                    manifestOutputFile.absolutePath.replace(\n                        \"/merged_manifest/\",\n                        \"/merged_manifests/\"\n                    )\n                )\n                var document = parseUtfXmlFile(correctedManifestFile, true)\n                var root = document.documentElement\n                if (root != null) {\n                    var children = root.childNodes\n                    for (i in 0 until children.length) {\n                        var application = children.item(i)\n\n                        if (application.nodeType == org.w3c.dom.Node.ELEMENT_NODE &&\n                            application.nodeName.equals(\"application\")\n                        ) {\n                            //遍历获取 Service\n                            var comps = application.childNodes\n                            for (j in 0 until comps.length) {\n                                var item = comps.item(j)\n                                if (item.nodeType == org.w3c.dom.Node.ELEMENT_NODE &&\n                                    item.nodeName.equals(\"service\")\n                                ) {\n                                    // 处理Service\n                                    PrivacyPluginUtil.privacyPluginUtil.i(\"setExportedProperties-${item.attributes}\")\n                                    var element = item as org.w3c.dom.Element\n                                    // 处理Service 的 priority\n                                    if (privacyExtension.enableReplacePriority && element.hasAttribute(\n                                            \"android:priority\"\n                                        )\n                                    ) {\n                                        var priority = element.getAttribute(\"android:priority\")\n                                        var bReplacePriority = false\n                                        try {\n                                            var p = Integer.parseInt(priority)\n                                            if (p >= privacyExtension.replacePriority) {\n                                                bReplacePriority = true\n                                            }\n                                        } catch (e: Exception) {\n                                            e.printStackTrace()\n                                        }\n                                        if (bReplacePriority) {\n                                            element.setAttribute(\n                                                \"android:priority\",\n                                                privacyExtension.replacePriority.toString()\n                                            )\n                                        }\n                                    }\n\n                                    // 强行把Service的exported属性设置为false\n                                    if (privacyExtension.enableCloseServiceExport && !isServiceExportWhite(\n                                            element.getAttribute(\"android:name\"),\n                                            privacyExtension.serviceExportPkgWhiteList\n                                                ?: emptySet()\n                                        )\n                                    ) {\n                                        if (element.hasAttribute(\"android:exported\")) {\n                                            if (element.getAttribute(\"android:exported\")\n                                                    .equals(\"true\")\n                                            ) {\n                                                element.setAttribute(\n                                                    \"android:exported\",\n                                                    \"false\"\n                                                )\n                                            }\n                                        } else {\n                                            element.setAttribute(\"android:exported\", \"false\")\n                                        }\n                                    }\n                                }\n                            }\n                            break\n                        }\n                    }\n                }\n                var transFactory = TransformerFactory.newInstance()\n                var transFormer = transFactory.newTransformer()\n                transFormer.setOutputProperty(javax.xml.transform.OutputKeys.INDENT, \"yes\")\n                var domSource = DOMSource(\n                    document\n                )\n                var realFile = File(correctedManifestFile.parentFile, \"realFile.xml\")\n                if (!realFile.exists()) {\n                    realFile.createNewFile()\n                }\n                var xmlResult = javax.xml.transform.stream.StreamResult(\n                    realFile\n                )\n                transFormer.transform(domSource, xmlResult)\n                correctedManifestFile.delete()\n                realFile.renameTo(correctedManifestFile)\n            }\n    } catch (e: Exception) {\n        e.printStackTrace()\n    }\n}\n\n    private fun isServiceExportWhite(\n        serviceName: String,\n        servicePkgWhiteList: Set<String>\n    ): Boolean {\n        servicePkgWhiteList.forEach {\n            if (serviceName.toUpperCase().contains(it.toUpperCase())) {\n                return true\n            }\n        }\n        return false\n    }\n\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/transform/booster/transformer/PrivacyBaseTransformer.kt",
    "content": "package com.yl.lib.plugin.sentry.transform.booster.transformer\n\nimport com.didiglobal.booster.annotations.Priority\nimport com.didiglobal.booster.transform.TransformContext\nimport com.didiglobal.booster.transform.Transformer\nimport com.didiglobal.booster.transform.asm.ClassTransformer\nimport org.objectweb.asm.ClassReader\nimport org.objectweb.asm.ClassWriter\nimport org.objectweb.asm.tree.ClassNode\nimport java.lang.management.ManagementFactory\nimport java.lang.management.ThreadMXBean\nimport java.util.*\n\n/**\n * @author yulun\n * @since 2023-08-10 11:14\n */\nclass PrivacyBaseTransformer : Transformer {\n    private val threadMxBean = ManagementFactory.getThreadMXBean()\n\n    private val durations = mutableMapOf<ClassTransformer, Long>()\n\n    private val classLoader: ClassLoader\n\n    internal val transformers: Iterable<ClassTransformer>\n\n\n    constructor() : this(Thread.currentThread().contextClassLoader)\n\n    constructor(classLoader: ClassLoader = Thread.currentThread().contextClassLoader) : this(\n        ServiceLoader.load(ClassTransformer::class.java, classLoader).sortedBy {\n            it.javaClass.getAnnotation(Priority::class.java)?.value ?: 0\n        }, classLoader\n    )\n\n    constructor(\n        transformers: Iterable<ClassTransformer>,\n        classLoader: ClassLoader = Thread.currentThread().contextClassLoader\n    ) {\n        this.classLoader = classLoader\n        this.transformers = transformers\n    }\n\n    override fun onPostTransform(context: TransformContext) {\n        transformers.forEach { it ->\n            threadMxBean.privacySumTime(\n                it\n            ) { it.onPostTransform(context) }\n        }\n    }\n\n    override fun onPreTransform(context: TransformContext) {\n        transformers.forEach { it ->\n            threadMxBean.privacySumTime(\n                it\n            ) { it.onPreTransform(context) }\n        }\n    }\n\n    override fun transform(context: TransformContext, bytecode: ByteArray): ByteArray {\n        return ClassWriter(ClassWriter.COMPUTE_MAXS).also { writer ->\n            this.transformers.fold(ClassNode().also { klass ->\n                try{\n                    ClassReader(bytecode).accept(klass, 0)\n                }catch (e:Exception){\n                    e.printStackTrace()\n                }\n            }) { klass, transformer ->\n                this.threadMxBean.privacySumTime(transformer) {\n                    transformer.transform(context, klass)\n                }\n            }.accept(writer)\n        }.toByteArray()\n    }\n\n    private fun <R> ThreadMXBean.privacySumTime(transformer: ClassTransformer, action: () -> R): R {\n        val start = this.currentThreadCpuTime\n        val result = action()\n        val end = this.currentThreadCpuTime\n        durations[transformer] = durations.getOrDefault(transformer, 0) + end - start\n        return result\n    }\n\n\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/transform/manager/HookFieldManager.kt",
    "content": "package com.yl.lib.plugin.sentry.transform.manager\n\n/**\n * @author yulun\n * @since 2022-08-30 11:10\n */\nopen class HookFieldManager {\n    object MANAGER {\n        private var hookFieldSet: HashSet<HookFieldItem> = HashSet()\n        /**\n         * 检测是否需要代理某个变量\n         * @param fieldName String\n         * @param classOwnerName String\n         * @param methodReturnDesc String\n         * @return Boolean\n         */\n        fun contains(\n            fieldName: String? = \"\",\n            classOwnerName: String? = \"\",\n            fieldDesc: String? = \"\"\n        ): Boolean {\n            if (fieldName == \"\") {\n                return false\n            }\n            return hookFieldSet.find {\n                isHookFieldItem(it, fieldName ?:\"\", classOwnerName ?:\"\", fieldDesc ?:\"\")\n            } != null\n        }\n\n        fun findHookItemByName(\n            fieldName: String ?= \"\", classOwnerName: String? = \"\",\n            fieldDesc: String? = \"\"\n        ): HookFieldItem? {\n            if (fieldName == \"\") {\n                return null\n            }\n\n            return hookFieldSet.find {\n                isHookFieldItem(it, fieldName ?: \"\", classOwnerName ?: \"\", fieldDesc ?: \"\")\n            }\n        }\n\n        private fun isHookFieldItem(\n            hookItem: HookFieldItem, fieldName: String,\n            classOwnerName: String = \"\",\n            fieldDesc: String = \"\"\n        ): Boolean {\n            if (fieldName.isEmpty()) {\n                return false\n            }\n            return if (classOwnerName.isEmpty() && fieldDesc.isNotEmpty()) {\n                fieldName == hookItem.originFieldName && fieldDesc == hookItem.proxyFieldDesc\n            } else if (classOwnerName.isNotEmpty() && fieldDesc.isEmpty()) {\n                fieldName == hookItem.originFieldName && classOwnerName == hookItem.originClassName\n            } else if (classOwnerName.isNotEmpty() && fieldDesc.isNotEmpty()) {\n                fieldName == hookItem.originFieldName && classOwnerName == hookItem.originClassName && fieldDesc == hookItem.proxyFieldDesc\n            } else {\n                fieldName == hookItem.originFieldName\n            }\n        }\n\n        /**\n         * 追加hook方法\n         * @param originClassName String 被代理方法的类名\n         * @param originMethodName String 被代理的方法\n         * @param proxyClassName String 代理方法的类名\n         * @param proxyMethodName String 代理方法名\n         * @param proxyMethodReturnDesc String 代理方法描述=被代理的方法描述\n         * @param documentMethodDesc String 方法注释信息\n         */\n        fun appendHookField(\n            originClassName: String,\n            originFieldName: String,\n            proxyClassName: String,\n            proxyFieldName: String,\n            proxyFieldDesc: String\n        ) {\n            hookFieldSet.add(\n                HookFieldItem(\n                    originClassName = originClassName,\n                    originFieldName = originFieldName,\n                    proxyClassName = proxyClassName,\n                    proxyFieldName = proxyFieldName,\n                    proxyFieldDesc = proxyFieldDesc\n                )\n            )\n        }\n\n        /**\n         * 加入hook集合\n         * 2022.06.15新增功能，支持业务方定义hook方法覆盖库内的方法\n         * @param hookFieldItem HookMethodItem\n         */\n        fun appendHookField(\n            hookFieldItem: HookFieldItem\n        ) {\n            if (hookFieldSet.contains(hookFieldItem)) {\n                // 这里有两种情况\n                // 1. 先扫描到privacy自身的配置方法，需要代理掉HashSet里的方法\n                // 2. 先扫描到业务自身的配置，那过滤掉不处理\n                // 3. 如果业务方重复定义，那就没办法了，最后被扫描到的会被加入\n                var bPrivacyItem =\n                    hookFieldItem.proxyClassName.contains(\"com.yl.lib.privacy_proxy\")\n                if (!bPrivacyItem){\n                    hookFieldSet.removeIf { it == hookFieldItem }\n                    hookFieldSet.add(hookFieldItem)\n                }\n                return\n            }\n            hookFieldSet.add(\n                hookFieldItem\n            )\n        }\n\n        /**\n         * 兼容kotlin lambda表达式，lambda会生成新的类，导致库本身的屏蔽失效\n         * @param className String\n         * @return Boolean\n         */\n        fun isProxyClass(className: String): Boolean {\n            return hookFieldSet.find {\n                it.proxyClassName == className ||  className.startsWith(it.proxyClassName)\n            } != null\n        }\n\n        /**\n         * 由于变量是静态的，防止gradle进程有缓存\n         */\n        fun clear() {\n            hookFieldSet.clear()\n        }\n    }\n}\n\nclass HookFieldItem {\n    // 原始类名\n    var originClassName: String? = \"\"\n\n    // 原始变量名\n    var originFieldName: String? = \"\"\n\n\n    // 代理的类名\n    var proxyClassName: String\n\n    // 代理的变量名\n    var proxyFieldName: String\n\n    // 代理变量签名，默认和原始变量签名一致\n    var proxyFieldDesc: String? = \"\"\n\n    constructor(\n        proxyClassName: String,\n        proxyFieldName: String,\n        proxyFieldDesc: String\n    ) {\n        this.proxyClassName = proxyClassName\n        this.proxyFieldName = proxyFieldName\n        this.proxyFieldDesc = proxyFieldDesc\n    }\n\n    constructor(\n        originClassName: String,\n        originFieldName: String,\n\n        proxyClassName: String,\n        proxyFieldName: String,\n        proxyFieldDesc: String\n    ) {\n        this.originClassName = originClassName\n        this.originFieldName = originFieldName\n        this.proxyFieldDesc = proxyFieldDesc\n        this.proxyClassName = proxyClassName\n        this.proxyFieldName = proxyFieldName\n    }\n\n    override fun equals(other: Any?): Boolean {\n        if (other is HookFieldItem) {\n            return (other.originClassName == originClassName &&\n                    other.originFieldName == originFieldName &&\n                    other.proxyFieldDesc == proxyFieldDesc)\n        }\n\n        return super.equals(other)\n    }\n\n    override fun hashCode(): Int {\n        return  originClassName.hashCode() + originFieldName.hashCode() + proxyFieldDesc.hashCode()\n    }\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/transform/manager/HookMethodManager.kt",
    "content": "package com.yl.lib.plugin.sentry.transform.manager\n\n/**\n * @author yulun\n * @sinice 2021-12-14 11:39\n * 汇总所有的hook方法配置\n */\nopen class HookMethodManager {\n    object MANAGER {\n        private var hookMethodList: HashSet<HookMethodItem> = HashSet()\n\n        /**\n         * 检测是否需要代理某个方法\n         * @param methodName String\n         * @param classOwnerName String\n         * @param methodReturnDesc String\n         * @return Boolean\n         */\n        fun contains(\n            methodName: String,\n            classOwnerName: String = \"\",\n            methodReturnDesc: String = \"\",\n            opcodeAndSource:Int\n        ): Boolean {\n            if (methodName == \"\") {\n                return false\n            }\n            return hookMethodList.find {\n                isHookMethodItem(it, methodName, classOwnerName, methodReturnDesc,opcodeAndSource)\n            } != null\n        }\n\n        fun findHookItemByName(\n            methodName: String\n        ): HookMethodItem? {\n            return findHookItemByName(methodName, \"\", \"\",-1)\n        }\n\n        /**\n         * 找到代理方法\n         * @param methodName String\n         * @param classOwnerName String\n         * @param methodReturnDesc String\n         * @return HookMethodItem?\n         */\n        fun findHookItemByName(\n            methodName: String, classOwnerName: String = \"\",\n            methodReturnDesc: String = \"\",\n            opcodeAndSource:Int\n        ): HookMethodItem? {\n            if (methodName == \"\") {\n                return null\n            }\n\n            return hookMethodList.find {\n                isHookMethodItem(it, methodName, classOwnerName, methodReturnDesc,opcodeAndSource)\n            }\n        }\n\n        /**\n         * 判断当前方法是否可以被代理\n         * @param hookItem HookMethodItem\n         * @param methodName String\n         * @param classOwnerName String\n         * @param methodReturnDesc String\n         * @return Boolean\n         */\n        private fun isHookMethodItem(\n            hookItem: HookMethodItem, methodName: String,\n            classOwnerName: String = \"\",\n            methodReturnDesc: String = \"\",\n            opcodeAndSource:Int\n        ): Boolean {\n            if (methodName.isEmpty()) {\n                return false\n            }\n\n            // 如果忽略类名，只要方法名和签名相同就可以\n            val replaceClassOwnerName = if (hookItem.ignoreClass) {\n                \"\"\n            } else {\n                classOwnerName\n            }\n\n            return if (replaceClassOwnerName.isEmpty() && methodReturnDesc.isNotEmpty()) {\n                methodName == hookItem.originMethodName && methodReturnDesc == hookItem.originMethodDesc && opcodeAndSource == hookItem.originMethodAccess\n            } else if (replaceClassOwnerName.isNotEmpty() && methodReturnDesc.isEmpty()) {\n                methodName == hookItem.originMethodName && replaceClassOwnerName == hookItem.originClassName && opcodeAndSource == hookItem.originMethodAccess\n            } else if (replaceClassOwnerName.isNotEmpty() && methodReturnDesc.isNotEmpty()) {\n                methodName == hookItem.originMethodName && replaceClassOwnerName == hookItem.originClassName && methodReturnDesc == hookItem.originMethodDesc && opcodeAndSource == hookItem.originMethodAccess\n            } else {\n                methodName == hookItem.originMethodName\n            }\n        }\n\n        /**\n         * 加入hook集合\n         * 2022.06.15新增功能，支持业务方定义hook方法覆盖库内的方法\n         * @param hookMethodItem HookMethodItem\n         */\n        fun appendHookMethod(\n            hookMethodItem: HookMethodItem\n        ) {\n            if (hookMethodList.contains(hookMethodItem)) {\n                // 这里有两种情况\n                // 1. 先扫描到privacy自身的配置方法，需要代理掉HashSet里的方法\n                // 2. 先扫描到业务自身的配置，那过滤掉不处理\n                // 3. 如果业务方重复定义，那就没办法了，最后被扫描到的会被加入\n                var bPrivacyItem =\n                    hookMethodItem.proxyClassName.contains(\"com.yl.lib.privacy_proxy\")\n                if (!bPrivacyItem) {\n                    hookMethodList.removeIf { it == hookMethodItem }\n                    hookMethodList.add(hookMethodItem)\n                }\n                return\n            }\n            hookMethodList.add(\n                hookMethodItem\n            )\n        }\n\n        //判断加载的字符串常量\n        fun findByClsOrMethod(\n            name: String,\n            reflexMap: Map<String, List<String>>?\n        ): Boolean {\n            if (reflexMap?.isEmpty() == false){\n                if (reflexMap.any {\n                        it.value.contains(name)\n                    }) {\n                    return true\n                }\n            }\n            return hookMethodList.find {\n                name.contains(it.originClassName ?: \"\")  ||  name.contains(it.originMethodName ?: \"\")\n            } !=null\n        }\n\n        /**\n         * 兼容kotlin lambda表达式，lambda会生成新的类，导致库本身的屏蔽失效\n         * @param className String\n         * @return Boolean\n         */\n        fun isProxyClass(className: String): Boolean {\n            return hookMethodList.find {\n                it.proxyClassName == className || className.startsWith(it.proxyClassName)\n            } != null\n        }\n\n        /**\n         * 由于变量是静态的，防止gradle进程有缓存\n         */\n        fun clear() {\n            hookMethodList.clear()\n        }\n    }\n}\n\nclass HookMethodItem {\n    // 原始类名\n    var originClassName: String? = \"\"\n\n    // 原始方法名\n    var originMethodName: String? = \"\"\n\n    // 原始方法签名\n    var originMethodDesc: String? = \"\"\n\n    var originMethodAccess: Int? = 0\n\n    var ignoreClass : Boolean = false\n\n    // 代理的类名\n    var proxyClassName: String\n\n    // 代理的方法名\n    var proxyMethodName: String\n\n    // 代理的方法签名\n    var proxyMethodDesc: String\n\n    constructor(\n        proxyClassName: String,\n        proxyMethodName: String,\n        proxyMethodReturnDesc: String\n    ) {\n        this.proxyClassName = proxyClassName\n        this.proxyMethodName = proxyMethodName\n        this.proxyMethodDesc = proxyMethodReturnDesc\n    }\n\n    constructor(\n        originClassName: String,\n        originMethodName: String,\n        originMethodDesc: String,\n        originMethodAccess: Int,\n        proxyClassName: String,\n        proxyMethodName: String,\n        proxyMethodDesc: String\n    ) {\n        this.originClassName = originClassName\n        this.originMethodName = originMethodName\n        this.originMethodDesc = originMethodDesc\n        this.originMethodAccess = originMethodAccess\n        this.proxyClassName = proxyClassName\n        this.proxyMethodName = proxyMethodName\n        this.proxyMethodDesc = proxyMethodDesc\n    }\n\n\n    override fun equals(other: Any?): Boolean {\n        if (other is HookMethodItem) {\n            return (other.originMethodAccess == originMethodAccess &&\n                    other.originClassName == originClassName &&\n                    other.originMethodName == originMethodName &&\n                    other.originMethodDesc == originMethodDesc)\n        }\n\n        return super.equals(other)\n    }\n\n    override fun hashCode(): Int {\n        return originMethodAccess.hashCode() + originClassName.hashCode() + originMethodName.hashCode() + originMethodDesc.hashCode()\n    }\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/transform/manager/HookedDataManger.kt",
    "content": "package com.yl.lib.plugin.sentry.transform.manager\n\nimport com.alibaba.fastjson.JSON\nimport com.alibaba.fastjson.annotation.JSONField\nimport com.alibaba.fastjson.serializer.SerializerFeature\nimport com.yl.lib.plugin.sentry.util.PrivacyPluginUtil\nimport org.gradle.api.Project\nimport org.gradle.util.GFileUtils\nimport java.io.File\n\n/**\n * @author yulun\n * @since 2022-06-16 20:06\n * 记录所有被代理的方法和类列表，方便做数据比对\n */\nclass HookedDataManger {\n    object MANAGER {\n        private var replaceMethodMap: HashMap<String, ReplaceMethodData> = HashMap()\n\n        private var hookServiceList: ArrayList<String> = ArrayList()\n        fun addReplaceMethodItem(methodItem: ReplaceMethodItem) {\n            var key = buildKey(methodItem)\n            var replaceMethodData = replaceMethodMap[key]\n            if (replaceMethodData == null) {\n                replaceMethodData = ReplaceMethodData()\n            }\n            PrivacyPluginUtil.privacyPluginUtil.i(\"addReplaceMethodItem methodItem is $methodItem\")\n            replaceMethodData.addReplaceMethodItem(replaceMethodItem = methodItem)\n            replaceMethodMap[key] = replaceMethodData\n        }\n\n        fun addHookService(serviceName: String) {\n            if (hookServiceList.contains(serviceName)) {\n                return\n            }\n            PrivacyPluginUtil.privacyPluginUtil.i(\"addHookService serviceName is $serviceName\")\n            hookServiceList.add(serviceName)\n        }\n\n        fun flushToFile(fileName: String, buildDir:File) {\n            if (fileName == null || (replaceMethodMap.isEmpty() && hookServiceList.isEmpty())) {\n                PrivacyPluginUtil.privacyPluginUtil.i(\"flushToFile but data is empty \")\n                return\n            }\n            var resultFile = File(buildDir.absolutePath + File.separator + fileName)\n            PrivacyPluginUtil.privacyPluginUtil.i(\"flushToFile fileName is ${resultFile.absolutePath}\")\n            if (resultFile?.parentFile != null && !resultFile.parentFile.exists()) {\n                GFileUtils.mkdirs(resultFile)\n            }\n\n            resultFile.let {\n                GFileUtils.deleteQuietly(resultFile)\n            }\n\n            var privacyHookData = PrivacyHookData()\n            privacyHookData.replaceMethodMap = replaceMethodMap\n            privacyHookData.hookServiceList = hookServiceList\n\n            objectToJsonString(\n                privacyHookData\n            ).let { content ->\n                PrivacyPluginUtil.privacyPluginUtil.i(\"flushToFile writeFile is ${resultFile.absolutePath}\")\n                GFileUtils.writeFile(content, resultFile)\n            }\n        }\n\n        private fun buildKey(methodItem: ReplaceMethodItem): String {\n            return \"${methodItem.proxyMethodClass}.${methodItem.proxyMethodName}\"\n        }\n\n        private fun objectToJsonString(o: Any?): String? {\n            return if (null != o) {\n                try {\n                    JSON.toJSONString(\n                        o, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue,\n                        SerializerFeature.WriteDateUseDateFormat\n                    );\n                } catch (var2: Exception) {\n                    null\n                }\n            } else {\n                null\n            }\n        }\n    }\n}\n\nclass PrivacyHookData{\n    var replaceMethodMap: HashMap<String, ReplaceMethodData> = HashMap()\n\n    var hookServiceList: ArrayList<String> = ArrayList()\n}\n\nclass ReplaceMethodData {\n    var count: Int = 0\n    var originMethodList: ArrayList<ReplaceMethodItem>? = null\n\n    constructor() {\n        originMethodList = ArrayList()\n    }\n\n    fun addReplaceMethodItem(replaceMethodItem: ReplaceMethodItem) {\n        if (originMethodList?.contains(replaceMethodItem) == true) {\n            return\n        }\n        count++\n        originMethodList?.add(replaceMethodItem)\n    }\n}\n\nclass ReplaceMethodItem {\n    // 原始类名，指的是调用敏感方法的 类和方法\n    var originClassName: String? = \"\"\n\n    // 原始方法名\n    var originMethodName: String? = \"\"\n\n    // 代理方法名，即敏感方法\n    @JSONField(serialize = false)\n    var proxyMethodName: String? = \"\"\n\n    // 加个类名是为了保证key的唯一性，虽然系统方法重名的概率很低很低\n    @JSONField(serialize = false)\n    var proxyMethodClass: String? = \"\"\n\n    constructor(\n        originClassName: String,\n        originMethodName: String,\n        proxyMethodClass: String,\n        proxyMethodName: String\n    ) {\n        this.originClassName = originClassName\n        this.originMethodName = originMethodName\n        this.proxyMethodClass = proxyMethodClass\n        this.proxyMethodName = proxyMethodName\n\n    }\n\n    override fun equals(other: Any?): Boolean {\n        if (other is ReplaceMethodItem) {\n            return (other.proxyMethodName == proxyMethodName &&\n                    other.originClassName == originClassName &&\n                    other.originMethodName == originMethodName &&\n                    other.proxyMethodClass == proxyMethodClass)\n        }\n\n        return super.equals(other)\n    }\n\n    override fun toString(): String {\n        return \"原始类名: $originClassName, 原始方法名: $originMethodName\\n\"\n    }\n\n\n    override fun hashCode(): Int {\n        return proxyMethodName.hashCode() + originClassName.hashCode() + originMethodName.hashCode() + proxyMethodClass.hashCode()\n    }\n}\n"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/transform/manager/ReplaceClassManager.kt",
    "content": "package com.yl.lib.plugin.sentry.transform.manager\n\n/**\n * @author yulun\n * @since 2022-11-18 15:09\n * 类代理，暂时主要用于构造函数代理\n */\nclass ReplaceClassManager {\n    object MANAGER {\n        private var replaceClassSet: HashSet<ReplaceClassItem> = HashSet()\n\n        /**\n         *\n         * @param originClassName String?\n         * @param proxyClassName String?\n         * @return Boolean\n         */\n        fun contains(\n            originClassName: String? = \"\",\n            proxyClassName: String? = \"\"\n        ): Boolean {\n            return replaceClassSet.find {\n                isHookItem(it, originClassName ?: \"\", proxyClassName ?: \"\")\n            } != null\n        }\n\n\n        fun findItemByName(\n            originClassName: String? = \"\", proxyClassName: String? = \"\"\n        ): ReplaceClassItem? {\n            return replaceClassSet.find {\n                isHookItem(it, originClassName ?: \"\", proxyClassName ?: \"\")\n            }\n        }\n\n        private fun isHookItem(\n            hookItem: ReplaceClassItem, originClassName: String,\n            proxyClassName: String = \"\"\n        ): Boolean {\n            return if (originClassName.isEmpty() && proxyClassName.isEmpty()) {\n                false\n            } else if (originClassName.isNotEmpty() && proxyClassName.isEmpty()) {\n                hookItem.originClassName == originClassName\n            } else if (originClassName.isEmpty() && proxyClassName.isNotEmpty()) {\n                hookItem.proxyClassName == proxyClassName\n            } else {\n                originClassName == hookItem.originClassName && proxyClassName == hookItem.proxyClassName\n            }\n        }\n\n        /**\n         * 追加待代理的类\n         * @param originClassName String\n         * @param proxyClassName String\n         */\n        fun appendHookItem(\n            originClassName: String,\n            proxyClassName: String\n        ) {\n            replaceClassSet.add(\n                ReplaceClassItem(\n                    originClassName = originClassName,\n                    proxyClassName = proxyClassName\n                )\n            )\n        }\n\n        /**\n         * 加入hook集合\n         * @param replaceClassItem ReplaceClassItem\n         */\n        fun appendHookItem(\n            replaceClassItem: ReplaceClassItem\n        ) {\n            if (replaceClassSet.contains(replaceClassItem)) {\n                // 这里有两种情况\n                // 1. 先扫描到privacy自身的配置方法，需要代理掉HashSet里的方法\n                // 2. 先扫描到业务自身的配置，那过滤掉不处理\n                // 3. 如果业务方重复定义，那就没办法了，最后被扫描到的会被加入\n                var bPrivacyItem =\n                    replaceClassItem.proxyClassName.contains(\"com.yl.lib.privacy_replace\")\n                if (!bPrivacyItem) {\n                    replaceClassSet.removeIf { it == replaceClassItem }\n                    replaceClassSet.add(replaceClassItem)\n                }\n                return\n            }\n            replaceClassSet.add(\n                replaceClassItem\n            )\n        }\n\n        /**\n         * 兼容kotlin lambda表达式，lambda会生成新的类，导致库本身的屏蔽失效\n         * @param className String\n         * @return Boolean\n         */\n        fun isProxyClass(className: String): Boolean {\n            return replaceClassSet.find {\n                it.proxyClassName == className || className.startsWith(it.proxyClassName)\n            } != null\n        }\n\n        /**\n         * 由于变量是静态的，防止gradle进程有缓存\n         */\n        fun clear() {\n            replaceClassSet.clear()\n        }\n    }\n}\n\nclass ReplaceClassItem {\n    // 原始类名\n    var originClassName: String\n\n    // 代理的类名\n    var proxyClassName: String\n\n    constructor(originClassName: String, proxyClassName: String) {\n        this.originClassName = originClassName\n        this.proxyClassName = proxyClassName\n    }\n\n\n    override fun equals(other: Any?): Boolean {\n        if (other is HookFieldItem) {\n            return (other.originClassName == originClassName &&\n                    other.originClassName == originClassName)\n        }\n\n        return super.equals(other)\n    }\n\n    override fun hashCode(): Int {\n        return originClassName.hashCode() + originClassName.hashCode()\n    }\n\n    override fun toString(): String {\n        return \"originClassName is $originClassName , proxyClassName is $proxyClassName\"\n    }\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/util/PrivacyExt.kt",
    "content": "package com.yl.lib.plugin.sentry.util\n\nimport com.didiglobal.booster.kotlinx.NCPU\nimport com.didiglobal.booster.kotlinx.redirect\nimport com.didiglobal.booster.kotlinx.search\nimport com.didiglobal.booster.kotlinx.touch\nimport com.didiglobal.booster.transform.util.transform\nimport org.apache.commons.compress.archivers.jar.JarArchiveEntry\nimport org.apache.commons.compress.archivers.zip.ParallelScatterZipCreator\nimport org.apache.commons.compress.archivers.zip.ZipArchiveEntry\nimport org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream\nimport org.apache.commons.compress.parallel.InputStreamSupplier\nimport org.objectweb.asm.tree.AnnotationNode\nimport org.objectweb.asm.tree.ClassNode\nimport java.io.File\nimport java.io.IOException\nimport java.io.OutputStream\nimport java.util.concurrent.Executors\nimport java.util.concurrent.LinkedBlockingQueue\nimport java.util.concurrent.RejectedExecutionHandler\nimport java.util.concurrent.ThreadPoolExecutor\nimport java.util.concurrent.TimeUnit\nimport java.util.jar.JarFile\nimport java.util.zip.ZipEntry\nimport java.util.zip.ZipFile\n\n/**\n * @author yulun\n * @since 2023-08-09 17:17\n */\n\n//fun File.privacyTransform(output: File, transformer: (ByteArray) -> ByteArray) {\n//    when {\n//        isDirectory -> this.toURI().let { base ->\n//            this.search().parallelStream().forEach {\n//                it.transform(File(output, base.relativize(it.toURI()).path), transformer)\n//            }\n//        }\n//        isFile -> when (extension.toLowerCase()) {\n//            \"jar\" -> JarFile(this).use {\n//                it.privacyTransform(output, ::JarArchiveEntry, transformer)\n//            }\n//            \"class\" -> this.inputStream().use {\n//                it.transform(transformer).redirect(output)\n//            }\n//            else -> this.copyTo(output, true)\n//        }\n//        else -> throw IOException(\"Unexpected file: ${this.canonicalPath}\")\n//    }\n//\n//}\n\n//fun ZipFile.privacyTransform(\n//    output: File,\n//    entryFactory: (ZipEntry) -> ZipArchiveEntry = ::ZipArchiveEntry,\n//    transformer: (ByteArray) -> ByteArray = { it -> it }\n//) = output.touch().outputStream().buffered().use {\n//    this.privacyTransform(it, entryFactory, transformer)\n//}\n\n\n//fun ZipFile.privacyTransform(\n//    output: OutputStream,\n//    entryFactory: (ZipEntry) -> ZipArchiveEntry = ::ZipArchiveEntry,\n//    transformer: (ByteArray) -> ByteArray = { it -> it }\n//) {\n//    val entries = mutableSetOf<String>()\n//    val creator = ParallelScatterZipCreator(\n//        ThreadPoolExecutor(\n//            NCPU,\n//            NCPU,\n//            0L,\n//            TimeUnit.MILLISECONDS,\n//            LinkedBlockingQueue<Runnable>(),\n//            Executors.defaultThreadFactory(),\n//            RejectedExecutionHandler { runnable, _ ->\n//                runnable.run()\n//            })\n//    )\n//    //将jar包里的文件序列化输出\n//    entries().asSequence().filterNot {\n//        it.name.startsWith(\"META-INF/\") && it.name.substringAfterLast('.') in JAR_SIGNATURE_EXTENSIONS\n//    }.forEach { entry ->\n//        if (!entries.contains(entry.name)) {\n//            val zae = entryFactory(entry)\n//            val stream = InputStreamSupplier {\n//                when (entry.name.substringAfterLast('.', \"\")) {\n//                    \"class\" -> getInputStream(entry).use { src ->\n//                        try {\n//                            src.transform(transformer).inputStream()\n//                        } catch (e: Throwable) {\n//                            System.err.println(\"Broken class: ${this.name}!/${entry.name}\")\n//                            getInputStream(entry)\n//                        }\n//                    }\n//                    else -> getInputStream(entry)\n//                }\n//            }\n//\n//            creator.addArchiveEntry(zae, stream)\n//            entries.add(entry.name)\n//        } else {\n//            System.err.println(\"Duplicated jar entry1: ${this.name}!/${entry.name}\")\n//        }\n//    }\n//    val zip = ZipArchiveOutputStream(output)\n//    zip.use { zipStream ->\n//        try {\n//            creator.writeTo(zipStream)\n//            zipStream.close()\n//        } catch (e: Exception) {\n//            zipStream.close()\n////            e.printStackTrace()\n////            \"e===>${e.message}\".println()\n//            System.err.println(\"Duplicated jar entry2: ${this.name}!\")\n//        }\n//    }\n//}\n\n//private val JAR_SIGNATURE_EXTENSIONS = setOf(\"SF\", \"RSA\", \"DSA\", \"EC\")\n\nfun <R> AnnotationNode.privacyGetValue(name: String = \"value\"): R? =\n    values?.withIndex()?.iterator()?.let {\n        while (it.hasNext()) {\n            val i = it.next()\n            if (i.index % 2 == 0 && i.value == name) {\n                return@let it.next().value as R\n            }\n        }\n        null\n    }\n\n\nfun ClassNode.formatName(): String {\n    return this.name.replace(\"/\", \".\")\n}\n\nfun ClassNode.formatSuperName(): String {\n    return this.superName.replace(\"/\", \".\")\n}\n\nfun String.privacyPrintln() {\n    println(\"[privacy plugin]===>$this\")\n}\n\nfun String.privacyClassProxy(): Boolean {\n    return this == \"Lcom/yl/lib/privacy_annotation/PrivacyClassProxy;\"\n}\n\nfun String.privacyClassBlack(): Boolean {\n    return this == \"Lcom/yl/lib/privacy_annotation/PrivacyClassBlack;\"\n}\n\nfun String.privacyClassReplace(): Boolean {\n    return this == \"Lcom/yl/lib/privacy_annotation/PrivacyClassReplace;\"\n}\n\nfun String.privacyFieldProxy(): Boolean {\n    return this == \"Lcom/yl/lib/privacy_annotation/PrivacyFieldProxy;\"\n}\n\nfun String.privacyMethodProxy(): Boolean {\n    return this == \"Lcom/yl/lib/privacy_annotation/PrivacyMethodProxy;\"\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/util/PrivacyMoveAssetsUtil.kt",
    "content": "package com.yl.lib.plugin.sentry.util\n\nimport com.yl.lib.plugin.sentry.transform.manager.HookedDataManger\nimport org.gradle.util.GFileUtils\nimport java.io.File\n\n/**\n * @author yulun\n * @since 2022-06-29 16:06\n * 把扫描生成的静态文件 写到apk assets目录下\n * todo  demo里task可以执行，但是在项目里，task注入不进去，待排查\n */\nopen class PrivacyMoveAssetsUtil{\n\n    object Asset{\n\n        var fileName: String? = null\n\n        var assetsPathList: ArrayList<String> = ArrayList()\n\n        var buildDir:File?=null\n\n        fun doFlushProxyData() {\n            PrivacyPluginUtil.privacyPluginUtil.i(\"MoveAssetsTask-flushToFile\")\n            // 写入被代理所有的类和文件\n            fileName?.let {\n                HookedDataManger.MANAGER.flushToFile(it, buildDir!!)\n            }\n\n            var originFile = File(buildDir?.absolutePath + File.separator + fileName)\n            if (!originFile.exists()) {\n                PrivacyPluginUtil.privacyPluginUtil.i(\"MoveAssetsTask originFile don't exist,path is ${buildDir?.absolutePath + File.separator + fileName}\")\n                return\n            }\n            assetsPathList.forEach { assetsPath ->\n                var assetsFile = File(assetsPath+ File.separator+ fileName)\n                PrivacyPluginUtil.privacyPluginUtil.i(\"MoveAssetsTask assetsPath  is ${assetsPath}\")\n                assetsFile.let {\n                    GFileUtils.deleteQuietly(assetsFile)\n                }\n                PrivacyPluginUtil.privacyPluginUtil.i(\"MoveAssetsTask originFile is ${originFile.absolutePath} assetsPath is $assetsPath\")\n                GFileUtils.copyFile(originFile, assetsFile)\n            }\n\n        }\n    }\n\n\n\n\n}"
  },
  {
    "path": "plugin-sentry/src/main/java/com/yl/lib/plugin/sentry/util/PrivacyPluginUtil.kt",
    "content": "package com.yl.lib.plugin.sentry.util\n\nimport org.gradle.api.logging.Logger\nimport kotlin.math.log\n\n/**\n * @author yulun\n * @since 2023-07-20 19:23\n */\nclass PrivacyPluginUtil {\n    companion object {\n        val privacyPluginUtil: PrivacyPluginUtil by lazy { PrivacyPluginUtil() }\n\n    }\n\n    var logger: Logger? = null\n        set(value) {\n            field = value\n        }\n\n    fun i(info: Any) {\n        logger?.info(info.toString())\n    }\n\n    fun d(info: Any) {\n        logger?.info(info.toString())\n    }\n\n    fun e(info: Any) {\n        logger?.info(info.toString())\n    }\n\n    fun isActivity(name: String, superName: String?): Boolean {\n        return lastIndexOfDot(name).endsWith(\"Activity\") && lastIndexOfDot(\n            superName\n        ).endsWith(\"\")\n    }\n\n    fun isService(name: String, superName: String?): Boolean {\n        return (lastIndexOfDot(name).endsWith(\"Service\") && lastIndexOfDot(\n            superName\n        ).endsWith(\"Service\"))\n    }\n\n    private fun lastIndexOfDot(name: String?): String {\n        logger?.info(\"lastIndexOfDot name = $name\")\n        var index = name?.lastIndexOf(\".\") ?: 0\n        if (index == -1) {\n            return name ?: \"\"\n        }\n        logger?.info(\n            \"lastIndexOfDot name = $name , index = $index ， result is ${\n                name?.substring(\n                    index,\n                    name.length\n                )\n            }\"\n        )\n        return name?.substring(index + 1, name.length) ?: \"\"\n    }\n\n    fun ignoreClass(className: String, blackList: Set<String>? = emptySet()): Boolean {\n        val entryName = className.replace(\"/\", \".\")\n        blackList?.forEach {\n            if (entryName.contains(it))\n                return true\n        }\n        if (entryName.endsWith(\"R.class\")\n            || entryName.endsWith(\"BuildConfig.class\")\n            || entryName.contains(\"android.support\")\n            || entryName.contains(\"android.arch\")\n            || entryName.contains(\"android.app\")\n            || entryName.contains(\"android.material\")\n            || entryName.contains(\"androidx\")\n            || entryName.endsWith(\".SF\")\n            || entryName.contains(\".DSA\")\n            || entryName.contains(\".RSA\")\n            || entryName.contains(\".MF\")\n            || entryName.contains(\"META-INF\")\n            // 过滤掉库本身\n            || entryName.contains(\"com.yl.lib.privacy_annotation\")\n        ) {\n            return true\n        }\n        return false\n    }\n\n}"
  },
  {
    "path": "plugin-sentry/src/main/resources/META-INF/gradle-plugins/com.allenymt.plugin.privacy.properties",
    "content": "implementation-class=com.yl.lib.plugin.sentry.PrivacySentryPlugin"
  },
  {
    "path": "plugin-sentry/src/main/resources/META-INF/gradle-plugins/privacy-sentry-plugin.properties",
    "content": "implementation-class=com.yl.lib.plugin.sentry.PrivacySentryPlugin"
  },
  {
    "path": "privacy-annotation/.gitignore",
    "content": "/build"
  },
  {
    "path": "privacy-annotation/build.gradle",
    "content": "apply plugin: 'java-library'\napply plugin: 'kotlin'\napply from: '../publish.gradle'  // Changed from 'maven' to 'maven-publish'\n\njava {\n    sourceCompatibility = JavaVersion.VERSION_1_8\n    targetCompatibility = JavaVersion.VERSION_1_8\n}"
  },
  {
    "path": "privacy-annotation/gradle.properties",
    "content": "ARTIFACT_ID=privacy-annotation"
  },
  {
    "path": "privacy-annotation/src/main/java/com/yl/lib/privacy_annotation/MethodInvokeOpcode.java",
    "content": "package com.yl.lib.privacy_annotation;\n\n/**\n * @author yulun\n * @sinice 2021-12-31 11:12\n * 猜测是编译顺序的关系，当插件里引用这个类时，插件里是kotlin代码，opcode计算出来都是0\n */\npublic class MethodInvokeOpcode {\n\n    /***\n     *   int INVOKEVIRTUAL = 182; // visitMethodInsn\n     *   int INVOKESPECIAL = 183; // -\n     *   int INVOKESTATIC = 184; // -\n     *   int INVOKEINTERFACE = 185; // -\n     *   int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn\n     */\n    // 调用对象的实例方法\n    public static final int INVOKEVIRTUAL = 182;\n\n    // 调用特殊方法，比如初始化，私有方法，父类方法\n    public static final int INVOKESPECIAL = 183;\n\n    // 调用类方法，也就是静态方法\n    public static final int INVOKESTATIC = 184;\n\n    // 接口方法\n    public static final int INVOKEINTERFACE = 185;\n\n    // 动态方法,支持解释性语言\n    public static final int INVOKEDYNAMIC = 186;\n\n}\n"
  },
  {
    "path": "privacy-annotation/src/main/java/com/yl/lib/privacy_annotation/PrivacyClassBlack.java",
    "content": "package com.yl.lib.privacy_annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * @author yulun\n * @since 2022-12-05 11:08\n * 不会被代理，黑名单注解\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.CLASS)\npublic @interface PrivacyClassBlack {\n}\n"
  },
  {
    "path": "privacy-annotation/src/main/java/com/yl/lib/privacy_annotation/PrivacyClassProxy.java",
    "content": "package com.yl.lib.privacy_annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * @author yulun\n * @sinice 2022-01-04 10:04\n * 有这个注解的类，才会被解析\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.CLASS)\npublic @interface PrivacyClassProxy {\n\n}\n"
  },
  {
    "path": "privacy-annotation/src/main/java/com/yl/lib/privacy_annotation/PrivacyClassReplace.java",
    "content": "package com.yl.lib.privacy_annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * @author yulun\n * @since 2022-11-18 14:29\n * 类替换，\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.CLASS)\npublic @interface PrivacyClassReplace {\n    Class originClass();\n}\n"
  },
  {
    "path": "privacy-annotation/src/main/java/com/yl/lib/privacy_annotation/PrivacyFieldProxy.java",
    "content": "package com.yl.lib.privacy_annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * @author yulun\n * @since 2022-08-30 11:39\n */\n@Target(ElementType.FIELD)\n@Retention(RetentionPolicy.CLASS)\npublic @interface PrivacyFieldProxy {\n    // 原始类\n    Class originalClass();\n\n    // 原始的变量名\n    String originalFieldName() default \"\";\n}\n"
  },
  {
    "path": "privacy-annotation/src/main/java/com/yl/lib/privacy_annotation/PrivacyMethodProxy.java",
    "content": "package com.yl.lib.privacy_annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * @author yulun\n * @sinice 2021-12-31 09:47\n */\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.CLASS)\npublic @interface PrivacyMethodProxy {\n    // 原始类\n    Class originalClass();\n\n    // 原始的方法名\n    String originalMethod() default \"\";\n\n    // 原始方法的描述信息，对于方法的返回值，我们默认为代理方法和原始方法要保持一致，所以这里只需要记录描述信息即可\n    // 默认是MethodInvokeOpcode.INVOKESTATIC\n    int originalOpcode() default MethodInvokeOpcode.INVOKESTATIC;\n\n    // 忽略originalClass参数，在校验方法替换时只校验方法名和方法描述信息\n    boolean ignoreClass() default false;\n}\n"
  },
  {
    "path": "privacy-annotation/~/.m2/repository/com/yl/lib/privacy/privacy-annotation/0.0.1-SNAPSHOT/maven-metadata-remote.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<metadata modelVersion=\"1.1.0\">\n  <groupId>com.yl.lib.privacy</groupId>\n  <artifactId>privacy-annotation</artifactId>\n  <version>0.0.1-SNAPSHOT</version>\n  <versioning>\n    <snapshot>\n      <timestamp>20211231.034702</timestamp>\n      <buildNumber>1</buildNumber>\n    </snapshot>\n    <lastUpdated>20211231034702</lastUpdated>\n    <snapshotVersions>\n      <snapshotVersion>\n        <extension>jar</extension>\n        <value>0.0.1-20211231.034702-1</value>\n        <updated>20211231034702</updated>\n      </snapshotVersion>\n      <snapshotVersion>\n        <extension>pom</extension>\n        <value>0.0.1-20211231.034702-1</value>\n        <updated>20211231034702</updated>\n      </snapshotVersion>\n    </snapshotVersions>\n  </versioning>\n</metadata>\n"
  },
  {
    "path": "privacy-annotation/~/.m2/repository/com/yl/lib/privacy/privacy-annotation/0.0.1-SNAPSHOT/resolver-status.properties",
    "content": "#NOTE: This is an internal implementation file, its format can be changed without prior notice.\n#Fri Dec 31 11:47:02 CST 2021\nmaven-metadata-remote.xml.lastUpdated=1640922422872\n"
  },
  {
    "path": "privacy-annotation/~/.m2/repository/com/yl/lib/privacy/privacy-annotation/0.0.2-SNAPSHOT/maven-metadata-remote.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<metadata modelVersion=\"1.1.0\">\n  <groupId>com.yl.lib.privacy</groupId>\n  <artifactId>privacy-annotation</artifactId>\n  <version>0.0.2-SNAPSHOT</version>\n  <versioning>\n    <snapshot>\n      <timestamp>20220104.074553</timestamp>\n      <buildNumber>1</buildNumber>\n    </snapshot>\n    <lastUpdated>20220104074553</lastUpdated>\n    <snapshotVersions>\n      <snapshotVersion>\n        <extension>jar</extension>\n        <value>0.0.2-20220104.074553-1</value>\n        <updated>20220104074553</updated>\n      </snapshotVersion>\n      <snapshotVersion>\n        <extension>pom</extension>\n        <value>0.0.2-20220104.074553-1</value>\n        <updated>20220104074553</updated>\n      </snapshotVersion>\n    </snapshotVersions>\n  </versioning>\n</metadata>\n"
  },
  {
    "path": "privacy-annotation/~/.m2/repository/com/yl/lib/privacy/privacy-annotation/0.0.2-SNAPSHOT/resolver-status.properties",
    "content": "#NOTE: This is an internal implementation file, its format can be changed without prior notice.\n#Tue Jan 04 15:45:53 CST 2022\nmaven-metadata-remote.xml.lastUpdated=1641282353090\n"
  },
  {
    "path": "privacy-annotation/~/.m2/repository/com/yl/lib/privacy/privacy-annotation/maven-metadata-remote.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<metadata>\n  <groupId>com.yl.lib.privacy</groupId>\n  <artifactId>privacy-annotation</artifactId>\n  <versioning>\n    <versions>\n      <version>0.0.1-SNAPSHOT</version>\n      <version>0.0.2-SNAPSHOT</version>\n    </versions>\n    <lastUpdated>20220104074553</lastUpdated>\n  </versioning>\n</metadata>\n"
  },
  {
    "path": "privacy-annotation/~/.m2/repository/com/yl/lib/privacy/privacy-annotation/maven-metadata-remote.xml.sha1",
    "content": "b11b5206278051fa303dd8d74cb4cf7dff7bbf6e"
  },
  {
    "path": "privacy-annotation/~/.m2/repository/com/yl/lib/privacy/privacy-annotation/resolver-status.properties",
    "content": "#NOTE: This is an internal implementation file, its format can be changed without prior notice.\n#Tue Jan 04 15:45:53 CST 2022\nmaven-metadata-remote.xml.lastUpdated=1641282353098\n"
  },
  {
    "path": "privacy-proxy/.gitignore",
    "content": "/build"
  },
  {
    "path": "privacy-proxy/README.md",
    "content": "# PrivacySentry\n    如果不想自建代理类，可以直接依赖这个库，同时也可以作为参考\n\n### 组件化项目建议把类拷贝出去自己维护; 插件化项目比较麻烦，还是封装一个aar比较好\n"
  },
  {
    "path": "privacy-proxy/build.gradle",
    "content": "apply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\napply from: '../publish.gradle'  // Changed from 'maven' to 'maven-publish'\nandroid {\n    compileSdkVersion 30\n    buildToolsVersion \"30.0.3\"\n    namespace \"com.yl.lib.privacy_proxy\"\n    defaultConfig {\n        minSdkVersion 19\n        targetSdkVersion 30\n        versionCode 1\n        versionName \"1.0\"\n\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n\n    buildTypes {\n        debug {\n            debuggable true\n        }\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    kotlinOptions {\n        jvmTarget = '1.8'\n    }\n}\n\ndependencies {\n\n    implementation 'androidx.core:core-ktx:1.3.2'\n    implementation 'com.google.android.material:material:1.4.0'\n    implementation project(\":hook-sentry\")\n    implementation project(path: ':privacy-annotation')\n}\n"
  },
  {
    "path": "privacy-proxy/gradle.properties",
    "content": "ARTIFACT_ID=privacy-proxy"
  },
  {
    "path": "privacy-proxy/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-permission android:name=\"android.permission.BLUETOOTH\" />\n    <uses-permission android:name=\"android.permission.READ_PRIVILEGED_PHONE_STATE\" />\n</manifest>"
  },
  {
    "path": "privacy-proxy/src/main/java/com/yl/lib/privacy_proxy/PrivacyPermissionProxy.kt",
    "content": "package com.yl.lib.privacy_proxy\n\nimport android.app.Activity\nimport android.os.Build\nimport androidx.annotation.Keep\nimport androidx.fragment.app.Fragment\nimport com.yl.lib.privacy_annotation.MethodInvokeOpcode\nimport com.yl.lib.privacy_annotation.PrivacyClassProxy\nimport com.yl.lib.privacy_annotation.PrivacyMethodProxy\nimport com.yl.lib.sentry.hook.util.PrivacyProxyUtil\nimport com.yl.lib.sentry.hook.util.ReflectUtils\n\n/**\n * @author yulun\n * @since 2022-11-09 17:41\n * 代理请求权限\n */\n@Keep\nclass PrivacyPermissionProxy {\n\n    @PrivacyClassProxy\n    @Keep\n    object Proxy {\n\n        // INVOKESPECIAL androidx/appcompat/app/AppCompatActivity.requestPermissions ([Ljava/lang/String;I)V\n        // 代理当前类调用super.requestPermissions\n        @JvmStatic\n        @PrivacyMethodProxy(\n            originalClass = Any::class,\n            originalMethod = \"requestPermissions\",\n            originalOpcode = MethodInvokeOpcode.INVOKESPECIAL,\n            ignoreClass = true\n        )\n        fun requestPermissionsSuper(obj: Any, permissions: Array<String?>, requestCode: Int) {\n            PrivacyProxyUtil.Util.doFilePrinter(\n                \"requestPermissions\",\n                methodDocumentDesc = \"${obj.javaClass.name}-INVOKESPECIAL-请求权限，权限列表：${permissions?.contentToString()}\"\n            )\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                ReflectUtils.Utils.invokeMethod<Unit>(\n                    obj, \"requestPermissions\", arrayOf(\n                        Array<String>::class.java, Integer.TYPE\n                    ), arrayOf<Any?>(permissions, requestCode)\n                )\n            }\n        }\n\n\n        // INVOKEVIRTUAL com/yl/lib/privacysentry/MainActivity.requestPermissions ([Ljava/lang/String;I)V\n        // 代理当前类调用requestPermissions\n        @JvmStatic\n        @PrivacyMethodProxy(\n            originalClass = Any::class,\n            originalMethod = \"requestPermissions\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL,\n            ignoreClass = true\n        )\n        fun requestPermissions(any: Any, permissions: Array<String?>, requestCode: Int) {\n            PrivacyProxyUtil.Util.doFilePrinter(\n                \"requestPermissions\",\n                methodDocumentDesc = \"${any.javaClass.name}-INVOKEVIRTUAL-请求权限，权限列表：${permissions?.contentToString()}\"\n            )\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                if (any is Activity) {\n                    // 这里可能会多次调用代理方法\n                    any.requestPermissions(permissions, requestCode)\n                } else if (any is Fragment) {\n                    // 这里可能会多次调用代理方法\n                    any.requestPermissions(permissions, requestCode)\n                } else {\n                    ReflectUtils.Utils.invokeMethod<Unit>(\n                        any, \"requestPermissions\", arrayOf(\n                            Array<String>::class.java, Integer.TYPE\n                        ), arrayOf<Any?>(permissions, requestCode)\n                    )\n                }\n            }\n        }\n\n    }\n}"
  },
  {
    "path": "privacy-proxy/src/main/java/com/yl/lib/privacy_proxy/PrivacyProxyCall.kt",
    "content": "package com.yl.lib.privacy_proxy\n\nimport android.annotation.SuppressLint\nimport android.app.ActivityManager\nimport android.bluetooth.BluetoothAdapter\nimport android.content.*\nimport android.content.ClipDescription.MIMETYPE_TEXT_PLAIN\nimport android.content.pm.*\nimport android.location.Location\nimport android.location.LocationListener\nimport android.location.LocationManager\nimport android.net.DhcpInfo\nimport android.net.wifi.ScanResult\nimport android.net.wifi.WifiConfiguration\nimport android.net.wifi.WifiInfo\nimport android.net.wifi.WifiManager\nimport android.os.Build\nimport android.os.Environment\nimport android.provider.Settings\nimport android.telephony.CellInfo\nimport android.telephony.TelephonyManager\nimport androidx.annotation.Keep\nimport androidx.annotation.RequiresApi\nimport com.yl.lib.privacy_annotation.MethodInvokeOpcode\nimport com.yl.lib.privacy_annotation.PrivacyClassProxy\nimport com.yl.lib.privacy_annotation.PrivacyMethodProxy\nimport com.yl.lib.sentry.hook.PrivacySentry\nimport com.yl.lib.sentry.hook.cache.CachePrivacyManager\nimport com.yl.lib.sentry.hook.cache.CacheUtils\nimport com.yl.lib.sentry.hook.util.PrivacyClipBoardManager\nimport com.yl.lib.sentry.hook.util.PrivacyLog\nimport com.yl.lib.sentry.hook.util.PrivacyProxyUtil.Util.doFilePrinter\nimport com.yl.lib.sentry.hook.util.PrivacyUtil\nimport java.io.File\nimport java.net.Inet4Address\nimport java.net.InetAddress\nimport java.net.NetworkInterface\n\n/**\n * @author yulun\n * @since 2021-12-22 14:23\n * 大部分敏感api拦截代理\n */\n@Keep\nopen class PrivacyProxyCall {\n\n    // kotlin里实际解析的是这个PrivacyProxyCall$Proxy 内部类\n    @PrivacyClassProxy\n    @Keep\n    object Proxy {\n        // 这个方法的注册放在了PrivacyProxyCall2中，提供了一个java注册的例子\n        @PrivacyMethodProxy(\n            originalClass = ActivityManager::class,\n            originalMethod = \"getRunningTasks\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getRunningTasks(\n            manager: ActivityManager,\n            maxNum: Int\n        ): List<ActivityManager.RunningTaskInfo?>? {\n            doFilePrinter(\"getRunningTasks\", methodDocumentDesc = \"当前运行中的任务\")\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                return emptyList()\n            }\n            return manager.getRunningTasks(maxNum)\n        }\n\n        @JvmStatic\n        @PrivacyMethodProxy(\n            originalClass = ActivityManager::class,\n            originalMethod = \"getRecentTasks\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        fun getRecentTasks(\n            manager: ActivityManager,\n            maxNum: Int,\n            flags: Int\n        ): List<ActivityManager.RecentTaskInfo>? {\n            doFilePrinter(\"getRecentTasks\", methodDocumentDesc = \"最近运行中的任务\")\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                return emptyList()\n            }\n            return manager.getRecentTasks(maxNum, flags)\n        }\n\n\n        @PrivacyMethodProxy(\n            originalClass = ActivityManager::class,\n            originalMethod = \"getRunningAppProcesses\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getRunningAppProcesses(manager: ActivityManager): List<ActivityManager.RunningAppProcessInfo> {\n            doFilePrinter(\"getRunningAppProcesses\", methodDocumentDesc = \"当前运行中的进程\")\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                return emptyList()\n            }\n\n            var appProcess: List<ActivityManager.RunningAppProcessInfo> = emptyList()\n            try {\n                // 线上三星11和12的机子 有上报，量不大\n                appProcess = manager.runningAppProcesses\n            } catch (e: Throwable) {\n                e.printStackTrace()\n            }\n            return appProcess\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = PackageManager::class,\n            originalMethod = \"getInstalledPackages\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getInstalledPackages(manager: PackageManager, flags: Int): List<PackageInfo> {\n            doFilePrinter(\"getInstalledPackages\", methodDocumentDesc = \"安装包-getInstalledPackages\")\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                return emptyList()\n            }\n            return manager.getInstalledPackages(flags)\n        }\n\n        @RequiresApi(Build.VERSION_CODES.O)\n        @PrivacyMethodProxy(\n            originalClass = PackageManager::class,\n            originalMethod = \"getPackageInfo\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getPackageInfo(\n            manager: PackageManager, versionedPackage: VersionedPackage,\n            flags: Int\n        ): PackageInfo? {\n\n//            if (PrivacySentry.Privacy.inDangerousState()) {\n//                doFilePrinter(\n//                    \"getPackageInfo\",\n//                    methodDocumentDesc = \"安装包-getPackageInfo-${versionedPackage.packageName}\",\n//                    bVisitorModel = true\n//                )\n//                throw PackageManager.NameNotFoundException(\"getPackageInfo-${versionedPackage.packageName}\")\n//            }\n            doFilePrinter(\n                \"getPackageInfo\",\n                methodDocumentDesc = \"安装包-getPackageInfo-${versionedPackage.packageName}\"\n            )\n            return manager.getPackageInfo(versionedPackage, flags)\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = PackageManager::class,\n            originalMethod = \"getPackageInfo\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getPackageInfo(\n            manager: PackageManager,\n            packageName: String,\n            flags: Int\n        ): PackageInfo? {\n//            if (PrivacySentry.Privacy.inDangerousState()) {\n//                doFilePrinter(\n//                    \"getPackageInfo\",\n//                    methodDocumentDesc = \"安装包-getPackageInfo-${packageName}\",\n//                    bVisitorModel = true\n//                )\n//                throw PackageManager.NameNotFoundException(\"getPackageInfo-${packageName}\")\n//            }\n            doFilePrinter(\n                \"getPackageInfo\",\n                methodDocumentDesc = \"安装包-getPackageInfo-${packageName}\"\n            )\n            return manager.getPackageInfo(packageName, flags)\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = PackageManager::class,\n            originalMethod = \"getInstalledPackagesAsUser\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getInstalledPackagesAsUser(\n            manager: PackageManager,\n            flags: Int,\n            userId: Int\n        ): List<PackageInfo> {\n            doFilePrinter(\n                \"getInstalledPackagesAsUser\",\n                methodDocumentDesc = \"安装包-getInstalledPackagesAsUser\"\n            )\n//            if (PrivacySentry.Privacy.inDangerousState()) {\n//                return emptyList()\n//            }\n            return getInstalledPackages(manager, flags);\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = PackageManager::class,\n            originalMethod = \"getInstalledApplications\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getInstalledApplications(manager: PackageManager, flags: Int): List<ApplicationInfo> {\n            doFilePrinter(\n                \"getInstalledApplications\",\n                methodDocumentDesc = \"安装包-getInstalledApplications\"\n            )\n//            if (PrivacySentry.Privacy.inDangerousState()) {\n//                return emptyList()\n//            }\n            return manager.getInstalledApplications(flags)\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = PackageManager::class,\n            originalMethod = \"getInstalledApplicationsAsUser\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getInstalledApplicationsAsUser(\n            manager: PackageManager, flags: Int,\n            userId: Int\n        ): List<ApplicationInfo> {\n            doFilePrinter(\n                \"getInstalledApplicationsAsUser\",\n                methodDocumentDesc = \"安装包-getInstalledApplicationsAsUser\"\n            )\n//            if (PrivacySentry.Privacy.inDangerousState()) {\n//                return emptyList()\n//            }\n            return getInstalledApplications(manager, flags);\n        }\n\n\n        // 这个方法比较特殊，是否合规完全取决于intent参数\n        // 如果指定了自己的包名，那可以认为是合规的，因为是查自己APP的AC\n        // 如果没有指定包名，那就是查询了其他APP的Ac，这不合规\n        // 思考，直接在SDK里拦截肯定不合适，对于业务方来说太黑盒了，如果触发bug开发会崩溃的，所以我们只打日志为业务方提供信息\n        @PrivacyMethodProxy(\n            originalClass = PackageManager::class,\n            originalMethod = \"queryIntentActivities\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun queryIntentActivities(\n            manager: PackageManager,\n            intent: Intent,\n            flags: Int\n        ): List<ResolveInfo> {\n            var paramBuilder = StringBuilder()\n            var legal = true\n            intent?.also {\n                intent?.categories?.also {\n                    paramBuilder.append(\"-categories:\").append(it.toString()).append(\"\\n\")\n                }\n                intent?.`package`?.also {\n                    paramBuilder.append(\"-packageName:\").append(it).append(\"\\n\")\n                }\n                intent?.data?.also {\n                    paramBuilder.append(\"-data:\").append(it.toString()).append(\"\\n\")\n                }\n                intent?.component?.packageName?.also {\n                    paramBuilder.append(\"-packageName:\").append(it).append(\"\\n\")\n                }\n            }\n\n            if (paramBuilder.isEmpty()) {\n                legal = false\n            }\n\n            //不指定包名，我们认为这个查询不合法\n            if (!paramBuilder.contains(\"packageName\")) {\n                legal = false\n            }\n            paramBuilder.append(\"-合法查询:${legal}\").append(\"\\n\")\n            doFilePrinter(\n                \"queryIntentActivities\",\n                methodDocumentDesc = \"读安装列表-queryIntentActivities${paramBuilder?.toString()}\"\n            )\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                return emptyList()\n            }\n            return manager.queryIntentActivities(intent, flags)\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = PackageManager::class,\n            originalMethod = \"queryIntentActivityOptions\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun queryIntentActivityOptions(\n            manager: PackageManager,\n            caller: ComponentName?,\n            specifics: Array<Intent?>?,\n            intent: Intent,\n            flags: Int\n        ): List<ResolveInfo> {\n            doFilePrinter(\n                \"queryIntentActivityOptions\",\n                methodDocumentDesc = \"读安装列表-queryIntentActivityOptions\"\n            )\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                return emptyList()\n            }\n            return manager.queryIntentActivityOptions(caller, specifics, intent, flags)\n        }\n\n\n        /**\n         * 基站信息，需要开启定位\n         */\n        @JvmStatic\n        @SuppressLint(\"MissingPermission\")\n        @PrivacyMethodProxy(\n            originalClass = TelephonyManager::class,\n            originalMethod = \"getAllCellInfo\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        fun getAllCellInfo(manager: TelephonyManager): List<CellInfo>? {\n            doFilePrinter(\"getAllCellInfo\", methodDocumentDesc = \"定位-基站信息\")\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                return emptyList()\n            }\n            return manager.getAllCellInfo()\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = ClipboardManager::class,\n            originalMethod = \"getPrimaryClip\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getPrimaryClip(manager: ClipboardManager): ClipData? {\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                return ClipData.newPlainText(\"Label\", \"\")\n            }\n            if (!PrivacyClipBoardManager.isReadClipboardEnable()) {\n                doFilePrinter(\"getPrimaryClip\", \"读取系统剪贴板关闭\")\n                return ClipData.newPlainText(\"Label\", \"\")\n            }\n\n            doFilePrinter(\"getPrimaryClip\", \"剪贴板内容-getPrimaryClip\")\n            return manager.primaryClip\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = ClipboardManager::class,\n            originalMethod = \"getPrimaryClipDescription\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getPrimaryClipDescription(manager: ClipboardManager): ClipDescription? {\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                return ClipDescription(\"\", arrayOf(MIMETYPE_TEXT_PLAIN))\n            }\n\n            if (!PrivacyClipBoardManager.isReadClipboardEnable()) {\n                doFilePrinter(\"getPrimaryClipDescription\", \"读取系统剪贴板关闭\")\n                return ClipDescription(\"\", arrayOf(MIMETYPE_TEXT_PLAIN))\n            }\n\n            doFilePrinter(\"getPrimaryClipDescription\", \"剪贴板内容-getPrimaryClipDescription\")\n            return manager.primaryClipDescription\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = ClipboardManager::class,\n            originalMethod = \"getText\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getText(manager: ClipboardManager): CharSequence? {\n\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                return \"\"\n            }\n\n            if (!PrivacyClipBoardManager.isReadClipboardEnable()) {\n                doFilePrinter(\"getText\", \"读取系统剪贴板关闭\")\n                return \"\"\n            }\n            doFilePrinter(\"getText\", \"剪贴板内容-getText\")\n            return manager.text\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = ClipboardManager::class,\n            originalMethod = \"setPrimaryClip\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun setPrimaryClip(manager: ClipboardManager, clip: ClipData?) {\n            doFilePrinter(\"setPrimaryClip\", \"设置剪贴板内容-setPrimaryClip\")\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                return\n            }\n            clip?.let { manager.setPrimaryClip(it) }\n\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = ClipboardManager::class,\n            originalMethod = \"setText\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun setText(manager: ClipboardManager, clip: CharSequence?) {\n            doFilePrinter(\"setText\", \"设置剪贴板内容-setText\")\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                return\n            }\n            manager.text = clip\n        }\n\n        /**\n         * WIFI的SSID\n         */\n        @JvmStatic\n        @PrivacyMethodProxy(\n            originalClass = WifiInfo::class,\n            originalMethod = \"getSSID\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        fun getSSID(manager: WifiInfo): String? {\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                doFilePrinter(\"getSSID\", \"SSID\")\n                return \"\"\n            }\n\n            var key = \"getSSID\"\n            doFilePrinter(\"getSSID\", \"SSID\")\n//            return CachePrivacyManager.Manager.loadWithTimeMemoryCache(\n//                key,\n//                \"getSSID\",\n//                \"\",\n//                duration = CacheUtils.Utils.MINUTE * 5\n//                ) { manager.ssid }\n            return manager.ssid\n        }\n\n        /**\n         * WIFI的SSID\n         */\n        @JvmStatic\n        @PrivacyMethodProxy(\n            originalClass = WifiInfo::class,\n            originalMethod = \"getBSSID\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        fun getBSSID(manager: WifiInfo): String? {\n\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                doFilePrinter(\"getBSSID\", \"getBSSID\")\n                return \"\"\n            }\n\n            var key = \"getBSSID\"\n            doFilePrinter(\"getBSSID\", \"getBSSID\")\n//            return CachePrivacyManager.Manager.loadWithTimeMemoryCache(\n//                key,\n//                \"getBSSID\",\n//                \"\",\n//                duration = CacheUtils.Utils.MINUTE * 5\n//            ) { manager.ssid }\n            return manager.bssid\n        }\n\n        /**\n         * WIFI扫描结果\n         */\n        @JvmStatic\n        @PrivacyMethodProxy(\n            originalClass = WifiManager::class,\n            originalMethod = \"getScanResults\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        fun getScanResults(manager: WifiManager): List<ScanResult>? {\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                doFilePrinter(\"getScanResults\", \"WIFI扫描结果\")\n                return emptyList()\n            }\n            doFilePrinter(\"getScanResults\", \"WIFI扫描结果\")\n            var key = \"getScanResults\"\n            return CachePrivacyManager.Manager.loadWithTimeMemoryCache(\n                key,\n                \"getScanResults\",\n                emptyList(),\n                duration = CacheUtils.Utils.MINUTE * 5\n            ) { manager.scanResults }\n        }\n\n        /**\n         * DHCP信息\n         */\n        @JvmStatic\n        @PrivacyMethodProxy(\n            originalClass = WifiManager::class,\n            originalMethod = \"getDhcpInfo\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        fun getDhcpInfo(manager: WifiManager): DhcpInfo? {\n            doFilePrinter(\"getDhcpInfo\", \"DHCP地址\")\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                return null\n            }\n            return manager.getDhcpInfo()\n        }\n\n        /**\n         * DHCP信息\n         */\n        @SuppressLint(\"MissingPermission\")\n        @JvmStatic\n        @PrivacyMethodProxy(\n            originalClass = WifiManager::class,\n            originalMethod = \"getConfiguredNetworks\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        fun getConfiguredNetworks(manager: WifiManager): List<WifiConfiguration>? {\n            doFilePrinter(\"getConfiguredNetworks\", \"前台用户配置的所有网络的列表\")\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                return emptyList()\n            }\n            return manager.getConfiguredNetworks()\n        }\n\n\n        /**\n         * 位置信息\n         */\n        @JvmStatic\n        @SuppressLint(\"MissingPermission\")\n        @PrivacyMethodProxy(\n            originalClass = LocationManager::class,\n            originalMethod = \"getLastKnownLocation\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        fun getLastKnownLocation(\n            manager: LocationManager, provider: String\n        ): Location? {\n            var key = \"getLastKnownLocation_${provider}\"\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                doFilePrinter(\"getLastKnownLocation\", \"上一次的位置信息\")\n                // 这里直接写空可能有风险\n                return null\n            }\n\n            var locationStr = CachePrivacyManager.Manager.loadWithTimeDiskCache(\n                key,\n                \"上一次的位置信息\",\n                \"\"\n            ) { PrivacyUtil.Util.formatLocation(manager.getLastKnownLocation(provider)) }\n\n            var location: Location? = null\n            locationStr.also {\n                location = PrivacyUtil.Util.formatLocation(it)\n            }\n            if (location == null) {\n                return manager.getLastKnownLocation(provider)\n            }\n            return location\n        }\n\n\n        @SuppressLint(\"MissingPermission\")\n        @JvmStatic\n        @PrivacyMethodProxy(\n            originalClass = LocationManager::class,\n            originalMethod = \"requestLocationUpdates\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        fun requestLocationUpdates(\n            manager: LocationManager, provider: String, minTime: Long, minDistance: Float,\n            listener: LocationListener\n        ) {\n            doFilePrinter(\"requestLocationUpdates\", \"监视精细行动轨迹\")\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                return\n            }\n            manager.requestLocationUpdates(provider, minTime, minDistance, listener)\n        }\n\n\n        var objectMacLock = Object()\n        var objectHardMacLock = Object()\n        var objectSNLock = Object()\n        var objectAndroidIdLock = Object()\n        var objectExternalStorageDirectoryLock = Object()\n\n\n        @PrivacyMethodProxy(\n            originalClass = WifiInfo::class,\n            originalMethod = \"getMacAddress\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getMacAddress(manager: WifiInfo): String? {\n            var key = \"WifiInfo-getMacAddress\"\n\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                doFilePrinter(\n                    key,\n                    \"mac地址-getMacAddress\"\n                )\n                return \"\"\n            }\n            doFilePrinter(\n                key,\n                \"mac地址-getMacAddress\"\n            )\n            synchronized(objectMacLock) {\n                return CachePrivacyManager.Manager.loadWithDiskCache(\n                    key,\n                    \"mac地址-getMacAddress\",\n                    \"\"\n                ) { manager.getMacAddress() }\n            }\n        }\n\n\n        @PrivacyMethodProxy(\n            originalClass = NetworkInterface::class,\n            originalMethod = \"getHardwareAddress\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getHardwareAddress(manager: NetworkInterface): ByteArray? {\n            var key = \"NetworkInterface-getHardwareAddress\"\n\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                doFilePrinter(\n                    key,\n                    \"mac地址-getHardwareAddress\"\n                )\n                return ByteArray(1)\n            }\n            doFilePrinter(\n                key,\n                \"mac地址-getHardwareAddress\"\n            )\n            synchronized(objectHardMacLock) {\n                return CachePrivacyManager.Manager.loadWithDiskCache(\n                    key,\n                    \"mac地址-getHardwareAddress\",\n                    \"\"\n                ) { manager.hardwareAddress.toString() }.toByteArray()\n            }\n        }\n\n        var objectBluetoothLock = Object()\n\n        @PrivacyMethodProxy(\n            originalClass = BluetoothAdapter::class,\n            originalMethod = \"getAddress\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getAddress(manager: BluetoothAdapter): String? {\n            var key = \"BluetoothAdapter-getAddress\"\n\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                doFilePrinter(key, \"蓝牙地址-getAddress\")\n                return \"\"\n            }\n            doFilePrinter(key, \"蓝牙地址-getAddress\")\n            synchronized(objectBluetoothLock) {\n                return CachePrivacyManager.Manager.loadWithMemoryCache(\n                    key,\n                    \"蓝牙地址-getAddress\",\n                    \"\"\n                ) { manager.address }\n            }\n        }\n\n\n        @PrivacyMethodProxy(\n            originalClass = Inet4Address::class,\n            originalMethod = \"getAddress\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getAddress(manager: Inet4Address): ByteArray? {\n            var key = \"ip地址-getAddress\"\n\n//            if (PrivacySentry.Privacy.inDangerousState()) {\n//                doFilePrinter(key, \"ip地址-getAddress\")\n//                return ByteArray(1)\n//            }\n            var address = manager.address\n            doFilePrinter(\n                key,\n                \"ip地址-getAddress-${manager.address ?: \"\"} , address is ${address ?: \"\"}\"\n            )\n            return address\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = InetAddress::class,\n            originalMethod = \"getAddress\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getAddress(manager: InetAddress): ByteArray? {\n            var key = \"ip地址-getAddress\"\n\n//            if (PrivacySentry.Privacy.inDangerousState()) {\n//                doFilePrinter(key, \"ip地址-getAddress\")\n//                return ByteArray(1)\n//            }\n            var address = manager.address\n            doFilePrinter(\n                key,\n                \"ip地址-getAddress-${manager.address ?: \"\"} , address is ${address ?: \"\"} \"\n            )\n            return address\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = Inet4Address::class,\n            originalMethod = \"getHostAddress\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getHostAddress(manager: Inet4Address): String? {\n            var key = \"ip地址-getHostAddress\"\n\n//            if (PrivacySentry.Privacy.inDangerousState()) {\n//                doFilePrinter(key, \"ip地址-getHostAddress\")\n//                return \"\"\n//            }\n\n            var address = manager.hostAddress\n            doFilePrinter(\n                key,\n                \"ip地址-getHostAddress-${manager.hostAddress ?: \"\"} , address is ${address ?: \"\"}\"\n            )\n            return address\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = InetAddress::class,\n            originalMethod = \"getHostAddress\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getHostAddress(manager: InetAddress): String? {\n            var key = \"ip地址-getHostAddress\"\n\n//            if (PrivacySentry.Privacy.inDangerousState()) {\n//                doFilePrinter(key, \"ip地址-getHostAddress\")\n//                return \"\"\n//            }\n\n            var address = manager.hostAddress\n            doFilePrinter(\n                key,\n                \"ip地址-getHostAddress-${manager.hostAddress ?: \"\"} , address is ${address ?: \"\"}\"\n            )\n            return address\n        }\n\n        // 拦截获取敏感字段 Android_id\n        @PrivacyMethodProxy(\n            originalClass = Settings.Secure::class,\n            originalMethod = \"getString\",\n            originalOpcode = MethodInvokeOpcode.INVOKESTATIC\n        )\n        @JvmStatic\n        fun getString(contentResolver: ContentResolver?, type: String?): String? {\n            var key = \"Secure-getString-$type\"\n            if (!\"android_id\".equals(type)) {\n                return Settings.Secure.getString(\n                    contentResolver,\n                    type\n                )\n            }\n\n            // 在用户同意协议之前，拦截获取Android_id\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                doFilePrinter(\n                    \"getString\",\n                    \"系统信息\",\n                    args = type\n                )\n                return \"\"\n            }\n            doFilePrinter(\n                \"getString\",\n                \"系统信息_android_id\",\n                args = type\n            )\n            // 控制读取频率，增加多线程磁盘缓存，保证APP只读取一次Android_id，防止三方SDK或者多次启动频繁读取Android_id\n            synchronized(objectAndroidIdLock) {\n                return CachePrivacyManager.Manager.loadWithDiskCache(\n                    key,\n                    \"getString-系统信息\",\n                    \"\"\n                ) {\n                    Settings.Secure.getString(\n                        contentResolver,\n                        type\n                    )\n                }\n            }\n        }\n\n\n        @PrivacyMethodProxy(\n            originalClass = Settings.System::class,\n            originalMethod = \"getString\",\n            originalOpcode = MethodInvokeOpcode.INVOKESTATIC\n        )\n        @JvmStatic\n        fun getStringSystem(contentResolver: ContentResolver?, type: String?): String? {\n            return getString(contentResolver, type)\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = android.os.Build::class,\n            originalMethod = \"getSerial\",\n            originalOpcode = MethodInvokeOpcode.INVOKESTATIC\n        )\n        @JvmStatic\n        fun getSerial(): String? {\n            var result = \"\"\n            var key = \"getSerial\"\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                doFilePrinter(\"getSerial\", \"Serial\")\n                return \"\"\n            }\n            doFilePrinter(\"getSerial\", \"Serial\")\n            synchronized(objectSNLock) {\n                return CachePrivacyManager.Manager.loadWithDiskCache(\n                    key,\n                    \"getSerial\",\n                    \"\"\n                ) {\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                        Build.getSerial()\n                    } else {\n                        Build.SERIAL\n                    }\n                }\n            }\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = android.os.Environment::class,\n            originalMethod = \"getExternalStorageDirectory\",\n            originalOpcode = MethodInvokeOpcode.INVOKESTATIC\n        )\n        @JvmStatic\n        fun getExternalStorageDirectory(): File? {\n            var result: File? = null\n            var key = \"externalStorageDirectory\"\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                doFilePrinter(\"getExternalStorageDirectory\", key)\n            }\n            doFilePrinter(\"getExternalStorageDirectory\", key)\n            synchronized(objectExternalStorageDirectoryLock) {\n                result = CachePrivacyManager.Manager.loadWithMemoryCache<File>(\n                    key,\n                    \"getExternalStorageDirectory\",\n                    File(\"\")\n                ) {\n                    Environment.getExternalStorageDirectory()\n                }\n            }\n            return result\n        }\n\n        // 拦截获取系统设备，简直离谱，这个也不能重复获取\n        @JvmStatic\n        fun getBrand(): String? {\n            PrivacyLog.i(\"getBrand\")\n            var key = \"getBrand\"\n            return CachePrivacyManager.Manager.loadWithMemoryCache(\n                key,\n                \"getBrand\",\n                \"\"\n            ) {\n                PrivacyLog.i(\"getBrand Value\")\n                Build.BRAND\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "privacy-proxy/src/main/java/com/yl/lib/privacy_proxy/PrivacyProxyCallJava.java",
    "content": "package com.yl.lib.privacy_proxy;\n\nimport android.content.ClipboardManager;\nimport android.net.wifi.WifiInfo;\nimport android.net.wifi.WifiManager;\n\nimport androidx.annotation.Keep;\n\nimport com.yl.lib.privacy_annotation.MethodInvokeOpcode;\nimport com.yl.lib.privacy_annotation.PrivacyClassBlack;\nimport com.yl.lib.privacy_annotation.PrivacyClassProxy;\nimport com.yl.lib.privacy_annotation.PrivacyMethodProxy;\nimport com.yl.lib.sentry.hook.PrivacySentry;\nimport com.yl.lib.sentry.hook.cache.CachePrivacyManager;\nimport com.yl.lib.sentry.hook.cache.CacheUtils;\nimport com.yl.lib.sentry.hook.util.PrivacyClipBoardManager;\nimport com.yl.lib.sentry.hook.util.PrivacyProxyUtil;\n\nimport java.util.Objects;\n\nimport kotlin.jvm.functions.Function0;\nimport kotlin.jvm.internal.Lambda;\n\n/**\n * @author yulun\n * @since 2022-11-30 17:47\n * kotlin Boolean 和 java boolean需要特殊处理，不然方法代理不了，在这里直接用java更方便\n */\n@PrivacyClassProxy\n@Keep\npublic class PrivacyProxyCallJava {\n    @PrivacyMethodProxy(\n            originalClass = ClipboardManager.class,\n            originalMethod = \"hasPrimaryClip\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n    )\n    public static boolean hasPrimaryClip(ClipboardManager manager) {\n        if (PrivacySentry.Privacy.INSTANCE.inDangerousState()) {\n            return false;\n        }\n        if (!PrivacyClipBoardManager.Companion.isReadClipboardEnable()) {\n            PrivacyProxyUtil.Util.INSTANCE.doFilePrinter(\"hasPrimaryClip\", \"读取系统剪贴板是否有值-拦截\", \"\", false);\n            return false;\n        }\n        PrivacyProxyUtil.Util.INSTANCE.doFilePrinter(\"hasPrimaryClip\", \"读取系统剪贴板是否有值-hasPrimaryClip\", \"\", false);\n        return manager.hasPrimaryClip();\n    }\n\n    /**\n     * WIFI是否开启\n     */\n    @PrivacyMethodProxy(\n            originalClass = WifiManager.class,\n            originalMethod = \"isWifiEnabled\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n    )\n    public static boolean isWifiEnabled(WifiManager manager) {\n        String key = \"isWifiEnabled\";\n        return  manager.isWifiEnabled();\n//        return CachePrivacyManager.Manager.INSTANCE.loadWithTimeMemoryCache(\n//                key,\n//                \"isWifiEnabled\",\n//                true,\n//                CacheUtils.Utils.MINUTE * 5,\n//                (new PrivacyProxyCallJavaWifiEnabled(manager)));\n    }\n\n    @PrivacyMethodProxy(\n            originalClass = WifiInfo.class,\n            originalMethod = \"getIpAddress\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n    )\n    public static int getIpAddress(WifiInfo wifiInfo) {\n        PrivacyProxyUtil.Util.INSTANCE.doFilePrinter(\"getIpAddress\", \"读取WifiInfo-getIpAddress\", \"\", false);\n        return wifiInfo.getIpAddress();\n    }\n\n    @PrivacyClassBlack\n    public static class PrivacyProxyCallJavaWifiEnabled extends Lambda<Boolean> implements Function0<Boolean> {\n        final /* synthetic */ WifiManager $manager;\n\n        PrivacyProxyCallJavaWifiEnabled(WifiManager wifiManager) {\n            super(0);\n            this.$manager = wifiManager;\n        }\n\n        public Boolean invoke() {\n            return this.$manager.isWifiEnabled();\n        }\n    }\n\n//    @PrivacyClassBlack\n//    public static class PrivacyProxyCallJavaBooleanTransform extends Lambda<Boolean> implements Function0<Boolean> {\n//        final /* synthetic */ String value;\n//\n//        PrivacyProxyCallJavaBooleanTransform(String value) {\n//            super(0);\n//            this.value = value;\n//        }\n//\n//        public Boolean invoke() {\n//            return Boolean.parseBoolean(value);\n//        }\n//    }\n}\n\n\n"
  },
  {
    "path": "privacy-proxy/src/main/java/com/yl/lib/privacy_proxy/PrivacyProxyResolver.kt",
    "content": "package com.yl.lib.privacy_proxy\n\nimport android.annotation.SuppressLint\nimport android.content.ContentResolver\nimport android.content.ContentValues\nimport android.database.Cursor\nimport android.net.Uri\nimport android.os.Build\nimport android.os.Bundle\nimport android.os.CancellationSignal\nimport androidx.annotation.Keep\nimport androidx.annotation.RequiresApi\nimport com.yl.lib.privacy_annotation.MethodInvokeOpcode\nimport com.yl.lib.privacy_annotation.PrivacyClassProxy\nimport com.yl.lib.privacy_annotation.PrivacyMethodProxy\nimport com.yl.lib.sentry.hook.util.PrivacyProxyUtil.Util.doFilePrinter\nimport com.yl.lib.sentry.hook.PrivacySentry\n\n/**\n * @author yulun\n * @since 2022-01-13 17:57\n * 代理ContentResolver 查增删改 ,主要是针对联系人，通讯录，日历等等\n */\n@Keep\nopen class PrivacyProxyResolver {\n    // kotlin里实际解析的是这个PrivacyProxyCall$Proxy 内部类\n    @PrivacyClassProxy\n    @Keep\n    object Proxy {\n\n        // 查询\n        @SuppressLint(\"MissingPermission\")\n        @PrivacyMethodProxy(\n            originalClass = ContentResolver::class,\n            originalMethod = \"query\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun query(\n            contentResolver: ContentResolver?,\n            uri: Uri,\n            projection: Array<String?>?, selection: String?,\n            selectionArgs: Array<String?>?, sortOrder: String?\n        ): Cursor? {\n            doFilePrinter(\"query\", \"查询服务: ${uriToLog(uri)}\")\n//            if (PrivacySentry.Privacy.inDangerousState()) {\n//                return null\n//            }\n            return contentResolver?.query(uri, projection, selection, selectionArgs, sortOrder)\n        }\n\n        @SuppressLint(\"MissingPermission\")\n        @PrivacyMethodProxy(\n            originalClass = ContentResolver::class,\n            originalMethod = \"query\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun query(\n            contentResolver: ContentResolver?,\n            uri: Uri,\n            projection: Array<String?>?, selection: String?,\n            selectionArgs: Array<String?>?, sortOrder: String?,\n            cancellationSignal: CancellationSignal?\n        ): Cursor? {\n            doFilePrinter(\"query\", \"查询服务: ${uriToLog(uri)}\")\n//            if (PrivacySentry.Privacy.inDangerousState()) {\n//                return null\n//            }\n            return contentResolver?.query(\n                uri,\n                projection,\n                selection,\n                selectionArgs,\n                sortOrder,\n                cancellationSignal\n            )\n        }\n\n        @RequiresApi(Build.VERSION_CODES.O)\n        @SuppressLint(\"MissingPermission\")\n        @PrivacyMethodProxy(\n            originalClass = ContentResolver::class,\n            originalMethod = \"query\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun query(\n            contentResolver: ContentResolver?,\n            uri: Uri,\n            projection: Array<String?>?, queryArgs: Bundle?,\n            cancellationSignal: CancellationSignal?\n        ): Cursor? {\n            doFilePrinter(\"query\", \"查询服务: ${uriToLog(uri)}\")\n//            if (PrivacySentry.Privacy.inDangerousState()) {\n//                return null\n//            }\n            return contentResolver?.query(uri, projection, queryArgs, cancellationSignal)\n        }\n\n        //增加\n        @SuppressLint(\"MissingPermission\")\n        @PrivacyMethodProxy(\n            originalClass = ContentResolver::class,\n            originalMethod = \"insert\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun insert(\n            contentResolver: ContentResolver?,\n            url: Uri,\n            values: ContentValues?\n        ): Uri? {\n            doFilePrinter(\"insert\", \"增加服务: ${uriToLog(url)}\")\n//            if (PrivacySentry.Privacy.inDangerousState()) {\n//                return null\n//            }\n            return contentResolver?.insert(url, values)\n        }\n\n        @RequiresApi(Build.VERSION_CODES.R)\n        @SuppressLint(\"MissingPermission\")\n        @PrivacyMethodProxy(\n            originalClass = ContentResolver::class,\n            originalMethod = \"insert\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun insert(\n            contentResolver: ContentResolver?,\n            url: Uri,\n            values: ContentValues?, extras: Bundle?\n        ): Uri? {\n            doFilePrinter(\"insert\", \"增加服务: ${uriToLog(url)}\")\n//            if (PrivacySentry.Privacy.inDangerousState()) {\n//                return null\n//            }\n            return contentResolver?.insert(url, values, extras)\n        }\n\n        // update\n        @SuppressLint(\"MissingPermission\")\n        @PrivacyMethodProxy(\n            originalClass = ContentResolver::class,\n            originalMethod = \"update\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun update(\n            contentResolver: ContentResolver?, uri: Uri,\n            values: ContentValues?, where: String?,\n            selectionArgs: Array<String?>?\n        ): Int? {\n            doFilePrinter(\"update\", \"更新服务: ${uriToLog(uri)}\")\n//            if (PrivacySentry.Privacy.inDangerousState()) {\n//                return -1\n//            }\n            return contentResolver?.update(uri, values, where, selectionArgs)\n        }\n\n\n        @RequiresApi(Build.VERSION_CODES.R)\n        @SuppressLint(\"MissingPermission\")\n        @PrivacyMethodProxy(\n            originalClass = ContentResolver::class,\n            originalMethod = \"update\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun update(\n            contentResolver: ContentResolver?, uri: Uri,\n            values: ContentValues?, extras: Bundle?\n        ): Int? {\n            doFilePrinter(\"update\", \"更新服务: ${uriToLog(uri)}\")\n//            if (PrivacySentry.Privacy.inDangerousState()) {\n//                return -1\n//            }\n            return contentResolver?.update(uri, values, extras)\n        }\n\n        //删\n        @SuppressLint(\"MissingPermission\")\n        @PrivacyMethodProxy(\n            originalClass = ContentResolver::class,\n            originalMethod = \"delete\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun delete(\n            contentResolver: ContentResolver?, url: Uri, where: String?,\n            selectionArgs: Array<String?>?\n        ): Int? {\n            doFilePrinter(\"delete\", \"删除服务: ${uriToLog(url)}\")\n//            if (PrivacySentry.Privacy.inDangerousState()) {\n//                return -1\n//            }\n            return contentResolver?.delete(url, where, selectionArgs)\n        }\n\n\n        @RequiresApi(Build.VERSION_CODES.R)\n        @SuppressLint(\"MissingPermission\")\n        @PrivacyMethodProxy(\n            originalClass = ContentResolver::class,\n            originalMethod = \"delete\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun delete(\n            contentResolver: ContentResolver?, url: Uri, extras: Bundle?\n        ): Int? {\n            doFilePrinter(\"delete\", \"删除服务: ${uriToLog(url)}\")\n//            if (PrivacySentry.Privacy.inDangerousState()) {\n//                return -1\n//            }\n            return contentResolver?.delete(url, extras)\n        }\n\n        /**\n         * 对常见的ContentResolver相关的uri做一层转换，方便日志理解\n         * @param url Uri\n         * @return String\n         */\n        private fun uriToLog(url: Uri): String {\n            if (url == null) {\n                return \"\"\n            }\n\n            if (url.toString().contains(\"contact\")) {\n                return \"联系人\"\n            }\n\n            if (url.toString().contains(\"calendar\")) {\n                return \"日历\"\n            }\n\n            if (url.toString().contains(\"calls\")) {\n                return \"通话\"\n            }\n\n            if (url.toString().contains(\"sms\")) {\n                return \"短信\"\n            }\n\n            return url.toString()\n        }\n    }\n\n\n}"
  },
  {
    "path": "privacy-proxy/src/main/java/com/yl/lib/privacy_proxy/PrivacyReflectProxy.kt",
    "content": "package com.yl.lib.privacy_proxy\n\nimport android.bluetooth.BluetoothAdapter\nimport android.net.wifi.WifiInfo\nimport android.telephony.TelephonyManager\nimport androidx.annotation.Keep\nimport com.yl.lib.privacy_annotation.MethodInvokeOpcode\nimport com.yl.lib.privacy_annotation.PrivacyClassProxy\nimport com.yl.lib.privacy_annotation.PrivacyMethodProxy\nimport com.yl.lib.sentry.hook.cache.CachePrivacyManager\nimport com.yl.lib.sentry.hook.util.PrivacyProxyUtil\nimport java.lang.reflect.Method\nimport java.net.NetworkInterface\n\n/**\n * @author yulun\n * @since 2022-06-17 17:56\n * 代理反射\n */\n@Keep\nopen class PrivacyReflectProxy {\n\n    @Keep\n    @PrivacyClassProxy\n    object ReflectProxy {\n\n        // 这个方法的注册放在了PrivacyProxyCall2中，提供了一个java注册的例子\n        @PrivacyMethodProxy(\n            originalClass = Method::class,\n            originalMethod = \"invoke\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun invoke(\n            method: Method,\n            obj: Any?,\n            vararg args: Any?\n        ): Any? {\n            if (obj is WifiInfo) {\n                if (\"getMacAddress\" == method.name) {\n                    if (args.isEmpty()) return PrivacyProxyCall.Proxy.getMacAddress(obj)\n                }\n            }\n\n            if (obj is TelephonyManager) {\n                if (\"getMeid\" == method.name && args.isEmpty()) {\n                    return PrivacyTelephonyProxy.TelephonyProxy.getMeid(obj)\n                }\n                if (\"getMeid\" == method.name && args.size == 1 && args[0] is Int) {\n                    return PrivacyTelephonyProxy.TelephonyProxy.getMeid(\n                        obj,\n                        args[0] as Int\n                    )\n                }\n                if (\"getDeviceId\" == method.name && args.isEmpty()) {\n                    return PrivacyTelephonyProxy.TelephonyProxy.getDeviceId(obj)\n                }\n                if (\"getDeviceId\" == method.name && args.size == 1 && args[0] is Int) {\n                    return PrivacyTelephonyProxy.TelephonyProxy.getDeviceId(\n                        obj,\n                        args[0] as Int\n                    )\n                }\n                if (\"getSubscriberId\" == method.name && args.isEmpty()) {\n                    return PrivacyTelephonyProxy.TelephonyProxy.getSubscriberId(obj)\n                }\n                if (\"getSubscriberId\" == method.name && args.size == 1 && args.get(0) is Int) {\n                    return PrivacyTelephonyProxy.TelephonyProxy.getSubscriberId(\n                        obj,\n                        args[0] as Int\n                    )\n                }\n                if (\"getImei\" == method.name && args.isEmpty()) {\n                    return PrivacyTelephonyProxy.TelephonyProxy.getImei(obj)\n                }\n                if (\"getImei\" == method.name && args.size == 1 && args[0] is Int) {\n                    return PrivacyTelephonyProxy.TelephonyProxy.getImei(\n                        obj,\n                        args[0] as Int\n                    )\n                }\n                if (\"getSimSerialNumber\" == method.name && args.isEmpty()) {\n                    return PrivacyTelephonyProxy.TelephonyProxy.getSimSerialNumber(obj)\n                }\n                if (\"getSimSerialNumber\" == method.name && args.size == 1 && args[0] is Int) {\n                    return PrivacyTelephonyProxy.TelephonyProxy.getSimSerialNumber(\n                        obj,\n                        args[0] as Int\n                    )\n                }\n            }\n\n            if (obj is NetworkInterface) {\n                if (\"getHardwareAddress\" == method.name && args.isEmpty()) {\n                    return PrivacyProxyCall.Proxy.getHardwareAddress(obj)\n                }\n            }\n\n            if (obj is BluetoothAdapter) {\n                if (\"getAddress\" == method.name && args.isEmpty()) {\n                    return PrivacyProxyCall.Proxy.getAddress(obj)\n                }\n            }\n\n            // 针对OAID AAID VAID的方法，特殊处理，不做映射了\n            var methodName = method.name.toUpperCase()\n            if (methodName.contains(\"OAID\") || methodName.contains(\"AAID\") || methodName.contains(\"VAID\")){\n                val cacheKey = obj?.javaClass?.name +\"_\"+ method.name\n                PrivacyProxyUtil.Util.doFilePrinter(\"methodName\", cacheKey)\n                return CachePrivacyManager.Manager.loadWithMemoryCache(\n                    cacheKey,\n                    cacheKey,\n                    \"\"\n                ) { method.invoke(obj, *args) }\n            }\n\n            if (obj?.javaClass?.name?.equals(\"com.android.id.impl.IdProviderImpl\") == true){\n                return method.invoke(obj, *args)\n            }\n            return method.invoke(obj, *args)\n        }\n    }\n}"
  },
  {
    "path": "privacy-proxy/src/main/java/com/yl/lib/privacy_proxy/PrivacySensorProxy.kt",
    "content": "package com.yl.lib.privacy_proxy\n\nimport android.hardware.Sensor\nimport android.hardware.SensorEventListener\nimport android.hardware.SensorManager\nimport android.os.Handler\nimport androidx.annotation.Keep\nimport com.yl.lib.privacy_annotation.MethodInvokeOpcode\nimport com.yl.lib.privacy_annotation.PrivacyClassProxy\nimport com.yl.lib.privacy_annotation.PrivacyMethodProxy\nimport com.yl.lib.sentry.hook.PrivacySentry\nimport com.yl.lib.sentry.hook.cache.CachePrivacyManager\nimport com.yl.lib.sentry.hook.util.PrivacyProxyUtil\n\n/**\n * @author yulun\n * @since 2022-06-17 17:56\n */\n@Keep\nopen class PrivacySensorProxy {\n\n    @Keep\n    @PrivacyClassProxy\n    object SensorProxy {\n\n        // 这个方法的注册放在了PrivacyProxyCall2中，提供了一个java注册的例子\n        @PrivacyMethodProxy(\n            originalClass = SensorManager::class,\n            originalMethod = \"registerListener\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun registerListener(\n            sensorManager: SensorManager?,\n            listener: SensorEventListener?, sensor: Sensor?,\n            samplingPeriodUs: Int\n        ): Boolean {\n            logSensorManager(sensor)\n            return sensorManager?.registerListener(listener, sensor, samplingPeriodUs) == true\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = SensorManager::class,\n            originalMethod = \"registerListener\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun registerListener(\n            sensorManager: SensorManager?,\n            listener: SensorEventListener?, sensor: Sensor?,\n            samplingPeriodUs: Int, maxReportLatencyUs: Int\n        ): Boolean {\n            logSensorManager(sensor)\n            return sensorManager?.registerListener(\n                listener,\n                sensor,\n                samplingPeriodUs,\n                maxReportLatencyUs\n            ) == true\n        }\n\n\n        @PrivacyMethodProxy(\n            originalClass = SensorManager::class,\n            originalMethod = \"registerListener\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun registerListener(\n            sensorManager: SensorManager?,\n            listener: SensorEventListener?, sensor: Sensor?,\n            samplingPeriodUs: Int, handler: Handler?\n        ): Boolean {\n            logSensorManager(sensor)\n            return sensorManager?.registerListener(\n                listener,\n                sensor,\n                samplingPeriodUs,\n                handler\n            ) == true\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = SensorManager::class,\n            originalMethod = \"registerListener\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun registerListener(\n            sensorManager: SensorManager?,\n            listener: SensorEventListener?, sensor: Sensor?,\n            samplingPeriodUs: Int, maxReportLatencyUs: Int, handler: Handler?\n        ): Boolean {\n            logSensorManager(sensor)\n            return sensorManager?.registerListener(\n                listener,\n                sensor,\n                samplingPeriodUs,\n                maxReportLatencyUs,\n                handler\n            ) == true\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = SensorManager::class,\n            originalMethod = \"getSensorList\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getSensorList(sensorManager: SensorManager?, type: Int): List<Sensor>? {\n            var logPair = transformSensorTypeToString(type)\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                PrivacyProxyUtil.Util.doFilePrinter(\n                    \"getSensorList-$type\",\n                    \"获取${logPair.first}-${logPair.second}\"\n                )\n                return emptyList()\n            }\n            return CachePrivacyManager.Manager.loadWithMemoryCache<List<Sensor>>(\n                \"getSensorList-$type\",\n                \"获取${logPair.first}-${logPair.second}\",\n                emptyList()\n            ) {\n                sensorManager?.getSensorList(type) ?: emptyList()\n            }\n        }\n\n        @JvmStatic\n        private fun logSensorManager(sensor: Sensor?) {\n            sensor?.let {\n                var sensorType: String? = \"\"\n                var sensorDesc: String? = \"\"\n                var logPair = transformSensorTypeToString(sensor?.type ?: 0)\n                sensorType = logPair.first\n                sensorDesc = logPair.second\n                PrivacyProxyUtil.Util.doFilePrinter(\n                    \"registerListener\",\n                    methodDocumentDesc = \"注册-${sensorType}传感器,$sensorDesc\"\n                )\n            }\n        }\n\n        @JvmStatic\n        private fun transformSensorTypeToString(sensorType: Int): Pair<String, String> {\n            var sensorTypeStr: String? = \"\"\n            var sensorDesc: String? = \"\"\n            when (sensorType) {\n                // 加速度，摇一摇\n                Sensor.TYPE_ACCELEROMETER -> {\n                    sensorTypeStr = \"加速度\"\n                    sensorDesc = \"常用于摇一摇\"\n                }\n                // 磁场。。\n                Sensor.TYPE_MAGNETIC_FIELD -> {\n                    sensorTypeStr = \"磁场\"\n                }\n                // 方向, 弃用了\n                Sensor.TYPE_ORIENTATION -> {\n                    sensorTypeStr = \"方向\"\n                }\n                // 陀螺仪。 用来感应手机的旋转和倾斜\n                Sensor.TYPE_GYROSCOPE -> {\n                    sensorTypeStr = \"陀螺仪\"\n                    sensorDesc = \"用来感应手机正面的光线强弱\"\n                }\n                // 光线 用来感应手机正面的光线强弱\n                Sensor.TYPE_LIGHT -> {\n                    sensorTypeStr = \"光线 \"\n                    sensorDesc = \"用来感应手机正面的光线强弱\"\n                }\n                // 压力。\n                Sensor.TYPE_PRESSURE -> {\n                    sensorTypeStr = \"压力\"\n                }\n                // 距离。\n                Sensor.TYPE_PROXIMITY -> {\n                    sensorTypeStr = \"距离\"\n                }\n                // 重力\n                Sensor.TYPE_GRAVITY -> {\n                    sensorTypeStr = \"重力\"\n                }\n                // 线性加速度\n                Sensor.TYPE_LINEAR_ACCELERATION -> {\n                    sensorTypeStr = \"线性加速度\"\n                }\n                // 旋转矢量。\n                Sensor.TYPE_ROTATION_VECTOR -> {\n                    sensorTypeStr = \"旋转矢量\"\n                }\n                // 相对湿度\n                Sensor.TYPE_RELATIVE_HUMIDITY -> {\n                    sensorTypeStr = \"相对湿度\"\n                }\n                // 环境温度\n                Sensor.TYPE_AMBIENT_TEMPERATURE -> {\n                    sensorTypeStr = \"环境温度\"\n                }\n                // 无标定磁场\n                Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED -> {\n                    sensorTypeStr = \"无标定磁场\"\n                }\n                // 无标定旋转矢量\n                Sensor.TYPE_GAME_ROTATION_VECTOR -> {\n                    sensorTypeStr = \"无标定旋转矢量\"\n                }\n                // 未校准陀螺仪\n                Sensor.TYPE_GYROSCOPE_UNCALIBRATED -> {\n                    sensorTypeStr = \"未校准陀螺仪\"\n                }\n                // 特殊动作\n                Sensor.TYPE_SIGNIFICANT_MOTION -> {\n                    sensorTypeStr = \"特殊动作\"\n                }\n                // 步行检测\n                Sensor.TYPE_STEP_DETECTOR -> {\n                    sensorTypeStr = \"步行检测\"\n                }\n                // 步行计数\n                Sensor.TYPE_STEP_COUNTER -> {\n                    sensorTypeStr = \"步行计数\"\n                }\n                // 地磁旋转矢量\n                Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR -> {\n                    sensorTypeStr = \"地磁旋转矢量\"\n                }\n                // 心跳速率\n                Sensor.TYPE_HEART_RATE -> {\n                    sensorTypeStr = \"心跳速率\"\n                }\n            }\n            return Pair(sensorTypeStr!!, sensorDesc!!)\n        }\n    }\n}"
  },
  {
    "path": "privacy-proxy/src/main/java/com/yl/lib/privacy_proxy/PrivacyTelephonyProxy.kt",
    "content": "package com.yl.lib.privacy_proxy\n\nimport android.Manifest\nimport android.annotation.SuppressLint\nimport android.os.Build\nimport android.telephony.TelephonyManager\nimport android.telephony.TelephonyManager.SIM_STATE_UNKNOWN\nimport androidx.annotation.Keep\nimport com.yl.lib.privacy_annotation.MethodInvokeOpcode\nimport com.yl.lib.privacy_annotation.PrivacyClassProxy\nimport com.yl.lib.privacy_annotation.PrivacyMethodProxy\nimport com.yl.lib.sentry.hook.PrivacySentry\nimport com.yl.lib.sentry.hook.cache.CachePrivacyManager\nimport com.yl.lib.sentry.hook.cache.CacheUtils\nimport com.yl.lib.sentry.hook.util.PrivacyProxyUtil\n\n/**\n * @author yulun\n * @since 2022-06-17 17:56\n * 代理电话权限的部分敏感API\n */\n@Keep\nopen class PrivacyTelephonyProxy {\n\n    @Keep\n    @PrivacyClassProxy\n    object TelephonyProxy {\n\n        private var objectImeiLock = Object()\n        private var objectImsiLock = Object()\n        private var objectMeidLock = Object()\n        private var objectSimOperatorLock = Object()\n        private var objectNetworkOperatorLock = Object()\n\n\n        @PrivacyMethodProxy(\n            originalClass = TelephonyManager::class,\n            originalMethod = \"getMeid\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getMeid(manager: TelephonyManager): String? {\n            var key = \"meid\"\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                PrivacyProxyUtil.Util.doFilePrinter(key, \"移动设备标识符-getMeid()\")\n                return \"\"\n            }\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {\n                return \"\"\n            }\n\n            if (!PrivacyProxyUtil.Util.checkPermission(Manifest.permission.READ_PHONE_STATE)) {\n                PrivacyProxyUtil.Util.doFilePrinter(\n                    \"getMeid\",\n                    methodDocumentDesc = \"移动设备标识符-getMeid()-无权限\"\n                )\n                return \"\"\n            }\n\n            synchronized(objectMeidLock) {\n                return CachePrivacyManager.Manager.loadWithDiskCache(\n                    key,\n                    \"移动设备标识符-getMeid()\",\n                    \"\"\n                ) { manager.meid }\n            }\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = TelephonyManager::class,\n            originalMethod = \"getMeid\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getMeid(manager: TelephonyManager, index: Int): String? {\n            var key = \"meid\"\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                PrivacyProxyUtil.Util.doFilePrinter(key, \"移动设备标识符-getMeid()\")\n                return \"\"\n            }\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {\n                return \"\"\n            }\n            if (!PrivacyProxyUtil.Util.checkPermission(Manifest.permission.READ_PHONE_STATE)) {\n                PrivacyProxyUtil.Util.doFilePrinter(\n                    \"getMeid\",\n                    methodDocumentDesc = \"移动设备标识符-getMeid()-无权限\"\n                )\n                return \"\"\n            }\n            synchronized(objectMeidLock) {\n                return CachePrivacyManager.Manager.loadWithDiskCache(\n                    key,\n                    \"移动设备标识符-getMeid(I)\",\n                    \"\"\n                ) { manager.meid }\n            }\n        }\n\n        var objectDeviceIdLock = Object()\n\n\n        // 配置代理拦截获取设备ID\n        @PrivacyMethodProxy(\n            originalClass = TelephonyManager::class,\n            originalMethod = \"getDeviceId\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getDeviceId(manager: TelephonyManager): String? {\n            var key = \"TelephonyManager-getDeviceId\"\n            // 在用户同意协议之前，拦截获取\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                PrivacyProxyUtil.Util.doFilePrinter(key, \"IMEI-getDeviceId()\")\n                return \"\"\n            }\n\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {\n                return \"\"\n            }\n\n            // 如果没有获得电话权限，拦截获取\n            if (!PrivacyProxyUtil.Util.checkPermission(Manifest.permission.READ_PHONE_STATE)) {\n                PrivacyProxyUtil.Util.doFilePrinter(key, \"IMEI-getDeviceId()-无权限\")\n                return \"\"\n            }\n            synchronized(objectDeviceIdLock) {\n                return CachePrivacyManager.Manager.loadWithDiskCache(\n                    key,\n                    \"IMEI-getDeviceId()\",\n                    \"\"\n                ) { manager.getDeviceId() }\n            }\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = TelephonyManager::class,\n            originalMethod = \"getDeviceId\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getDeviceId(manager: TelephonyManager, index: Int): String? {\n            var key = \"TelephonyManager-getDeviceId-$index\"\n\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                PrivacyProxyUtil.Util.doFilePrinter(\n                    key,\n                    \"IMEI-getDeviceId(I)\"\n                )\n                return \"\"\n            }\n\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {\n                return \"\"\n            }\n\n            if (!PrivacyProxyUtil.Util.checkPermission(Manifest.permission.READ_PHONE_STATE)) {\n                PrivacyProxyUtil.Util.doFilePrinter(key, \"IMEI-getDeviceId()-无权限\")\n                return \"\"\n            }\n            synchronized(objectDeviceIdLock) {\n                return CachePrivacyManager.Manager.loadWithDiskCache(\n                    key,\n                    \"IMEI-getDeviceId(I)\",\n                    \"\"\n                ) { manager.getDeviceId(index) }\n            }\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = TelephonyManager::class,\n            originalMethod = \"getSubscriberId\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getSubscriberId(manager: TelephonyManager): String? {\n            var key = \"TelephonyManager-getSubscriberId\"\n\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                PrivacyProxyUtil.Util.doFilePrinter(\n                    key,\n                    \"IMSI-getSubscriberId(I)\"\n                )\n                return \"\"\n            }\n\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {\n                return \"\"\n            }\n\n            if (!PrivacyProxyUtil.Util.checkPermission(Manifest.permission.READ_PHONE_STATE)) {\n                PrivacyProxyUtil.Util.doFilePrinter(key, \"IMSI-getSubscriberId(I)-无权限\")\n                return \"\"\n            }\n\n            synchronized(objectImsiLock) {\n                return CachePrivacyManager.Manager.loadWithDiskCache(\n                    key,\n                    \"IMSI-getSubscriberId()\",\n                    \"\"\n                ) { manager.subscriberId }\n            }\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = TelephonyManager::class,\n            originalMethod = \"getSubscriberId\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getSubscriberId(manager: TelephonyManager, index: Int): String? {\n            return getSubscriberId(manager)\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = TelephonyManager::class,\n            originalMethod = \"getImei\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getImei(manager: TelephonyManager): String? {\n            var key = \"TelephonyManager-getImei\"\n\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                PrivacyProxyUtil.Util.doFilePrinter(key, \"IMEI-getImei()\")\n                return \"\"\n            }\n\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {\n                return \"\"\n            }\n\n            if (!PrivacyProxyUtil.Util.checkPermission(Manifest.permission.READ_PHONE_STATE)) {\n                PrivacyProxyUtil.Util.doFilePrinter(key, \"IMEI-getImei()-无权限\")\n                return \"\"\n            }\n\n            synchronized(objectImeiLock) {\n                return CachePrivacyManager.Manager.loadWithDiskCache(\n                    key,\n                    \"IMEI-getImei()\",\n                    \"\"\n                ) { manager.imei }\n            }\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = TelephonyManager::class,\n            originalMethod = \"getImei\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getImei(manager: TelephonyManager, index: Int): String? {\n            var key = \"TelephonyManager-getImei-$index\"\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                PrivacyProxyUtil.Util.doFilePrinter(key, \"设备id-getImei(I)\")\n                return \"\"\n            }\n\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {\n                return \"\"\n            }\n\n            if (!PrivacyProxyUtil.Util.checkPermission(Manifest.permission.READ_PHONE_STATE)) {\n                PrivacyProxyUtil.Util.doFilePrinter(key, \"设备id-getImei(I)-无权限\")\n                return \"\"\n            }\n\n            synchronized(objectImeiLock) {\n                return CachePrivacyManager.Manager.loadWithDiskCache(\n                    key,\n                    \"IMEI-getImei(I)\",\n                    \"\"\n                ) { manager.getImei(index) }\n            }\n        }\n\n        var objectSimLock = Object()\n\n        @PrivacyMethodProxy(\n            originalClass = TelephonyManager::class,\n            originalMethod = \"getSimSerialNumber\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getSimSerialNumber(manager: TelephonyManager): String? {\n            var key = \"TelephonyManager-getSimSerialNumber\"\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                PrivacyProxyUtil.Util.doFilePrinter(\n                    key,\n                    \"SIM卡-getSimSerialNumber()\"\n                )\n                return \"\"\n            }\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {\n                return \"\"\n            }\n\n            if (!PrivacyProxyUtil.Util.checkPermission(Manifest.permission.READ_PHONE_STATE)) {\n                PrivacyProxyUtil.Util.doFilePrinter(key, \"SIM卡-getSimSerialNumber()-无权限\")\n                return \"\"\n            }\n            synchronized(objectSimLock) {\n                return CachePrivacyManager.Manager.loadWithDiskCache(\n                    key,\n                    \"SIM卡-getSimSerialNumber()\",\n                    \"\"\n                ) { manager.getSimSerialNumber() }\n            }\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = TelephonyManager::class,\n            originalMethod = \"getSimSerialNumber\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getSimSerialNumber(manager: TelephonyManager, index: Int): String? {\n            return getSimSerialNumber(manager)\n        }\n\n        var objectPhoneNumberLock = Object()\n\n        @PrivacyMethodProxy(\n            originalClass = TelephonyManager::class,\n            originalMethod = \"getLine1Number\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @SuppressLint(\"MissingPermission\")\n        @JvmStatic\n        fun getLine1Number(manager: TelephonyManager): String? {\n\n            var key = \"TelephonyManager-getLine1Number\"\n\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                PrivacyProxyUtil.Util.doFilePrinter(key, \"手机号-getLine1Number\")\n                return \"\"\n            }\n            synchronized(objectPhoneNumberLock) {\n                return CachePrivacyManager.Manager.loadWithDiskCache(\n                    key,\n                    \"手机号-getLine1Number\",\n                    \"\"\n                ) { manager.line1Number }\n            }\n        }\n\n\n        @PrivacyMethodProxy(\n            originalClass = TelephonyManager::class,\n            originalMethod = \"getSimOperator\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getSimOperator(manager: TelephonyManager): String? {\n            var key = \"TelephonyManager-getSimOperator\"\n\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                PrivacyProxyUtil.Util.doFilePrinter(\n                    key,\n                    \"运营商信息-getSimOperator()\"\n                )\n                return \"\"\n            }\n\n            synchronized(objectSimOperatorLock) {\n                return CachePrivacyManager.Manager.loadWithMemoryCache(\n                    key,\n                    \"运营商信息-getSimOperator()\",\n                    \"\"\n                ) { manager.simOperator }\n            }\n        }\n\n\n        @PrivacyMethodProxy(\n            originalClass = TelephonyManager::class,\n            originalMethod = \"getNetworkOperator\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getNetworkOperator(manager: TelephonyManager): String? {\n            var key = \"TelephonyManager-getNetworkOperator\"\n\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                PrivacyProxyUtil.Util.doFilePrinter(\n                    key,\n                    \"运营商信息-getNetworkOperator()\"\n                )\n                return \"\"\n            }\n\n            synchronized(objectNetworkOperatorLock) {\n                return CachePrivacyManager.Manager.loadWithMemoryCache(\n                    key,\n                    \"运营商信息-getNetworkOperator()\",\n                    \"\"\n                ) { manager.networkOperator }\n            }\n        }\n\n        @PrivacyMethodProxy(\n            originalClass = TelephonyManager::class,\n            originalMethod = \"getSimState\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n        )\n        @JvmStatic\n        fun getSimState(manager: TelephonyManager): Int {\n            var key = \"TelephonyManager-getNetworkOperator\"\n\n            if (PrivacySentry.Privacy.inDangerousState()) {\n                PrivacyProxyUtil.Util.doFilePrinter(\n                    key,\n                    \"运营商信息-getNetworkOperator()\"\n                )\n                return SIM_STATE_UNKNOWN\n            }\n\n            synchronized(objectNetworkOperatorLock) {\n                return CachePrivacyManager.Manager.loadWithTimeMemoryCache(\n                    key,\n                    \"运营商信息-getNetworkOperator()\",\n                    SIM_STATE_UNKNOWN,\n                    duration = CacheUtils.Utils.MINUTE * 5\n                ) { manager.simState }\n            }\n        }\n    }\n}"
  },
  {
    "path": "privacy-proxy/src/main/java/com/yl/lib/privacy_proxy/ProxyProxyField.java",
    "content": "package com.yl.lib.privacy_proxy;\n\nimport android.os.Build;\n\nimport androidx.annotation.Keep;\n\nimport com.yl.lib.privacy_annotation.PrivacyClassProxy;\nimport com.yl.lib.privacy_annotation.PrivacyFieldProxy;\n\n/**\n * @author yulun\n * @since 2022-03-03 19:42\n * 注意变量的初始化是在类初始化的时候就执行了，所以这里只适合hook不可变的变量\n */\n@Keep\n@PrivacyClassProxy\npublic class ProxyProxyField {\n\n    @PrivacyFieldProxy(\n            originalClass = android.os.Build.class,\n            originalFieldName = \"SERIAL\"\n    )\n    public static final String proxySerial = PrivacyProxyCall.Proxy.getSerial();\n\n    // 虽然能保证全局只读取一次，但检测机构是抓包识别的，好像也没什么用，他们好像不能检测变量的读取\n    @PrivacyFieldProxy(\n            originalClass = android.os.Build.class,\n            originalFieldName = \"BRAND\"\n    )\n    public static final String proxyBrand = PrivacyProxyCall.Proxy.getBrand();\n}\n"
  },
  {
    "path": "privacy-replace/.gitignore",
    "content": "/build"
  },
  {
    "path": "privacy-replace/README.md",
    "content": "# PrivacySentry\n    替换类，主要是想代理构造方法\n"
  },
  {
    "path": "privacy-replace/build.gradle",
    "content": "plugins {\n    id 'com.android.library'\n    id 'kotlin-android'\n    id 'maven-publish'\n}\napply from: '../publish.gradle'  // Changed from 'maven' to 'maven-publish'\nandroid {\n    compileSdkVersion 30\n    namespace \"com.yl.lib.privacy_replace\"\n    defaultConfig {\n        minSdkVersion 19\n        targetSdkVersion 30\n\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n        consumerProguardFiles \"consumer-rules.pro\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    kotlinOptions {\n        jvmTarget = '1.8'\n    }\n}\n\ndependencies {\n\n    implementation 'androidx.core:core-ktx:1.3.2'\n    implementation 'com.google.android.material:material:1.4.0'\n    implementation project(\":hook-sentry\")\n    implementation project(path: ':privacy-annotation')\n}\n\n//apply plugin: 'com.github.dcendents.android-maven'\n"
  },
  {
    "path": "privacy-replace/consumer-rules.pro",
    "content": ""
  },
  {
    "path": "privacy-replace/gradle.properties",
    "content": "ARTIFACT_ID=privacy-replace"
  },
  {
    "path": "privacy-replace/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile"
  },
  {
    "path": "privacy-replace/src/androidTest/java/com/vdian/android/wdb/privacy_replace/ExampleInstrumentedTest.kt",
    "content": "package com.vdian.android.wdb.privacy_replace\n\nimport androidx.test.platform.app.InstrumentationRegistry\nimport androidx.test.ext.junit.runners.AndroidJUnit4\n\nimport org.junit.Test\nimport org.junit.runner.RunWith\n\nimport org.junit.Assert.*\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * See [testing documentation](http://d.android.com/tools/testing).\n */\n@RunWith(AndroidJUnit4::class)\nclass ExampleInstrumentedTest {\n    @Test\n    fun useAppContext() {\n        // Context of the app under test.\n        val appContext = InstrumentationRegistry.getInstrumentation().targetContext\n        assertEquals(\"com.vdian.android.wdb.privacy_replace.test\", appContext.packageName)\n    }\n}"
  },
  {
    "path": "privacy-replace/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n</manifest>"
  },
  {
    "path": "privacy-replace/src/main/java/com/yl/lib/privacy_replace/PrivacyFile.java",
    "content": "package com.yl.lib.privacy_replace;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.yl.lib.privacy_annotation.PrivacyClassReplace;\nimport com.yl.lib.sentry.hook.PrivacySentry;\nimport com.yl.lib.sentry.hook.util.PrivacyLog;\nimport com.yl.lib.sentry.hook.util.PrivacyProxyUtil;\n\nimport java.io.File;\nimport java.net.URI;\n\n/**\n * @author yulun\n * @since 2022-11-18 15:01\n * 代理File的构造方法，如果是自定义的file类，需要业务方单独配置自行处理\n */\n@PrivacyClassReplace(originClass = File.class)\npublic class PrivacyFile extends File {\n\n    public PrivacyFile(@NonNull String pathname) {\n        super(pathname);\n        record(pathname);\n    }\n\n    public PrivacyFile(@Nullable String parent, @NonNull String child) {\n        super(parent, child);\n        record(parent + child);\n    }\n\n    public PrivacyFile(@Nullable File parent, @NonNull String child) {\n        super(parent, child);\n        record(parent.getPath() + child);\n    }\n\n    public PrivacyFile(@NonNull URI uri) {\n        super(uri);\n        record(uri.toString());\n    }\n\n    private void record(String path) {\n        PrivacyProxyUtil.Util.INSTANCE.doFilePrinter(\"PrivacyFile\", \"访问文件\", \"path is \" + path, false);\n    }\n}\n"
  },
  {
    "path": "privacy-replace/src/main/java/com/yl/lib/privacy_replace/PrivacyFileInputStream.java",
    "content": "package com.yl.lib.privacy_replace;\n\nimport com.yl.lib.privacy_annotation.PrivacyClassReplace;\nimport com.yl.lib.sentry.hook.PrivacySentry;\nimport com.yl.lib.sentry.hook.util.PrivacyLog;\nimport com.yl.lib.sentry.hook.util.PrivacyProxyUtil;\n\nimport java.io.File;\nimport java.io.FileDescriptor;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\n\n/**\n * @author yulun\n * @since 2022-11-18 15:01\n */\n@PrivacyClassReplace(originClass = FileInputStream.class)\npublic class PrivacyFileInputStream extends FileInputStream {\n    public PrivacyFileInputStream(String name) throws FileNotFoundException {\n        super(name);\n        record(name);\n    }\n\n    public PrivacyFileInputStream(File file) throws FileNotFoundException {\n        super(file);\n        record(file.getAbsolutePath());\n    }\n\n    public PrivacyFileInputStream(FileDescriptor fdObj) {\n        super(fdObj);\n        record(fdObj.toString());\n    }\n\n    private void record(String path) {\n        PrivacyProxyUtil.Util.INSTANCE.doFilePrinter(\"FileInputStream\", \"访问文件\", \"path is \" + path,  false);\n    }\n}\n"
  },
  {
    "path": "privacy-replace/src/main/java/com/yl/lib/privacy_replace/PrivacyFileReader.java",
    "content": "package com.yl.lib.privacy_replace;\n\nimport com.yl.lib.privacy_annotation.PrivacyClassReplace;\nimport com.yl.lib.sentry.hook.PrivacySentry;\nimport com.yl.lib.sentry.hook.util.PrivacyProxyUtil;\n\nimport java.io.File;\nimport java.io.FileDescriptor;\nimport java.io.FileNotFoundException;\nimport java.io.FileReader;\n\n/**\n * @author yulun\n * @since 2022-11-18 15:02\n */\n@PrivacyClassReplace(originClass = FileReader.class)\npublic class PrivacyFileReader extends FileReader {\n    public PrivacyFileReader(String fileName) throws FileNotFoundException {\n        super(fileName);\n        record(fileName);\n    }\n\n    public PrivacyFileReader(File file) throws FileNotFoundException {\n        super(file);\n        record(file.getAbsolutePath());\n    }\n\n    public PrivacyFileReader(FileDescriptor fd) {\n        super(fd);\n        record(fd.toString());\n    }\n\n    private void record(String path) {\n        PrivacyProxyUtil.Util.INSTANCE.doFilePrinter(\"FileReader\", \"访问文件\", \"path is \" + path, false);\n    }\n}\n"
  },
  {
    "path": "privacy-replace/src/test/java/com/vdian/android/wdb/privacy_replace/ExampleUnitTest.kt",
    "content": "package com.vdian.android.wdb.privacy_replace\n\nimport org.junit.Test\n\nimport org.junit.Assert.*\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * See [testing documentation](http://d.android.com/tools/testing).\n */\nclass ExampleUnitTest {\n    @Test\n    fun addition_isCorrect() {\n        assertEquals(4, 2 + 2)\n    }\n}"
  },
  {
    "path": "privacy-test/.gitignore",
    "content": "/build"
  },
  {
    "path": "privacy-test/build.gradle",
    "content": "apply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\nandroid {\n    compileSdkVersion 30\n    buildToolsVersion \"30.0.3\"\n    namespace \"com.yl.lib.privacy_test\"\n    defaultConfig {\n        minSdkVersion 19\n        targetSdkVersion 30\n        versionCode 1\n        versionName \"1.0\"\n    }\n\n    buildTypes {\n        debug {\n            debuggable true\n        }\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    kotlinOptions {\n        jvmTarget = '1.8'\n    }\n}\n\ndependencies {\n\n    implementation 'androidx.core:core-ktx:1.3.2'\n    implementation project(path: ':privacy-annotation')\n}\n\n"
  },
  {
    "path": "privacy-test/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile"
  },
  {
    "path": "privacy-test/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <uses-permission android:name=\"android.permission.READ_PRIVILEGED_PHONE_STATE\" />\n</manifest>"
  },
  {
    "path": "privacy-test/src/main/java/com/yl/lib/privacy_test/PrivacyProxySelfTest2.java",
    "content": "package com.yl.lib.privacy_test;\n\nimport android.app.ActivityManager;\n\nimport androidx.annotation.Keep;\n\nimport com.yl.lib.privacy_annotation.MethodInvokeOpcode;\nimport com.yl.lib.privacy_annotation.PrivacyClassProxy;\nimport com.yl.lib.privacy_annotation.PrivacyMethodProxy;\n\nimport java.util.List;\n\nimport kotlin.jvm.JvmStatic;\n\n/**\n * @author yulun\n * @since 2022-06-15 20:32\n */\n@PrivacyClassProxy\n@Keep\npublic class PrivacyProxySelfTest2 {\n\n    // 这个方法的注册放在了PrivacyProxyCall2中，提供了一个java注册的例子\n    @PrivacyMethodProxy(\n            originalClass = ActivityManager.class,\n            originalMethod = \"getRunningTasks\",\n            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL\n    )\n    @JvmStatic\n    public static List<ActivityManager.RunningTaskInfo> getRunningTasks456(\n            ActivityManager manager,\n            int maxNum\n    ) {\n        android.util.Log.i(\"yulun\", \"PrivacyProxySelfTest2\");\n        return manager.getRunningTasks(maxNum);\n    }\n}\n"
  },
  {
    "path": "privacy-test/src/main/java/com/yl/lib/privacy_test/TestMethod.kt",
    "content": "package com.yl.lib.privacy_test\n\nimport android.Manifest\nimport android.annotation.SuppressLint\nimport android.app.Activity\nimport android.app.ActivityManager\nimport android.content.ClipData\nimport android.content.ClipboardManager\nimport android.content.Context\nimport android.content.pm.PackageInfo\nimport android.content.pm.PackageManager\nimport android.net.wifi.WifiManager\nimport android.os.Build\nimport android.telephony.TelephonyManager\nimport android.text.TextUtils\nimport androidx.annotation.NonNull\nimport androidx.annotation.RequiresApi\nimport java.net.NetworkInterface\n\n\n/**\n * @author yulun\n * @sinice 2021-11-16 15:08\n */\nclass TestMethod {\n    object PrivacyMethod {\n\n\n        /**TMS START================================**/\n        /**\n         * test for device id\n         */\n        fun getDeviceId(context: Context?): String {\n            if (context == null) {\n                return \"\"\n            }\n//        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {\n//            return \"\"\n//        }\n            var imei = \"\"\n            // 在某些平板上可能会抛出异常\n            try {\n                if (checkPermissions(\n                        context,\n                        Manifest.permission.READ_PHONE_STATE\n                    )\n                ) {\n                    val mTelephonyMgr = context\n                        .getSystemService(Activity.TELEPHONY_SERVICE) as TelephonyManager\n                    imei = mTelephonyMgr.getDeviceId()\n                }\n            } catch (e: Throwable) {\n//                e.printStackTrace()\n            }\n            return imei\n        }\n\n\n        @RequiresApi(Build.VERSION_CODES.M)\n        fun getDeviceId1(context: Context?): String {\n            if (context == null) {\n                return \"\"\n            }\n//        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {\n//            return \"\"\n//        }\n            var imei = \"\"\n            // 在某些平板上可能会抛出异常\n            try {\n                if (checkPermissions(\n                        context,\n                        Manifest.permission.READ_PHONE_STATE\n                    )\n                ) {\n                    val mTelephonyMgr = context\n                        .getSystemService(Activity.TELEPHONY_SERVICE) as TelephonyManager\n                    imei = mTelephonyMgr.getDeviceId(1)\n                }\n            } catch (e: Throwable) {\n//                e.printStackTrace()\n            }\n            return imei ?: \"\"\n        }\n\n        /**\n         * imei\n         */\n        @RequiresApi(Build.VERSION_CODES.O)\n        fun getIMEI(context: Context?): String {\n            if (context == null) {\n                return \"\"\n            }\n//        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {\n//            return \"\"\n//        }\n            var imei = \"\"\n            // 在某些平板上可能会抛出异常\n            try {\n                if (checkPermissions(\n                        context,\n                        Manifest.permission.READ_PHONE_STATE\n                    )\n                ) {\n                    val mTelephonyMgr = context\n                        .getSystemService(Activity.TELEPHONY_SERVICE) as TelephonyManager\n                    imei = mTelephonyMgr.getImei()\n                }\n            } catch (e: Throwable) {\n                e.printStackTrace()\n            }\n            return imei ?: \"\"\n        }\n\n        /**\n         * 获得imsi\n         * @return\n         */\n        @SuppressLint(\"HardwareIds\")\n        fun getIMSI(context: Context?): String? {\n            if (context == null) {\n                return \"\"\n            }\n//        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {\n//            return \"\"\n//        }\n            var imsi = \"\"\n            try {\n                if (checkPermissions(\n                        context,\n                        Manifest.permission.READ_PHONE_STATE\n                    )\n                ) {\n                    val mTelephonyMgr = context\n                        .getSystemService(Activity.TELEPHONY_SERVICE) as TelephonyManager\n                        ?: return \"\"\n                    imsi =\n                        mTelephonyMgr.subscriberId\n                }\n            } catch (e: Throwable) {\n                e.printStackTrace()\n            }\n            return imsi ?: \"\"\n        }\n\n        /**\n         * 获取sim卡唯一标示\n         *\n         * @param context\n         * @return\n         */\n        @SuppressLint(\"HardwareIds\")\n        fun getICCID(context: Context?): String? {\n            if (context == null) {\n                return \"\"\n            }\n            var iccid = \"\"\n            try {\n                if (checkPermissions(\n                        context,\n                        Manifest.permission.READ_PHONE_STATE\n                    )\n                ) {\n                    val mTelephonyMgr = context\n                        .getSystemService(Activity.TELEPHONY_SERVICE) as TelephonyManager\n                        ?: return \"\"\n                    iccid =\n                        mTelephonyMgr.simSerialNumber\n                }\n            } catch (e: Throwable) {\n                e.printStackTrace()\n            }\n            return iccid ?: \"\"\n        }\n\n        /**TMS END================================**/\n\n\n        val MAC_DEFAULT = \"00:00:00:00:00:00\"\n        val MAC_SYSTEM = \"02:00:00:00:00:00\"\n\n        /**\n         *  wifiInfo.macAddress\n         *  networkInterface.hardwareAddress\n         */\n        fun getMacRaw(context: Context?): String? {\n            var mac: String? = MAC_DEFAULT\n            if (context == null) {\n                return mac\n            }\n            try {\n                val wifiManager =\n                    context.applicationContext.getSystemService(Activity.WIFI_SERVICE) as WifiManager\n                if (wifiManager != null) {\n                    val wifiInfo = wifiManager.connectionInfo\n                    if (wifiInfo != null) {\n                        val result = wifiInfo.macAddress\n                        if (result != null && result.length > 0) {\n                            mac = result\n                            mac = mac.replace(\"\\u0000\".toRegex(), \"\")\n                            mac = mac.replace(\"null\".toRegex(), \"\")\n                        }\n                    }\n                }\n            } catch (e: Exception) {\n                e.printStackTrace()\n            }\n\n            //7.0以上获取不到，获得的都是02:00:00:00:00:00\n            if (mac == null || TextUtils.equals(mac, MAC_DEFAULT) || TextUtils.equals(\n                    mac, MAC_SYSTEM\n                )\n            ) {\n                try {\n                    var networkInterface = NetworkInterface.getByName(\"eth1\")\n                    if (networkInterface == null) {\n                        networkInterface = NetworkInterface.getByName(\"wlan0\")\n                    }\n                    if (networkInterface == null) {\n                        return mac\n                    }\n                    val address = networkInterface.hardwareAddress ?: return mac\n                    val builder = StringBuilder()\n                    for (b in address) {\n                        builder.append(String.format(\"%02X:\", b))\n                    }\n                    if (builder.length > 0) {\n                        builder.deleteCharAt(builder.length - 1)\n                    }\n                    mac = builder.toString()\n                } catch (e: Throwable) {\n                    e.printStackTrace()\n                }\n            }\n            return if (TextUtils.isEmpty(mac)) MAC_DEFAULT else mac\n        }\n\n\n        private fun checkPermissions(context: Context, permission: String): Boolean {\n            val localPackageManager = context.packageManager ?: return false\n            return localPackageManager.checkPermission(\n                permission,\n                context.packageName\n            ) == PackageManager.PERMISSION_GRANTED\n        }\n\n\n        /**PMS START================================**/\n        /**\n         * 判断指定app应用是否已安装\n         *\n         * @param context 上下文\n         * @param pkgName app 包名\n         * @return 指定app应用是否已安装\n         */\n        fun isInstalled(@NonNull context: Context, pkgName: String): Boolean {\n            if (TextUtils.isEmpty(pkgName)) {\n                return false\n            }\n            // 获取所有已安装程序的包信息\n            val packages = getInstalledPackages(context)\n            for (i in packages.indices) {\n                // 循环判断是否存在指定包名\n                if (packages[i].packageName == pkgName) {\n                    return true\n                }\n            }\n            return false\n        }\n\n\n        /**\n         * 获取手机中所有安装的app应用\n         *\n         * @param context 上下文\n         * @return 所有安装的app应用信息\n         */\n        private fun getInstalledPackages(@NonNull context: Context): List<PackageInfo> {\n            val packageManager = context.packageManager\n            return packageManager.getInstalledPackages(0)\n        }\n        /**PMS END================================**/\n\n        /**CMS START================================**/\n        fun testHookCms(@NonNull context: Context) {\n            //获取剪切板服务\n            val cm: ClipboardManager? =\n                context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager?\n            //设置剪切板内容\n            cm?.setPrimaryClip(ClipData.newPlainText(\"data\", \"yl_vd\"))\n            //获取剪切板数据对象\n            val cd: ClipData? = cm?.primaryClip\n            val clipStr = cd?.getItemAt(0)?.text.toString()\n//            PrivacyLog.i(\"testHookCms cms data is :$clipStr\")\n        }\n\n        /**CMS END================================**/\n\n        fun testRunningProcess(@NonNull context: Context) {\n            val manager = context\n                .getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager\n            val runningAppProcesses = manager\n                .runningAppProcesses\n        }\n\n        fun testRunningTask(@NonNull context: Context) {\n            val manager = context\n                .getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager\n            val runningAppProcesses = manager\n                .getRunningTasks(100)\n        }\n    }\n}"
  },
  {
    "path": "privacy-test/src/main/java/com/yl/lib/privacy_test/TestMethodInJava.java",
    "content": "package com.yl.lib.privacy_test;\n\nimport android.app.ActivityManager;\nimport android.content.Context;\nimport android.provider.Settings;\nimport android.telephony.TelephonyManager;\n\n/**\n * @author yulun\n * @sinice 2021-12-22 19:46\n */\npublic class TestMethodInJava {\n    public static String getAndroidId(Context context) {\n        String androidId = \"\" + Settings.Secure.getString(context.getContentResolver(), \"android_id\");\n        return androidId;\n    }\n\n    public static String getAndroidId2(Context context) {\n        String androidId = \"\" + Settings.Secure.getString(context.getContentResolver(), \"android_id\");\n        return androidId;\n    }\n\n    public static String getAndroidIdSystem(Context context) {\n        String androidId = \"\" + Settings.System.getString(context.getContentResolver(), \"android_id\");\n        return androidId;\n    }\n\n    public static void getSubscriberId(Context context) {\n        try {\n            TelephonyManager tm = (TelephonyManager) context.getSystemService(\"phone\");\n            String mImsi = tm.getSubscriberId();\n            if (null == mImsi || mImsi.trim().length() == 0) {\n                mImsi = \"000000\";\n            }\n        } catch (Exception var2) {\n            var2.printStackTrace();\n        }\n    }\n\n\n\n    public static void testRunningProcess(Context context) {\n        ActivityManager manager = (ActivityManager) context\n                .getSystemService(Context.ACTIVITY_SERVICE);\n        manager.getRunningAppProcesses();\n    }\n\n    public static void testRunningTask(Context context) {\n        ActivityManager manager = (ActivityManager) context\n                .getSystemService(Context.ACTIVITY_SERVICE);\n        manager.getRunningTasks(100);\n    }\n}\n"
  },
  {
    "path": "privacy-ui/build/generated/source/buildConfig/debug/com/yl/lib/privacy_ui/BuildConfig.java",
    "content": "/**\n * Automatically generated file. DO NOT MODIFY\n */\npackage com.yl.lib.privacy_ui;\n\npublic final class BuildConfig {\n  public static final boolean DEBUG = Boolean.parseBoolean(\"true\");\n  public static final String LIBRARY_PACKAGE_NAME = \"com.yl.lib.privacy_ui\";\n  public static final String BUILD_TYPE = \"debug\";\n}\n"
  },
  {
    "path": "privacy-ui/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.yl.lib.privacy_ui\"\n    android:versionCode=\"1\"\n    android:versionName=\"1.0\" >\n\n    <uses-sdk\n        android:minSdkVersion=\"19\"\n        android:targetSdkVersion=\"29\" />\n\n    <application>\n        <activity\n            android:name=\"com.yl.lib.privacy_ui.RealTimePrivacyItemActivity\"\n            android:exported=\"false\" />\n        <activity\n            android:name=\"com.yl.lib.privacy_ui.ReplaceListActivity\"\n            android:exported=\"false\"\n            android:theme=\"@style/Theme.AppCompat.DayNight.NoActionBar\" />\n        <activity\n            android:name=\"com.yl.lib.privacy_ui.PermissionListActivity\"\n            android:exported=\"false\"\n            android:theme=\"@style/Theme.AppCompat.DayNight.NoActionBar\" />\n    </application>\n\n</manifest>"
  },
  {
    "path": "privacy-ui/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/output-metadata.json",
    "content": "{\n  \"version\": 2,\n  \"artifactType\": {\n    \"type\": \"AAPT_FRIENDLY_MERGED_MANIFESTS\",\n    \"kind\": \"Directory\"\n  },\n  \"applicationId\": \"com.yl.lib.privacy_ui\",\n  \"variantName\": \"debug\",\n  \"elements\": [\n    {\n      \"type\": \"SINGLE\",\n      \"filters\": [],\n      \"outputFile\": \"AndroidManifest.xml\"\n    }\n  ]\n}"
  },
  {
    "path": "privacy-ui/build/intermediates/aar_metadata/debug/aar-metadata.properties",
    "content": "aarFormatVersion=1.0\naarMetadataVersion=1.0\n"
  },
  {
    "path": "privacy-ui/build/intermediates/annotation_processor_list/debug/annotationProcessors.json",
    "content": "{}"
  },
  {
    "path": "privacy-ui/build/intermediates/compile_symbol_list/debug/R.txt",
    "content": "int anim abc_fade_in 0x0\nint anim abc_fade_out 0x0\nint anim abc_grow_fade_in_from_bottom 0x0\nint anim abc_popup_enter 0x0\nint anim abc_popup_exit 0x0\nint anim abc_shrink_fade_out_from_bottom 0x0\nint anim abc_slide_in_bottom 0x0\nint anim abc_slide_in_top 0x0\nint anim abc_slide_out_bottom 0x0\nint anim abc_slide_out_top 0x0\nint anim abc_tooltip_enter 0x0\nint anim abc_tooltip_exit 0x0\nint anim btn_checkbox_to_checked_box_inner_merged_animation 0x0\nint anim btn_checkbox_to_checked_box_outer_merged_animation 0x0\nint anim btn_checkbox_to_checked_icon_null_animation 0x0\nint anim btn_checkbox_to_unchecked_box_inner_merged_animation 0x0\nint anim btn_checkbox_to_unchecked_check_path_merged_animation 0x0\nint anim btn_checkbox_to_unchecked_icon_null_animation 0x0\nint anim btn_radio_to_off_mtrl_dot_group_animation 0x0\nint anim btn_radio_to_off_mtrl_ring_outer_animation 0x0\nint anim btn_radio_to_off_mtrl_ring_outer_path_animation 0x0\nint anim btn_radio_to_on_mtrl_dot_group_animation 0x0\nint anim btn_radio_to_on_mtrl_ring_outer_animation 0x0\nint anim btn_radio_to_on_mtrl_ring_outer_path_animation 0x0\nint anim design_bottom_sheet_slide_in 0x0\nint anim design_bottom_sheet_slide_out 0x0\nint anim design_snackbar_in 0x0\nint anim design_snackbar_out 0x0\nint anim mtrl_bottom_sheet_slide_in 0x0\nint anim mtrl_bottom_sheet_slide_out 0x0\nint anim mtrl_card_lowers_interpolator 0x0\nint animator design_appbar_state_list_animator 0x0\nint animator design_fab_hide_motion_spec 0x0\nint animator design_fab_show_motion_spec 0x0\nint animator linear_indeterminate_line1_head_interpolator 0x0\nint animator linear_indeterminate_line1_tail_interpolator 0x0\nint animator linear_indeterminate_line2_head_interpolator 0x0\nint animator linear_indeterminate_line2_tail_interpolator 0x0\nint animator mtrl_btn_state_list_anim 0x0\nint animator mtrl_btn_unelevated_state_list_anim 0x0\nint animator mtrl_card_state_list_anim 0x0\nint animator mtrl_chip_state_list_anim 0x0\nint animator mtrl_extended_fab_change_size_collapse_motion_spec 0x0\nint animator mtrl_extended_fab_change_size_expand_motion_spec 0x0\nint animator mtrl_extended_fab_hide_motion_spec 0x0\nint animator mtrl_extended_fab_show_motion_spec 0x0\nint animator mtrl_extended_fab_state_list_animator 0x0\nint animator mtrl_fab_hide_motion_spec 0x0\nint animator mtrl_fab_show_motion_spec 0x0\nint animator mtrl_fab_transformation_sheet_collapse_spec 0x0\nint animator mtrl_fab_transformation_sheet_expand_spec 0x0\nint attr actionBarDivider 0x0\nint attr actionBarItemBackground 0x0\nint attr actionBarPopupTheme 0x0\nint attr actionBarSize 0x0\nint attr actionBarSplitStyle 0x0\nint attr actionBarStyle 0x0\nint attr actionBarTabBarStyle 0x0\nint attr actionBarTabStyle 0x0\nint attr actionBarTabTextStyle 0x0\nint attr actionBarTheme 0x0\nint attr actionBarWidgetTheme 0x0\nint attr actionButtonStyle 0x0\nint attr actionDropDownStyle 0x0\nint attr actionLayout 0x0\nint attr actionMenuTextAppearance 0x0\nint attr actionMenuTextColor 0x0\nint attr actionModeBackground 0x0\nint attr actionModeCloseButtonStyle 0x0\nint attr actionModeCloseDrawable 0x0\nint attr actionModeCopyDrawable 0x0\nint attr actionModeCutDrawable 0x0\nint attr actionModeFindDrawable 0x0\nint attr actionModePasteDrawable 0x0\nint attr actionModePopupWindowStyle 0x0\nint attr actionModeSelectAllDrawable 0x0\nint attr actionModeShareDrawable 0x0\nint attr actionModeSplitBackground 0x0\nint attr actionModeStyle 0x0\nint attr actionModeWebSearchDrawable 0x0\nint attr actionOverflowButtonStyle 0x0\nint attr actionOverflowMenuStyle 0x0\nint attr actionProviderClass 0x0\nint attr actionTextColorAlpha 0x0\nint attr actionViewClass 0x0\nint attr activityChooserViewStyle 0x0\nint attr alertDialogButtonGroupStyle 0x0\nint attr alertDialogCenterButtons 0x0\nint attr alertDialogStyle 0x0\nint attr alertDialogTheme 0x0\nint attr allowStacking 0x0\nint attr alpha 0x0\nint attr alphabeticModifiers 0x0\nint attr altSrc 0x0\nint attr animate_relativeTo 0x0\nint attr animationMode 0x0\nint attr appBarLayoutStyle 0x0\nint attr applyMotionScene 0x0\nint attr arcMode 0x0\nint attr arrowHeadLength 0x0\nint attr arrowShaftLength 0x0\nint attr attributeName 0x0\nint attr autoCompleteTextViewStyle 0x0\nint attr autoSizeMaxTextSize 0x0\nint attr autoSizeMinTextSize 0x0\nint attr autoSizePresetSizes 0x0\nint attr autoSizeStepGranularity 0x0\nint attr autoSizeTextType 0x0\nint attr autoTransition 0x0\nint attr background 0x0\nint attr backgroundColor 0x0\nint attr backgroundInsetBottom 0x0\nint attr backgroundInsetEnd 0x0\nint attr backgroundInsetStart 0x0\nint attr backgroundInsetTop 0x0\nint attr backgroundOverlayColorAlpha 0x0\nint attr backgroundSplit 0x0\nint attr backgroundStacked 0x0\nint attr backgroundTint 0x0\nint attr backgroundTintMode 0x0\nint attr badgeGravity 0x0\nint attr badgeStyle 0x0\nint attr badgeTextColor 0x0\nint attr barLength 0x0\nint attr barrierAllowsGoneWidgets 0x0\nint attr barrierDirection 0x0\nint attr barrierMargin 0x0\nint attr behavior_autoHide 0x0\nint attr behavior_autoShrink 0x0\nint attr behavior_draggable 0x0\nint attr behavior_expandedOffset 0x0\nint attr behavior_fitToContents 0x0\nint attr behavior_halfExpandedRatio 0x0\nint attr behavior_hideable 0x0\nint attr behavior_overlapTop 0x0\nint attr behavior_peekHeight 0x0\nint attr behavior_saveFlags 0x0\nint attr behavior_skipCollapsed 0x0\nint attr borderWidth 0x0\nint attr borderlessButtonStyle 0x0\nint attr bottomAppBarStyle 0x0\nint attr bottomNavigationStyle 0x0\nint attr bottomSheetDialogTheme 0x0\nint attr bottomSheetStyle 0x0\nint attr boxBackgroundColor 0x0\nint attr boxBackgroundMode 0x0\nint attr boxCollapsedPaddingTop 0x0\nint attr boxCornerRadiusBottomEnd 0x0\nint attr boxCornerRadiusBottomStart 0x0\nint attr boxCornerRadiusTopEnd 0x0\nint attr boxCornerRadiusTopStart 0x0\nint attr boxStrokeColor 0x0\nint attr boxStrokeErrorColor 0x0\nint attr boxStrokeWidth 0x0\nint attr boxStrokeWidthFocused 0x0\nint attr brightness 0x0\nint attr buttonBarButtonStyle 0x0\nint attr buttonBarNegativeButtonStyle 0x0\nint attr buttonBarNeutralButtonStyle 0x0\nint attr buttonBarPositiveButtonStyle 0x0\nint attr buttonBarStyle 0x0\nint attr buttonCompat 0x0\nint attr buttonGravity 0x0\nint attr buttonIconDimen 0x0\nint attr buttonPanelSideLayout 0x0\nint attr buttonStyle 0x0\nint attr buttonStyleSmall 0x0\nint attr buttonTint 0x0\nint attr buttonTintMode 0x0\nint attr cardBackgroundColor 0x0\nint attr cardCornerRadius 0x0\nint attr cardElevation 0x0\nint attr cardForegroundColor 0x0\nint attr cardMaxElevation 0x0\nint attr cardPreventCornerOverlap 0x0\nint attr cardUseCompatPadding 0x0\nint attr cardViewStyle 0x0\nint attr chainUseRtl 0x0\nint attr checkboxStyle 0x0\nint attr checkedButton 0x0\nint attr checkedChip 0x0\nint attr checkedIcon 0x0\nint attr checkedIconEnabled 0x0\nint attr checkedIconMargin 0x0\nint attr checkedIconSize 0x0\nint attr checkedIconTint 0x0\nint attr checkedIconVisible 0x0\nint attr checkedTextViewStyle 0x0\nint attr chipBackgroundColor 0x0\nint attr chipCornerRadius 0x0\nint attr chipEndPadding 0x0\nint attr chipGroupStyle 0x0\nint attr chipIcon 0x0\nint attr chipIconEnabled 0x0\nint attr chipIconSize 0x0\nint attr chipIconTint 0x0\nint attr chipIconVisible 0x0\nint attr chipMinHeight 0x0\nint attr chipMinTouchTargetSize 0x0\nint attr chipSpacing 0x0\nint attr chipSpacingHorizontal 0x0\nint attr chipSpacingVertical 0x0\nint attr chipStandaloneStyle 0x0\nint attr chipStartPadding 0x0\nint attr chipStrokeColor 0x0\nint attr chipStrokeWidth 0x0\nint attr chipStyle 0x0\nint attr chipSurfaceColor 0x0\nint attr circleRadius 0x0\nint attr circularProgressIndicatorStyle 0x0\nint attr clickAction 0x0\nint attr clockFaceBackgroundColor 0x0\nint attr clockHandColor 0x0\nint attr clockIcon 0x0\nint attr clockNumberTextColor 0x0\nint attr closeIcon 0x0\nint attr closeIconEnabled 0x0\nint attr closeIconEndPadding 0x0\nint attr closeIconSize 0x0\nint attr closeIconStartPadding 0x0\nint attr closeIconTint 0x0\nint attr closeIconVisible 0x0\nint attr closeItemLayout 0x0\nint attr collapseContentDescription 0x0\nint attr collapseIcon 0x0\nint attr collapsedSize 0x0\nint attr collapsedTitleGravity 0x0\nint attr collapsedTitleTextAppearance 0x0\nint attr collapsingToolbarLayoutStyle 0x0\nint attr color 0x0\nint attr colorAccent 0x0\nint attr colorBackgroundFloating 0x0\nint attr colorButtonNormal 0x0\nint attr colorControlActivated 0x0\nint attr colorControlHighlight 0x0\nint attr colorControlNormal 0x0\nint attr colorError 0x0\nint attr colorOnBackground 0x0\nint attr colorOnError 0x0\nint attr colorOnPrimary 0x0\nint attr colorOnPrimarySurface 0x0\nint attr colorOnSecondary 0x0\nint attr colorOnSurface 0x0\nint attr colorPrimary 0x0\nint attr colorPrimaryDark 0x0\nint attr colorPrimarySurface 0x0\nint attr colorPrimaryVariant 0x0\nint attr colorSecondary 0x0\nint attr colorSecondaryVariant 0x0\nint attr colorSurface 0x0\nint attr colorSwitchThumbNormal 0x0\nint attr commitIcon 0x0\nint attr constraintSet 0x0\nint attr constraintSetEnd 0x0\nint attr constraintSetStart 0x0\nint attr constraint_referenced_ids 0x0\nint attr constraints 0x0\nint attr content 0x0\nint attr contentDescription 0x0\nint attr contentInsetEnd 0x0\nint attr contentInsetEndWithActions 0x0\nint attr contentInsetLeft 0x0\nint attr contentInsetRight 0x0\nint attr contentInsetStart 0x0\nint attr contentInsetStartWithNavigation 0x0\nint attr contentPadding 0x0\nint attr contentPaddingBottom 0x0\nint attr contentPaddingEnd 0x0\nint attr contentPaddingLeft 0x0\nint attr contentPaddingRight 0x0\nint attr contentPaddingStart 0x0\nint attr contentPaddingTop 0x0\nint attr contentScrim 0x0\nint attr contrast 0x0\nint attr controlBackground 0x0\nint attr coordinatorLayoutStyle 0x0\nint attr cornerFamily 0x0\nint attr cornerFamilyBottomLeft 0x0\nint attr cornerFamilyBottomRight 0x0\nint attr cornerFamilyTopLeft 0x0\nint attr cornerFamilyTopRight 0x0\nint attr cornerRadius 0x0\nint attr cornerSize 0x0\nint attr cornerSizeBottomLeft 0x0\nint attr cornerSizeBottomRight 0x0\nint attr cornerSizeTopLeft 0x0\nint attr cornerSizeTopRight 0x0\nint attr counterEnabled 0x0\nint attr counterMaxLength 0x0\nint attr counterOverflowTextAppearance 0x0\nint attr counterOverflowTextColor 0x0\nint attr counterTextAppearance 0x0\nint attr counterTextColor 0x0\nint attr crossfade 0x0\nint attr currentState 0x0\nint attr curveFit 0x0\nint attr customBoolean 0x0\nint attr customColorDrawableValue 0x0\nint attr customColorValue 0x0\nint attr customDimension 0x0\nint attr customFloatValue 0x0\nint attr customIntegerValue 0x0\nint attr customNavigationLayout 0x0\nint attr customPixelDimension 0x0\nint attr customStringValue 0x0\nint attr dayInvalidStyle 0x0\nint attr daySelectedStyle 0x0\nint attr dayStyle 0x0\nint attr dayTodayStyle 0x0\nint attr defaultDuration 0x0\nint attr defaultQueryHint 0x0\nint attr defaultState 0x0\nint attr deltaPolarAngle 0x0\nint attr deltaPolarRadius 0x0\nint attr deriveConstraintsFrom 0x0\nint attr dialogCornerRadius 0x0\nint attr dialogPreferredPadding 0x0\nint attr dialogTheme 0x0\nint attr displayOptions 0x0\nint attr divider 0x0\nint attr dividerHorizontal 0x0\nint attr dividerPadding 0x0\nint attr dividerVertical 0x0\nint attr dragDirection 0x0\nint attr dragScale 0x0\nint attr dragThreshold 0x0\nint attr drawPath 0x0\nint attr drawableBottomCompat 0x0\nint attr drawableEndCompat 0x0\nint attr drawableLeftCompat 0x0\nint attr drawableRightCompat 0x0\nint attr drawableSize 0x0\nint attr drawableStartCompat 0x0\nint attr drawableTint 0x0\nint attr drawableTintMode 0x0\nint attr drawableTopCompat 0x0\nint attr drawerArrowStyle 0x0\nint attr dropDownListViewStyle 0x0\nint attr dropdownListPreferredItemHeight 0x0\nint attr duration 0x0\nint attr editTextBackground 0x0\nint attr editTextColor 0x0\nint attr editTextStyle 0x0\nint attr elevation 0x0\nint attr elevationOverlayColor 0x0\nint attr elevationOverlayEnabled 0x0\nint attr endIconCheckable 0x0\nint attr endIconContentDescription 0x0\nint attr endIconDrawable 0x0\nint attr endIconMode 0x0\nint attr endIconTint 0x0\nint attr endIconTintMode 0x0\nint attr enforceMaterialTheme 0x0\nint attr enforceTextAppearance 0x0\nint attr ensureMinTouchTargetSize 0x0\nint attr errorContentDescription 0x0\nint attr errorEnabled 0x0\nint attr errorIconDrawable 0x0\nint attr errorIconTint 0x0\nint attr errorIconTintMode 0x0\nint attr errorTextAppearance 0x0\nint attr errorTextColor 0x0\nint attr expandActivityOverflowButtonDrawable 0x0\nint attr expanded 0x0\nint attr expandedHintEnabled 0x0\nint attr expandedTitleGravity 0x0\nint attr expandedTitleMargin 0x0\nint attr expandedTitleMarginBottom 0x0\nint attr expandedTitleMarginEnd 0x0\nint attr expandedTitleMarginStart 0x0\nint attr expandedTitleMarginTop 0x0\nint attr expandedTitleTextAppearance 0x0\nint attr extendMotionSpec 0x0\nint attr extendedFloatingActionButtonStyle 0x0\nint attr fabAlignmentMode 0x0\nint attr fabAnimationMode 0x0\nint attr fabCradleMargin 0x0\nint attr fabCradleRoundedCornerRadius 0x0\nint attr fabCradleVerticalOffset 0x0\nint attr fabCustomSize 0x0\nint attr fabSize 0x0\nint attr fastScrollEnabled 0x0\nint attr fastScrollHorizontalThumbDrawable 0x0\nint attr fastScrollHorizontalTrackDrawable 0x0\nint attr fastScrollVerticalThumbDrawable 0x0\nint attr fastScrollVerticalTrackDrawable 0x0\nint attr firstBaselineToTopHeight 0x0\nint attr floatingActionButtonStyle 0x0\nint attr flow_firstHorizontalBias 0x0\nint attr flow_firstHorizontalStyle 0x0\nint attr flow_firstVerticalBias 0x0\nint attr flow_firstVerticalStyle 0x0\nint attr flow_horizontalAlign 0x0\nint attr flow_horizontalBias 0x0\nint attr flow_horizontalGap 0x0\nint attr flow_horizontalStyle 0x0\nint attr flow_lastHorizontalBias 0x0\nint attr flow_lastHorizontalStyle 0x0\nint attr flow_lastVerticalBias 0x0\nint attr flow_lastVerticalStyle 0x0\nint attr flow_maxElementsWrap 0x0\nint attr flow_padding 0x0\nint attr flow_verticalAlign 0x0\nint attr flow_verticalBias 0x0\nint attr flow_verticalGap 0x0\nint attr flow_verticalStyle 0x0\nint attr flow_wrapMode 0x0\nint attr font 0x0\nint attr fontFamily 0x0\nint attr fontProviderAuthority 0x0\nint attr fontProviderCerts 0x0\nint attr fontProviderFetchStrategy 0x0\nint attr fontProviderFetchTimeout 0x0\nint attr fontProviderPackage 0x0\nint attr fontProviderQuery 0x0\nint attr fontStyle 0x0\nint attr fontVariationSettings 0x0\nint attr fontWeight 0x0\nint attr foregroundInsidePadding 0x0\nint attr framePosition 0x0\nint attr gapBetweenBars 0x0\nint attr gestureInsetBottomIgnored 0x0\nint attr goIcon 0x0\nint attr haloColor 0x0\nint attr haloRadius 0x0\nint attr headerLayout 0x0\nint attr height 0x0\nint attr helperText 0x0\nint attr helperTextEnabled 0x0\nint attr helperTextTextAppearance 0x0\nint attr helperTextTextColor 0x0\nint attr hideAnimationBehavior 0x0\nint attr hideMotionSpec 0x0\nint attr hideOnContentScroll 0x0\nint attr hideOnScroll 0x0\nint attr hintAnimationEnabled 0x0\nint attr hintEnabled 0x0\nint attr hintTextAppearance 0x0\nint attr hintTextColor 0x0\nint attr homeAsUpIndicator 0x0\nint attr homeLayout 0x0\nint attr horizontalOffset 0x0\nint attr hoveredFocusedTranslationZ 0x0\nint attr icon 0x0\nint attr iconEndPadding 0x0\nint attr iconGravity 0x0\nint attr iconPadding 0x0\nint attr iconSize 0x0\nint attr iconStartPadding 0x0\nint attr iconTint 0x0\nint attr iconTintMode 0x0\nint attr iconifiedByDefault 0x0\nint attr imageButtonStyle 0x0\nint attr indeterminateAnimationType 0x0\nint attr indeterminateProgressStyle 0x0\nint attr indicatorColor 0x0\nint attr indicatorDirectionCircular 0x0\nint attr indicatorDirectionLinear 0x0\nint attr indicatorInset 0x0\nint attr indicatorSize 0x0\nint attr initialActivityCount 0x0\nint attr insetForeground 0x0\nint attr isLightTheme 0x0\nint attr isMaterialTheme 0x0\nint attr itemBackground 0x0\nint attr itemFillColor 0x0\nint attr itemHorizontalPadding 0x0\nint attr itemHorizontalTranslationEnabled 0x0\nint attr itemIconPadding 0x0\nint attr itemIconSize 0x0\nint attr itemIconTint 0x0\nint attr itemMaxLines 0x0\nint attr itemPadding 0x0\nint attr itemRippleColor 0x0\nint attr itemShapeAppearance 0x0\nint attr itemShapeAppearanceOverlay 0x0\nint attr itemShapeFillColor 0x0\nint attr itemShapeInsetBottom 0x0\nint attr itemShapeInsetEnd 0x0\nint attr itemShapeInsetStart 0x0\nint attr itemShapeInsetTop 0x0\nint attr itemSpacing 0x0\nint attr itemStrokeColor 0x0\nint attr itemStrokeWidth 0x0\nint attr itemTextAppearance 0x0\nint attr itemTextAppearanceActive 0x0\nint attr itemTextAppearanceInactive 0x0\nint attr itemTextColor 0x0\nint attr keyPositionType 0x0\nint attr keyboardIcon 0x0\nint attr keylines 0x0\nint attr labelBehavior 0x0\nint attr labelStyle 0x0\nint attr labelVisibilityMode 0x0\nint attr lastBaselineToBottomHeight 0x0\nint attr layout 0x0\nint attr layoutDescription 0x0\nint attr layoutDuringTransition 0x0\nint attr layoutManager 0x0\nint attr layout_anchor 0x0\nint attr layout_anchorGravity 0x0\nint attr layout_behavior 0x0\nint attr layout_collapseMode 0x0\nint attr layout_collapseParallaxMultiplier 0x0\nint attr layout_constrainedHeight 0x0\nint attr layout_constrainedWidth 0x0\nint attr layout_constraintBaseline_creator 0x0\nint attr layout_constraintBaseline_toBaselineOf 0x0\nint attr layout_constraintBottom_creator 0x0\nint attr layout_constraintBottom_toBottomOf 0x0\nint attr layout_constraintBottom_toTopOf 0x0\nint attr layout_constraintCircle 0x0\nint attr layout_constraintCircleAngle 0x0\nint attr layout_constraintCircleRadius 0x0\nint attr layout_constraintDimensionRatio 0x0\nint attr layout_constraintEnd_toEndOf 0x0\nint attr layout_constraintEnd_toStartOf 0x0\nint attr layout_constraintGuide_begin 0x0\nint attr layout_constraintGuide_end 0x0\nint attr layout_constraintGuide_percent 0x0\nint attr layout_constraintHeight_default 0x0\nint attr layout_constraintHeight_max 0x0\nint attr layout_constraintHeight_min 0x0\nint attr layout_constraintHeight_percent 0x0\nint attr layout_constraintHorizontal_bias 0x0\nint attr layout_constraintHorizontal_chainStyle 0x0\nint attr layout_constraintHorizontal_weight 0x0\nint attr layout_constraintLeft_creator 0x0\nint attr layout_constraintLeft_toLeftOf 0x0\nint attr layout_constraintLeft_toRightOf 0x0\nint attr layout_constraintRight_creator 0x0\nint attr layout_constraintRight_toLeftOf 0x0\nint attr layout_constraintRight_toRightOf 0x0\nint attr layout_constraintStart_toEndOf 0x0\nint attr layout_constraintStart_toStartOf 0x0\nint attr layout_constraintTag 0x0\nint attr layout_constraintTop_creator 0x0\nint attr layout_constraintTop_toBottomOf 0x0\nint attr layout_constraintTop_toTopOf 0x0\nint attr layout_constraintVertical_bias 0x0\nint attr layout_constraintVertical_chainStyle 0x0\nint attr layout_constraintVertical_weight 0x0\nint attr layout_constraintWidth_default 0x0\nint attr layout_constraintWidth_max 0x0\nint attr layout_constraintWidth_min 0x0\nint attr layout_constraintWidth_percent 0x0\nint attr layout_dodgeInsetEdges 0x0\nint attr layout_editor_absoluteX 0x0\nint attr layout_editor_absoluteY 0x0\nint attr layout_goneMarginBottom 0x0\nint attr layout_goneMarginEnd 0x0\nint attr layout_goneMarginLeft 0x0\nint attr layout_goneMarginRight 0x0\nint attr layout_goneMarginStart 0x0\nint attr layout_goneMarginTop 0x0\nint attr layout_insetEdge 0x0\nint attr layout_keyline 0x0\nint attr layout_optimizationLevel 0x0\nint attr layout_scrollFlags 0x0\nint attr layout_scrollInterpolator 0x0\nint attr liftOnScroll 0x0\nint attr liftOnScrollTargetViewId 0x0\nint attr limitBoundsTo 0x0\nint attr lineHeight 0x0\nint attr lineSpacing 0x0\nint attr linearProgressIndicatorStyle 0x0\nint attr listChoiceBackgroundIndicator 0x0\nint attr listChoiceIndicatorMultipleAnimated 0x0\nint attr listChoiceIndicatorSingleAnimated 0x0\nint attr listDividerAlertDialog 0x0\nint attr listItemLayout 0x0\nint attr listLayout 0x0\nint attr listMenuViewStyle 0x0\nint attr listPopupWindowStyle 0x0\nint attr listPreferredItemHeight 0x0\nint attr listPreferredItemHeightLarge 0x0\nint attr listPreferredItemHeightSmall 0x0\nint attr listPreferredItemPaddingEnd 0x0\nint attr listPreferredItemPaddingLeft 0x0\nint attr listPreferredItemPaddingRight 0x0\nint attr listPreferredItemPaddingStart 0x0\nint attr logo 0x0\nint attr logoDescription 0x0\nint attr materialAlertDialogBodyTextStyle 0x0\nint attr materialAlertDialogTheme 0x0\nint attr materialAlertDialogTitleIconStyle 0x0\nint attr materialAlertDialogTitlePanelStyle 0x0\nint attr materialAlertDialogTitleTextStyle 0x0\nint attr materialButtonOutlinedStyle 0x0\nint attr materialButtonStyle 0x0\nint attr materialButtonToggleGroupStyle 0x0\nint attr materialCalendarDay 0x0\nint attr materialCalendarFullscreenTheme 0x0\nint attr materialCalendarHeaderCancelButton 0x0\nint attr materialCalendarHeaderConfirmButton 0x0\nint attr materialCalendarHeaderDivider 0x0\nint attr materialCalendarHeaderLayout 0x0\nint attr materialCalendarHeaderSelection 0x0\nint attr materialCalendarHeaderTitle 0x0\nint attr materialCalendarHeaderToggleButton 0x0\nint attr materialCalendarMonth 0x0\nint attr materialCalendarMonthNavigationButton 0x0\nint attr materialCalendarStyle 0x0\nint attr materialCalendarTheme 0x0\nint attr materialCalendarYearNavigationButton 0x0\nint attr materialCardViewStyle 0x0\nint attr materialCircleRadius 0x0\nint attr materialClockStyle 0x0\nint attr materialThemeOverlay 0x0\nint attr materialTimePickerStyle 0x0\nint attr materialTimePickerTheme 0x0\nint attr maxAcceleration 0x0\nint attr maxActionInlineWidth 0x0\nint attr maxButtonHeight 0x0\nint attr maxCharacterCount 0x0\nint attr maxHeight 0x0\nint attr maxImageSize 0x0\nint attr maxLines 0x0\nint attr maxVelocity 0x0\nint attr maxWidth 0x0\nint attr measureWithLargestChild 0x0\nint attr menu 0x0\nint attr minHeight 0x0\nint attr minHideDelay 0x0\nint attr minSeparation 0x0\nint attr minTouchTargetSize 0x0\nint attr minWidth 0x0\nint attr mock_diagonalsColor 0x0\nint attr mock_label 0x0\nint attr mock_labelBackgroundColor 0x0\nint attr mock_labelColor 0x0\nint attr mock_showDiagonals 0x0\nint attr mock_showLabel 0x0\nint attr motionDebug 0x0\nint attr motionInterpolator 0x0\nint attr motionPathRotate 0x0\nint attr motionProgress 0x0\nint attr motionStagger 0x0\nint attr motionTarget 0x0\nint attr motion_postLayoutCollision 0x0\nint attr motion_triggerOnCollision 0x0\nint attr moveWhenScrollAtTop 0x0\nint attr multiChoiceItemLayout 0x0\nint attr navigationContentDescription 0x0\nint attr navigationIcon 0x0\nint attr navigationIconTint 0x0\nint attr navigationMode 0x0\nint attr navigationViewStyle 0x0\nint attr nestedScrollFlags 0x0\nint attr nestedScrollable 0x0\nint attr number 0x0\nint attr numericModifiers 0x0\nint attr onCross 0x0\nint attr onHide 0x0\nint attr onNegativeCross 0x0\nint attr onPositiveCross 0x0\nint attr onShow 0x0\nint attr onTouchUp 0x0\nint attr overlapAnchor 0x0\nint attr overlay 0x0\nint attr paddingBottomNoButtons 0x0\nint attr paddingBottomSystemWindowInsets 0x0\nint attr paddingEnd 0x0\nint attr paddingLeftSystemWindowInsets 0x0\nint attr paddingRightSystemWindowInsets 0x0\nint attr paddingStart 0x0\nint attr paddingTopNoTitle 0x0\nint attr panelBackground 0x0\nint attr panelMenuListTheme 0x0\nint attr panelMenuListWidth 0x0\nint attr passwordToggleContentDescription 0x0\nint attr passwordToggleDrawable 0x0\nint attr passwordToggleEnabled 0x0\nint attr passwordToggleTint 0x0\nint attr passwordToggleTintMode 0x0\nint attr pathMotionArc 0x0\nint attr path_percent 0x0\nint attr percentHeight 0x0\nint attr percentWidth 0x0\nint attr percentX 0x0\nint attr percentY 0x0\nint attr perpendicularPath_percent 0x0\nint attr pivotAnchor 0x0\nint attr placeholderText 0x0\nint attr placeholderTextAppearance 0x0\nint attr placeholderTextColor 0x0\nint attr placeholder_emptyVisibility 0x0\nint attr popupMenuBackground 0x0\nint attr popupMenuStyle 0x0\nint attr popupTheme 0x0\nint attr popupWindowStyle 0x0\nint attr prefixText 0x0\nint attr prefixTextAppearance 0x0\nint attr prefixTextColor 0x0\nint attr preserveIconSpacing 0x0\nint attr pressedTranslationZ 0x0\nint attr progressBarPadding 0x0\nint attr progressBarStyle 0x0\nint attr queryBackground 0x0\nint attr queryHint 0x0\nint attr radioButtonStyle 0x0\nint attr rangeFillColor 0x0\nint attr ratingBarStyle 0x0\nint attr ratingBarStyleIndicator 0x0\nint attr ratingBarStyleSmall 0x0\nint attr recyclerViewStyle 0x0\nint attr region_heightLessThan 0x0\nint attr region_heightMoreThan 0x0\nint attr region_widthLessThan 0x0\nint attr region_widthMoreThan 0x0\nint attr reverseLayout 0x0\nint attr rippleColor 0x0\nint attr round 0x0\nint attr roundPercent 0x0\nint attr saturation 0x0\nint attr scrimAnimationDuration 0x0\nint attr scrimBackground 0x0\nint attr scrimVisibleHeightTrigger 0x0\nint attr searchHintIcon 0x0\nint attr searchIcon 0x0\nint attr searchViewStyle 0x0\nint attr seekBarStyle 0x0\nint attr selectableItemBackground 0x0\nint attr selectableItemBackgroundBorderless 0x0\nint attr selectionRequired 0x0\nint attr selectorSize 0x0\nint attr shapeAppearance 0x0\nint attr shapeAppearanceLargeComponent 0x0\nint attr shapeAppearanceMediumComponent 0x0\nint attr shapeAppearanceOverlay 0x0\nint attr shapeAppearanceSmallComponent 0x0\nint attr showAnimationBehavior 0x0\nint attr showAsAction 0x0\nint attr showDelay 0x0\nint attr showDividers 0x0\nint attr showMotionSpec 0x0\nint attr showPaths 0x0\nint attr showText 0x0\nint attr showTitle 0x0\nint attr shrinkMotionSpec 0x0\nint attr singleChoiceItemLayout 0x0\nint attr singleLine 0x0\nint attr singleSelection 0x0\nint attr sizePercent 0x0\nint attr sliderStyle 0x0\nint attr snackbarButtonStyle 0x0\nint attr snackbarStyle 0x0\nint attr snackbarTextViewStyle 0x0\nint attr spanCount 0x0\nint attr spinBars 0x0\nint attr spinnerDropDownItemStyle 0x0\nint attr spinnerStyle 0x0\nint attr splitTrack 0x0\nint attr srcCompat 0x0\nint attr stackFromEnd 0x0\nint attr staggered 0x0\nint attr startIconCheckable 0x0\nint attr startIconContentDescription 0x0\nint attr startIconDrawable 0x0\nint attr startIconTint 0x0\nint attr startIconTintMode 0x0\nint attr state_above_anchor 0x0\nint attr state_collapsed 0x0\nint attr state_collapsible 0x0\nint attr state_dragged 0x0\nint attr state_liftable 0x0\nint attr state_lifted 0x0\nint attr statusBarBackground 0x0\nint attr statusBarForeground 0x0\nint attr statusBarScrim 0x0\nint attr strokeColor 0x0\nint attr strokeWidth 0x0\nint attr subMenuArrow 0x0\nint attr submitBackground 0x0\nint attr subtitle 0x0\nint attr subtitleTextAppearance 0x0\nint attr subtitleTextColor 0x0\nint attr subtitleTextStyle 0x0\nint attr suffixText 0x0\nint attr suffixTextAppearance 0x0\nint attr suffixTextColor 0x0\nint attr suggestionRowLayout 0x0\nint attr switchMinWidth 0x0\nint attr switchPadding 0x0\nint attr switchStyle 0x0\nint attr switchTextAppearance 0x0\nint attr tabBackground 0x0\nint attr tabContentStart 0x0\nint attr tabGravity 0x0\nint attr tabIconTint 0x0\nint attr tabIconTintMode 0x0\nint attr tabIndicator 0x0\nint attr tabIndicatorAnimationDuration 0x0\nint attr tabIndicatorAnimationMode 0x0\nint attr tabIndicatorColor 0x0\nint attr tabIndicatorFullWidth 0x0\nint attr tabIndicatorGravity 0x0\nint attr tabIndicatorHeight 0x0\nint attr tabInlineLabel 0x0\nint attr tabMaxWidth 0x0\nint attr tabMinWidth 0x0\nint attr tabMode 0x0\nint attr tabPadding 0x0\nint attr tabPaddingBottom 0x0\nint attr tabPaddingEnd 0x0\nint attr tabPaddingStart 0x0\nint attr tabPaddingTop 0x0\nint attr tabRippleColor 0x0\nint attr tabSelectedTextColor 0x0\nint attr tabStyle 0x0\nint attr tabTextAppearance 0x0\nint attr tabTextColor 0x0\nint attr tabUnboundedRipple 0x0\nint attr targetId 0x0\nint attr telltales_tailColor 0x0\nint attr telltales_tailScale 0x0\nint attr telltales_velocityMode 0x0\nint attr textAllCaps 0x0\nint attr textAppearanceBody1 0x0\nint attr textAppearanceBody2 0x0\nint attr textAppearanceButton 0x0\nint attr textAppearanceCaption 0x0\nint attr textAppearanceHeadline1 0x0\nint attr textAppearanceHeadline2 0x0\nint attr textAppearanceHeadline3 0x0\nint attr textAppearanceHeadline4 0x0\nint attr textAppearanceHeadline5 0x0\nint attr textAppearanceHeadline6 0x0\nint attr textAppearanceLargePopupMenu 0x0\nint attr textAppearanceLineHeightEnabled 0x0\nint attr textAppearanceListItem 0x0\nint attr textAppearanceListItemSecondary 0x0\nint attr textAppearanceListItemSmall 0x0\nint attr textAppearanceOverline 0x0\nint attr textAppearancePopupMenuHeader 0x0\nint attr textAppearanceSearchResultSubtitle 0x0\nint attr textAppearanceSearchResultTitle 0x0\nint attr textAppearanceSmallPopupMenu 0x0\nint attr textAppearanceSubtitle1 0x0\nint attr textAppearanceSubtitle2 0x0\nint attr textColorAlertDialogListItem 0x0\nint attr textColorSearchUrl 0x0\nint attr textEndPadding 0x0\nint attr textInputLayoutFocusedRectEnabled 0x0\nint attr textInputStyle 0x0\nint attr textLocale 0x0\nint attr textStartPadding 0x0\nint attr theme 0x0\nint attr themeLineHeight 0x0\nint attr thickness 0x0\nint attr thumbColor 0x0\nint attr thumbElevation 0x0\nint attr thumbRadius 0x0\nint attr thumbStrokeColor 0x0\nint attr thumbStrokeWidth 0x0\nint attr thumbTextPadding 0x0\nint attr thumbTint 0x0\nint attr thumbTintMode 0x0\nint attr tickColor 0x0\nint attr tickColorActive 0x0\nint attr tickColorInactive 0x0\nint attr tickMark 0x0\nint attr tickMarkTint 0x0\nint attr tickMarkTintMode 0x0\nint attr tickVisible 0x0\nint attr tint 0x0\nint attr tintMode 0x0\nint attr title 0x0\nint attr titleEnabled 0x0\nint attr titleMargin 0x0\nint attr titleMarginBottom 0x0\nint attr titleMarginEnd 0x0\nint attr titleMarginStart 0x0\nint attr titleMarginTop 0x0\nint attr titleMargins 0x0\nint attr titleTextAppearance 0x0\nint attr titleTextColor 0x0\nint attr titleTextStyle 0x0\nint attr toolbarId 0x0\nint attr toolbarNavigationButtonStyle 0x0\nint attr toolbarStyle 0x0\nint attr tooltipForegroundColor 0x0\nint attr tooltipFrameBackground 0x0\nint attr tooltipStyle 0x0\nint attr tooltipText 0x0\nint attr touchAnchorId 0x0\nint attr touchAnchorSide 0x0\nint attr touchRegionId 0x0\nint attr track 0x0\nint attr trackColor 0x0\nint attr trackColorActive 0x0\nint attr trackColorInactive 0x0\nint attr trackCornerRadius 0x0\nint attr trackHeight 0x0\nint attr trackThickness 0x0\nint attr trackTint 0x0\nint attr trackTintMode 0x0\nint attr transitionDisable 0x0\nint attr transitionEasing 0x0\nint attr transitionFlags 0x0\nint attr transitionPathRotate 0x0\nint attr transitionShapeAppearance 0x0\nint attr triggerId 0x0\nint attr triggerReceiver 0x0\nint attr triggerSlack 0x0\nint attr ttcIndex 0x0\nint attr useCompatPadding 0x0\nint attr useMaterialThemeColors 0x0\nint attr values 0x0\nint attr verticalOffset 0x0\nint attr viewInflaterClass 0x0\nint attr visibilityMode 0x0\nint attr voiceIcon 0x0\nint attr warmth 0x0\nint attr waveDecay 0x0\nint attr waveOffset 0x0\nint attr wavePeriod 0x0\nint attr waveShape 0x0\nint attr waveVariesBy 0x0\nint attr windowActionBar 0x0\nint attr windowActionBarOverlay 0x0\nint attr windowActionModeOverlay 0x0\nint attr windowFixedHeightMajor 0x0\nint attr windowFixedHeightMinor 0x0\nint attr windowFixedWidthMajor 0x0\nint attr windowFixedWidthMinor 0x0\nint attr windowMinWidthMajor 0x0\nint attr windowMinWidthMinor 0x0\nint attr windowNoTitle 0x0\nint attr yearSelectedStyle 0x0\nint attr yearStyle 0x0\nint attr yearTodayStyle 0x0\nint bool abc_action_bar_embed_tabs 0x0\nint bool abc_allow_stacked_button_bar 0x0\nint bool abc_config_actionMenuItemAllCaps 0x0\nint bool mtrl_btn_textappearance_all_caps 0x0\nint color abc_background_cache_hint_selector_material_dark 0x0\nint color abc_background_cache_hint_selector_material_light 0x0\nint color abc_btn_colored_borderless_text_material 0x0\nint color abc_btn_colored_text_material 0x0\nint color abc_color_highlight_material 0x0\nint color abc_decor_view_status_guard 0x0\nint color abc_decor_view_status_guard_light 0x0\nint color abc_hint_foreground_material_dark 0x0\nint color abc_hint_foreground_material_light 0x0\nint color abc_input_method_navigation_guard 0x0\nint color abc_primary_text_disable_only_material_dark 0x0\nint color abc_primary_text_disable_only_material_light 0x0\nint color abc_primary_text_material_dark 0x0\nint color abc_primary_text_material_light 0x0\nint color abc_search_url_text 0x0\nint color abc_search_url_text_normal 0x0\nint color abc_search_url_text_pressed 0x0\nint color abc_search_url_text_selected 0x0\nint color abc_secondary_text_material_dark 0x0\nint color abc_secondary_text_material_light 0x0\nint color abc_tint_btn_checkable 0x0\nint color abc_tint_default 0x0\nint color abc_tint_edittext 0x0\nint color abc_tint_seek_thumb 0x0\nint color abc_tint_spinner 0x0\nint color abc_tint_switch_track 0x0\nint color accent_material_dark 0x0\nint color accent_material_light 0x0\nint color androidx_core_ripple_material_light 0x0\nint color androidx_core_secondary_text_default_material_light 0x0\nint color background_floating_material_dark 0x0\nint color background_floating_material_light 0x0\nint color background_material_dark 0x0\nint color background_material_light 0x0\nint color bright_foreground_disabled_material_dark 0x0\nint color bright_foreground_disabled_material_light 0x0\nint color bright_foreground_inverse_material_dark 0x0\nint color bright_foreground_inverse_material_light 0x0\nint color bright_foreground_material_dark 0x0\nint color bright_foreground_material_light 0x0\nint color button_material_dark 0x0\nint color button_material_light 0x0\nint color cardview_dark_background 0x0\nint color cardview_light_background 0x0\nint color cardview_shadow_end_color 0x0\nint color cardview_shadow_start_color 0x0\nint color checkbox_themeable_attribute_color 0x0\nint color design_bottom_navigation_shadow_color 0x0\nint color design_box_stroke_color 0x0\nint color design_dark_default_color_background 0x0\nint color design_dark_default_color_error 0x0\nint color design_dark_default_color_on_background 0x0\nint color design_dark_default_color_on_error 0x0\nint color design_dark_default_color_on_primary 0x0\nint color design_dark_default_color_on_secondary 0x0\nint color design_dark_default_color_on_surface 0x0\nint color design_dark_default_color_primary 0x0\nint color design_dark_default_color_primary_dark 0x0\nint color design_dark_default_color_primary_variant 0x0\nint color design_dark_default_color_secondary 0x0\nint color design_dark_default_color_secondary_variant 0x0\nint color design_dark_default_color_surface 0x0\nint color design_default_color_background 0x0\nint color design_default_color_error 0x0\nint color design_default_color_on_background 0x0\nint color design_default_color_on_error 0x0\nint color design_default_color_on_primary 0x0\nint color design_default_color_on_secondary 0x0\nint color design_default_color_on_surface 0x0\nint color design_default_color_primary 0x0\nint color design_default_color_primary_dark 0x0\nint color design_default_color_primary_variant 0x0\nint color design_default_color_secondary 0x0\nint color design_default_color_secondary_variant 0x0\nint color design_default_color_surface 0x0\nint color design_error 0x0\nint color design_fab_shadow_end_color 0x0\nint color design_fab_shadow_mid_color 0x0\nint color design_fab_shadow_start_color 0x0\nint color design_fab_stroke_end_inner_color 0x0\nint color design_fab_stroke_end_outer_color 0x0\nint color design_fab_stroke_top_inner_color 0x0\nint color design_fab_stroke_top_outer_color 0x0\nint color design_icon_tint 0x0\nint color design_snackbar_background_color 0x0\nint color dim_foreground_disabled_material_dark 0x0\nint color dim_foreground_disabled_material_light 0x0\nint color dim_foreground_material_dark 0x0\nint color dim_foreground_material_light 0x0\nint color error_color_material_dark 0x0\nint color error_color_material_light 0x0\nint color foreground_material_dark 0x0\nint color foreground_material_light 0x0\nint color highlighted_text_material_dark 0x0\nint color highlighted_text_material_light 0x0\nint color material_blue_grey_800 0x0\nint color material_blue_grey_900 0x0\nint color material_blue_grey_950 0x0\nint color material_cursor_color 0x0\nint color material_deep_teal_200 0x0\nint color material_deep_teal_500 0x0\nint color material_grey_100 0x0\nint color material_grey_300 0x0\nint color material_grey_50 0x0\nint color material_grey_600 0x0\nint color material_grey_800 0x0\nint color material_grey_850 0x0\nint color material_grey_900 0x0\nint color material_on_background_disabled 0x0\nint color material_on_background_emphasis_high_type 0x0\nint color material_on_background_emphasis_medium 0x0\nint color material_on_primary_disabled 0x0\nint color material_on_primary_emphasis_high_type 0x0\nint color material_on_primary_emphasis_medium 0x0\nint color material_on_surface_disabled 0x0\nint color material_on_surface_emphasis_high_type 0x0\nint color material_on_surface_emphasis_medium 0x0\nint color material_on_surface_stroke 0x0\nint color material_slider_active_tick_marks_color 0x0\nint color material_slider_active_track_color 0x0\nint color material_slider_halo_color 0x0\nint color material_slider_inactive_tick_marks_color 0x0\nint color material_slider_inactive_track_color 0x0\nint color material_slider_thumb_color 0x0\nint color material_timepicker_button_background 0x0\nint color material_timepicker_button_stroke 0x0\nint color material_timepicker_clock_text_color 0x0\nint color material_timepicker_clockface 0x0\nint color material_timepicker_modebutton_tint 0x0\nint color mtrl_bottom_nav_colored_item_tint 0x0\nint color mtrl_bottom_nav_colored_ripple_color 0x0\nint color mtrl_bottom_nav_item_tint 0x0\nint color mtrl_bottom_nav_ripple_color 0x0\nint color mtrl_btn_bg_color_selector 0x0\nint color mtrl_btn_ripple_color 0x0\nint color mtrl_btn_stroke_color_selector 0x0\nint color mtrl_btn_text_btn_bg_color_selector 0x0\nint color mtrl_btn_text_btn_ripple_color 0x0\nint color mtrl_btn_text_color_disabled 0x0\nint color mtrl_btn_text_color_selector 0x0\nint color mtrl_btn_transparent_bg_color 0x0\nint color mtrl_calendar_item_stroke_color 0x0\nint color mtrl_calendar_selected_range 0x0\nint color mtrl_card_view_foreground 0x0\nint color mtrl_card_view_ripple 0x0\nint color mtrl_chip_background_color 0x0\nint color mtrl_chip_close_icon_tint 0x0\nint color mtrl_chip_surface_color 0x0\nint color mtrl_chip_text_color 0x0\nint color mtrl_choice_chip_background_color 0x0\nint color mtrl_choice_chip_ripple_color 0x0\nint color mtrl_choice_chip_text_color 0x0\nint color mtrl_error 0x0\nint color mtrl_fab_bg_color_selector 0x0\nint color mtrl_fab_icon_text_color_selector 0x0\nint color mtrl_fab_ripple_color 0x0\nint color mtrl_filled_background_color 0x0\nint color mtrl_filled_icon_tint 0x0\nint color mtrl_filled_stroke_color 0x0\nint color mtrl_indicator_text_color 0x0\nint color mtrl_navigation_item_background_color 0x0\nint color mtrl_navigation_item_icon_tint 0x0\nint color mtrl_navigation_item_text_color 0x0\nint color mtrl_on_primary_text_btn_text_color_selector 0x0\nint color mtrl_on_surface_ripple_color 0x0\nint color mtrl_outlined_icon_tint 0x0\nint color mtrl_outlined_stroke_color 0x0\nint color mtrl_popupmenu_overlay_color 0x0\nint color mtrl_scrim_color 0x0\nint color mtrl_tabs_colored_ripple_color 0x0\nint color mtrl_tabs_icon_color_selector 0x0\nint color mtrl_tabs_icon_color_selector_colored 0x0\nint color mtrl_tabs_legacy_text_color_selector 0x0\nint color mtrl_tabs_ripple_color 0x0\nint color mtrl_text_btn_text_color_selector 0x0\nint color mtrl_textinput_default_box_stroke_color 0x0\nint color mtrl_textinput_disabled_color 0x0\nint color mtrl_textinput_filled_box_default_background_color 0x0\nint color mtrl_textinput_focused_box_stroke_color 0x0\nint color mtrl_textinput_hovered_box_stroke_color 0x0\nint color notification_action_color_filter 0x0\nint color notification_icon_bg_color 0x0\nint color primary_dark_material_dark 0x0\nint color primary_dark_material_light 0x0\nint color primary_material_dark 0x0\nint color primary_material_light 0x0\nint color primary_text_default_material_dark 0x0\nint color primary_text_default_material_light 0x0\nint color primary_text_disabled_material_dark 0x0\nint color primary_text_disabled_material_light 0x0\nint color radiobutton_themeable_attribute_color 0x0\nint color ripple_material_dark 0x0\nint color ripple_material_light 0x0\nint color secondary_text_default_material_dark 0x0\nint color secondary_text_default_material_light 0x0\nint color secondary_text_disabled_material_dark 0x0\nint color secondary_text_disabled_material_light 0x0\nint color switch_thumb_disabled_material_dark 0x0\nint color switch_thumb_disabled_material_light 0x0\nint color switch_thumb_material_dark 0x0\nint color switch_thumb_material_light 0x0\nint color switch_thumb_normal_material_dark 0x0\nint color switch_thumb_normal_material_light 0x0\nint color test_mtrl_calendar_day 0x0\nint color test_mtrl_calendar_day_selected 0x0\nint color tooltip_background_dark 0x0\nint color tooltip_background_light 0x0\nint dimen abc_action_bar_content_inset_material 0x0\nint dimen abc_action_bar_content_inset_with_nav 0x0\nint dimen abc_action_bar_default_height_material 0x0\nint dimen abc_action_bar_default_padding_end_material 0x0\nint dimen abc_action_bar_default_padding_start_material 0x0\nint dimen abc_action_bar_elevation_material 0x0\nint dimen abc_action_bar_icon_vertical_padding_material 0x0\nint dimen abc_action_bar_overflow_padding_end_material 0x0\nint dimen abc_action_bar_overflow_padding_start_material 0x0\nint dimen abc_action_bar_stacked_max_height 0x0\nint dimen abc_action_bar_stacked_tab_max_width 0x0\nint dimen abc_action_bar_subtitle_bottom_margin_material 0x0\nint dimen abc_action_bar_subtitle_top_margin_material 0x0\nint dimen abc_action_button_min_height_material 0x0\nint dimen abc_action_button_min_width_material 0x0\nint dimen abc_action_button_min_width_overflow_material 0x0\nint dimen abc_alert_dialog_button_bar_height 0x0\nint dimen abc_alert_dialog_button_dimen 0x0\nint dimen abc_button_inset_horizontal_material 0x0\nint dimen abc_button_inset_vertical_material 0x0\nint dimen abc_button_padding_horizontal_material 0x0\nint dimen abc_button_padding_vertical_material 0x0\nint dimen abc_cascading_menus_min_smallest_width 0x0\nint dimen abc_config_prefDialogWidth 0x0\nint dimen abc_control_corner_material 0x0\nint dimen abc_control_inset_material 0x0\nint dimen abc_control_padding_material 0x0\nint dimen abc_dialog_corner_radius_material 0x0\nint dimen abc_dialog_fixed_height_major 0x0\nint dimen abc_dialog_fixed_height_minor 0x0\nint dimen abc_dialog_fixed_width_major 0x0\nint dimen abc_dialog_fixed_width_minor 0x0\nint dimen abc_dialog_list_padding_bottom_no_buttons 0x0\nint dimen abc_dialog_list_padding_top_no_title 0x0\nint dimen abc_dialog_min_width_major 0x0\nint dimen abc_dialog_min_width_minor 0x0\nint dimen abc_dialog_padding_material 0x0\nint dimen abc_dialog_padding_top_material 0x0\nint dimen abc_dialog_title_divider_material 0x0\nint dimen abc_disabled_alpha_material_dark 0x0\nint dimen abc_disabled_alpha_material_light 0x0\nint dimen abc_dropdownitem_icon_width 0x0\nint dimen abc_dropdownitem_text_padding_left 0x0\nint dimen abc_dropdownitem_text_padding_right 0x0\nint dimen abc_edit_text_inset_bottom_material 0x0\nint dimen abc_edit_text_inset_horizontal_material 0x0\nint dimen abc_edit_text_inset_top_material 0x0\nint dimen abc_floating_window_z 0x0\nint dimen abc_list_item_height_large_material 0x0\nint dimen abc_list_item_height_material 0x0\nint dimen abc_list_item_height_small_material 0x0\nint dimen abc_list_item_padding_horizontal_material 0x0\nint dimen abc_panel_menu_list_width 0x0\nint dimen abc_progress_bar_height_material 0x0\nint dimen abc_search_view_preferred_height 0x0\nint dimen abc_search_view_preferred_width 0x0\nint dimen abc_seekbar_track_background_height_material 0x0\nint dimen abc_seekbar_track_progress_height_material 0x0\nint dimen abc_select_dialog_padding_start_material 0x0\nint dimen abc_switch_padding 0x0\nint dimen abc_text_size_body_1_material 0x0\nint dimen abc_text_size_body_2_material 0x0\nint dimen abc_text_size_button_material 0x0\nint dimen abc_text_size_caption_material 0x0\nint dimen abc_text_size_display_1_material 0x0\nint dimen abc_text_size_display_2_material 0x0\nint dimen abc_text_size_display_3_material 0x0\nint dimen abc_text_size_display_4_material 0x0\nint dimen abc_text_size_headline_material 0x0\nint dimen abc_text_size_large_material 0x0\nint dimen abc_text_size_medium_material 0x0\nint dimen abc_text_size_menu_header_material 0x0\nint dimen abc_text_size_menu_material 0x0\nint dimen abc_text_size_small_material 0x0\nint dimen abc_text_size_subhead_material 0x0\nint dimen abc_text_size_subtitle_material_toolbar 0x0\nint dimen abc_text_size_title_material 0x0\nint dimen abc_text_size_title_material_toolbar 0x0\nint dimen action_bar_size 0x0\nint dimen appcompat_dialog_background_inset 0x0\nint dimen cardview_compat_inset_shadow 0x0\nint dimen cardview_default_elevation 0x0\nint dimen cardview_default_radius 0x0\nint dimen clock_face_margin_start 0x0\nint dimen compat_button_inset_horizontal_material 0x0\nint dimen compat_button_inset_vertical_material 0x0\nint dimen compat_button_padding_horizontal_material 0x0\nint dimen compat_button_padding_vertical_material 0x0\nint dimen compat_control_corner_material 0x0\nint dimen compat_notification_large_icon_max_height 0x0\nint dimen compat_notification_large_icon_max_width 0x0\nint dimen default_dimension 0x0\nint dimen design_appbar_elevation 0x0\nint dimen design_bottom_navigation_active_item_max_width 0x0\nint dimen design_bottom_navigation_active_item_min_width 0x0\nint dimen design_bottom_navigation_active_text_size 0x0\nint dimen design_bottom_navigation_elevation 0x0\nint dimen design_bottom_navigation_height 0x0\nint dimen design_bottom_navigation_icon_size 0x0\nint dimen design_bottom_navigation_item_max_width 0x0\nint dimen design_bottom_navigation_item_min_width 0x0\nint dimen design_bottom_navigation_label_padding 0x0\nint dimen design_bottom_navigation_margin 0x0\nint dimen design_bottom_navigation_shadow_height 0x0\nint dimen design_bottom_navigation_text_size 0x0\nint dimen design_bottom_sheet_elevation 0x0\nint dimen design_bottom_sheet_modal_elevation 0x0\nint dimen design_bottom_sheet_peek_height_min 0x0\nint dimen design_fab_border_width 0x0\nint dimen design_fab_elevation 0x0\nint dimen design_fab_image_size 0x0\nint dimen design_fab_size_mini 0x0\nint dimen design_fab_size_normal 0x0\nint dimen design_fab_translation_z_hovered_focused 0x0\nint dimen design_fab_translation_z_pressed 0x0\nint dimen design_navigation_elevation 0x0\nint dimen design_navigation_icon_padding 0x0\nint dimen design_navigation_icon_size 0x0\nint dimen design_navigation_item_horizontal_padding 0x0\nint dimen design_navigation_item_icon_padding 0x0\nint dimen design_navigation_max_width 0x0\nint dimen design_navigation_padding_bottom 0x0\nint dimen design_navigation_separator_vertical_padding 0x0\nint dimen design_snackbar_action_inline_max_width 0x0\nint dimen design_snackbar_action_text_color_alpha 0x0\nint dimen design_snackbar_background_corner_radius 0x0\nint dimen design_snackbar_elevation 0x0\nint dimen design_snackbar_extra_spacing_horizontal 0x0\nint dimen design_snackbar_max_width 0x0\nint dimen design_snackbar_min_width 0x0\nint dimen design_snackbar_padding_horizontal 0x0\nint dimen design_snackbar_padding_vertical 0x0\nint dimen design_snackbar_padding_vertical_2lines 0x0\nint dimen design_snackbar_text_size 0x0\nint dimen design_tab_max_width 0x0\nint dimen design_tab_scrollable_min_width 0x0\nint dimen design_tab_text_size 0x0\nint dimen design_tab_text_size_2line 0x0\nint dimen design_textinput_caption_translate_y 0x0\nint dimen disabled_alpha_material_dark 0x0\nint dimen disabled_alpha_material_light 0x0\nint dimen fastscroll_default_thickness 0x0\nint dimen fastscroll_margin 0x0\nint dimen fastscroll_minimum_range 0x0\nint dimen highlight_alpha_material_colored 0x0\nint dimen highlight_alpha_material_dark 0x0\nint dimen highlight_alpha_material_light 0x0\nint dimen hint_alpha_material_dark 0x0\nint dimen hint_alpha_material_light 0x0\nint dimen hint_pressed_alpha_material_dark 0x0\nint dimen hint_pressed_alpha_material_light 0x0\nint dimen item_touch_helper_max_drag_scroll_per_frame 0x0\nint dimen item_touch_helper_swipe_escape_max_velocity 0x0\nint dimen item_touch_helper_swipe_escape_velocity 0x0\nint dimen material_clock_display_padding 0x0\nint dimen material_clock_face_margin_top 0x0\nint dimen material_clock_hand_center_dot_radius 0x0\nint dimen material_clock_hand_padding 0x0\nint dimen material_clock_hand_stroke_width 0x0\nint dimen material_clock_number_text_size 0x0\nint dimen material_clock_period_toggle_height 0x0\nint dimen material_clock_period_toggle_margin_left 0x0\nint dimen material_clock_period_toggle_width 0x0\nint dimen material_clock_size 0x0\nint dimen material_cursor_inset_bottom 0x0\nint dimen material_cursor_inset_top 0x0\nint dimen material_cursor_width 0x0\nint dimen material_emphasis_disabled 0x0\nint dimen material_emphasis_high_type 0x0\nint dimen material_emphasis_medium 0x0\nint dimen material_filled_edittext_font_1_3_padding_bottom 0x0\nint dimen material_filled_edittext_font_1_3_padding_top 0x0\nint dimen material_filled_edittext_font_2_0_padding_bottom 0x0\nint dimen material_filled_edittext_font_2_0_padding_top 0x0\nint dimen material_font_1_3_box_collapsed_padding_top 0x0\nint dimen material_font_2_0_box_collapsed_padding_top 0x0\nint dimen material_helper_text_default_padding_top 0x0\nint dimen material_helper_text_font_1_3_padding_horizontal 0x0\nint dimen material_helper_text_font_1_3_padding_top 0x0\nint dimen material_input_text_to_prefix_suffix_padding 0x0\nint dimen material_text_view_test_line_height 0x0\nint dimen material_text_view_test_line_height_override 0x0\nint dimen material_timepicker_dialog_buttons_margin_top 0x0\nint dimen mtrl_alert_dialog_background_inset_bottom 0x0\nint dimen mtrl_alert_dialog_background_inset_end 0x0\nint dimen mtrl_alert_dialog_background_inset_start 0x0\nint dimen mtrl_alert_dialog_background_inset_top 0x0\nint dimen mtrl_alert_dialog_picker_background_inset 0x0\nint dimen mtrl_badge_horizontal_edge_offset 0x0\nint dimen mtrl_badge_long_text_horizontal_padding 0x0\nint dimen mtrl_badge_radius 0x0\nint dimen mtrl_badge_text_horizontal_edge_offset 0x0\nint dimen mtrl_badge_text_size 0x0\nint dimen mtrl_badge_toolbar_action_menu_item_horizontal_offset 0x0\nint dimen mtrl_badge_toolbar_action_menu_item_vertical_offset 0x0\nint dimen mtrl_badge_with_text_radius 0x0\nint dimen mtrl_bottomappbar_fabOffsetEndMode 0x0\nint dimen mtrl_bottomappbar_fab_bottom_margin 0x0\nint dimen mtrl_bottomappbar_fab_cradle_margin 0x0\nint dimen mtrl_bottomappbar_fab_cradle_rounded_corner_radius 0x0\nint dimen mtrl_bottomappbar_fab_cradle_vertical_offset 0x0\nint dimen mtrl_bottomappbar_height 0x0\nint dimen mtrl_btn_corner_radius 0x0\nint dimen mtrl_btn_dialog_btn_min_width 0x0\nint dimen mtrl_btn_disabled_elevation 0x0\nint dimen mtrl_btn_disabled_z 0x0\nint dimen mtrl_btn_elevation 0x0\nint dimen mtrl_btn_focused_z 0x0\nint dimen mtrl_btn_hovered_z 0x0\nint dimen mtrl_btn_icon_btn_padding_left 0x0\nint dimen mtrl_btn_icon_padding 0x0\nint dimen mtrl_btn_inset 0x0\nint dimen mtrl_btn_letter_spacing 0x0\nint dimen mtrl_btn_padding_bottom 0x0\nint dimen mtrl_btn_padding_left 0x0\nint dimen mtrl_btn_padding_right 0x0\nint dimen mtrl_btn_padding_top 0x0\nint dimen mtrl_btn_pressed_z 0x0\nint dimen mtrl_btn_snackbar_margin_horizontal 0x0\nint dimen mtrl_btn_stroke_size 0x0\nint dimen mtrl_btn_text_btn_icon_padding 0x0\nint dimen mtrl_btn_text_btn_padding_left 0x0\nint dimen mtrl_btn_text_btn_padding_right 0x0\nint dimen mtrl_btn_text_size 0x0\nint dimen mtrl_btn_z 0x0\nint dimen mtrl_calendar_action_confirm_button_min_width 0x0\nint dimen mtrl_calendar_action_height 0x0\nint dimen mtrl_calendar_action_padding 0x0\nint dimen mtrl_calendar_bottom_padding 0x0\nint dimen mtrl_calendar_content_padding 0x0\nint dimen mtrl_calendar_day_corner 0x0\nint dimen mtrl_calendar_day_height 0x0\nint dimen mtrl_calendar_day_horizontal_padding 0x0\nint dimen mtrl_calendar_day_today_stroke 0x0\nint dimen mtrl_calendar_day_vertical_padding 0x0\nint dimen mtrl_calendar_day_width 0x0\nint dimen mtrl_calendar_days_of_week_height 0x0\nint dimen mtrl_calendar_dialog_background_inset 0x0\nint dimen mtrl_calendar_header_content_padding 0x0\nint dimen mtrl_calendar_header_content_padding_fullscreen 0x0\nint dimen mtrl_calendar_header_divider_thickness 0x0\nint dimen mtrl_calendar_header_height 0x0\nint dimen mtrl_calendar_header_height_fullscreen 0x0\nint dimen mtrl_calendar_header_selection_line_height 0x0\nint dimen mtrl_calendar_header_text_padding 0x0\nint dimen mtrl_calendar_header_toggle_margin_bottom 0x0\nint dimen mtrl_calendar_header_toggle_margin_top 0x0\nint dimen mtrl_calendar_landscape_header_width 0x0\nint dimen mtrl_calendar_maximum_default_fullscreen_minor_axis 0x0\nint dimen mtrl_calendar_month_horizontal_padding 0x0\nint dimen mtrl_calendar_month_vertical_padding 0x0\nint dimen mtrl_calendar_navigation_bottom_padding 0x0\nint dimen mtrl_calendar_navigation_height 0x0\nint dimen mtrl_calendar_navigation_top_padding 0x0\nint dimen mtrl_calendar_pre_l_text_clip_padding 0x0\nint dimen mtrl_calendar_selection_baseline_to_top_fullscreen 0x0\nint dimen mtrl_calendar_selection_text_baseline_to_bottom 0x0\nint dimen mtrl_calendar_selection_text_baseline_to_bottom_fullscreen 0x0\nint dimen mtrl_calendar_selection_text_baseline_to_top 0x0\nint dimen mtrl_calendar_text_input_padding_top 0x0\nint dimen mtrl_calendar_title_baseline_to_top 0x0\nint dimen mtrl_calendar_title_baseline_to_top_fullscreen 0x0\nint dimen mtrl_calendar_year_corner 0x0\nint dimen mtrl_calendar_year_height 0x0\nint dimen mtrl_calendar_year_horizontal_padding 0x0\nint dimen mtrl_calendar_year_vertical_padding 0x0\nint dimen mtrl_calendar_year_width 0x0\nint dimen mtrl_card_checked_icon_margin 0x0\nint dimen mtrl_card_checked_icon_size 0x0\nint dimen mtrl_card_corner_radius 0x0\nint dimen mtrl_card_dragged_z 0x0\nint dimen mtrl_card_elevation 0x0\nint dimen mtrl_card_spacing 0x0\nint dimen mtrl_chip_pressed_translation_z 0x0\nint dimen mtrl_chip_text_size 0x0\nint dimen mtrl_edittext_rectangle_top_offset 0x0\nint dimen mtrl_exposed_dropdown_menu_popup_elevation 0x0\nint dimen mtrl_exposed_dropdown_menu_popup_vertical_offset 0x0\nint dimen mtrl_exposed_dropdown_menu_popup_vertical_padding 0x0\nint dimen mtrl_extended_fab_bottom_padding 0x0\nint dimen mtrl_extended_fab_corner_radius 0x0\nint dimen mtrl_extended_fab_disabled_elevation 0x0\nint dimen mtrl_extended_fab_disabled_translation_z 0x0\nint dimen mtrl_extended_fab_elevation 0x0\nint dimen mtrl_extended_fab_end_padding 0x0\nint dimen mtrl_extended_fab_end_padding_icon 0x0\nint dimen mtrl_extended_fab_icon_size 0x0\nint dimen mtrl_extended_fab_icon_text_spacing 0x0\nint dimen mtrl_extended_fab_min_height 0x0\nint dimen mtrl_extended_fab_min_width 0x0\nint dimen mtrl_extended_fab_start_padding 0x0\nint dimen mtrl_extended_fab_start_padding_icon 0x0\nint dimen mtrl_extended_fab_top_padding 0x0\nint dimen mtrl_extended_fab_translation_z_base 0x0\nint dimen mtrl_extended_fab_translation_z_hovered_focused 0x0\nint dimen mtrl_extended_fab_translation_z_pressed 0x0\nint dimen mtrl_fab_elevation 0x0\nint dimen mtrl_fab_min_touch_target 0x0\nint dimen mtrl_fab_translation_z_hovered_focused 0x0\nint dimen mtrl_fab_translation_z_pressed 0x0\nint dimen mtrl_high_ripple_default_alpha 0x0\nint dimen mtrl_high_ripple_focused_alpha 0x0\nint dimen mtrl_high_ripple_hovered_alpha 0x0\nint dimen mtrl_high_ripple_pressed_alpha 0x0\nint dimen mtrl_large_touch_target 0x0\nint dimen mtrl_low_ripple_default_alpha 0x0\nint dimen mtrl_low_ripple_focused_alpha 0x0\nint dimen mtrl_low_ripple_hovered_alpha 0x0\nint dimen mtrl_low_ripple_pressed_alpha 0x0\nint dimen mtrl_min_touch_target_size 0x0\nint dimen mtrl_navigation_elevation 0x0\nint dimen mtrl_navigation_item_horizontal_padding 0x0\nint dimen mtrl_navigation_item_icon_padding 0x0\nint dimen mtrl_navigation_item_icon_size 0x0\nint dimen mtrl_navigation_item_shape_horizontal_margin 0x0\nint dimen mtrl_navigation_item_shape_vertical_margin 0x0\nint dimen mtrl_progress_circular_inset 0x0\nint dimen mtrl_progress_circular_inset_extra_small 0x0\nint dimen mtrl_progress_circular_inset_medium 0x0\nint dimen mtrl_progress_circular_inset_small 0x0\nint dimen mtrl_progress_circular_radius 0x0\nint dimen mtrl_progress_circular_size 0x0\nint dimen mtrl_progress_circular_size_extra_small 0x0\nint dimen mtrl_progress_circular_size_medium 0x0\nint dimen mtrl_progress_circular_size_small 0x0\nint dimen mtrl_progress_circular_track_thickness_extra_small 0x0\nint dimen mtrl_progress_circular_track_thickness_medium 0x0\nint dimen mtrl_progress_circular_track_thickness_small 0x0\nint dimen mtrl_progress_indicator_full_rounded_corner_radius 0x0\nint dimen mtrl_progress_track_thickness 0x0\nint dimen mtrl_shape_corner_size_large_component 0x0\nint dimen mtrl_shape_corner_size_medium_component 0x0\nint dimen mtrl_shape_corner_size_small_component 0x0\nint dimen mtrl_slider_halo_radius 0x0\nint dimen mtrl_slider_label_padding 0x0\nint dimen mtrl_slider_label_radius 0x0\nint dimen mtrl_slider_label_square_side 0x0\nint dimen mtrl_slider_thumb_elevation 0x0\nint dimen mtrl_slider_thumb_radius 0x0\nint dimen mtrl_slider_track_height 0x0\nint dimen mtrl_slider_track_side_padding 0x0\nint dimen mtrl_slider_track_top 0x0\nint dimen mtrl_slider_widget_height 0x0\nint dimen mtrl_snackbar_action_text_color_alpha 0x0\nint dimen mtrl_snackbar_background_corner_radius 0x0\nint dimen mtrl_snackbar_background_overlay_color_alpha 0x0\nint dimen mtrl_snackbar_margin 0x0\nint dimen mtrl_snackbar_message_margin_horizontal 0x0\nint dimen mtrl_snackbar_padding_horizontal 0x0\nint dimen mtrl_switch_thumb_elevation 0x0\nint dimen mtrl_textinput_box_corner_radius_medium 0x0\nint dimen mtrl_textinput_box_corner_radius_small 0x0\nint dimen mtrl_textinput_box_label_cutout_padding 0x0\nint dimen mtrl_textinput_box_stroke_width_default 0x0\nint dimen mtrl_textinput_box_stroke_width_focused 0x0\nint dimen mtrl_textinput_counter_margin_start 0x0\nint dimen mtrl_textinput_end_icon_margin_start 0x0\nint dimen mtrl_textinput_outline_box_expanded_padding 0x0\nint dimen mtrl_textinput_start_icon_margin_end 0x0\nint dimen mtrl_toolbar_default_height 0x0\nint dimen mtrl_tooltip_arrowSize 0x0\nint dimen mtrl_tooltip_cornerSize 0x0\nint dimen mtrl_tooltip_minHeight 0x0\nint dimen mtrl_tooltip_minWidth 0x0\nint dimen mtrl_tooltip_padding 0x0\nint dimen mtrl_transition_shared_axis_slide_distance 0x0\nint dimen notification_action_icon_size 0x0\nint dimen notification_action_text_size 0x0\nint dimen notification_big_circle_margin 0x0\nint dimen notification_content_margin_start 0x0\nint dimen notification_large_icon_height 0x0\nint dimen notification_large_icon_width 0x0\nint dimen notification_main_column_padding_top 0x0\nint dimen notification_media_narrow_margin 0x0\nint dimen notification_right_icon_size 0x0\nint dimen notification_right_side_padding_top 0x0\nint dimen notification_small_icon_background_padding 0x0\nint dimen notification_small_icon_size_as_large 0x0\nint dimen notification_subtext_size 0x0\nint dimen notification_top_pad 0x0\nint dimen notification_top_pad_large_text 0x0\nint dimen test_mtrl_calendar_day_cornerSize 0x0\nint dimen tooltip_corner_radius 0x0\nint dimen tooltip_horizontal_padding 0x0\nint dimen tooltip_margin 0x0\nint dimen tooltip_precise_anchor_extra_offset 0x0\nint dimen tooltip_precise_anchor_threshold 0x0\nint dimen tooltip_vertical_padding 0x0\nint dimen tooltip_y_offset_non_touch 0x0\nint dimen tooltip_y_offset_touch 0x0\nint drawable abc_ab_share_pack_mtrl_alpha 0x0\nint drawable abc_action_bar_item_background_material 0x0\nint drawable abc_btn_borderless_material 0x0\nint drawable abc_btn_check_material 0x0\nint drawable abc_btn_check_material_anim 0x0\nint drawable abc_btn_check_to_on_mtrl_000 0x0\nint drawable abc_btn_check_to_on_mtrl_015 0x0\nint drawable abc_btn_colored_material 0x0\nint drawable abc_btn_default_mtrl_shape 0x0\nint drawable abc_btn_radio_material 0x0\nint drawable abc_btn_radio_material_anim 0x0\nint drawable abc_btn_radio_to_on_mtrl_000 0x0\nint drawable abc_btn_radio_to_on_mtrl_015 0x0\nint drawable abc_btn_switch_to_on_mtrl_00001 0x0\nint drawable abc_btn_switch_to_on_mtrl_00012 0x0\nint drawable abc_cab_background_internal_bg 0x0\nint drawable abc_cab_background_top_material 0x0\nint drawable abc_cab_background_top_mtrl_alpha 0x0\nint drawable abc_control_background_material 0x0\nint drawable abc_dialog_material_background 0x0\nint drawable abc_edit_text_material 0x0\nint drawable abc_ic_ab_back_material 0x0\nint drawable abc_ic_arrow_drop_right_black_24dp 0x0\nint drawable abc_ic_clear_material 0x0\nint drawable abc_ic_commit_search_api_mtrl_alpha 0x0\nint drawable abc_ic_go_search_api_material 0x0\nint drawable abc_ic_menu_copy_mtrl_am_alpha 0x0\nint drawable abc_ic_menu_cut_mtrl_alpha 0x0\nint drawable abc_ic_menu_overflow_material 0x0\nint drawable abc_ic_menu_paste_mtrl_am_alpha 0x0\nint drawable abc_ic_menu_selectall_mtrl_alpha 0x0\nint drawable abc_ic_menu_share_mtrl_alpha 0x0\nint drawable abc_ic_search_api_material 0x0\nint drawable abc_ic_star_black_16dp 0x0\nint drawable abc_ic_star_black_36dp 0x0\nint drawable abc_ic_star_black_48dp 0x0\nint drawable abc_ic_star_half_black_16dp 0x0\nint drawable abc_ic_star_half_black_36dp 0x0\nint drawable abc_ic_star_half_black_48dp 0x0\nint drawable abc_ic_voice_search_api_material 0x0\nint drawable abc_item_background_holo_dark 0x0\nint drawable abc_item_background_holo_light 0x0\nint drawable abc_list_divider_material 0x0\nint drawable abc_list_divider_mtrl_alpha 0x0\nint drawable abc_list_focused_holo 0x0\nint drawable abc_list_longpressed_holo 0x0\nint drawable abc_list_pressed_holo_dark 0x0\nint drawable abc_list_pressed_holo_light 0x0\nint drawable abc_list_selector_background_transition_holo_dark 0x0\nint drawable abc_list_selector_background_transition_holo_light 0x0\nint drawable abc_list_selector_disabled_holo_dark 0x0\nint drawable abc_list_selector_disabled_holo_light 0x0\nint drawable abc_list_selector_holo_dark 0x0\nint drawable abc_list_selector_holo_light 0x0\nint drawable abc_menu_hardkey_panel_mtrl_mult 0x0\nint drawable abc_popup_background_mtrl_mult 0x0\nint drawable abc_ratingbar_indicator_material 0x0\nint drawable abc_ratingbar_material 0x0\nint drawable abc_ratingbar_small_material 0x0\nint drawable abc_scrubber_control_off_mtrl_alpha 0x0\nint drawable abc_scrubber_control_to_pressed_mtrl_000 0x0\nint drawable abc_scrubber_control_to_pressed_mtrl_005 0x0\nint drawable abc_scrubber_primary_mtrl_alpha 0x0\nint drawable abc_scrubber_track_mtrl_alpha 0x0\nint drawable abc_seekbar_thumb_material 0x0\nint drawable abc_seekbar_tick_mark_material 0x0\nint drawable abc_seekbar_track_material 0x0\nint drawable abc_spinner_mtrl_am_alpha 0x0\nint drawable abc_spinner_textfield_background_material 0x0\nint drawable abc_switch_thumb_material 0x0\nint drawable abc_switch_track_mtrl_alpha 0x0\nint drawable abc_tab_indicator_material 0x0\nint drawable abc_tab_indicator_mtrl_alpha 0x0\nint drawable abc_text_cursor_material 0x0\nint drawable abc_text_select_handle_left_mtrl_dark 0x0\nint drawable abc_text_select_handle_left_mtrl_light 0x0\nint drawable abc_text_select_handle_middle_mtrl_dark 0x0\nint drawable abc_text_select_handle_middle_mtrl_light 0x0\nint drawable abc_text_select_handle_right_mtrl_dark 0x0\nint drawable abc_text_select_handle_right_mtrl_light 0x0\nint drawable abc_textfield_activated_mtrl_alpha 0x0\nint drawable abc_textfield_default_mtrl_alpha 0x0\nint drawable abc_textfield_search_activated_mtrl_alpha 0x0\nint drawable abc_textfield_search_default_mtrl_alpha 0x0\nint drawable abc_textfield_search_material 0x0\nint drawable abc_vector_test 0x0\nint drawable avd_hide_password 0x0\nint drawable avd_show_password 0x0\nint drawable btn_checkbox_checked_mtrl 0x0\nint drawable btn_checkbox_checked_to_unchecked_mtrl_animation 0x0\nint drawable btn_checkbox_unchecked_mtrl 0x0\nint drawable btn_checkbox_unchecked_to_checked_mtrl_animation 0x0\nint drawable btn_radio_off_mtrl 0x0\nint drawable btn_radio_off_to_on_mtrl_animation 0x0\nint drawable btn_radio_on_mtrl 0x0\nint drawable btn_radio_on_to_off_mtrl_animation 0x0\nint drawable design_bottom_navigation_item_background 0x0\nint drawable design_fab_background 0x0\nint drawable design_ic_visibility 0x0\nint drawable design_ic_visibility_off 0x0\nint drawable design_password_eye 0x0\nint drawable design_snackbar_background 0x0\nint drawable ic_clock_black_24dp 0x0\nint drawable ic_keyboard_black_24dp 0x0\nint drawable ic_mtrl_checked_circle 0x0\nint drawable ic_mtrl_chip_checked_black 0x0\nint drawable ic_mtrl_chip_checked_circle 0x0\nint drawable ic_mtrl_chip_close_circle 0x0\nint drawable material_cursor_drawable 0x0\nint drawable material_ic_calendar_black_24dp 0x0\nint drawable material_ic_clear_black_24dp 0x0\nint drawable material_ic_edit_black_24dp 0x0\nint drawable material_ic_keyboard_arrow_left_black_24dp 0x0\nint drawable material_ic_keyboard_arrow_next_black_24dp 0x0\nint drawable material_ic_keyboard_arrow_previous_black_24dp 0x0\nint drawable material_ic_keyboard_arrow_right_black_24dp 0x0\nint drawable material_ic_menu_arrow_down_black_24dp 0x0\nint drawable material_ic_menu_arrow_up_black_24dp 0x0\nint drawable mtrl_dialog_background 0x0\nint drawable mtrl_dropdown_arrow 0x0\nint drawable mtrl_ic_arrow_drop_down 0x0\nint drawable mtrl_ic_arrow_drop_up 0x0\nint drawable mtrl_ic_cancel 0x0\nint drawable mtrl_ic_error 0x0\nint drawable mtrl_popupmenu_background 0x0\nint drawable mtrl_popupmenu_background_dark 0x0\nint drawable mtrl_tabs_default_indicator 0x0\nint drawable navigation_empty_icon 0x0\nint drawable notification_action_background 0x0\nint drawable notification_bg 0x0\nint drawable notification_bg_low 0x0\nint drawable notification_bg_low_normal 0x0\nint drawable notification_bg_low_pressed 0x0\nint drawable notification_bg_normal 0x0\nint drawable notification_bg_normal_pressed 0x0\nint drawable notification_icon_background 0x0\nint drawable notification_template_icon_bg 0x0\nint drawable notification_template_icon_low_bg 0x0\nint drawable notification_tile_bg 0x0\nint drawable notify_panel_notification_icon_bg 0x0\nint drawable test_custom_background 0x0\nint drawable tooltip_frame_dark 0x0\nint drawable tooltip_frame_light 0x0\nint id BOTTOM_END 0x0\nint id BOTTOM_START 0x0\nint id NO_DEBUG 0x0\nint id SHOW_ALL 0x0\nint id SHOW_PATH 0x0\nint id SHOW_PROGRESS 0x0\nint id TOP_END 0x0\nint id TOP_START 0x0\nint id accelerate 0x0\nint id accessibility_action_clickable_span 0x0\nint id accessibility_custom_action_0 0x0\nint id accessibility_custom_action_1 0x0\nint id accessibility_custom_action_10 0x0\nint id accessibility_custom_action_11 0x0\nint id accessibility_custom_action_12 0x0\nint id accessibility_custom_action_13 0x0\nint id accessibility_custom_action_14 0x0\nint id accessibility_custom_action_15 0x0\nint id accessibility_custom_action_16 0x0\nint id accessibility_custom_action_17 0x0\nint id accessibility_custom_action_18 0x0\nint id accessibility_custom_action_19 0x0\nint id accessibility_custom_action_2 0x0\nint id accessibility_custom_action_20 0x0\nint id accessibility_custom_action_21 0x0\nint id accessibility_custom_action_22 0x0\nint id accessibility_custom_action_23 0x0\nint id accessibility_custom_action_24 0x0\nint id accessibility_custom_action_25 0x0\nint id accessibility_custom_action_26 0x0\nint id accessibility_custom_action_27 0x0\nint id accessibility_custom_action_28 0x0\nint id accessibility_custom_action_29 0x0\nint id accessibility_custom_action_3 0x0\nint id accessibility_custom_action_30 0x0\nint id accessibility_custom_action_31 0x0\nint id accessibility_custom_action_4 0x0\nint id accessibility_custom_action_5 0x0\nint id accessibility_custom_action_6 0x0\nint id accessibility_custom_action_7 0x0\nint id accessibility_custom_action_8 0x0\nint id accessibility_custom_action_9 0x0\nint id action_bar 0x0\nint id action_bar_activity_content 0x0\nint id action_bar_container 0x0\nint id action_bar_root 0x0\nint id action_bar_spinner 0x0\nint id action_bar_subtitle 0x0\nint id action_bar_title 0x0\nint id action_container 0x0\nint id action_context_bar 0x0\nint id action_divider 0x0\nint id action_image 0x0\nint id action_menu_divider 0x0\nint id action_menu_presenter 0x0\nint id action_mode_bar 0x0\nint id action_mode_bar_stub 0x0\nint id action_mode_close_button 0x0\nint id action_text 0x0\nint id actions 0x0\nint id activity_chooser_view_content 0x0\nint id add 0x0\nint id alertTitle 0x0\nint id aligned 0x0\nint id animateToEnd 0x0\nint id animateToStart 0x0\nint id asConfigured 0x0\nint id async 0x0\nint id auto 0x0\nint id autoComplete 0x0\nint id autoCompleteToEnd 0x0\nint id autoCompleteToStart 0x0\nint id barrier 0x0\nint id baseline 0x0\nint id blocking 0x0\nint id bottom 0x0\nint id bounce 0x0\nint id buttonPanel 0x0\nint id cancel_button 0x0\nint id center 0x0\nint id chain 0x0\nint id checkbox 0x0\nint id checked 0x0\nint id chip 0x0\nint id chip1 0x0\nint id chip2 0x0\nint id chip3 0x0\nint id chip_group 0x0\nint id chronometer 0x0\nint id circle_center 0x0\nint id clear_text 0x0\nint id clockwise 0x0\nint id confirm_button 0x0\nint id container 0x0\nint id content 0x0\nint id contentPanel 0x0\nint id contiguous 0x0\nint id coordinator 0x0\nint id cos 0x0\nint id counterclockwise 0x0\nint id custom 0x0\nint id customPanel 0x0\nint id cut 0x0\nint id date_picker_actions 0x0\nint id decelerate 0x0\nint id decelerateAndComplete 0x0\nint id decor_content_parent 0x0\nint id default_activity_button 0x0\nint id deltaRelative 0x0\nint id design_bottom_sheet 0x0\nint id design_menu_item_action_area 0x0\nint id design_menu_item_action_area_stub 0x0\nint id design_menu_item_text 0x0\nint id design_navigation_view 0x0\nint id dialog_button 0x0\nint id disjoint 0x0\nint id dragDown 0x0\nint id dragEnd 0x0\nint id dragLeft 0x0\nint id dragRight 0x0\nint id dragStart 0x0\nint id dragUp 0x0\nint id dropdown_menu 0x0\nint id easeIn 0x0\nint id easeInOut 0x0\nint id easeOut 0x0\nint id edit_query 0x0\nint id elastic 0x0\nint id end 0x0\nint id endToStart 0x0\nint id expand_activities_button 0x0\nint id expanded_menu 0x0\nint id fade 0x0\nint id fill 0x0\nint id filled 0x0\nint id fixed 0x0\nint id flip 0x0\nint id floating 0x0\nint id forever 0x0\nint id function_name_tv 0x0\nint id ghost_view 0x0\nint id ghost_view_holder 0x0\nint id gone 0x0\nint id group_divider 0x0\nint id guideline 0x0\nint id header_title 0x0\nint id home 0x0\nint id honorRequest 0x0\nint id icon 0x0\nint id icon_group 0x0\nint id ignore 0x0\nint id ignoreRequest 0x0\nint id image 0x0\nint id info 0x0\nint id invisible 0x0\nint id inward 0x0\nint id italic 0x0\nint id item_touch_helper_previous_elevation 0x0\nint id jumpToEnd 0x0\nint id jumpToStart 0x0\nint id labelGroup 0x0\nint id labeled 0x0\nint id largeLabel 0x0\nint id layout 0x0\nint id left 0x0\nint id leftToRight 0x0\nint id line1 0x0\nint id line3 0x0\nint id linear 0x0\nint id listMode 0x0\nint id list_item 0x0\nint id masked 0x0\nint id material_clock_display 0x0\nint id material_clock_face 0x0\nint id material_clock_hand 0x0\nint id material_clock_period_am_button 0x0\nint id material_clock_period_pm_button 0x0\nint id material_clock_period_toggle 0x0\nint id material_hour_text_input 0x0\nint id material_hour_tv 0x0\nint id material_label 0x0\nint id material_minute_text_input 0x0\nint id material_minute_tv 0x0\nint id material_textinput_timepicker 0x0\nint id material_timepicker_cancel_button 0x0\nint id material_timepicker_container 0x0\nint id material_timepicker_edit_text 0x0\nint id material_timepicker_mode_button 0x0\nint id material_timepicker_ok_button 0x0\nint id material_timepicker_view 0x0\nint id material_value_index 0x0\nint id message 0x0\nint id middle 0x0\nint id mini 0x0\nint id month_grid 0x0\nint id month_navigation_bar 0x0\nint id month_navigation_fragment_toggle 0x0\nint id month_navigation_next 0x0\nint id month_navigation_previous 0x0\nint id month_title 0x0\nint id motion_base 0x0\nint id mtrl_anchor_parent 0x0\nint id mtrl_calendar_day_selector_frame 0x0\nint id mtrl_calendar_days_of_week 0x0\nint id mtrl_calendar_frame 0x0\nint id mtrl_calendar_main_pane 0x0\nint id mtrl_calendar_months 0x0\nint id mtrl_calendar_selection_frame 0x0\nint id mtrl_calendar_text_input_frame 0x0\nint id mtrl_calendar_year_selector_frame 0x0\nint id mtrl_card_checked_layer_id 0x0\nint id mtrl_child_content_container 0x0\nint id mtrl_internal_children_alpha_tag 0x0\nint id mtrl_motion_snapshot_view 0x0\nint id mtrl_picker_fullscreen 0x0\nint id mtrl_picker_header 0x0\nint id mtrl_picker_header_selection_text 0x0\nint id mtrl_picker_header_title_and_selection 0x0\nint id mtrl_picker_header_toggle 0x0\nint id mtrl_picker_text_input_date 0x0\nint id mtrl_picker_text_input_range_end 0x0\nint id mtrl_picker_text_input_range_start 0x0\nint id mtrl_picker_title_text 0x0\nint id mtrl_view_tag_bottom_padding 0x0\nint id multiply 0x0\nint id navigation_header_container 0x0\nint id none 0x0\nint id normal 0x0\nint id notification_background 0x0\nint id notification_main_column 0x0\nint id notification_main_column_container 0x0\nint id off 0x0\nint id on 0x0\nint id origin_count_tv 0x0\nint id origin_method_tv 0x0\nint id outline 0x0\nint id outward 0x0\nint id packed 0x0\nint id parallax 0x0\nint id parent 0x0\nint id parentPanel 0x0\nint id parentRelative 0x0\nint id parent_matrix 0x0\nint id password_toggle 0x0\nint id path 0x0\nint id pathRelative 0x0\nint id percent 0x0\nint id permission_desc_tv 0x0\nint id permission_tv 0x0\nint id pin 0x0\nint id position 0x0\nint id postLayout 0x0\nint id progress_circular 0x0\nint id progress_horizontal 0x0\nint id radio 0x0\nint id rectangles 0x0\nint id reverseSawtooth 0x0\nint id right 0x0\nint id rightToLeft 0x0\nint id right_icon 0x0\nint id right_side 0x0\nint id rounded 0x0\nint id row_index_key 0x0\nint id save_non_transition_alpha 0x0\nint id save_overlay_view 0x0\nint id sawtooth 0x0\nint id scale 0x0\nint id screen 0x0\nint id scrollIndicatorDown 0x0\nint id scrollIndicatorUp 0x0\nint id scrollView 0x0\nint id scrollable 0x0\nint id search_badge 0x0\nint id search_bar 0x0\nint id search_button 0x0\nint id search_close_btn 0x0\nint id search_edit_frame 0x0\nint id search_go_btn 0x0\nint id search_mag_icon 0x0\nint id search_plate 0x0\nint id search_src_text 0x0\nint id search_voice_btn 0x0\nint id select_dialog_listview 0x0\nint id selected 0x0\nint id selection_type 0x0\nint id shortcut 0x0\nint id sin 0x0\nint id slide 0x0\nint id smallLabel 0x0\nint id snackbar_action 0x0\nint id snackbar_text 0x0\nint id spacer 0x0\nint id spline 0x0\nint id split_action_bar 0x0\nint id spread 0x0\nint id spread_inside 0x0\nint id square 0x0\nint id src_atop 0x0\nint id src_in 0x0\nint id src_over 0x0\nint id standard 0x0\nint id start 0x0\nint id startHorizontal 0x0\nint id startToEnd 0x0\nint id startVertical 0x0\nint id staticLayout 0x0\nint id staticPostLayout 0x0\nint id stop 0x0\nint id stretch 0x0\nint id submenuarrow 0x0\nint id submit_area 0x0\nint id tabMode 0x0\nint id tag_accessibility_actions 0x0\nint id tag_accessibility_clickable_spans 0x0\nint id tag_accessibility_heading 0x0\nint id tag_accessibility_pane_title 0x0\nint id tag_screen_reader_focusable 0x0\nint id tag_transition_group 0x0\nint id tag_unhandled_key_event_manager 0x0\nint id tag_unhandled_key_listeners 0x0\nint id test_checkbox_android_button_tint 0x0\nint id test_checkbox_app_button_tint 0x0\nint id test_radiobutton_android_button_tint 0x0\nint id test_radiobutton_app_button_tint 0x0\nint id text 0x0\nint id text2 0x0\nint id textSpacerNoButtons 0x0\nint id textSpacerNoTitle 0x0\nint id text_input_end_icon 0x0\nint id text_input_error_icon 0x0\nint id text_input_start_icon 0x0\nint id textinput_counter 0x0\nint id textinput_error 0x0\nint id textinput_helper_text 0x0\nint id textinput_placeholder 0x0\nint id textinput_prefix_text 0x0\nint id textinput_suffix_text 0x0\nint id time 0x0\nint id time_tv 0x0\nint id title 0x0\nint id titleDividerNoCustom 0x0\nint id title_template 0x0\nint id top 0x0\nint id topPanel 0x0\nint id touch_outside 0x0\nint id transition_current_scene 0x0\nint id transition_layout_save 0x0\nint id transition_position 0x0\nint id transition_scene_layoutid_cache 0x0\nint id transition_transform 0x0\nint id triangle 0x0\nint id unchecked 0x0\nint id uniform 0x0\nint id unlabeled 0x0\nint id up 0x0\nint id view_offset_helper 0x0\nint id visible 0x0\nint id withinBounds 0x0\nint id wrap 0x0\nint id wrap_content 0x0\nint id zero_corner_chip 0x0\nint integer abc_config_activityDefaultDur 0x0\nint integer abc_config_activityShortDur 0x0\nint integer app_bar_elevation_anim_duration 0x0\nint integer bottom_sheet_slide_duration 0x0\nint integer cancel_button_image_alpha 0x0\nint integer config_tooltipAnimTime 0x0\nint integer design_snackbar_text_max_lines 0x0\nint integer design_tab_indicator_anim_duration_ms 0x0\nint integer hide_password_duration 0x0\nint integer mtrl_badge_max_character_count 0x0\nint integer mtrl_btn_anim_delay_ms 0x0\nint integer mtrl_btn_anim_duration_ms 0x0\nint integer mtrl_calendar_header_orientation 0x0\nint integer mtrl_calendar_selection_text_lines 0x0\nint integer mtrl_calendar_year_selector_span 0x0\nint integer mtrl_card_anim_delay_ms 0x0\nint integer mtrl_card_anim_duration_ms 0x0\nint integer mtrl_chip_anim_duration 0x0\nint integer mtrl_tab_indicator_anim_duration_ms 0x0\nint integer show_password_duration 0x0\nint integer status_bar_notification_info_maxnum 0x0\nint interpolator btn_checkbox_checked_mtrl_animation_interpolator_0 0x0\nint interpolator btn_checkbox_checked_mtrl_animation_interpolator_1 0x0\nint interpolator btn_checkbox_unchecked_mtrl_animation_interpolator_0 0x0\nint interpolator btn_checkbox_unchecked_mtrl_animation_interpolator_1 0x0\nint interpolator btn_radio_to_off_mtrl_animation_interpolator_0 0x0\nint interpolator btn_radio_to_on_mtrl_animation_interpolator_0 0x0\nint interpolator fast_out_slow_in 0x0\nint interpolator mtrl_fast_out_linear_in 0x0\nint interpolator mtrl_fast_out_slow_in 0x0\nint interpolator mtrl_linear 0x0\nint interpolator mtrl_linear_out_slow_in 0x0\nint layout abc_action_bar_title_item 0x0\nint layout abc_action_bar_up_container 0x0\nint layout abc_action_menu_item_layout 0x0\nint layout abc_action_menu_layout 0x0\nint layout abc_action_mode_bar 0x0\nint layout abc_action_mode_close_item_material 0x0\nint layout abc_activity_chooser_view 0x0\nint layout abc_activity_chooser_view_list_item 0x0\nint layout abc_alert_dialog_button_bar_material 0x0\nint layout abc_alert_dialog_material 0x0\nint layout abc_alert_dialog_title_material 0x0\nint layout abc_cascading_menu_item_layout 0x0\nint layout abc_dialog_title_material 0x0\nint layout abc_expanded_menu_layout 0x0\nint layout abc_list_menu_item_checkbox 0x0\nint layout abc_list_menu_item_icon 0x0\nint layout abc_list_menu_item_layout 0x0\nint layout abc_list_menu_item_radio 0x0\nint layout abc_popup_menu_header_item_layout 0x0\nint layout abc_popup_menu_item_layout 0x0\nint layout abc_screen_content_include 0x0\nint layout abc_screen_simple 0x0\nint layout abc_screen_simple_overlay_action_mode 0x0\nint layout abc_screen_toolbar 0x0\nint layout abc_search_dropdown_item_icons_2line 0x0\nint layout abc_search_view 0x0\nint layout abc_select_dialog_material 0x0\nint layout abc_tooltip 0x0\nint layout activity_permission_list 0x0\nint layout activity_real_time_privacy_item 0x0\nint layout activity_replace_list 0x0\nint layout custom_dialog 0x0\nint layout design_bottom_navigation_item 0x0\nint layout design_bottom_sheet_dialog 0x0\nint layout design_layout_snackbar 0x0\nint layout design_layout_snackbar_include 0x0\nint layout design_layout_tab_icon 0x0\nint layout design_layout_tab_text 0x0\nint layout design_menu_item_action_area 0x0\nint layout design_navigation_item 0x0\nint layout design_navigation_item_header 0x0\nint layout design_navigation_item_separator 0x0\nint layout design_navigation_item_subheader 0x0\nint layout design_navigation_menu 0x0\nint layout design_navigation_menu_item 0x0\nint layout design_text_input_end_icon 0x0\nint layout design_text_input_start_icon 0x0\nint layout material_chip_input_combo 0x0\nint layout material_clock_display 0x0\nint layout material_clock_display_divider 0x0\nint layout material_clock_period_toggle 0x0\nint layout material_clock_period_toggle_land 0x0\nint layout material_clockface_textview 0x0\nint layout material_clockface_view 0x0\nint layout material_radial_view_group 0x0\nint layout material_textinput_timepicker 0x0\nint layout material_time_chip 0x0\nint layout material_time_input 0x0\nint layout material_timepicker 0x0\nint layout material_timepicker_dialog 0x0\nint layout material_timepicker_textinput_display 0x0\nint layout mtrl_alert_dialog 0x0\nint layout mtrl_alert_dialog_actions 0x0\nint layout mtrl_alert_dialog_title 0x0\nint layout mtrl_alert_select_dialog_item 0x0\nint layout mtrl_alert_select_dialog_multichoice 0x0\nint layout mtrl_alert_select_dialog_singlechoice 0x0\nint layout mtrl_calendar_day 0x0\nint layout mtrl_calendar_day_of_week 0x0\nint layout mtrl_calendar_days_of_week 0x0\nint layout mtrl_calendar_horizontal 0x0\nint layout mtrl_calendar_month 0x0\nint layout mtrl_calendar_month_labeled 0x0\nint layout mtrl_calendar_month_navigation 0x0\nint layout mtrl_calendar_months 0x0\nint layout mtrl_calendar_vertical 0x0\nint layout mtrl_calendar_year 0x0\nint layout mtrl_layout_snackbar 0x0\nint layout mtrl_layout_snackbar_include 0x0\nint layout mtrl_picker_actions 0x0\nint layout mtrl_picker_dialog 0x0\nint layout mtrl_picker_fullscreen 0x0\nint layout mtrl_picker_header_dialog 0x0\nint layout mtrl_picker_header_fullscreen 0x0\nint layout mtrl_picker_header_selection_text 0x0\nint layout mtrl_picker_header_title_text 0x0\nint layout mtrl_picker_header_toggle 0x0\nint layout mtrl_picker_text_input_date 0x0\nint layout mtrl_picker_text_input_date_range 0x0\nint layout notification_action 0x0\nint layout notification_action_tombstone 0x0\nint layout notification_template_custom_big 0x0\nint layout notification_template_icon_group 0x0\nint layout notification_template_part_chronometer 0x0\nint layout notification_template_part_time 0x0\nint layout permission_item_view 0x0\nint layout real_tile_item_view 0x0\nint layout replace_item_view 0x0\nint layout select_dialog_item_material 0x0\nint layout select_dialog_multichoice_material 0x0\nint layout select_dialog_singlechoice_material 0x0\nint layout support_simple_spinner_dropdown_item 0x0\nint layout test_action_chip 0x0\nint layout test_chip_zero_corner_radius 0x0\nint layout test_design_checkbox 0x0\nint layout test_design_radiobutton 0x0\nint layout test_reflow_chipgroup 0x0\nint layout test_toolbar 0x0\nint layout test_toolbar_custom_background 0x0\nint layout test_toolbar_elevation 0x0\nint layout test_toolbar_surface 0x0\nint layout text_view_with_line_height_from_appearance 0x0\nint layout text_view_with_line_height_from_layout 0x0\nint layout text_view_with_line_height_from_style 0x0\nint layout text_view_with_theme_line_height 0x0\nint layout text_view_without_line_height 0x0\nint plurals mtrl_badge_content_description 0x0\nint string abc_action_bar_home_description 0x0\nint string abc_action_bar_up_description 0x0\nint string abc_action_menu_overflow_description 0x0\nint string abc_action_mode_done 0x0\nint string abc_activity_chooser_view_see_all 0x0\nint string abc_activitychooserview_choose_application 0x0\nint string abc_capital_off 0x0\nint string abc_capital_on 0x0\nint string abc_menu_alt_shortcut_label 0x0\nint string abc_menu_ctrl_shortcut_label 0x0\nint string abc_menu_delete_shortcut_label 0x0\nint string abc_menu_enter_shortcut_label 0x0\nint string abc_menu_function_shortcut_label 0x0\nint string abc_menu_meta_shortcut_label 0x0\nint string abc_menu_shift_shortcut_label 0x0\nint string abc_menu_space_shortcut_label 0x0\nint string abc_menu_sym_shortcut_label 0x0\nint string abc_prepend_shortcut_label 0x0\nint string abc_search_hint 0x0\nint string abc_searchview_description_clear 0x0\nint string abc_searchview_description_query 0x0\nint string abc_searchview_description_search 0x0\nint string abc_searchview_description_submit 0x0\nint string abc_searchview_description_voice 0x0\nint string abc_shareactionprovider_share_with 0x0\nint string abc_shareactionprovider_share_with_application 0x0\nint string abc_toolbar_collapse_description 0x0\nint string appbar_scrolling_view_behavior 0x0\nint string bottom_sheet_behavior 0x0\nint string bottomsheet_action_expand_halfway 0x0\nint string character_counter_content_description 0x0\nint string character_counter_overflowed_content_description 0x0\nint string character_counter_pattern 0x0\nint string chip_text 0x0\nint string clear_text_end_icon_content_description 0x0\nint string error_icon_content_description 0x0\nint string exposed_dropdown_menu_content_description 0x0\nint string fab_transformation_scrim_behavior 0x0\nint string fab_transformation_sheet_behavior 0x0\nint string hide_bottom_view_on_scroll_behavior 0x0\nint string icon_content_description 0x0\nint string item_view_role_description 0x0\nint string material_clock_display_divider 0x0\nint string material_clock_toggle_content_description 0x0\nint string material_hour_selection 0x0\nint string material_hour_suffix 0x0\nint string material_minute_selection 0x0\nint string material_minute_suffix 0x0\nint string material_slider_range_end 0x0\nint string material_slider_range_start 0x0\nint string material_timepicker_am 0x0\nint string material_timepicker_clock_mode_description 0x0\nint string material_timepicker_hour 0x0\nint string material_timepicker_minute 0x0\nint string material_timepicker_pm 0x0\nint string material_timepicker_select_time 0x0\nint string material_timepicker_text_input_mode_description 0x0\nint string mtrl_badge_numberless_content_description 0x0\nint string mtrl_chip_close_icon_content_description 0x0\nint string mtrl_exceed_max_badge_number_content_description 0x0\nint string mtrl_exceed_max_badge_number_suffix 0x0\nint string mtrl_picker_a11y_next_month 0x0\nint string mtrl_picker_a11y_prev_month 0x0\nint string mtrl_picker_announce_current_selection 0x0\nint string mtrl_picker_cancel 0x0\nint string mtrl_picker_confirm 0x0\nint string mtrl_picker_date_header_selected 0x0\nint string mtrl_picker_date_header_title 0x0\nint string mtrl_picker_date_header_unselected 0x0\nint string mtrl_picker_day_of_week_column_header 0x0\nint string mtrl_picker_invalid_format 0x0\nint string mtrl_picker_invalid_format_example 0x0\nint string mtrl_picker_invalid_format_use 0x0\nint string mtrl_picker_invalid_range 0x0\nint string mtrl_picker_navigate_to_year_description 0x0\nint string mtrl_picker_out_of_range 0x0\nint string mtrl_picker_range_header_only_end_selected 0x0\nint string mtrl_picker_range_header_only_start_selected 0x0\nint string mtrl_picker_range_header_selected 0x0\nint string mtrl_picker_range_header_title 0x0\nint string mtrl_picker_range_header_unselected 0x0\nint string mtrl_picker_save 0x0\nint string mtrl_picker_text_input_date_hint 0x0\nint string mtrl_picker_text_input_date_range_end_hint 0x0\nint string mtrl_picker_text_input_date_range_start_hint 0x0\nint string mtrl_picker_text_input_day_abbr 0x0\nint string mtrl_picker_text_input_month_abbr 0x0\nint string mtrl_picker_text_input_year_abbr 0x0\nint string mtrl_picker_toggle_to_calendar_input_mode 0x0\nint string mtrl_picker_toggle_to_day_selection 0x0\nint string mtrl_picker_toggle_to_text_input_mode 0x0\nint string mtrl_picker_toggle_to_year_selection 0x0\nint string password_toggle_content_description 0x0\nint string path_password_eye 0x0\nint string path_password_eye_mask_strike_through 0x0\nint string path_password_eye_mask_visible 0x0\nint string path_password_strike_through 0x0\nint string search_menu_title 0x0\nint string status_bar_notification_info_overflow 0x0\nint style AlertDialog_AppCompat 0x0\nint style AlertDialog_AppCompat_Light 0x0\nint style AndroidThemeColorAccentYellow 0x0\nint style Animation_AppCompat_Dialog 0x0\nint style Animation_AppCompat_DropDownUp 0x0\nint style Animation_AppCompat_Tooltip 0x0\nint style Animation_Design_BottomSheetDialog 0x0\nint style Animation_MaterialComponents_BottomSheetDialog 0x0\nint style Base_AlertDialog_AppCompat 0x0\nint style Base_AlertDialog_AppCompat_Light 0x0\nint style Base_Animation_AppCompat_Dialog 0x0\nint style Base_Animation_AppCompat_DropDownUp 0x0\nint style Base_Animation_AppCompat_Tooltip 0x0\nint style Base_CardView 0x0\nint style Base_DialogWindowTitleBackground_AppCompat 0x0\nint style Base_DialogWindowTitle_AppCompat 0x0\nint style Base_MaterialAlertDialog_MaterialComponents_Title_Icon 0x0\nint style Base_MaterialAlertDialog_MaterialComponents_Title_Panel 0x0\nint style Base_MaterialAlertDialog_MaterialComponents_Title_Text 0x0\nint style Base_TextAppearance_AppCompat 0x0\nint style Base_TextAppearance_AppCompat_Body1 0x0\nint style Base_TextAppearance_AppCompat_Body2 0x0\nint style Base_TextAppearance_AppCompat_Button 0x0\nint style Base_TextAppearance_AppCompat_Caption 0x0\nint style Base_TextAppearance_AppCompat_Display1 0x0\nint style Base_TextAppearance_AppCompat_Display2 0x0\nint style Base_TextAppearance_AppCompat_Display3 0x0\nint style Base_TextAppearance_AppCompat_Display4 0x0\nint style Base_TextAppearance_AppCompat_Headline 0x0\nint style Base_TextAppearance_AppCompat_Inverse 0x0\nint style Base_TextAppearance_AppCompat_Large 0x0\nint style Base_TextAppearance_AppCompat_Large_Inverse 0x0\nint style Base_TextAppearance_AppCompat_Light_Widget_PopupMenu_Large 0x0\nint style Base_TextAppearance_AppCompat_Light_Widget_PopupMenu_Small 0x0\nint style Base_TextAppearance_AppCompat_Medium 0x0\nint style Base_TextAppearance_AppCompat_Medium_Inverse 0x0\nint style Base_TextAppearance_AppCompat_Menu 0x0\nint style Base_TextAppearance_AppCompat_SearchResult 0x0\nint style Base_TextAppearance_AppCompat_SearchResult_Subtitle 0x0\nint style Base_TextAppearance_AppCompat_SearchResult_Title 0x0\nint style Base_TextAppearance_AppCompat_Small 0x0\nint style Base_TextAppearance_AppCompat_Small_Inverse 0x0\nint style Base_TextAppearance_AppCompat_Subhead 0x0\nint style Base_TextAppearance_AppCompat_Subhead_Inverse 0x0\nint style Base_TextAppearance_AppCompat_Title 0x0\nint style Base_TextAppearance_AppCompat_Title_Inverse 0x0\nint style Base_TextAppearance_AppCompat_Tooltip 0x0\nint style Base_TextAppearance_AppCompat_Widget_ActionBar_Menu 0x0\nint style Base_TextAppearance_AppCompat_Widget_ActionBar_Subtitle 0x0\nint style Base_TextAppearance_AppCompat_Widget_ActionBar_Subtitle_Inverse 0x0\nint style Base_TextAppearance_AppCompat_Widget_ActionBar_Title 0x0\nint style Base_TextAppearance_AppCompat_Widget_ActionBar_Title_Inverse 0x0\nint style Base_TextAppearance_AppCompat_Widget_ActionMode_Subtitle 0x0\nint style Base_TextAppearance_AppCompat_Widget_ActionMode_Title 0x0\nint style Base_TextAppearance_AppCompat_Widget_Button 0x0\nint style Base_TextAppearance_AppCompat_Widget_Button_Borderless_Colored 0x0\nint style Base_TextAppearance_AppCompat_Widget_Button_Colored 0x0\nint style Base_TextAppearance_AppCompat_Widget_Button_Inverse 0x0\nint style Base_TextAppearance_AppCompat_Widget_DropDownItem 0x0\nint style Base_TextAppearance_AppCompat_Widget_PopupMenu_Header 0x0\nint style Base_TextAppearance_AppCompat_Widget_PopupMenu_Large 0x0\nint style Base_TextAppearance_AppCompat_Widget_PopupMenu_Small 0x0\nint style Base_TextAppearance_AppCompat_Widget_Switch 0x0\nint style Base_TextAppearance_AppCompat_Widget_TextView_SpinnerItem 0x0\nint style Base_TextAppearance_MaterialComponents_Badge 0x0\nint style Base_TextAppearance_MaterialComponents_Button 0x0\nint style Base_TextAppearance_MaterialComponents_Headline6 0x0\nint style Base_TextAppearance_MaterialComponents_Subtitle2 0x0\nint style Base_TextAppearance_Widget_AppCompat_ExpandedMenu_Item 0x0\nint style Base_TextAppearance_Widget_AppCompat_Toolbar_Subtitle 0x0\nint style Base_TextAppearance_Widget_AppCompat_Toolbar_Title 0x0\nint style Base_ThemeOverlay_AppCompat 0x0\nint style Base_ThemeOverlay_AppCompat_ActionBar 0x0\nint style Base_ThemeOverlay_AppCompat_Dark 0x0\nint style Base_ThemeOverlay_AppCompat_Dark_ActionBar 0x0\nint style Base_ThemeOverlay_AppCompat_Dialog 0x0\nint style Base_ThemeOverlay_AppCompat_Dialog_Alert 0x0\nint style Base_ThemeOverlay_AppCompat_Light 0x0\nint style Base_ThemeOverlay_MaterialComponents_Dialog 0x0\nint style Base_ThemeOverlay_MaterialComponents_Dialog_Alert 0x0\nint style Base_ThemeOverlay_MaterialComponents_Dialog_Alert_Framework 0x0\nint style Base_ThemeOverlay_MaterialComponents_Light_Dialog_Alert_Framework 0x0\nint style Base_ThemeOverlay_MaterialComponents_MaterialAlertDialog 0x0\nint style Base_Theme_AppCompat 0x0\nint style Base_Theme_AppCompat_CompactMenu 0x0\nint style Base_Theme_AppCompat_Dialog 0x0\nint style Base_Theme_AppCompat_DialogWhenLarge 0x0\nint style Base_Theme_AppCompat_Dialog_Alert 0x0\nint style Base_Theme_AppCompat_Dialog_FixedSize 0x0\nint style Base_Theme_AppCompat_Dialog_MinWidth 0x0\nint style Base_Theme_AppCompat_Light 0x0\nint style Base_Theme_AppCompat_Light_DarkActionBar 0x0\nint style Base_Theme_AppCompat_Light_Dialog 0x0\nint style Base_Theme_AppCompat_Light_DialogWhenLarge 0x0\nint style Base_Theme_AppCompat_Light_Dialog_Alert 0x0\nint style Base_Theme_AppCompat_Light_Dialog_FixedSize 0x0\nint style Base_Theme_AppCompat_Light_Dialog_MinWidth 0x0\nint style Base_Theme_MaterialComponents 0x0\nint style Base_Theme_MaterialComponents_Bridge 0x0\nint style Base_Theme_MaterialComponents_CompactMenu 0x0\nint style Base_Theme_MaterialComponents_Dialog 0x0\nint style Base_Theme_MaterialComponents_DialogWhenLarge 0x0\nint style Base_Theme_MaterialComponents_Dialog_Alert 0x0\nint style Base_Theme_MaterialComponents_Dialog_Bridge 0x0\nint style Base_Theme_MaterialComponents_Dialog_FixedSize 0x0\nint style Base_Theme_MaterialComponents_Dialog_MinWidth 0x0\nint style Base_Theme_MaterialComponents_Light 0x0\nint style Base_Theme_MaterialComponents_Light_Bridge 0x0\nint style Base_Theme_MaterialComponents_Light_DarkActionBar 0x0\nint style Base_Theme_MaterialComponents_Light_DarkActionBar_Bridge 0x0\nint style Base_Theme_MaterialComponents_Light_Dialog 0x0\nint style Base_Theme_MaterialComponents_Light_DialogWhenLarge 0x0\nint style Base_Theme_MaterialComponents_Light_Dialog_Alert 0x0\nint style Base_Theme_MaterialComponents_Light_Dialog_Bridge 0x0\nint style Base_Theme_MaterialComponents_Light_Dialog_FixedSize 0x0\nint style Base_Theme_MaterialComponents_Light_Dialog_MinWidth 0x0\nint style Base_V14_ThemeOverlay_MaterialComponents_Dialog 0x0\nint style Base_V14_ThemeOverlay_MaterialComponents_Dialog_Alert 0x0\nint style Base_V14_ThemeOverlay_MaterialComponents_MaterialAlertDialog 0x0\nint style Base_V14_Theme_MaterialComponents 0x0\nint style Base_V14_Theme_MaterialComponents_Bridge 0x0\nint style Base_V14_Theme_MaterialComponents_Dialog 0x0\nint style Base_V14_Theme_MaterialComponents_Dialog_Bridge 0x0\nint style Base_V14_Theme_MaterialComponents_Light 0x0\nint style Base_V14_Theme_MaterialComponents_Light_Bridge 0x0\nint style Base_V14_Theme_MaterialComponents_Light_DarkActionBar_Bridge 0x0\nint style Base_V14_Theme_MaterialComponents_Light_Dialog 0x0\nint style Base_V14_Theme_MaterialComponents_Light_Dialog_Bridge 0x0\nint style Base_V21_ThemeOverlay_AppCompat_Dialog 0x0\nint style Base_V21_Theme_AppCompat 0x0\nint style Base_V21_Theme_AppCompat_Dialog 0x0\nint style Base_V21_Theme_AppCompat_Light 0x0\nint style Base_V21_Theme_AppCompat_Light_Dialog 0x0\nint style Base_V21_Theme_MaterialComponents 0x0\nint style Base_V21_Theme_MaterialComponents_Dialog 0x0\nint style Base_V21_Theme_MaterialComponents_Light 0x0\nint style Base_V21_Theme_MaterialComponents_Light_Dialog 0x0\nint style Base_V22_Theme_AppCompat 0x0\nint style Base_V22_Theme_AppCompat_Light 0x0\nint style Base_V23_Theme_AppCompat 0x0\nint style Base_V23_Theme_AppCompat_Light 0x0\nint style Base_V26_Theme_AppCompat 0x0\nint style Base_V26_Theme_AppCompat_Light 0x0\nint style Base_V26_Widget_AppCompat_Toolbar 0x0\nint style Base_V28_Theme_AppCompat 0x0\nint style Base_V28_Theme_AppCompat_Light 0x0\nint style Base_V7_ThemeOverlay_AppCompat_Dialog 0x0\nint style Base_V7_Theme_AppCompat 0x0\nint style Base_V7_Theme_AppCompat_Dialog 0x0\nint style Base_V7_Theme_AppCompat_Light 0x0\nint style Base_V7_Theme_AppCompat_Light_Dialog 0x0\nint style Base_V7_Widget_AppCompat_AutoCompleteTextView 0x0\nint style Base_V7_Widget_AppCompat_EditText 0x0\nint style Base_V7_Widget_AppCompat_Toolbar 0x0\nint style Base_Widget_AppCompat_ActionBar 0x0\nint style Base_Widget_AppCompat_ActionBar_Solid 0x0\nint style Base_Widget_AppCompat_ActionBar_TabBar 0x0\nint style Base_Widget_AppCompat_ActionBar_TabText 0x0\nint style Base_Widget_AppCompat_ActionBar_TabView 0x0\nint style Base_Widget_AppCompat_ActionButton 0x0\nint style Base_Widget_AppCompat_ActionButton_CloseMode 0x0\nint style Base_Widget_AppCompat_ActionButton_Overflow 0x0\nint style Base_Widget_AppCompat_ActionMode 0x0\nint style Base_Widget_AppCompat_ActivityChooserView 0x0\nint style Base_Widget_AppCompat_AutoCompleteTextView 0x0\nint style Base_Widget_AppCompat_Button 0x0\nint style Base_Widget_AppCompat_ButtonBar 0x0\nint style Base_Widget_AppCompat_ButtonBar_AlertDialog 0x0\nint style Base_Widget_AppCompat_Button_Borderless 0x0\nint style Base_Widget_AppCompat_Button_Borderless_Colored 0x0\nint style Base_Widget_AppCompat_Button_ButtonBar_AlertDialog 0x0\nint style Base_Widget_AppCompat_Button_Colored 0x0\nint style Base_Widget_AppCompat_Button_Small 0x0\nint style Base_Widget_AppCompat_CompoundButton_CheckBox 0x0\nint style Base_Widget_AppCompat_CompoundButton_RadioButton 0x0\nint style Base_Widget_AppCompat_CompoundButton_Switch 0x0\nint style Base_Widget_AppCompat_DrawerArrowToggle 0x0\nint style Base_Widget_AppCompat_DrawerArrowToggle_Common 0x0\nint style Base_Widget_AppCompat_DropDownItem_Spinner 0x0\nint style Base_Widget_AppCompat_EditText 0x0\nint style Base_Widget_AppCompat_ImageButton 0x0\nint style Base_Widget_AppCompat_Light_ActionBar 0x0\nint style Base_Widget_AppCompat_Light_ActionBar_Solid 0x0\nint style Base_Widget_AppCompat_Light_ActionBar_TabBar 0x0\nint style Base_Widget_AppCompat_Light_ActionBar_TabText 0x0\nint style Base_Widget_AppCompat_Light_ActionBar_TabText_Inverse 0x0\nint style Base_Widget_AppCompat_Light_ActionBar_TabView 0x0\nint style Base_Widget_AppCompat_Light_PopupMenu 0x0\nint style Base_Widget_AppCompat_Light_PopupMenu_Overflow 0x0\nint style Base_Widget_AppCompat_ListMenuView 0x0\nint style Base_Widget_AppCompat_ListPopupWindow 0x0\nint style Base_Widget_AppCompat_ListView 0x0\nint style Base_Widget_AppCompat_ListView_DropDown 0x0\nint style Base_Widget_AppCompat_ListView_Menu 0x0\nint style Base_Widget_AppCompat_PopupMenu 0x0\nint style Base_Widget_AppCompat_PopupMenu_Overflow 0x0\nint style Base_Widget_AppCompat_PopupWindow 0x0\nint style Base_Widget_AppCompat_ProgressBar 0x0\nint style Base_Widget_AppCompat_ProgressBar_Horizontal 0x0\nint style Base_Widget_AppCompat_RatingBar 0x0\nint style Base_Widget_AppCompat_RatingBar_Indicator 0x0\nint style Base_Widget_AppCompat_RatingBar_Small 0x0\nint style Base_Widget_AppCompat_SearchView 0x0\nint style Base_Widget_AppCompat_SearchView_ActionBar 0x0\nint style Base_Widget_AppCompat_SeekBar 0x0\nint style Base_Widget_AppCompat_SeekBar_Discrete 0x0\nint style Base_Widget_AppCompat_Spinner 0x0\nint style Base_Widget_AppCompat_Spinner_Underlined 0x0\nint style Base_Widget_AppCompat_TextView 0x0\nint style Base_Widget_AppCompat_TextView_SpinnerItem 0x0\nint style Base_Widget_AppCompat_Toolbar 0x0\nint style Base_Widget_AppCompat_Toolbar_Button_Navigation 0x0\nint style Base_Widget_Design_TabLayout 0x0\nint style Base_Widget_MaterialComponents_AutoCompleteTextView 0x0\nint style Base_Widget_MaterialComponents_CheckedTextView 0x0\nint style Base_Widget_MaterialComponents_Chip 0x0\nint style Base_Widget_MaterialComponents_MaterialCalendar_NavigationButton 0x0\nint style Base_Widget_MaterialComponents_PopupMenu 0x0\nint style Base_Widget_MaterialComponents_PopupMenu_ContextMenu 0x0\nint style Base_Widget_MaterialComponents_PopupMenu_ListPopupWindow 0x0\nint style Base_Widget_MaterialComponents_PopupMenu_Overflow 0x0\nint style Base_Widget_MaterialComponents_Slider 0x0\nint style Base_Widget_MaterialComponents_Snackbar 0x0\nint style Base_Widget_MaterialComponents_TextInputEditText 0x0\nint style Base_Widget_MaterialComponents_TextInputLayout 0x0\nint style Base_Widget_MaterialComponents_TextView 0x0\nint style CardView 0x0\nint style CardView_Dark 0x0\nint style CardView_Light 0x0\nint style EmptyTheme 0x0\nint style MaterialAlertDialog_MaterialComponents 0x0\nint style MaterialAlertDialog_MaterialComponents_Body_Text 0x0\nint style MaterialAlertDialog_MaterialComponents_Picker_Date_Calendar 0x0\nint style MaterialAlertDialog_MaterialComponents_Picker_Date_Spinner 0x0\nint style MaterialAlertDialog_MaterialComponents_Title_Icon 0x0\nint style MaterialAlertDialog_MaterialComponents_Title_Icon_CenterStacked 0x0\nint style MaterialAlertDialog_MaterialComponents_Title_Panel 0x0\nint style MaterialAlertDialog_MaterialComponents_Title_Panel_CenterStacked 0x0\nint style MaterialAlertDialog_MaterialComponents_Title_Text 0x0\nint style MaterialAlertDialog_MaterialComponents_Title_Text_CenterStacked 0x0\nint style Platform_AppCompat 0x0\nint style Platform_AppCompat_Light 0x0\nint style Platform_MaterialComponents 0x0\nint style Platform_MaterialComponents_Dialog 0x0\nint style Platform_MaterialComponents_Light 0x0\nint style Platform_MaterialComponents_Light_Dialog 0x0\nint style Platform_ThemeOverlay_AppCompat 0x0\nint style Platform_ThemeOverlay_AppCompat_Dark 0x0\nint style Platform_ThemeOverlay_AppCompat_Light 0x0\nint style Platform_V21_AppCompat 0x0\nint style Platform_V21_AppCompat_Light 0x0\nint style Platform_V25_AppCompat 0x0\nint style Platform_V25_AppCompat_Light 0x0\nint style Platform_Widget_AppCompat_Spinner 0x0\nint style RtlOverlay_DialogWindowTitle_AppCompat 0x0\nint style RtlOverlay_Widget_AppCompat_ActionBar_TitleItem 0x0\nint style RtlOverlay_Widget_AppCompat_DialogTitle_Icon 0x0\nint style RtlOverlay_Widget_AppCompat_PopupMenuItem 0x0\nint style RtlOverlay_Widget_AppCompat_PopupMenuItem_InternalGroup 0x0\nint style RtlOverlay_Widget_AppCompat_PopupMenuItem_Shortcut 0x0\nint style RtlOverlay_Widget_AppCompat_PopupMenuItem_SubmenuArrow 0x0\nint style RtlOverlay_Widget_AppCompat_PopupMenuItem_Text 0x0\nint style RtlOverlay_Widget_AppCompat_PopupMenuItem_Title 0x0\nint style RtlOverlay_Widget_AppCompat_SearchView_MagIcon 0x0\nint style RtlOverlay_Widget_AppCompat_Search_DropDown 0x0\nint style RtlOverlay_Widget_AppCompat_Search_DropDown_Icon1 0x0\nint style RtlOverlay_Widget_AppCompat_Search_DropDown_Icon2 0x0\nint style RtlOverlay_Widget_AppCompat_Search_DropDown_Query 0x0\nint style RtlOverlay_Widget_AppCompat_Search_DropDown_Text 0x0\nint style RtlUnderlay_Widget_AppCompat_ActionButton 0x0\nint style RtlUnderlay_Widget_AppCompat_ActionButton_Overflow 0x0\nint style ShapeAppearanceOverlay 0x0\nint style ShapeAppearanceOverlay_BottomLeftDifferentCornerSize 0x0\nint style ShapeAppearanceOverlay_BottomRightCut 0x0\nint style ShapeAppearanceOverlay_Cut 0x0\nint style ShapeAppearanceOverlay_DifferentCornerSize 0x0\nint style ShapeAppearanceOverlay_MaterialComponents_BottomSheet 0x0\nint style ShapeAppearanceOverlay_MaterialComponents_Chip 0x0\nint style ShapeAppearanceOverlay_MaterialComponents_ExtendedFloatingActionButton 0x0\nint style ShapeAppearanceOverlay_MaterialComponents_FloatingActionButton 0x0\nint style ShapeAppearanceOverlay_MaterialComponents_MaterialCalendar_Day 0x0\nint style ShapeAppearanceOverlay_MaterialComponents_MaterialCalendar_Window_Fullscreen 0x0\nint style ShapeAppearanceOverlay_MaterialComponents_MaterialCalendar_Year 0x0\nint style ShapeAppearanceOverlay_MaterialComponents_TextInputLayout_FilledBox 0x0\nint style ShapeAppearanceOverlay_TopLeftCut 0x0\nint style ShapeAppearanceOverlay_TopRightDifferentCornerSize 0x0\nint style ShapeAppearance_MaterialComponents 0x0\nint style ShapeAppearance_MaterialComponents_LargeComponent 0x0\nint style ShapeAppearance_MaterialComponents_MediumComponent 0x0\nint style ShapeAppearance_MaterialComponents_SmallComponent 0x0\nint style ShapeAppearance_MaterialComponents_Test 0x0\nint style ShapeAppearance_MaterialComponents_Tooltip 0x0\nint style TestStyleWithLineHeight 0x0\nint style TestStyleWithLineHeightAppearance 0x0\nint style TestStyleWithThemeLineHeightAttribute 0x0\nint style TestStyleWithoutLineHeight 0x0\nint style TestThemeWithLineHeight 0x0\nint style TestThemeWithLineHeightDisabled 0x0\nint style Test_ShapeAppearanceOverlay_MaterialComponents_MaterialCalendar_Day 0x0\nint style Test_Theme_MaterialComponents_MaterialCalendar 0x0\nint style Test_Widget_MaterialComponents_MaterialCalendar 0x0\nint style Test_Widget_MaterialComponents_MaterialCalendar_Day 0x0\nint style Test_Widget_MaterialComponents_MaterialCalendar_Day_Selected 0x0\nint style TextAppearance_AppCompat 0x0\nint style TextAppearance_AppCompat_Body1 0x0\nint style TextAppearance_AppCompat_Body2 0x0\nint style TextAppearance_AppCompat_Button 0x0\nint style TextAppearance_AppCompat_Caption 0x0\nint style TextAppearance_AppCompat_Display1 0x0\nint style TextAppearance_AppCompat_Display2 0x0\nint style TextAppearance_AppCompat_Display3 0x0\nint style TextAppearance_AppCompat_Display4 0x0\nint style TextAppearance_AppCompat_Headline 0x0\nint style TextAppearance_AppCompat_Inverse 0x0\nint style TextAppearance_AppCompat_Large 0x0\nint style TextAppearance_AppCompat_Large_Inverse 0x0\nint style TextAppearance_AppCompat_Light_SearchResult_Subtitle 0x0\nint style TextAppearance_AppCompat_Light_SearchResult_Title 0x0\nint style TextAppearance_AppCompat_Light_Widget_PopupMenu_Large 0x0\nint style TextAppearance_AppCompat_Light_Widget_PopupMenu_Small 0x0\nint style TextAppearance_AppCompat_Medium 0x0\nint style TextAppearance_AppCompat_Medium_Inverse 0x0\nint style TextAppearance_AppCompat_Menu 0x0\nint style TextAppearance_AppCompat_SearchResult_Subtitle 0x0\nint style TextAppearance_AppCompat_SearchResult_Title 0x0\nint style TextAppearance_AppCompat_Small 0x0\nint style TextAppearance_AppCompat_Small_Inverse 0x0\nint style TextAppearance_AppCompat_Subhead 0x0\nint style TextAppearance_AppCompat_Subhead_Inverse 0x0\nint style TextAppearance_AppCompat_Title 0x0\nint style TextAppearance_AppCompat_Title_Inverse 0x0\nint style TextAppearance_AppCompat_Tooltip 0x0\nint style TextAppearance_AppCompat_Widget_ActionBar_Menu 0x0\nint style TextAppearance_AppCompat_Widget_ActionBar_Subtitle 0x0\nint style TextAppearance_AppCompat_Widget_ActionBar_Subtitle_Inverse 0x0\nint style TextAppearance_AppCompat_Widget_ActionBar_Title 0x0\nint style TextAppearance_AppCompat_Widget_ActionBar_Title_Inverse 0x0\nint style TextAppearance_AppCompat_Widget_ActionMode_Subtitle 0x0\nint style TextAppearance_AppCompat_Widget_ActionMode_Subtitle_Inverse 0x0\nint style TextAppearance_AppCompat_Widget_ActionMode_Title 0x0\nint style TextAppearance_AppCompat_Widget_ActionMode_Title_Inverse 0x0\nint style TextAppearance_AppCompat_Widget_Button 0x0\nint style TextAppearance_AppCompat_Widget_Button_Borderless_Colored 0x0\nint style TextAppearance_AppCompat_Widget_Button_Colored 0x0\nint style TextAppearance_AppCompat_Widget_Button_Inverse 0x0\nint style TextAppearance_AppCompat_Widget_DropDownItem 0x0\nint style TextAppearance_AppCompat_Widget_PopupMenu_Header 0x0\nint style TextAppearance_AppCompat_Widget_PopupMenu_Large 0x0\nint style TextAppearance_AppCompat_Widget_PopupMenu_Small 0x0\nint style TextAppearance_AppCompat_Widget_Switch 0x0\nint style TextAppearance_AppCompat_Widget_TextView_SpinnerItem 0x0\nint style TextAppearance_Compat_Notification 0x0\nint style TextAppearance_Compat_Notification_Info 0x0\nint style TextAppearance_Compat_Notification_Line2 0x0\nint style TextAppearance_Compat_Notification_Time 0x0\nint style TextAppearance_Compat_Notification_Title 0x0\nint style TextAppearance_Design_CollapsingToolbar_Expanded 0x0\nint style TextAppearance_Design_Counter 0x0\nint style TextAppearance_Design_Counter_Overflow 0x0\nint style TextAppearance_Design_Error 0x0\nint style TextAppearance_Design_HelperText 0x0\nint style TextAppearance_Design_Hint 0x0\nint style TextAppearance_Design_Placeholder 0x0\nint style TextAppearance_Design_Prefix 0x0\nint style TextAppearance_Design_Snackbar_Message 0x0\nint style TextAppearance_Design_Suffix 0x0\nint style TextAppearance_Design_Tab 0x0\nint style TextAppearance_MaterialComponents_Badge 0x0\nint style TextAppearance_MaterialComponents_Body1 0x0\nint style TextAppearance_MaterialComponents_Body2 0x0\nint style TextAppearance_MaterialComponents_Button 0x0\nint style TextAppearance_MaterialComponents_Caption 0x0\nint style TextAppearance_MaterialComponents_Chip 0x0\nint style TextAppearance_MaterialComponents_Headline1 0x0\nint style TextAppearance_MaterialComponents_Headline2 0x0\nint style TextAppearance_MaterialComponents_Headline3 0x0\nint style TextAppearance_MaterialComponents_Headline4 0x0\nint style TextAppearance_MaterialComponents_Headline5 0x0\nint style TextAppearance_MaterialComponents_Headline6 0x0\nint style TextAppearance_MaterialComponents_Overline 0x0\nint style TextAppearance_MaterialComponents_Subtitle1 0x0\nint style TextAppearance_MaterialComponents_Subtitle2 0x0\nint style TextAppearance_MaterialComponents_TimePicker_Title 0x0\nint style TextAppearance_MaterialComponents_Tooltip 0x0\nint style TextAppearance_Widget_AppCompat_ExpandedMenu_Item 0x0\nint style TextAppearance_Widget_AppCompat_Toolbar_Subtitle 0x0\nint style TextAppearance_Widget_AppCompat_Toolbar_Title 0x0\nint style ThemeOverlayColorAccentRed 0x0\nint style ThemeOverlay_AppCompat 0x0\nint style ThemeOverlay_AppCompat_ActionBar 0x0\nint style ThemeOverlay_AppCompat_Dark 0x0\nint style ThemeOverlay_AppCompat_Dark_ActionBar 0x0\nint style ThemeOverlay_AppCompat_DayNight 0x0\nint style ThemeOverlay_AppCompat_DayNight_ActionBar 0x0\nint style ThemeOverlay_AppCompat_Dialog 0x0\nint style ThemeOverlay_AppCompat_Dialog_Alert 0x0\nint style ThemeOverlay_AppCompat_Light 0x0\nint style ThemeOverlay_Design_TextInputEditText 0x0\nint style ThemeOverlay_MaterialComponents 0x0\nint style ThemeOverlay_MaterialComponents_ActionBar 0x0\nint style ThemeOverlay_MaterialComponents_ActionBar_Primary 0x0\nint style ThemeOverlay_MaterialComponents_ActionBar_Surface 0x0\nint style ThemeOverlay_MaterialComponents_AutoCompleteTextView 0x0\nint style ThemeOverlay_MaterialComponents_AutoCompleteTextView_FilledBox 0x0\nint style ThemeOverlay_MaterialComponents_AutoCompleteTextView_FilledBox_Dense 0x0\nint style ThemeOverlay_MaterialComponents_AutoCompleteTextView_OutlinedBox 0x0\nint style ThemeOverlay_MaterialComponents_AutoCompleteTextView_OutlinedBox_Dense 0x0\nint style ThemeOverlay_MaterialComponents_BottomAppBar_Primary 0x0\nint style ThemeOverlay_MaterialComponents_BottomAppBar_Surface 0x0\nint style ThemeOverlay_MaterialComponents_BottomSheetDialog 0x0\nint style ThemeOverlay_MaterialComponents_Dark 0x0\nint style ThemeOverlay_MaterialComponents_Dark_ActionBar 0x0\nint style ThemeOverlay_MaterialComponents_DayNight_BottomSheetDialog 0x0\nint style ThemeOverlay_MaterialComponents_Dialog 0x0\nint style ThemeOverlay_MaterialComponents_Dialog_Alert 0x0\nint style ThemeOverlay_MaterialComponents_Dialog_Alert_Framework 0x0\nint style ThemeOverlay_MaterialComponents_Light 0x0\nint style ThemeOverlay_MaterialComponents_Light_BottomSheetDialog 0x0\nint style ThemeOverlay_MaterialComponents_Light_Dialog_Alert_Framework 0x0\nint style ThemeOverlay_MaterialComponents_MaterialAlertDialog 0x0\nint style ThemeOverlay_MaterialComponents_MaterialAlertDialog_Centered 0x0\nint style ThemeOverlay_MaterialComponents_MaterialAlertDialog_Picker_Date 0x0\nint style ThemeOverlay_MaterialComponents_MaterialAlertDialog_Picker_Date_Calendar 0x0\nint style ThemeOverlay_MaterialComponents_MaterialAlertDialog_Picker_Date_Header_Text 0x0\nint style ThemeOverlay_MaterialComponents_MaterialAlertDialog_Picker_Date_Header_Text_Day 0x0\nint style ThemeOverlay_MaterialComponents_MaterialAlertDialog_Picker_Date_Spinner 0x0\nint style ThemeOverlay_MaterialComponents_MaterialCalendar 0x0\nint style ThemeOverlay_MaterialComponents_MaterialCalendar_Fullscreen 0x0\nint style ThemeOverlay_MaterialComponents_TextInputEditText 0x0\nint style ThemeOverlay_MaterialComponents_TextInputEditText_FilledBox 0x0\nint style ThemeOverlay_MaterialComponents_TextInputEditText_FilledBox_Dense 0x0\nint style ThemeOverlay_MaterialComponents_TextInputEditText_OutlinedBox 0x0\nint style ThemeOverlay_MaterialComponents_TextInputEditText_OutlinedBox_Dense 0x0\nint style ThemeOverlay_MaterialComponents_TimePicker 0x0\nint style ThemeOverlay_MaterialComponents_TimePicker_Display 0x0\nint style ThemeOverlay_MaterialComponents_Toolbar_Primary 0x0\nint style ThemeOverlay_MaterialComponents_Toolbar_Surface 0x0\nint style Theme_AppCompat 0x0\nint style Theme_AppCompat_CompactMenu 0x0\nint style Theme_AppCompat_DayNight 0x0\nint style Theme_AppCompat_DayNight_DarkActionBar 0x0\nint style Theme_AppCompat_DayNight_Dialog 0x0\nint style Theme_AppCompat_DayNight_DialogWhenLarge 0x0\nint style Theme_AppCompat_DayNight_Dialog_Alert 0x0\nint style Theme_AppCompat_DayNight_Dialog_MinWidth 0x0\nint style Theme_AppCompat_DayNight_NoActionBar 0x0\nint style Theme_AppCompat_Dialog 0x0\nint style Theme_AppCompat_DialogWhenLarge 0x0\nint style Theme_AppCompat_Dialog_Alert 0x0\nint style Theme_AppCompat_Dialog_MinWidth 0x0\nint style Theme_AppCompat_Empty 0x0\nint style Theme_AppCompat_Light 0x0\nint style Theme_AppCompat_Light_DarkActionBar 0x0\nint style Theme_AppCompat_Light_Dialog 0x0\nint style Theme_AppCompat_Light_DialogWhenLarge 0x0\nint style Theme_AppCompat_Light_Dialog_Alert 0x0\nint style Theme_AppCompat_Light_Dialog_MinWidth 0x0\nint style Theme_AppCompat_Light_NoActionBar 0x0\nint style Theme_AppCompat_NoActionBar 0x0\nint style Theme_Design 0x0\nint style Theme_Design_BottomSheetDialog 0x0\nint style Theme_Design_Light 0x0\nint style Theme_Design_Light_BottomSheetDialog 0x0\nint style Theme_Design_Light_NoActionBar 0x0\nint style Theme_Design_NoActionBar 0x0\nint style Theme_MaterialComponents 0x0\nint style Theme_MaterialComponents_BottomSheetDialog 0x0\nint style Theme_MaterialComponents_Bridge 0x0\nint style Theme_MaterialComponents_CompactMenu 0x0\nint style Theme_MaterialComponents_DayNight 0x0\nint style Theme_MaterialComponents_DayNight_BottomSheetDialog 0x0\nint style Theme_MaterialComponents_DayNight_Bridge 0x0\nint style Theme_MaterialComponents_DayNight_DarkActionBar 0x0\nint style Theme_MaterialComponents_DayNight_DarkActionBar_Bridge 0x0\nint style Theme_MaterialComponents_DayNight_Dialog 0x0\nint style Theme_MaterialComponents_DayNight_DialogWhenLarge 0x0\nint style Theme_MaterialComponents_DayNight_Dialog_Alert 0x0\nint style Theme_MaterialComponents_DayNight_Dialog_Alert_Bridge 0x0\nint style Theme_MaterialComponents_DayNight_Dialog_Bridge 0x0\nint style Theme_MaterialComponents_DayNight_Dialog_FixedSize 0x0\nint style Theme_MaterialComponents_DayNight_Dialog_FixedSize_Bridge 0x0\nint style Theme_MaterialComponents_DayNight_Dialog_MinWidth 0x0\nint style Theme_MaterialComponents_DayNight_Dialog_MinWidth_Bridge 0x0\nint style Theme_MaterialComponents_DayNight_NoActionBar 0x0\nint style Theme_MaterialComponents_DayNight_NoActionBar_Bridge 0x0\nint style Theme_MaterialComponents_Dialog 0x0\nint style Theme_MaterialComponents_DialogWhenLarge 0x0\nint style Theme_MaterialComponents_Dialog_Alert 0x0\nint style Theme_MaterialComponents_Dialog_Alert_Bridge 0x0\nint style Theme_MaterialComponents_Dialog_Bridge 0x0\nint style Theme_MaterialComponents_Dialog_FixedSize 0x0\nint style Theme_MaterialComponents_Dialog_FixedSize_Bridge 0x0\nint style Theme_MaterialComponents_Dialog_MinWidth 0x0\nint style Theme_MaterialComponents_Dialog_MinWidth_Bridge 0x0\nint style Theme_MaterialComponents_Light 0x0\nint style Theme_MaterialComponents_Light_BarSize 0x0\nint style Theme_MaterialComponents_Light_BottomSheetDialog 0x0\nint style Theme_MaterialComponents_Light_Bridge 0x0\nint style Theme_MaterialComponents_Light_DarkActionBar 0x0\nint style Theme_MaterialComponents_Light_DarkActionBar_Bridge 0x0\nint style Theme_MaterialComponents_Light_Dialog 0x0\nint style Theme_MaterialComponents_Light_DialogWhenLarge 0x0\nint style Theme_MaterialComponents_Light_Dialog_Alert 0x0\nint style Theme_MaterialComponents_Light_Dialog_Alert_Bridge 0x0\nint style Theme_MaterialComponents_Light_Dialog_Bridge 0x0\nint style Theme_MaterialComponents_Light_Dialog_FixedSize 0x0\nint style Theme_MaterialComponents_Light_Dialog_FixedSize_Bridge 0x0\nint style Theme_MaterialComponents_Light_Dialog_MinWidth 0x0\nint style Theme_MaterialComponents_Light_Dialog_MinWidth_Bridge 0x0\nint style Theme_MaterialComponents_Light_LargeTouch 0x0\nint style Theme_MaterialComponents_Light_NoActionBar 0x0\nint style Theme_MaterialComponents_Light_NoActionBar_Bridge 0x0\nint style Theme_MaterialComponents_NoActionBar 0x0\nint style Theme_MaterialComponents_NoActionBar_Bridge 0x0\nint style Widget_AppCompat_ActionBar 0x0\nint style Widget_AppCompat_ActionBar_Solid 0x0\nint style Widget_AppCompat_ActionBar_TabBar 0x0\nint style Widget_AppCompat_ActionBar_TabText 0x0\nint style Widget_AppCompat_ActionBar_TabView 0x0\nint style Widget_AppCompat_ActionButton 0x0\nint style Widget_AppCompat_ActionButton_CloseMode 0x0\nint style Widget_AppCompat_ActionButton_Overflow 0x0\nint style Widget_AppCompat_ActionMode 0x0\nint style Widget_AppCompat_ActivityChooserView 0x0\nint style Widget_AppCompat_AutoCompleteTextView 0x0\nint style Widget_AppCompat_Button 0x0\nint style Widget_AppCompat_ButtonBar 0x0\nint style Widget_AppCompat_ButtonBar_AlertDialog 0x0\nint style Widget_AppCompat_Button_Borderless 0x0\nint style Widget_AppCompat_Button_Borderless_Colored 0x0\nint style Widget_AppCompat_Button_ButtonBar_AlertDialog 0x0\nint style Widget_AppCompat_Button_Colored 0x0\nint style Widget_AppCompat_Button_Small 0x0\nint style Widget_AppCompat_CompoundButton_CheckBox 0x0\nint style Widget_AppCompat_CompoundButton_RadioButton 0x0\nint style Widget_AppCompat_CompoundButton_Switch 0x0\nint style Widget_AppCompat_DrawerArrowToggle 0x0\nint style Widget_AppCompat_DropDownItem_Spinner 0x0\nint style Widget_AppCompat_EditText 0x0\nint style Widget_AppCompat_ImageButton 0x0\nint style Widget_AppCompat_Light_ActionBar 0x0\nint style Widget_AppCompat_Light_ActionBar_Solid 0x0\nint style Widget_AppCompat_Light_ActionBar_Solid_Inverse 0x0\nint style Widget_AppCompat_Light_ActionBar_TabBar 0x0\nint style Widget_AppCompat_Light_ActionBar_TabBar_Inverse 0x0\nint style Widget_AppCompat_Light_ActionBar_TabText 0x0\nint style Widget_AppCompat_Light_ActionBar_TabText_Inverse 0x0\nint style Widget_AppCompat_Light_ActionBar_TabView 0x0\nint style Widget_AppCompat_Light_ActionBar_TabView_Inverse 0x0\nint style Widget_AppCompat_Light_ActionButton 0x0\nint style Widget_AppCompat_Light_ActionButton_CloseMode 0x0\nint style Widget_AppCompat_Light_ActionButton_Overflow 0x0\nint style Widget_AppCompat_Light_ActionMode_Inverse 0x0\nint style Widget_AppCompat_Light_ActivityChooserView 0x0\nint style Widget_AppCompat_Light_AutoCompleteTextView 0x0\nint style Widget_AppCompat_Light_DropDownItem_Spinner 0x0\nint style Widget_AppCompat_Light_ListPopupWindow 0x0\nint style Widget_AppCompat_Light_ListView_DropDown 0x0\nint style Widget_AppCompat_Light_PopupMenu 0x0\nint style Widget_AppCompat_Light_PopupMenu_Overflow 0x0\nint style Widget_AppCompat_Light_SearchView 0x0\nint style Widget_AppCompat_Light_Spinner_DropDown_ActionBar 0x0\nint style Widget_AppCompat_ListMenuView 0x0\nint style Widget_AppCompat_ListPopupWindow 0x0\nint style Widget_AppCompat_ListView 0x0\nint style Widget_AppCompat_ListView_DropDown 0x0\nint style Widget_AppCompat_ListView_Menu 0x0\nint style Widget_AppCompat_PopupMenu 0x0\nint style Widget_AppCompat_PopupMenu_Overflow 0x0\nint style Widget_AppCompat_PopupWindow 0x0\nint style Widget_AppCompat_ProgressBar 0x0\nint style Widget_AppCompat_ProgressBar_Horizontal 0x0\nint style Widget_AppCompat_RatingBar 0x0\nint style Widget_AppCompat_RatingBar_Indicator 0x0\nint style Widget_AppCompat_RatingBar_Small 0x0\nint style Widget_AppCompat_SearchView 0x0\nint style Widget_AppCompat_SearchView_ActionBar 0x0\nint style Widget_AppCompat_SeekBar 0x0\nint style Widget_AppCompat_SeekBar_Discrete 0x0\nint style Widget_AppCompat_Spinner 0x0\nint style Widget_AppCompat_Spinner_DropDown 0x0\nint style Widget_AppCompat_Spinner_DropDown_ActionBar 0x0\nint style Widget_AppCompat_Spinner_Underlined 0x0\nint style Widget_AppCompat_TextView 0x0\nint style Widget_AppCompat_TextView_SpinnerItem 0x0\nint style Widget_AppCompat_Toolbar 0x0\nint style Widget_AppCompat_Toolbar_Button_Navigation 0x0\nint style Widget_Compat_NotificationActionContainer 0x0\nint style Widget_Compat_NotificationActionText 0x0\nint style Widget_Design_AppBarLayout 0x0\nint style Widget_Design_BottomNavigationView 0x0\nint style Widget_Design_BottomSheet_Modal 0x0\nint style Widget_Design_CollapsingToolbar 0x0\nint style Widget_Design_FloatingActionButton 0x0\nint style Widget_Design_NavigationView 0x0\nint style Widget_Design_ScrimInsetsFrameLayout 0x0\nint style Widget_Design_Snackbar 0x0\nint style Widget_Design_TabLayout 0x0\nint style Widget_Design_TextInputEditText 0x0\nint style Widget_Design_TextInputLayout 0x0\nint style Widget_MaterialComponents_ActionBar_Primary 0x0\nint style Widget_MaterialComponents_ActionBar_PrimarySurface 0x0\nint style Widget_MaterialComponents_ActionBar_Solid 0x0\nint style Widget_MaterialComponents_ActionBar_Surface 0x0\nint style Widget_MaterialComponents_AppBarLayout_Primary 0x0\nint style Widget_MaterialComponents_AppBarLayout_PrimarySurface 0x0\nint style Widget_MaterialComponents_AppBarLayout_Surface 0x0\nint style Widget_MaterialComponents_AutoCompleteTextView_FilledBox 0x0\nint style Widget_MaterialComponents_AutoCompleteTextView_FilledBox_Dense 0x0\nint style Widget_MaterialComponents_AutoCompleteTextView_OutlinedBox 0x0\nint style Widget_MaterialComponents_AutoCompleteTextView_OutlinedBox_Dense 0x0\nint style Widget_MaterialComponents_Badge 0x0\nint style Widget_MaterialComponents_BottomAppBar 0x0\nint style Widget_MaterialComponents_BottomAppBar_Colored 0x0\nint style Widget_MaterialComponents_BottomAppBar_PrimarySurface 0x0\nint style Widget_MaterialComponents_BottomNavigationView 0x0\nint style Widget_MaterialComponents_BottomNavigationView_Colored 0x0\nint style Widget_MaterialComponents_BottomNavigationView_PrimarySurface 0x0\nint style Widget_MaterialComponents_BottomSheet 0x0\nint style Widget_MaterialComponents_BottomSheet_Modal 0x0\nint style Widget_MaterialComponents_Button 0x0\nint style Widget_MaterialComponents_Button_Icon 0x0\nint style Widget_MaterialComponents_Button_OutlinedButton 0x0\nint style Widget_MaterialComponents_Button_OutlinedButton_Icon 0x0\nint style Widget_MaterialComponents_Button_TextButton 0x0\nint style Widget_MaterialComponents_Button_TextButton_Dialog 0x0\nint style Widget_MaterialComponents_Button_TextButton_Dialog_Flush 0x0\nint style Widget_MaterialComponents_Button_TextButton_Dialog_Icon 0x0\nint style Widget_MaterialComponents_Button_TextButton_Icon 0x0\nint style Widget_MaterialComponents_Button_TextButton_Snackbar 0x0\nint style Widget_MaterialComponents_Button_UnelevatedButton 0x0\nint style Widget_MaterialComponents_Button_UnelevatedButton_Icon 0x0\nint style Widget_MaterialComponents_CardView 0x0\nint style Widget_MaterialComponents_CheckedTextView 0x0\nint style Widget_MaterialComponents_ChipGroup 0x0\nint style Widget_MaterialComponents_Chip_Action 0x0\nint style Widget_MaterialComponents_Chip_Choice 0x0\nint style Widget_MaterialComponents_Chip_Entry 0x0\nint style Widget_MaterialComponents_Chip_Filter 0x0\nint style Widget_MaterialComponents_CircularProgressIndicator 0x0\nint style Widget_MaterialComponents_CircularProgressIndicator_ExtraSmall 0x0\nint style Widget_MaterialComponents_CircularProgressIndicator_Medium 0x0\nint style Widget_MaterialComponents_CircularProgressIndicator_Small 0x0\nint style Widget_MaterialComponents_CollapsingToolbar 0x0\nint style Widget_MaterialComponents_CompoundButton_CheckBox 0x0\nint style Widget_MaterialComponents_CompoundButton_RadioButton 0x0\nint style Widget_MaterialComponents_CompoundButton_Switch 0x0\nint style Widget_MaterialComponents_ExtendedFloatingActionButton 0x0\nint style Widget_MaterialComponents_ExtendedFloatingActionButton_Icon 0x0\nint style Widget_MaterialComponents_FloatingActionButton 0x0\nint style Widget_MaterialComponents_Light_ActionBar_Solid 0x0\nint style Widget_MaterialComponents_LinearProgressIndicator 0x0\nint style Widget_MaterialComponents_MaterialButtonToggleGroup 0x0\nint style Widget_MaterialComponents_MaterialCalendar 0x0\nint style Widget_MaterialComponents_MaterialCalendar_Day 0x0\nint style Widget_MaterialComponents_MaterialCalendar_DayTextView 0x0\nint style Widget_MaterialComponents_MaterialCalendar_Day_Invalid 0x0\nint style Widget_MaterialComponents_MaterialCalendar_Day_Selected 0x0\nint style Widget_MaterialComponents_MaterialCalendar_Day_Today 0x0\nint style Widget_MaterialComponents_MaterialCalendar_Fullscreen 0x0\nint style Widget_MaterialComponents_MaterialCalendar_HeaderCancelButton 0x0\nint style Widget_MaterialComponents_MaterialCalendar_HeaderConfirmButton 0x0\nint style Widget_MaterialComponents_MaterialCalendar_HeaderDivider 0x0\nint style Widget_MaterialComponents_MaterialCalendar_HeaderLayout 0x0\nint style Widget_MaterialComponents_MaterialCalendar_HeaderSelection 0x0\nint style Widget_MaterialComponents_MaterialCalendar_HeaderSelection_Fullscreen 0x0\nint style Widget_MaterialComponents_MaterialCalendar_HeaderTitle 0x0\nint style Widget_MaterialComponents_MaterialCalendar_HeaderToggleButton 0x0\nint style Widget_MaterialComponents_MaterialCalendar_Item 0x0\nint style Widget_MaterialComponents_MaterialCalendar_MonthNavigationButton 0x0\nint style Widget_MaterialComponents_MaterialCalendar_MonthTextView 0x0\nint style Widget_MaterialComponents_MaterialCalendar_Year 0x0\nint style Widget_MaterialComponents_MaterialCalendar_YearNavigationButton 0x0\nint style Widget_MaterialComponents_MaterialCalendar_Year_Selected 0x0\nint style Widget_MaterialComponents_MaterialCalendar_Year_Today 0x0\nint style Widget_MaterialComponents_NavigationView 0x0\nint style Widget_MaterialComponents_PopupMenu 0x0\nint style Widget_MaterialComponents_PopupMenu_ContextMenu 0x0\nint style Widget_MaterialComponents_PopupMenu_ListPopupWindow 0x0\nint style Widget_MaterialComponents_PopupMenu_Overflow 0x0\nint style Widget_MaterialComponents_ProgressIndicator 0x0\nint style Widget_MaterialComponents_ShapeableImageView 0x0\nint style Widget_MaterialComponents_Slider 0x0\nint style Widget_MaterialComponents_Snackbar 0x0\nint style Widget_MaterialComponents_Snackbar_FullWidth 0x0\nint style Widget_MaterialComponents_Snackbar_TextView 0x0\nint style Widget_MaterialComponents_TabLayout 0x0\nint style Widget_MaterialComponents_TabLayout_Colored 0x0\nint style Widget_MaterialComponents_TabLayout_PrimarySurface 0x0\nint style Widget_MaterialComponents_TextInputEditText_FilledBox 0x0\nint style Widget_MaterialComponents_TextInputEditText_FilledBox_Dense 0x0\nint style Widget_MaterialComponents_TextInputEditText_OutlinedBox 0x0\nint style Widget_MaterialComponents_TextInputEditText_OutlinedBox_Dense 0x0\nint style Widget_MaterialComponents_TextInputLayout_FilledBox 0x0\nint style Widget_MaterialComponents_TextInputLayout_FilledBox_Dense 0x0\nint style Widget_MaterialComponents_TextInputLayout_FilledBox_Dense_ExposedDropdownMenu 0x0\nint style Widget_MaterialComponents_TextInputLayout_FilledBox_ExposedDropdownMenu 0x0\nint style Widget_MaterialComponents_TextInputLayout_OutlinedBox 0x0\nint style Widget_MaterialComponents_TextInputLayout_OutlinedBox_Dense 0x0\nint style Widget_MaterialComponents_TextInputLayout_OutlinedBox_Dense_ExposedDropdownMenu 0x0\nint style Widget_MaterialComponents_TextInputLayout_OutlinedBox_ExposedDropdownMenu 0x0\nint style Widget_MaterialComponents_TextView 0x0\nint style Widget_MaterialComponents_TimePicker 0x0\nint style Widget_MaterialComponents_TimePicker_Button 0x0\nint style Widget_MaterialComponents_TimePicker_Clock 0x0\nint style Widget_MaterialComponents_TimePicker_Display 0x0\nint style Widget_MaterialComponents_TimePicker_Display_TextInputEditText 0x0\nint style Widget_MaterialComponents_TimePicker_ImageButton 0x0\nint style Widget_MaterialComponents_TimePicker_ImageButton_ShapeAppearance 0x0\nint style Widget_MaterialComponents_Toolbar 0x0\nint style Widget_MaterialComponents_Toolbar_Primary 0x0\nint style Widget_MaterialComponents_Toolbar_PrimarySurface 0x0\nint style Widget_MaterialComponents_Toolbar_Surface 0x0\nint style Widget_MaterialComponents_Tooltip 0x0\nint style Widget_Support_CoordinatorLayout 0x0\nint[] styleable ActionBar { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable ActionBar_background 0\nint styleable ActionBar_backgroundSplit 1\nint styleable ActionBar_backgroundStacked 2\nint styleable ActionBar_contentInsetEnd 3\nint styleable ActionBar_contentInsetEndWithActions 4\nint styleable ActionBar_contentInsetLeft 5\nint styleable ActionBar_contentInsetRight 6\nint styleable ActionBar_contentInsetStart 7\nint styleable ActionBar_contentInsetStartWithNavigation 8\nint styleable ActionBar_customNavigationLayout 9\nint styleable ActionBar_displayOptions 10\nint styleable ActionBar_divider 11\nint styleable ActionBar_elevation 12\nint styleable ActionBar_height 13\nint styleable ActionBar_hideOnContentScroll 14\nint styleable ActionBar_homeAsUpIndicator 15\nint styleable ActionBar_homeLayout 16\nint styleable ActionBar_icon 17\nint styleable ActionBar_indeterminateProgressStyle 18\nint styleable ActionBar_itemPadding 19\nint styleable ActionBar_logo 20\nint styleable ActionBar_navigationMode 21\nint styleable ActionBar_popupTheme 22\nint styleable ActionBar_progressBarPadding 23\nint styleable ActionBar_progressBarStyle 24\nint styleable ActionBar_subtitle 25\nint styleable ActionBar_subtitleTextStyle 26\nint styleable ActionBar_title 27\nint styleable ActionBar_titleTextStyle 28\nint[] styleable ActionBarLayout { 0x10100b3 }\nint styleable ActionBarLayout_android_layout_gravity 0\nint[] styleable ActionMenuItemView { 0x101013f }\nint styleable ActionMenuItemView_android_minWidth 0\nint[] styleable ActionMenuView {  }\nint[] styleable ActionMode { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable ActionMode_background 0\nint styleable ActionMode_backgroundSplit 1\nint styleable ActionMode_closeItemLayout 2\nint styleable ActionMode_height 3\nint styleable ActionMode_subtitleTextStyle 4\nint styleable ActionMode_titleTextStyle 5\nint[] styleable ActivityChooserView { 0x0, 0x0 }\nint styleable ActivityChooserView_expandActivityOverflowButtonDrawable 0\nint styleable ActivityChooserView_initialActivityCount 1\nint[] styleable AlertDialog { 0x10100f2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable AlertDialog_android_layout 0\nint styleable AlertDialog_buttonIconDimen 1\nint styleable AlertDialog_buttonPanelSideLayout 2\nint styleable AlertDialog_listItemLayout 3\nint styleable AlertDialog_listLayout 4\nint styleable AlertDialog_multiChoiceItemLayout 5\nint styleable AlertDialog_showTitle 6\nint styleable AlertDialog_singleChoiceItemLayout 7\nint[] styleable AnimatedStateListDrawableCompat { 0x1010196, 0x101011c, 0x101030c, 0x101030d, 0x1010195, 0x1010194 }\nint styleable AnimatedStateListDrawableCompat_android_constantSize 0\nint styleable AnimatedStateListDrawableCompat_android_dither 1\nint styleable AnimatedStateListDrawableCompat_android_enterFadeDuration 2\nint styleable AnimatedStateListDrawableCompat_android_exitFadeDuration 3\nint styleable AnimatedStateListDrawableCompat_android_variablePadding 4\nint styleable AnimatedStateListDrawableCompat_android_visible 5\nint[] styleable AnimatedStateListDrawableItem { 0x1010199, 0x10100d0 }\nint styleable AnimatedStateListDrawableItem_android_drawable 0\nint styleable AnimatedStateListDrawableItem_android_id 1\nint[] styleable AnimatedStateListDrawableTransition { 0x1010199, 0x101044a, 0x101044b, 0x1010449 }\nint styleable AnimatedStateListDrawableTransition_android_drawable 0\nint styleable AnimatedStateListDrawableTransition_android_fromId 1\nint styleable AnimatedStateListDrawableTransition_android_reversible 2\nint styleable AnimatedStateListDrawableTransition_android_toId 3\nint[] styleable AppBarLayout { 0x10100d4, 0x1010540, 0x101048f, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable AppBarLayout_android_background 0\nint styleable AppBarLayout_android_keyboardNavigationCluster 1\nint styleable AppBarLayout_android_touchscreenBlocksFocus 2\nint styleable AppBarLayout_elevation 3\nint styleable AppBarLayout_expanded 4\nint styleable AppBarLayout_liftOnScroll 5\nint styleable AppBarLayout_liftOnScrollTargetViewId 6\nint styleable AppBarLayout_statusBarForeground 7\nint[] styleable AppBarLayoutStates { 0x0, 0x0, 0x0, 0x0 }\nint styleable AppBarLayoutStates_state_collapsed 0\nint styleable AppBarLayoutStates_state_collapsible 1\nint styleable AppBarLayoutStates_state_liftable 2\nint styleable AppBarLayoutStates_state_lifted 3\nint[] styleable AppBarLayout_Layout { 0x0, 0x0 }\nint styleable AppBarLayout_Layout_layout_scrollFlags 0\nint styleable AppBarLayout_Layout_layout_scrollInterpolator 1\nint[] styleable AppCompatImageView { 0x1010119, 0x0, 0x0, 0x0 }\nint styleable AppCompatImageView_android_src 0\nint styleable AppCompatImageView_srcCompat 1\nint styleable AppCompatImageView_tint 2\nint styleable AppCompatImageView_tintMode 3\nint[] styleable AppCompatSeekBar { 0x1010142, 0x0, 0x0, 0x0 }\nint styleable AppCompatSeekBar_android_thumb 0\nint styleable AppCompatSeekBar_tickMark 1\nint styleable AppCompatSeekBar_tickMarkTint 2\nint styleable AppCompatSeekBar_tickMarkTintMode 3\nint[] styleable AppCompatTextHelper { 0x101016e, 0x1010393, 0x101016f, 0x1010170, 0x1010392, 0x101016d, 0x1010034 }\nint styleable AppCompatTextHelper_android_drawableBottom 0\nint styleable AppCompatTextHelper_android_drawableEnd 1\nint styleable AppCompatTextHelper_android_drawableLeft 2\nint styleable AppCompatTextHelper_android_drawableRight 3\nint styleable AppCompatTextHelper_android_drawableStart 4\nint styleable AppCompatTextHelper_android_drawableTop 5\nint styleable AppCompatTextHelper_android_textAppearance 6\nint[] styleable AppCompatTextView { 0x1010034, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable AppCompatTextView_android_textAppearance 0\nint styleable AppCompatTextView_autoSizeMaxTextSize 1\nint styleable AppCompatTextView_autoSizeMinTextSize 2\nint styleable AppCompatTextView_autoSizePresetSizes 3\nint styleable AppCompatTextView_autoSizeStepGranularity 4\nint styleable AppCompatTextView_autoSizeTextType 5\nint styleable AppCompatTextView_drawableBottomCompat 6\nint styleable AppCompatTextView_drawableEndCompat 7\nint styleable AppCompatTextView_drawableLeftCompat 8\nint styleable AppCompatTextView_drawableRightCompat 9\nint styleable AppCompatTextView_drawableStartCompat 10\nint styleable AppCompatTextView_drawableTint 11\nint styleable AppCompatTextView_drawableTintMode 12\nint styleable AppCompatTextView_drawableTopCompat 13\nint styleable AppCompatTextView_firstBaselineToTopHeight 14\nint styleable AppCompatTextView_fontFamily 15\nint styleable AppCompatTextView_fontVariationSettings 16\nint styleable AppCompatTextView_lastBaselineToBottomHeight 17\nint styleable AppCompatTextView_lineHeight 18\nint styleable AppCompatTextView_textAllCaps 19\nint styleable AppCompatTextView_textLocale 20\nint[] styleable AppCompatTheme { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10100ae, 0x1010057, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable AppCompatTheme_actionBarDivider 0\nint styleable AppCompatTheme_actionBarItemBackground 1\nint styleable AppCompatTheme_actionBarPopupTheme 2\nint styleable AppCompatTheme_actionBarSize 3\nint styleable AppCompatTheme_actionBarSplitStyle 4\nint styleable AppCompatTheme_actionBarStyle 5\nint styleable AppCompatTheme_actionBarTabBarStyle 6\nint styleable AppCompatTheme_actionBarTabStyle 7\nint styleable AppCompatTheme_actionBarTabTextStyle 8\nint styleable AppCompatTheme_actionBarTheme 9\nint styleable AppCompatTheme_actionBarWidgetTheme 10\nint styleable AppCompatTheme_actionButtonStyle 11\nint styleable AppCompatTheme_actionDropDownStyle 12\nint styleable AppCompatTheme_actionMenuTextAppearance 13\nint styleable AppCompatTheme_actionMenuTextColor 14\nint styleable AppCompatTheme_actionModeBackground 15\nint styleable AppCompatTheme_actionModeCloseButtonStyle 16\nint styleable AppCompatTheme_actionModeCloseDrawable 17\nint styleable AppCompatTheme_actionModeCopyDrawable 18\nint styleable AppCompatTheme_actionModeCutDrawable 19\nint styleable AppCompatTheme_actionModeFindDrawable 20\nint styleable AppCompatTheme_actionModePasteDrawable 21\nint styleable AppCompatTheme_actionModePopupWindowStyle 22\nint styleable AppCompatTheme_actionModeSelectAllDrawable 23\nint styleable AppCompatTheme_actionModeShareDrawable 24\nint styleable AppCompatTheme_actionModeSplitBackground 25\nint styleable AppCompatTheme_actionModeStyle 26\nint styleable AppCompatTheme_actionModeWebSearchDrawable 27\nint styleable AppCompatTheme_actionOverflowButtonStyle 28\nint styleable AppCompatTheme_actionOverflowMenuStyle 29\nint styleable AppCompatTheme_activityChooserViewStyle 30\nint styleable AppCompatTheme_alertDialogButtonGroupStyle 31\nint styleable AppCompatTheme_alertDialogCenterButtons 32\nint styleable AppCompatTheme_alertDialogStyle 33\nint styleable AppCompatTheme_alertDialogTheme 34\nint styleable AppCompatTheme_android_windowAnimationStyle 35\nint styleable AppCompatTheme_android_windowIsFloating 36\nint styleable AppCompatTheme_autoCompleteTextViewStyle 37\nint styleable AppCompatTheme_borderlessButtonStyle 38\nint styleable AppCompatTheme_buttonBarButtonStyle 39\nint styleable AppCompatTheme_buttonBarNegativeButtonStyle 40\nint styleable AppCompatTheme_buttonBarNeutralButtonStyle 41\nint styleable AppCompatTheme_buttonBarPositiveButtonStyle 42\nint styleable AppCompatTheme_buttonBarStyle 43\nint styleable AppCompatTheme_buttonStyle 44\nint styleable AppCompatTheme_buttonStyleSmall 45\nint styleable AppCompatTheme_checkboxStyle 46\nint styleable AppCompatTheme_checkedTextViewStyle 47\nint styleable AppCompatTheme_colorAccent 48\nint styleable AppCompatTheme_colorBackgroundFloating 49\nint styleable AppCompatTheme_colorButtonNormal 50\nint styleable AppCompatTheme_colorControlActivated 51\nint styleable AppCompatTheme_colorControlHighlight 52\nint styleable AppCompatTheme_colorControlNormal 53\nint styleable AppCompatTheme_colorError 54\nint styleable AppCompatTheme_colorPrimary 55\nint styleable AppCompatTheme_colorPrimaryDark 56\nint styleable AppCompatTheme_colorSwitchThumbNormal 57\nint styleable AppCompatTheme_controlBackground 58\nint styleable AppCompatTheme_dialogCornerRadius 59\nint styleable AppCompatTheme_dialogPreferredPadding 60\nint styleable AppCompatTheme_dialogTheme 61\nint styleable AppCompatTheme_dividerHorizontal 62\nint styleable AppCompatTheme_dividerVertical 63\nint styleable AppCompatTheme_dropDownListViewStyle 64\nint styleable AppCompatTheme_dropdownListPreferredItemHeight 65\nint styleable AppCompatTheme_editTextBackground 66\nint styleable AppCompatTheme_editTextColor 67\nint styleable AppCompatTheme_editTextStyle 68\nint styleable AppCompatTheme_homeAsUpIndicator 69\nint styleable AppCompatTheme_imageButtonStyle 70\nint styleable AppCompatTheme_listChoiceBackgroundIndicator 71\nint styleable AppCompatTheme_listChoiceIndicatorMultipleAnimated 72\nint styleable AppCompatTheme_listChoiceIndicatorSingleAnimated 73\nint styleable AppCompatTheme_listDividerAlertDialog 74\nint styleable AppCompatTheme_listMenuViewStyle 75\nint styleable AppCompatTheme_listPopupWindowStyle 76\nint styleable AppCompatTheme_listPreferredItemHeight 77\nint styleable AppCompatTheme_listPreferredItemHeightLarge 78\nint styleable AppCompatTheme_listPreferredItemHeightSmall 79\nint styleable AppCompatTheme_listPreferredItemPaddingEnd 80\nint styleable AppCompatTheme_listPreferredItemPaddingLeft 81\nint styleable AppCompatTheme_listPreferredItemPaddingRight 82\nint styleable AppCompatTheme_listPreferredItemPaddingStart 83\nint styleable AppCompatTheme_panelBackground 84\nint styleable AppCompatTheme_panelMenuListTheme 85\nint styleable AppCompatTheme_panelMenuListWidth 86\nint styleable AppCompatTheme_popupMenuStyle 87\nint styleable AppCompatTheme_popupWindowStyle 88\nint styleable AppCompatTheme_radioButtonStyle 89\nint styleable AppCompatTheme_ratingBarStyle 90\nint styleable AppCompatTheme_ratingBarStyleIndicator 91\nint styleable AppCompatTheme_ratingBarStyleSmall 92\nint styleable AppCompatTheme_searchViewStyle 93\nint styleable AppCompatTheme_seekBarStyle 94\nint styleable AppCompatTheme_selectableItemBackground 95\nint styleable AppCompatTheme_selectableItemBackgroundBorderless 96\nint styleable AppCompatTheme_spinnerDropDownItemStyle 97\nint styleable AppCompatTheme_spinnerStyle 98\nint styleable AppCompatTheme_switchStyle 99\nint styleable AppCompatTheme_textAppearanceLargePopupMenu 100\nint styleable AppCompatTheme_textAppearanceListItem 101\nint styleable AppCompatTheme_textAppearanceListItemSecondary 102\nint styleable AppCompatTheme_textAppearanceListItemSmall 103\nint styleable AppCompatTheme_textAppearancePopupMenuHeader 104\nint styleable AppCompatTheme_textAppearanceSearchResultSubtitle 105\nint styleable AppCompatTheme_textAppearanceSearchResultTitle 106\nint styleable AppCompatTheme_textAppearanceSmallPopupMenu 107\nint styleable AppCompatTheme_textColorAlertDialogListItem 108\nint styleable AppCompatTheme_textColorSearchUrl 109\nint styleable AppCompatTheme_toolbarNavigationButtonStyle 110\nint styleable AppCompatTheme_toolbarStyle 111\nint styleable AppCompatTheme_tooltipForegroundColor 112\nint styleable AppCompatTheme_tooltipFrameBackground 113\nint styleable AppCompatTheme_viewInflaterClass 114\nint styleable AppCompatTheme_windowActionBar 115\nint styleable AppCompatTheme_windowActionBarOverlay 116\nint styleable AppCompatTheme_windowActionModeOverlay 117\nint styleable AppCompatTheme_windowFixedHeightMajor 118\nint styleable AppCompatTheme_windowFixedHeightMinor 119\nint styleable AppCompatTheme_windowFixedWidthMajor 120\nint styleable AppCompatTheme_windowFixedWidthMinor 121\nint styleable AppCompatTheme_windowMinWidthMajor 122\nint styleable AppCompatTheme_windowMinWidthMinor 123\nint styleable AppCompatTheme_windowNoTitle 124\nint[] styleable Badge { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable Badge_backgroundColor 0\nint styleable Badge_badgeGravity 1\nint styleable Badge_badgeTextColor 2\nint styleable Badge_horizontalOffset 3\nint styleable Badge_maxCharacterCount 4\nint styleable Badge_number 5\nint styleable Badge_verticalOffset 6\nint[] styleable BaseProgressIndicator { 0x1010139, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable BaseProgressIndicator_android_indeterminate 0\nint styleable BaseProgressIndicator_hideAnimationBehavior 1\nint styleable BaseProgressIndicator_indicatorColor 2\nint styleable BaseProgressIndicator_minHideDelay 3\nint styleable BaseProgressIndicator_showAnimationBehavior 4\nint styleable BaseProgressIndicator_showDelay 5\nint styleable BaseProgressIndicator_trackColor 6\nint styleable BaseProgressIndicator_trackCornerRadius 7\nint styleable BaseProgressIndicator_trackThickness 8\nint[] styleable BottomAppBar { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable BottomAppBar_backgroundTint 0\nint styleable BottomAppBar_elevation 1\nint styleable BottomAppBar_fabAlignmentMode 2\nint styleable BottomAppBar_fabAnimationMode 3\nint styleable BottomAppBar_fabCradleMargin 4\nint styleable BottomAppBar_fabCradleRoundedCornerRadius 5\nint styleable BottomAppBar_fabCradleVerticalOffset 6\nint styleable BottomAppBar_hideOnScroll 7\nint styleable BottomAppBar_paddingBottomSystemWindowInsets 8\nint styleable BottomAppBar_paddingLeftSystemWindowInsets 9\nint styleable BottomAppBar_paddingRightSystemWindowInsets 10\nint[] styleable BottomNavigationView { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable BottomNavigationView_backgroundTint 0\nint styleable BottomNavigationView_elevation 1\nint styleable BottomNavigationView_itemBackground 2\nint styleable BottomNavigationView_itemHorizontalTranslationEnabled 3\nint styleable BottomNavigationView_itemIconSize 4\nint styleable BottomNavigationView_itemIconTint 5\nint styleable BottomNavigationView_itemRippleColor 6\nint styleable BottomNavigationView_itemTextAppearanceActive 7\nint styleable BottomNavigationView_itemTextAppearanceInactive 8\nint styleable BottomNavigationView_itemTextColor 9\nint styleable BottomNavigationView_labelVisibilityMode 10\nint styleable BottomNavigationView_menu 11\nint[] styleable BottomSheetBehavior_Layout { 0x1010440, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable BottomSheetBehavior_Layout_android_elevation 0\nint styleable BottomSheetBehavior_Layout_backgroundTint 1\nint styleable BottomSheetBehavior_Layout_behavior_draggable 2\nint styleable BottomSheetBehavior_Layout_behavior_expandedOffset 3\nint styleable BottomSheetBehavior_Layout_behavior_fitToContents 4\nint styleable BottomSheetBehavior_Layout_behavior_halfExpandedRatio 5\nint styleable BottomSheetBehavior_Layout_behavior_hideable 6\nint styleable BottomSheetBehavior_Layout_behavior_peekHeight 7\nint styleable BottomSheetBehavior_Layout_behavior_saveFlags 8\nint styleable BottomSheetBehavior_Layout_behavior_skipCollapsed 9\nint styleable BottomSheetBehavior_Layout_gestureInsetBottomIgnored 10\nint styleable BottomSheetBehavior_Layout_shapeAppearance 11\nint styleable BottomSheetBehavior_Layout_shapeAppearanceOverlay 12\nint[] styleable ButtonBarLayout { 0x0 }\nint styleable ButtonBarLayout_allowStacking 0\nint[] styleable CardView { 0x1010140, 0x101013f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable CardView_android_minHeight 0\nint styleable CardView_android_minWidth 1\nint styleable CardView_cardBackgroundColor 2\nint styleable CardView_cardCornerRadius 3\nint styleable CardView_cardElevation 4\nint styleable CardView_cardMaxElevation 5\nint styleable CardView_cardPreventCornerOverlap 6\nint styleable CardView_cardUseCompatPadding 7\nint styleable CardView_contentPadding 8\nint styleable CardView_contentPaddingBottom 9\nint styleable CardView_contentPaddingLeft 10\nint styleable CardView_contentPaddingRight 11\nint styleable CardView_contentPaddingTop 12\nint[] styleable Chip { 0x10101e5, 0x10100ab, 0x101011f, 0x101014f, 0x1010034, 0x1010098, 0x1010095, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable Chip_android_checkable 0\nint styleable Chip_android_ellipsize 1\nint styleable Chip_android_maxWidth 2\nint styleable Chip_android_text 3\nint styleable Chip_android_textAppearance 4\nint styleable Chip_android_textColor 5\nint styleable Chip_android_textSize 6\nint styleable Chip_checkedIcon 7\nint styleable Chip_checkedIconEnabled 8\nint styleable Chip_checkedIconTint 9\nint styleable Chip_checkedIconVisible 10\nint styleable Chip_chipBackgroundColor 11\nint styleable Chip_chipCornerRadius 12\nint styleable Chip_chipEndPadding 13\nint styleable Chip_chipIcon 14\nint styleable Chip_chipIconEnabled 15\nint styleable Chip_chipIconSize 16\nint styleable Chip_chipIconTint 17\nint styleable Chip_chipIconVisible 18\nint styleable Chip_chipMinHeight 19\nint styleable Chip_chipMinTouchTargetSize 20\nint styleable Chip_chipStartPadding 21\nint styleable Chip_chipStrokeColor 22\nint styleable Chip_chipStrokeWidth 23\nint styleable Chip_chipSurfaceColor 24\nint styleable Chip_closeIcon 25\nint styleable Chip_closeIconEnabled 26\nint styleable Chip_closeIconEndPadding 27\nint styleable Chip_closeIconSize 28\nint styleable Chip_closeIconStartPadding 29\nint styleable Chip_closeIconTint 30\nint styleable Chip_closeIconVisible 31\nint styleable Chip_ensureMinTouchTargetSize 32\nint styleable Chip_hideMotionSpec 33\nint styleable Chip_iconEndPadding 34\nint styleable Chip_iconStartPadding 35\nint styleable Chip_rippleColor 36\nint styleable Chip_shapeAppearance 37\nint styleable Chip_shapeAppearanceOverlay 38\nint styleable Chip_showMotionSpec 39\nint styleable Chip_textEndPadding 40\nint styleable Chip_textStartPadding 41\nint[] styleable ChipGroup { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable ChipGroup_checkedChip 0\nint styleable ChipGroup_chipSpacing 1\nint styleable ChipGroup_chipSpacingHorizontal 2\nint styleable ChipGroup_chipSpacingVertical 3\nint styleable ChipGroup_selectionRequired 4\nint styleable ChipGroup_singleLine 5\nint styleable ChipGroup_singleSelection 6\nint[] styleable CircularProgressIndicator { 0x0, 0x0, 0x0 }\nint styleable CircularProgressIndicator_indicatorDirectionCircular 0\nint styleable CircularProgressIndicator_indicatorInset 1\nint styleable CircularProgressIndicator_indicatorSize 2\nint[] styleable ClockFaceView { 0x0, 0x0 }\nint styleable ClockFaceView_clockFaceBackgroundColor 0\nint styleable ClockFaceView_clockNumberTextColor 1\nint[] styleable ClockHandView { 0x0, 0x0, 0x0 }\nint styleable ClockHandView_clockHandColor 0\nint styleable ClockHandView_materialCircleRadius 1\nint styleable ClockHandView_selectorSize 2\nint[] styleable CollapsingToolbarLayout { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable CollapsingToolbarLayout_collapsedTitleGravity 0\nint styleable CollapsingToolbarLayout_collapsedTitleTextAppearance 1\nint styleable CollapsingToolbarLayout_contentScrim 2\nint styleable CollapsingToolbarLayout_expandedTitleGravity 3\nint styleable CollapsingToolbarLayout_expandedTitleMargin 4\nint styleable CollapsingToolbarLayout_expandedTitleMarginBottom 5\nint styleable CollapsingToolbarLayout_expandedTitleMarginEnd 6\nint styleable CollapsingToolbarLayout_expandedTitleMarginStart 7\nint styleable CollapsingToolbarLayout_expandedTitleMarginTop 8\nint styleable CollapsingToolbarLayout_expandedTitleTextAppearance 9\nint styleable CollapsingToolbarLayout_maxLines 10\nint styleable CollapsingToolbarLayout_scrimAnimationDuration 11\nint styleable CollapsingToolbarLayout_scrimVisibleHeightTrigger 12\nint styleable CollapsingToolbarLayout_statusBarScrim 13\nint styleable CollapsingToolbarLayout_title 14\nint styleable CollapsingToolbarLayout_titleEnabled 15\nint styleable CollapsingToolbarLayout_toolbarId 16\nint[] styleable CollapsingToolbarLayout_Layout { 0x0, 0x0 }\nint styleable CollapsingToolbarLayout_Layout_layout_collapseMode 0\nint styleable CollapsingToolbarLayout_Layout_layout_collapseParallaxMultiplier 1\nint[] styleable ColorStateListItem { 0x0, 0x101031f, 0x10101a5 }\nint styleable ColorStateListItem_alpha 0\nint styleable ColorStateListItem_android_alpha 1\nint styleable ColorStateListItem_android_color 2\nint[] styleable CompoundButton { 0x1010107, 0x0, 0x0, 0x0 }\nint styleable CompoundButton_android_button 0\nint styleable CompoundButton_buttonCompat 1\nint styleable CompoundButton_buttonTint 2\nint styleable CompoundButton_buttonTintMode 3\nint[] styleable Constraint { 0x101031f, 0x1010440, 0x10100d0, 0x10100f5, 0x10100fa, 0x10103b6, 0x10100f7, 0x10100f9, 0x10103b5, 0x10100f8, 0x10100f4, 0x1010120, 0x101011f, 0x1010140, 0x101013f, 0x10100c4, 0x1010326, 0x1010327, 0x1010328, 0x1010324, 0x1010325, 0x1010320, 0x1010321, 0x1010322, 0x1010323, 0x10103fa, 0x10100dc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable Constraint_android_alpha 0\nint styleable Constraint_android_elevation 1\nint styleable Constraint_android_id 2\nint styleable Constraint_android_layout_height 3\nint styleable Constraint_android_layout_marginBottom 4\nint styleable Constraint_android_layout_marginEnd 5\nint styleable Constraint_android_layout_marginLeft 6\nint styleable Constraint_android_layout_marginRight 7\nint styleable Constraint_android_layout_marginStart 8\nint styleable Constraint_android_layout_marginTop 9\nint styleable Constraint_android_layout_width 10\nint styleable Constraint_android_maxHeight 11\nint styleable Constraint_android_maxWidth 12\nint styleable Constraint_android_minHeight 13\nint styleable Constraint_android_minWidth 14\nint styleable Constraint_android_orientation 15\nint styleable Constraint_android_rotation 16\nint styleable Constraint_android_rotationX 17\nint styleable Constraint_android_rotationY 18\nint styleable Constraint_android_scaleX 19\nint styleable Constraint_android_scaleY 20\nint styleable Constraint_android_transformPivotX 21\nint styleable Constraint_android_transformPivotY 22\nint styleable Constraint_android_translationX 23\nint styleable Constraint_android_translationY 24\nint styleable Constraint_android_translationZ 25\nint styleable Constraint_android_visibility 26\nint styleable Constraint_animate_relativeTo 27\nint styleable Constraint_barrierAllowsGoneWidgets 28\nint styleable Constraint_barrierDirection 29\nint styleable Constraint_barrierMargin 30\nint styleable Constraint_chainUseRtl 31\nint styleable Constraint_constraint_referenced_ids 32\nint styleable Constraint_drawPath 33\nint styleable Constraint_flow_firstHorizontalBias 34\nint styleable Constraint_flow_firstHorizontalStyle 35\nint styleable Constraint_flow_firstVerticalBias 36\nint styleable Constraint_flow_firstVerticalStyle 37\nint styleable Constraint_flow_horizontalAlign 38\nint styleable Constraint_flow_horizontalBias 39\nint styleable Constraint_flow_horizontalGap 40\nint styleable Constraint_flow_horizontalStyle 41\nint styleable Constraint_flow_lastHorizontalBias 42\nint styleable Constraint_flow_lastHorizontalStyle 43\nint styleable Constraint_flow_lastVerticalBias 44\nint styleable Constraint_flow_lastVerticalStyle 45\nint styleable Constraint_flow_maxElementsWrap 46\nint styleable Constraint_flow_verticalAlign 47\nint styleable Constraint_flow_verticalBias 48\nint styleable Constraint_flow_verticalGap 49\nint styleable Constraint_flow_verticalStyle 50\nint styleable Constraint_flow_wrapMode 51\nint styleable Constraint_layout_constrainedHeight 52\nint styleable Constraint_layout_constrainedWidth 53\nint styleable Constraint_layout_constraintBaseline_creator 54\nint styleable Constraint_layout_constraintBaseline_toBaselineOf 55\nint styleable Constraint_layout_constraintBottom_creator 56\nint styleable Constraint_layout_constraintBottom_toBottomOf 57\nint styleable Constraint_layout_constraintBottom_toTopOf 58\nint styleable Constraint_layout_constraintCircle 59\nint styleable Constraint_layout_constraintCircleAngle 60\nint styleable Constraint_layout_constraintCircleRadius 61\nint styleable Constraint_layout_constraintDimensionRatio 62\nint styleable Constraint_layout_constraintEnd_toEndOf 63\nint styleable Constraint_layout_constraintEnd_toStartOf 64\nint styleable Constraint_layout_constraintGuide_begin 65\nint styleable Constraint_layout_constraintGuide_end 66\nint styleable Constraint_layout_constraintGuide_percent 67\nint styleable Constraint_layout_constraintHeight_default 68\nint styleable Constraint_layout_constraintHeight_max 69\nint styleable Constraint_layout_constraintHeight_min 70\nint styleable Constraint_layout_constraintHeight_percent 71\nint styleable Constraint_layout_constraintHorizontal_bias 72\nint styleable Constraint_layout_constraintHorizontal_chainStyle 73\nint styleable Constraint_layout_constraintHorizontal_weight 74\nint styleable Constraint_layout_constraintLeft_creator 75\nint styleable Constraint_layout_constraintLeft_toLeftOf 76\nint styleable Constraint_layout_constraintLeft_toRightOf 77\nint styleable Constraint_layout_constraintRight_creator 78\nint styleable Constraint_layout_constraintRight_toLeftOf 79\nint styleable Constraint_layout_constraintRight_toRightOf 80\nint styleable Constraint_layout_constraintStart_toEndOf 81\nint styleable Constraint_layout_constraintStart_toStartOf 82\nint styleable Constraint_layout_constraintTag 83\nint styleable Constraint_layout_constraintTop_creator 84\nint styleable Constraint_layout_constraintTop_toBottomOf 85\nint styleable Constraint_layout_constraintTop_toTopOf 86\nint styleable Constraint_layout_constraintVertical_bias 87\nint styleable Constraint_layout_constraintVertical_chainStyle 88\nint styleable Constraint_layout_constraintVertical_weight 89\nint styleable Constraint_layout_constraintWidth_default 90\nint styleable Constraint_layout_constraintWidth_max 91\nint styleable Constraint_layout_constraintWidth_min 92\nint styleable Constraint_layout_constraintWidth_percent 93\nint styleable Constraint_layout_editor_absoluteX 94\nint styleable Constraint_layout_editor_absoluteY 95\nint styleable Constraint_layout_goneMarginBottom 96\nint styleable Constraint_layout_goneMarginEnd 97\nint styleable Constraint_layout_goneMarginLeft 98\nint styleable Constraint_layout_goneMarginRight 99\nint styleable Constraint_layout_goneMarginStart 100\nint styleable Constraint_layout_goneMarginTop 101\nint styleable Constraint_motionProgress 102\nint styleable Constraint_motionStagger 103\nint styleable Constraint_pathMotionArc 104\nint styleable Constraint_pivotAnchor 105\nint styleable Constraint_transitionEasing 106\nint styleable Constraint_transitionPathRotate 107\nint styleable Constraint_visibilityMode 108\nint[] styleable ConstraintLayout_Layout { 0x1010440, 0x1010120, 0x101011f, 0x1010140, 0x101013f, 0x10100c4, 0x10100d5, 0x10100d9, 0x10103b4, 0x10100d6, 0x10100d8, 0x10103b3, 0x10100d7, 0x10100dc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable ConstraintLayout_Layout_android_elevation 0\nint styleable ConstraintLayout_Layout_android_maxHeight 1\nint styleable ConstraintLayout_Layout_android_maxWidth 2\nint styleable ConstraintLayout_Layout_android_minHeight 3\nint styleable ConstraintLayout_Layout_android_minWidth 4\nint styleable ConstraintLayout_Layout_android_orientation 5\nint styleable ConstraintLayout_Layout_android_padding 6\nint styleable ConstraintLayout_Layout_android_paddingBottom 7\nint styleable ConstraintLayout_Layout_android_paddingEnd 8\nint styleable ConstraintLayout_Layout_android_paddingLeft 9\nint styleable ConstraintLayout_Layout_android_paddingRight 10\nint styleable ConstraintLayout_Layout_android_paddingStart 11\nint styleable ConstraintLayout_Layout_android_paddingTop 12\nint styleable ConstraintLayout_Layout_android_visibility 13\nint styleable ConstraintLayout_Layout_barrierAllowsGoneWidgets 14\nint styleable ConstraintLayout_Layout_barrierDirection 15\nint styleable ConstraintLayout_Layout_barrierMargin 16\nint styleable ConstraintLayout_Layout_chainUseRtl 17\nint styleable ConstraintLayout_Layout_constraintSet 18\nint styleable ConstraintLayout_Layout_constraint_referenced_ids 19\nint styleable ConstraintLayout_Layout_flow_firstHorizontalBias 20\nint styleable ConstraintLayout_Layout_flow_firstHorizontalStyle 21\nint styleable ConstraintLayout_Layout_flow_firstVerticalBias 22\nint styleable ConstraintLayout_Layout_flow_firstVerticalStyle 23\nint styleable ConstraintLayout_Layout_flow_horizontalAlign 24\nint styleable ConstraintLayout_Layout_flow_horizontalBias 25\nint styleable ConstraintLayout_Layout_flow_horizontalGap 26\nint styleable ConstraintLayout_Layout_flow_horizontalStyle 27\nint styleable ConstraintLayout_Layout_flow_lastHorizontalBias 28\nint styleable ConstraintLayout_Layout_flow_lastHorizontalStyle 29\nint styleable ConstraintLayout_Layout_flow_lastVerticalBias 30\nint styleable ConstraintLayout_Layout_flow_lastVerticalStyle 31\nint styleable ConstraintLayout_Layout_flow_maxElementsWrap 32\nint styleable ConstraintLayout_Layout_flow_verticalAlign 33\nint styleable ConstraintLayout_Layout_flow_verticalBias 34\nint styleable ConstraintLayout_Layout_flow_verticalGap 35\nint styleable ConstraintLayout_Layout_flow_verticalStyle 36\nint styleable ConstraintLayout_Layout_flow_wrapMode 37\nint styleable ConstraintLayout_Layout_layoutDescription 38\nint styleable ConstraintLayout_Layout_layout_constrainedHeight 39\nint styleable ConstraintLayout_Layout_layout_constrainedWidth 40\nint styleable ConstraintLayout_Layout_layout_constraintBaseline_creator 41\nint styleable ConstraintLayout_Layout_layout_constraintBaseline_toBaselineOf 42\nint styleable ConstraintLayout_Layout_layout_constraintBottom_creator 43\nint styleable ConstraintLayout_Layout_layout_constraintBottom_toBottomOf 44\nint styleable ConstraintLayout_Layout_layout_constraintBottom_toTopOf 45\nint styleable ConstraintLayout_Layout_layout_constraintCircle 46\nint styleable ConstraintLayout_Layout_layout_constraintCircleAngle 47\nint styleable ConstraintLayout_Layout_layout_constraintCircleRadius 48\nint styleable ConstraintLayout_Layout_layout_constraintDimensionRatio 49\nint styleable ConstraintLayout_Layout_layout_constraintEnd_toEndOf 50\nint styleable ConstraintLayout_Layout_layout_constraintEnd_toStartOf 51\nint styleable ConstraintLayout_Layout_layout_constraintGuide_begin 52\nint styleable ConstraintLayout_Layout_layout_constraintGuide_end 53\nint styleable ConstraintLayout_Layout_layout_constraintGuide_percent 54\nint styleable ConstraintLayout_Layout_layout_constraintHeight_default 55\nint styleable ConstraintLayout_Layout_layout_constraintHeight_max 56\nint styleable ConstraintLayout_Layout_layout_constraintHeight_min 57\nint styleable ConstraintLayout_Layout_layout_constraintHeight_percent 58\nint styleable ConstraintLayout_Layout_layout_constraintHorizontal_bias 59\nint styleable ConstraintLayout_Layout_layout_constraintHorizontal_chainStyle 60\nint styleable ConstraintLayout_Layout_layout_constraintHorizontal_weight 61\nint styleable ConstraintLayout_Layout_layout_constraintLeft_creator 62\nint styleable ConstraintLayout_Layout_layout_constraintLeft_toLeftOf 63\nint styleable ConstraintLayout_Layout_layout_constraintLeft_toRightOf 64\nint styleable ConstraintLayout_Layout_layout_constraintRight_creator 65\nint styleable ConstraintLayout_Layout_layout_constraintRight_toLeftOf 66\nint styleable ConstraintLayout_Layout_layout_constraintRight_toRightOf 67\nint styleable ConstraintLayout_Layout_layout_constraintStart_toEndOf 68\nint styleable ConstraintLayout_Layout_layout_constraintStart_toStartOf 69\nint styleable ConstraintLayout_Layout_layout_constraintTag 70\nint styleable ConstraintLayout_Layout_layout_constraintTop_creator 71\nint styleable ConstraintLayout_Layout_layout_constraintTop_toBottomOf 72\nint styleable ConstraintLayout_Layout_layout_constraintTop_toTopOf 73\nint styleable ConstraintLayout_Layout_layout_constraintVertical_bias 74\nint styleable ConstraintLayout_Layout_layout_constraintVertical_chainStyle 75\nint styleable ConstraintLayout_Layout_layout_constraintVertical_weight 76\nint styleable ConstraintLayout_Layout_layout_constraintWidth_default 77\nint styleable ConstraintLayout_Layout_layout_constraintWidth_max 78\nint styleable ConstraintLayout_Layout_layout_constraintWidth_min 79\nint styleable ConstraintLayout_Layout_layout_constraintWidth_percent 80\nint styleable ConstraintLayout_Layout_layout_editor_absoluteX 81\nint styleable ConstraintLayout_Layout_layout_editor_absoluteY 82\nint styleable ConstraintLayout_Layout_layout_goneMarginBottom 83\nint styleable ConstraintLayout_Layout_layout_goneMarginEnd 84\nint styleable ConstraintLayout_Layout_layout_goneMarginLeft 85\nint styleable ConstraintLayout_Layout_layout_goneMarginRight 86\nint styleable ConstraintLayout_Layout_layout_goneMarginStart 87\nint styleable ConstraintLayout_Layout_layout_goneMarginTop 88\nint styleable ConstraintLayout_Layout_layout_optimizationLevel 89\nint[] styleable ConstraintLayout_placeholder { 0x0, 0x0 }\nint styleable ConstraintLayout_placeholder_content 0\nint styleable ConstraintLayout_placeholder_placeholder_emptyVisibility 1\nint[] styleable ConstraintSet { 0x101031f, 0x1010440, 0x10100d0, 0x10100f5, 0x10100fa, 0x10103b6, 0x10100f7, 0x10100f9, 0x10103b5, 0x10100f8, 0x10100f4, 0x1010120, 0x101011f, 0x1010140, 0x101013f, 0x10100c4, 0x10101b5, 0x10101b6, 0x1010326, 0x1010327, 0x1010328, 0x1010324, 0x1010325, 0x1010320, 0x1010321, 0x1010322, 0x1010323, 0x10103fa, 0x10100dc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable ConstraintSet_android_alpha 0\nint styleable ConstraintSet_android_elevation 1\nint styleable ConstraintSet_android_id 2\nint styleable ConstraintSet_android_layout_height 3\nint styleable ConstraintSet_android_layout_marginBottom 4\nint styleable ConstraintSet_android_layout_marginEnd 5\nint styleable ConstraintSet_android_layout_marginLeft 6\nint styleable ConstraintSet_android_layout_marginRight 7\nint styleable ConstraintSet_android_layout_marginStart 8\nint styleable ConstraintSet_android_layout_marginTop 9\nint styleable ConstraintSet_android_layout_width 10\nint styleable ConstraintSet_android_maxHeight 11\nint styleable ConstraintSet_android_maxWidth 12\nint styleable ConstraintSet_android_minHeight 13\nint styleable ConstraintSet_android_minWidth 14\nint styleable ConstraintSet_android_orientation 15\nint styleable ConstraintSet_android_pivotX 16\nint styleable ConstraintSet_android_pivotY 17\nint styleable ConstraintSet_android_rotation 18\nint styleable ConstraintSet_android_rotationX 19\nint styleable ConstraintSet_android_rotationY 20\nint styleable ConstraintSet_android_scaleX 21\nint styleable ConstraintSet_android_scaleY 22\nint styleable ConstraintSet_android_transformPivotX 23\nint styleable ConstraintSet_android_transformPivotY 24\nint styleable ConstraintSet_android_translationX 25\nint styleable ConstraintSet_android_translationY 26\nint styleable ConstraintSet_android_translationZ 27\nint styleable ConstraintSet_android_visibility 28\nint styleable ConstraintSet_animate_relativeTo 29\nint styleable ConstraintSet_barrierAllowsGoneWidgets 30\nint styleable ConstraintSet_barrierDirection 31\nint styleable ConstraintSet_barrierMargin 32\nint styleable ConstraintSet_chainUseRtl 33\nint styleable ConstraintSet_constraint_referenced_ids 34\nint styleable ConstraintSet_deriveConstraintsFrom 35\nint styleable ConstraintSet_drawPath 36\nint styleable ConstraintSet_flow_firstHorizontalBias 37\nint styleable ConstraintSet_flow_firstHorizontalStyle 38\nint styleable ConstraintSet_flow_firstVerticalBias 39\nint styleable ConstraintSet_flow_firstVerticalStyle 40\nint styleable ConstraintSet_flow_horizontalAlign 41\nint styleable ConstraintSet_flow_horizontalBias 42\nint styleable ConstraintSet_flow_horizontalGap 43\nint styleable ConstraintSet_flow_horizontalStyle 44\nint styleable ConstraintSet_flow_lastHorizontalBias 45\nint styleable ConstraintSet_flow_lastHorizontalStyle 46\nint styleable ConstraintSet_flow_lastVerticalBias 47\nint styleable ConstraintSet_flow_lastVerticalStyle 48\nint styleable ConstraintSet_flow_maxElementsWrap 49\nint styleable ConstraintSet_flow_verticalAlign 50\nint styleable ConstraintSet_flow_verticalBias 51\nint styleable ConstraintSet_flow_verticalGap 52\nint styleable ConstraintSet_flow_verticalStyle 53\nint styleable ConstraintSet_flow_wrapMode 54\nint styleable ConstraintSet_layout_constrainedHeight 55\nint styleable ConstraintSet_layout_constrainedWidth 56\nint styleable ConstraintSet_layout_constraintBaseline_creator 57\nint styleable ConstraintSet_layout_constraintBaseline_toBaselineOf 58\nint styleable ConstraintSet_layout_constraintBottom_creator 59\nint styleable ConstraintSet_layout_constraintBottom_toBottomOf 60\nint styleable ConstraintSet_layout_constraintBottom_toTopOf 61\nint styleable ConstraintSet_layout_constraintCircle 62\nint styleable ConstraintSet_layout_constraintCircleAngle 63\nint styleable ConstraintSet_layout_constraintCircleRadius 64\nint styleable ConstraintSet_layout_constraintDimensionRatio 65\nint styleable ConstraintSet_layout_constraintEnd_toEndOf 66\nint styleable ConstraintSet_layout_constraintEnd_toStartOf 67\nint styleable ConstraintSet_layout_constraintGuide_begin 68\nint styleable ConstraintSet_layout_constraintGuide_end 69\nint styleable ConstraintSet_layout_constraintGuide_percent 70\nint styleable ConstraintSet_layout_constraintHeight_default 71\nint styleable ConstraintSet_layout_constraintHeight_max 72\nint styleable ConstraintSet_layout_constraintHeight_min 73\nint styleable ConstraintSet_layout_constraintHeight_percent 74\nint styleable ConstraintSet_layout_constraintHorizontal_bias 75\nint styleable ConstraintSet_layout_constraintHorizontal_chainStyle 76\nint styleable ConstraintSet_layout_constraintHorizontal_weight 77\nint styleable ConstraintSet_layout_constraintLeft_creator 78\nint styleable ConstraintSet_layout_constraintLeft_toLeftOf 79\nint styleable ConstraintSet_layout_constraintLeft_toRightOf 80\nint styleable ConstraintSet_layout_constraintRight_creator 81\nint styleable ConstraintSet_layout_constraintRight_toLeftOf 82\nint styleable ConstraintSet_layout_constraintRight_toRightOf 83\nint styleable ConstraintSet_layout_constraintStart_toEndOf 84\nint styleable ConstraintSet_layout_constraintStart_toStartOf 85\nint styleable ConstraintSet_layout_constraintTag 86\nint styleable ConstraintSet_layout_constraintTop_creator 87\nint styleable ConstraintSet_layout_constraintTop_toBottomOf 88\nint styleable ConstraintSet_layout_constraintTop_toTopOf 89\nint styleable ConstraintSet_layout_constraintVertical_bias 90\nint styleable ConstraintSet_layout_constraintVertical_chainStyle 91\nint styleable ConstraintSet_layout_constraintVertical_weight 92\nint styleable ConstraintSet_layout_constraintWidth_default 93\nint styleable ConstraintSet_layout_constraintWidth_max 94\nint styleable ConstraintSet_layout_constraintWidth_min 95\nint styleable ConstraintSet_layout_constraintWidth_percent 96\nint styleable ConstraintSet_layout_editor_absoluteX 97\nint styleable ConstraintSet_layout_editor_absoluteY 98\nint styleable ConstraintSet_layout_goneMarginBottom 99\nint styleable ConstraintSet_layout_goneMarginEnd 100\nint styleable ConstraintSet_layout_goneMarginLeft 101\nint styleable ConstraintSet_layout_goneMarginRight 102\nint styleable ConstraintSet_layout_goneMarginStart 103\nint styleable ConstraintSet_layout_goneMarginTop 104\nint styleable ConstraintSet_motionProgress 105\nint styleable ConstraintSet_motionStagger 106\nint styleable ConstraintSet_pathMotionArc 107\nint styleable ConstraintSet_pivotAnchor 108\nint styleable ConstraintSet_transitionEasing 109\nint styleable ConstraintSet_transitionPathRotate 110\nint[] styleable CoordinatorLayout { 0x0, 0x0 }\nint styleable CoordinatorLayout_keylines 0\nint styleable CoordinatorLayout_statusBarBackground 1\nint[] styleable CoordinatorLayout_Layout { 0x10100b3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable CoordinatorLayout_Layout_android_layout_gravity 0\nint styleable CoordinatorLayout_Layout_layout_anchor 1\nint styleable CoordinatorLayout_Layout_layout_anchorGravity 2\nint styleable CoordinatorLayout_Layout_layout_behavior 3\nint styleable CoordinatorLayout_Layout_layout_dodgeInsetEdges 4\nint styleable CoordinatorLayout_Layout_layout_insetEdge 5\nint styleable CoordinatorLayout_Layout_layout_keyline 6\nint[] styleable CustomAttribute { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable CustomAttribute_attributeName 0\nint styleable CustomAttribute_customBoolean 1\nint styleable CustomAttribute_customColorDrawableValue 2\nint styleable CustomAttribute_customColorValue 3\nint styleable CustomAttribute_customDimension 4\nint styleable CustomAttribute_customFloatValue 5\nint styleable CustomAttribute_customIntegerValue 6\nint styleable CustomAttribute_customPixelDimension 7\nint styleable CustomAttribute_customStringValue 8\nint[] styleable DrawerArrowToggle { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable DrawerArrowToggle_arrowHeadLength 0\nint styleable DrawerArrowToggle_arrowShaftLength 1\nint styleable DrawerArrowToggle_barLength 2\nint styleable DrawerArrowToggle_color 3\nint styleable DrawerArrowToggle_drawableSize 4\nint styleable DrawerArrowToggle_gapBetweenBars 5\nint styleable DrawerArrowToggle_spinBars 6\nint styleable DrawerArrowToggle_thickness 7\nint[] styleable ExtendedFloatingActionButton { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable ExtendedFloatingActionButton_collapsedSize 0\nint styleable ExtendedFloatingActionButton_elevation 1\nint styleable ExtendedFloatingActionButton_extendMotionSpec 2\nint styleable ExtendedFloatingActionButton_hideMotionSpec 3\nint styleable ExtendedFloatingActionButton_showMotionSpec 4\nint styleable ExtendedFloatingActionButton_shrinkMotionSpec 5\nint[] styleable ExtendedFloatingActionButton_Behavior_Layout { 0x0, 0x0 }\nint styleable ExtendedFloatingActionButton_Behavior_Layout_behavior_autoHide 0\nint styleable ExtendedFloatingActionButton_Behavior_Layout_behavior_autoShrink 1\nint[] styleable FloatingActionButton { 0x101000e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable FloatingActionButton_android_enabled 0\nint styleable FloatingActionButton_backgroundTint 1\nint styleable FloatingActionButton_backgroundTintMode 2\nint styleable FloatingActionButton_borderWidth 3\nint styleable FloatingActionButton_elevation 4\nint styleable FloatingActionButton_ensureMinTouchTargetSize 5\nint styleable FloatingActionButton_fabCustomSize 6\nint styleable FloatingActionButton_fabSize 7\nint styleable FloatingActionButton_hideMotionSpec 8\nint styleable FloatingActionButton_hoveredFocusedTranslationZ 9\nint styleable FloatingActionButton_maxImageSize 10\nint styleable FloatingActionButton_pressedTranslationZ 11\nint styleable FloatingActionButton_rippleColor 12\nint styleable FloatingActionButton_shapeAppearance 13\nint styleable FloatingActionButton_shapeAppearanceOverlay 14\nint styleable FloatingActionButton_showMotionSpec 15\nint styleable FloatingActionButton_useCompatPadding 16\nint[] styleable FloatingActionButton_Behavior_Layout { 0x0 }\nint styleable FloatingActionButton_Behavior_Layout_behavior_autoHide 0\nint[] styleable FlowLayout { 0x0, 0x0 }\nint styleable FlowLayout_itemSpacing 0\nint styleable FlowLayout_lineSpacing 1\nint[] styleable FontFamily { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable FontFamily_fontProviderAuthority 0\nint styleable FontFamily_fontProviderCerts 1\nint styleable FontFamily_fontProviderFetchStrategy 2\nint styleable FontFamily_fontProviderFetchTimeout 3\nint styleable FontFamily_fontProviderPackage 4\nint styleable FontFamily_fontProviderQuery 5\nint[] styleable FontFamilyFont { 0x1010532, 0x101053f, 0x1010570, 0x1010533, 0x101056f, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable FontFamilyFont_android_font 0\nint styleable FontFamilyFont_android_fontStyle 1\nint styleable FontFamilyFont_android_fontVariationSettings 2\nint styleable FontFamilyFont_android_fontWeight 3\nint styleable FontFamilyFont_android_ttcIndex 4\nint styleable FontFamilyFont_font 5\nint styleable FontFamilyFont_fontStyle 6\nint styleable FontFamilyFont_fontVariationSettings 7\nint styleable FontFamilyFont_fontWeight 8\nint styleable FontFamilyFont_ttcIndex 9\nint[] styleable ForegroundLinearLayout { 0x1010109, 0x1010200, 0x0 }\nint styleable ForegroundLinearLayout_android_foreground 0\nint styleable ForegroundLinearLayout_android_foregroundGravity 1\nint styleable ForegroundLinearLayout_foregroundInsidePadding 2\nint[] styleable GradientColor { 0x101020b, 0x10101a2, 0x10101a3, 0x101019e, 0x1010512, 0x1010513, 0x10101a4, 0x101019d, 0x1010510, 0x1010511, 0x1010201, 0x10101a1 }\nint styleable GradientColor_android_centerColor 0\nint styleable GradientColor_android_centerX 1\nint styleable GradientColor_android_centerY 2\nint styleable GradientColor_android_endColor 3\nint styleable GradientColor_android_endX 4\nint styleable GradientColor_android_endY 5\nint styleable GradientColor_android_gradientRadius 6\nint styleable GradientColor_android_startColor 7\nint styleable GradientColor_android_startX 8\nint styleable GradientColor_android_startY 9\nint styleable GradientColor_android_tileMode 10\nint styleable GradientColor_android_type 11\nint[] styleable GradientColorItem { 0x10101a5, 0x1010514 }\nint styleable GradientColorItem_android_color 0\nint styleable GradientColorItem_android_offset 1\nint[] styleable ImageFilterView { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable ImageFilterView_altSrc 0\nint styleable ImageFilterView_brightness 1\nint styleable ImageFilterView_contrast 2\nint styleable ImageFilterView_crossfade 3\nint styleable ImageFilterView_overlay 4\nint styleable ImageFilterView_round 5\nint styleable ImageFilterView_roundPercent 6\nint styleable ImageFilterView_saturation 7\nint styleable ImageFilterView_warmth 8\nint[] styleable Insets { 0x0, 0x0, 0x0 }\nint styleable Insets_paddingBottomSystemWindowInsets 0\nint styleable Insets_paddingLeftSystemWindowInsets 1\nint styleable Insets_paddingRightSystemWindowInsets 2\nint[] styleable KeyAttribute { 0x101031f, 0x1010440, 0x1010326, 0x1010327, 0x1010328, 0x1010324, 0x1010325, 0x1010320, 0x1010321, 0x1010322, 0x1010323, 0x10103fa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable KeyAttribute_android_alpha 0\nint styleable KeyAttribute_android_elevation 1\nint styleable KeyAttribute_android_rotation 2\nint styleable KeyAttribute_android_rotationX 3\nint styleable KeyAttribute_android_rotationY 4\nint styleable KeyAttribute_android_scaleX 5\nint styleable KeyAttribute_android_scaleY 6\nint styleable KeyAttribute_android_transformPivotX 7\nint styleable KeyAttribute_android_transformPivotY 8\nint styleable KeyAttribute_android_translationX 9\nint styleable KeyAttribute_android_translationY 10\nint styleable KeyAttribute_android_translationZ 11\nint styleable KeyAttribute_curveFit 12\nint styleable KeyAttribute_framePosition 13\nint styleable KeyAttribute_motionProgress 14\nint styleable KeyAttribute_motionTarget 15\nint styleable KeyAttribute_transitionEasing 16\nint styleable KeyAttribute_transitionPathRotate 17\nint[] styleable KeyCycle { 0x101031f, 0x1010440, 0x1010326, 0x1010327, 0x1010328, 0x1010324, 0x1010325, 0x1010322, 0x1010323, 0x10103fa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable KeyCycle_android_alpha 0\nint styleable KeyCycle_android_elevation 1\nint styleable KeyCycle_android_rotation 2\nint styleable KeyCycle_android_rotationX 3\nint styleable KeyCycle_android_rotationY 4\nint styleable KeyCycle_android_scaleX 5\nint styleable KeyCycle_android_scaleY 6\nint styleable KeyCycle_android_translationX 7\nint styleable KeyCycle_android_translationY 8\nint styleable KeyCycle_android_translationZ 9\nint styleable KeyCycle_curveFit 10\nint styleable KeyCycle_framePosition 11\nint styleable KeyCycle_motionProgress 12\nint styleable KeyCycle_motionTarget 13\nint styleable KeyCycle_transitionEasing 14\nint styleable KeyCycle_transitionPathRotate 15\nint styleable KeyCycle_waveOffset 16\nint styleable KeyCycle_wavePeriod 17\nint styleable KeyCycle_waveShape 18\nint styleable KeyCycle_waveVariesBy 19\nint[] styleable KeyPosition { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable KeyPosition_curveFit 0\nint styleable KeyPosition_drawPath 1\nint styleable KeyPosition_framePosition 2\nint styleable KeyPosition_keyPositionType 3\nint styleable KeyPosition_motionTarget 4\nint styleable KeyPosition_pathMotionArc 5\nint styleable KeyPosition_percentHeight 6\nint styleable KeyPosition_percentWidth 7\nint styleable KeyPosition_percentX 8\nint styleable KeyPosition_percentY 9\nint styleable KeyPosition_sizePercent 10\nint styleable KeyPosition_transitionEasing 11\nint[] styleable KeyTimeCycle { 0x101031f, 0x1010440, 0x1010326, 0x1010327, 0x1010328, 0x1010324, 0x1010325, 0x1010322, 0x1010323, 0x10103fa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable KeyTimeCycle_android_alpha 0\nint styleable KeyTimeCycle_android_elevation 1\nint styleable KeyTimeCycle_android_rotation 2\nint styleable KeyTimeCycle_android_rotationX 3\nint styleable KeyTimeCycle_android_rotationY 4\nint styleable KeyTimeCycle_android_scaleX 5\nint styleable KeyTimeCycle_android_scaleY 6\nint styleable KeyTimeCycle_android_translationX 7\nint styleable KeyTimeCycle_android_translationY 8\nint styleable KeyTimeCycle_android_translationZ 9\nint styleable KeyTimeCycle_curveFit 10\nint styleable KeyTimeCycle_framePosition 11\nint styleable KeyTimeCycle_motionProgress 12\nint styleable KeyTimeCycle_motionTarget 13\nint styleable KeyTimeCycle_transitionEasing 14\nint styleable KeyTimeCycle_transitionPathRotate 15\nint styleable KeyTimeCycle_waveDecay 16\nint styleable KeyTimeCycle_waveOffset 17\nint styleable KeyTimeCycle_wavePeriod 18\nint styleable KeyTimeCycle_waveShape 19\nint[] styleable KeyTrigger { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable KeyTrigger_framePosition 0\nint styleable KeyTrigger_motionTarget 1\nint styleable KeyTrigger_motion_postLayoutCollision 2\nint styleable KeyTrigger_motion_triggerOnCollision 3\nint styleable KeyTrigger_onCross 4\nint styleable KeyTrigger_onNegativeCross 5\nint styleable KeyTrigger_onPositiveCross 6\nint styleable KeyTrigger_triggerId 7\nint styleable KeyTrigger_triggerReceiver 8\nint styleable KeyTrigger_triggerSlack 9\nint[] styleable Layout { 0x10100f5, 0x10100fa, 0x10103b6, 0x10100f7, 0x10100f9, 0x10103b5, 0x10100f8, 0x10100f4, 0x10100c4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable Layout_android_layout_height 0\nint styleable Layout_android_layout_marginBottom 1\nint styleable Layout_android_layout_marginEnd 2\nint styleable Layout_android_layout_marginLeft 3\nint styleable Layout_android_layout_marginRight 4\nint styleable Layout_android_layout_marginStart 5\nint styleable Layout_android_layout_marginTop 6\nint styleable Layout_android_layout_width 7\nint styleable Layout_android_orientation 8\nint styleable Layout_barrierAllowsGoneWidgets 9\nint styleable Layout_barrierDirection 10\nint styleable Layout_barrierMargin 11\nint styleable Layout_chainUseRtl 12\nint styleable Layout_constraint_referenced_ids 13\nint styleable Layout_layout_constrainedHeight 14\nint styleable Layout_layout_constrainedWidth 15\nint styleable Layout_layout_constraintBaseline_creator 16\nint styleable Layout_layout_constraintBaseline_toBaselineOf 17\nint styleable Layout_layout_constraintBottom_creator 18\nint styleable Layout_layout_constraintBottom_toBottomOf 19\nint styleable Layout_layout_constraintBottom_toTopOf 20\nint styleable Layout_layout_constraintCircle 21\nint styleable Layout_layout_constraintCircleAngle 22\nint styleable Layout_layout_constraintCircleRadius 23\nint styleable Layout_layout_constraintDimensionRatio 24\nint styleable Layout_layout_constraintEnd_toEndOf 25\nint styleable Layout_layout_constraintEnd_toStartOf 26\nint styleable Layout_layout_constraintGuide_begin 27\nint styleable Layout_layout_constraintGuide_end 28\nint styleable Layout_layout_constraintGuide_percent 29\nint styleable Layout_layout_constraintHeight_default 30\nint styleable Layout_layout_constraintHeight_max 31\nint styleable Layout_layout_constraintHeight_min 32\nint styleable Layout_layout_constraintHeight_percent 33\nint styleable Layout_layout_constraintHorizontal_bias 34\nint styleable Layout_layout_constraintHorizontal_chainStyle 35\nint styleable Layout_layout_constraintHorizontal_weight 36\nint styleable Layout_layout_constraintLeft_creator 37\nint styleable Layout_layout_constraintLeft_toLeftOf 38\nint styleable Layout_layout_constraintLeft_toRightOf 39\nint styleable Layout_layout_constraintRight_creator 40\nint styleable Layout_layout_constraintRight_toLeftOf 41\nint styleable Layout_layout_constraintRight_toRightOf 42\nint styleable Layout_layout_constraintStart_toEndOf 43\nint styleable Layout_layout_constraintStart_toStartOf 44\nint styleable Layout_layout_constraintTop_creator 45\nint styleable Layout_layout_constraintTop_toBottomOf 46\nint styleable Layout_layout_constraintTop_toTopOf 47\nint styleable Layout_layout_constraintVertical_bias 48\nint styleable Layout_layout_constraintVertical_chainStyle 49\nint styleable Layout_layout_constraintVertical_weight 50\nint styleable Layout_layout_constraintWidth_default 51\nint styleable Layout_layout_constraintWidth_max 52\nint styleable Layout_layout_constraintWidth_min 53\nint styleable Layout_layout_constraintWidth_percent 54\nint styleable Layout_layout_editor_absoluteX 55\nint styleable Layout_layout_editor_absoluteY 56\nint styleable Layout_layout_goneMarginBottom 57\nint styleable Layout_layout_goneMarginEnd 58\nint styleable Layout_layout_goneMarginLeft 59\nint styleable Layout_layout_goneMarginRight 60\nint styleable Layout_layout_goneMarginStart 61\nint styleable Layout_layout_goneMarginTop 62\nint styleable Layout_maxHeight 63\nint styleable Layout_maxWidth 64\nint styleable Layout_minHeight 65\nint styleable Layout_minWidth 66\nint[] styleable LinearLayoutCompat { 0x1010126, 0x1010127, 0x10100af, 0x10100c4, 0x1010128, 0x0, 0x0, 0x0, 0x0 }\nint styleable LinearLayoutCompat_android_baselineAligned 0\nint styleable LinearLayoutCompat_android_baselineAlignedChildIndex 1\nint styleable LinearLayoutCompat_android_gravity 2\nint styleable LinearLayoutCompat_android_orientation 3\nint styleable LinearLayoutCompat_android_weightSum 4\nint styleable LinearLayoutCompat_divider 5\nint styleable LinearLayoutCompat_dividerPadding 6\nint styleable LinearLayoutCompat_measureWithLargestChild 7\nint styleable LinearLayoutCompat_showDividers 8\nint[] styleable LinearLayoutCompat_Layout { 0x10100b3, 0x10100f5, 0x1010181, 0x10100f4 }\nint styleable LinearLayoutCompat_Layout_android_layout_gravity 0\nint styleable LinearLayoutCompat_Layout_android_layout_height 1\nint styleable LinearLayoutCompat_Layout_android_layout_weight 2\nint styleable LinearLayoutCompat_Layout_android_layout_width 3\nint[] styleable LinearProgressIndicator { 0x0, 0x0 }\nint styleable LinearProgressIndicator_indeterminateAnimationType 0\nint styleable LinearProgressIndicator_indicatorDirectionLinear 1\nint[] styleable ListPopupWindow { 0x10102ac, 0x10102ad }\nint styleable ListPopupWindow_android_dropDownHorizontalOffset 0\nint styleable ListPopupWindow_android_dropDownVerticalOffset 1\nint[] styleable MaterialAlertDialog { 0x0, 0x0, 0x0, 0x0 }\nint styleable MaterialAlertDialog_backgroundInsetBottom 0\nint styleable MaterialAlertDialog_backgroundInsetEnd 1\nint styleable MaterialAlertDialog_backgroundInsetStart 2\nint styleable MaterialAlertDialog_backgroundInsetTop 3\nint[] styleable MaterialAlertDialogTheme { 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable MaterialAlertDialogTheme_materialAlertDialogBodyTextStyle 0\nint styleable MaterialAlertDialogTheme_materialAlertDialogTheme 1\nint styleable MaterialAlertDialogTheme_materialAlertDialogTitleIconStyle 2\nint styleable MaterialAlertDialogTheme_materialAlertDialogTitlePanelStyle 3\nint styleable MaterialAlertDialogTheme_materialAlertDialogTitleTextStyle 4\nint[] styleable MaterialAutoCompleteTextView { 0x1010220 }\nint styleable MaterialAutoCompleteTextView_android_inputType 0\nint[] styleable MaterialButton { 0x10100d4, 0x10101e5, 0x10101ba, 0x10101b7, 0x10101b8, 0x10101b9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable MaterialButton_android_background 0\nint styleable MaterialButton_android_checkable 1\nint styleable MaterialButton_android_insetBottom 2\nint styleable MaterialButton_android_insetLeft 3\nint styleable MaterialButton_android_insetRight 4\nint styleable MaterialButton_android_insetTop 5\nint styleable MaterialButton_backgroundTint 6\nint styleable MaterialButton_backgroundTintMode 7\nint styleable MaterialButton_cornerRadius 8\nint styleable MaterialButton_elevation 9\nint styleable MaterialButton_icon 10\nint styleable MaterialButton_iconGravity 11\nint styleable MaterialButton_iconPadding 12\nint styleable MaterialButton_iconSize 13\nint styleable MaterialButton_iconTint 14\nint styleable MaterialButton_iconTintMode 15\nint styleable MaterialButton_rippleColor 16\nint styleable MaterialButton_shapeAppearance 17\nint styleable MaterialButton_shapeAppearanceOverlay 18\nint styleable MaterialButton_strokeColor 19\nint styleable MaterialButton_strokeWidth 20\nint[] styleable MaterialButtonToggleGroup { 0x0, 0x0, 0x0 }\nint styleable MaterialButtonToggleGroup_checkedButton 0\nint styleable MaterialButtonToggleGroup_selectionRequired 1\nint styleable MaterialButtonToggleGroup_singleSelection 2\nint[] styleable MaterialCalendar { 0x101020d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable MaterialCalendar_android_windowFullscreen 0\nint styleable MaterialCalendar_dayInvalidStyle 1\nint styleable MaterialCalendar_daySelectedStyle 2\nint styleable MaterialCalendar_dayStyle 3\nint styleable MaterialCalendar_dayTodayStyle 4\nint styleable MaterialCalendar_nestedScrollable 5\nint styleable MaterialCalendar_rangeFillColor 6\nint styleable MaterialCalendar_yearSelectedStyle 7\nint styleable MaterialCalendar_yearStyle 8\nint styleable MaterialCalendar_yearTodayStyle 9\nint[] styleable MaterialCalendarItem { 0x10101ba, 0x10101b7, 0x10101b8, 0x10101b9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable MaterialCalendarItem_android_insetBottom 0\nint styleable MaterialCalendarItem_android_insetLeft 1\nint styleable MaterialCalendarItem_android_insetRight 2\nint styleable MaterialCalendarItem_android_insetTop 3\nint styleable MaterialCalendarItem_itemFillColor 4\nint styleable MaterialCalendarItem_itemShapeAppearance 5\nint styleable MaterialCalendarItem_itemShapeAppearanceOverlay 6\nint styleable MaterialCalendarItem_itemStrokeColor 7\nint styleable MaterialCalendarItem_itemStrokeWidth 8\nint styleable MaterialCalendarItem_itemTextColor 9\nint[] styleable MaterialCardView { 0x10101e5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable MaterialCardView_android_checkable 0\nint styleable MaterialCardView_cardForegroundColor 1\nint styleable MaterialCardView_checkedIcon 2\nint styleable MaterialCardView_checkedIconMargin 3\nint styleable MaterialCardView_checkedIconSize 4\nint styleable MaterialCardView_checkedIconTint 5\nint styleable MaterialCardView_rippleColor 6\nint styleable MaterialCardView_shapeAppearance 7\nint styleable MaterialCardView_shapeAppearanceOverlay 8\nint styleable MaterialCardView_state_dragged 9\nint styleable MaterialCardView_strokeColor 10\nint styleable MaterialCardView_strokeWidth 11\nint[] styleable MaterialCheckBox { 0x0, 0x0 }\nint styleable MaterialCheckBox_buttonTint 0\nint styleable MaterialCheckBox_useMaterialThemeColors 1\nint[] styleable MaterialRadioButton { 0x0, 0x0 }\nint styleable MaterialRadioButton_buttonTint 0\nint styleable MaterialRadioButton_useMaterialThemeColors 1\nint[] styleable MaterialShape { 0x0, 0x0 }\nint styleable MaterialShape_shapeAppearance 0\nint styleable MaterialShape_shapeAppearanceOverlay 1\nint[] styleable MaterialTextAppearance { 0x10104b6, 0x101057f, 0x0 }\nint styleable MaterialTextAppearance_android_letterSpacing 0\nint styleable MaterialTextAppearance_android_lineHeight 1\nint styleable MaterialTextAppearance_lineHeight 2\nint[] styleable MaterialTextView { 0x101057f, 0x1010034, 0x0 }\nint styleable MaterialTextView_android_lineHeight 0\nint styleable MaterialTextView_android_textAppearance 1\nint styleable MaterialTextView_lineHeight 2\nint[] styleable MaterialTimePicker { 0x0, 0x0 }\nint styleable MaterialTimePicker_clockIcon 0\nint styleable MaterialTimePicker_keyboardIcon 1\nint[] styleable MaterialToolbar { 0x0 }\nint styleable MaterialToolbar_navigationIconTint 0\nint[] styleable MenuGroup { 0x10101e0, 0x101000e, 0x10100d0, 0x10101de, 0x10101df, 0x1010194 }\nint styleable MenuGroup_android_checkableBehavior 0\nint styleable MenuGroup_android_enabled 1\nint styleable MenuGroup_android_id 2\nint styleable MenuGroup_android_menuCategory 3\nint styleable MenuGroup_android_orderInCategory 4\nint styleable MenuGroup_android_visible 5\nint[] styleable MenuItem { 0x0, 0x0, 0x0, 0x0, 0x10101e3, 0x10101e5, 0x1010106, 0x101000e, 0x1010002, 0x10100d0, 0x10101de, 0x10101e4, 0x101026f, 0x10101df, 0x10101e1, 0x10101e2, 0x1010194, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable MenuItem_actionLayout 0\nint styleable MenuItem_actionProviderClass 1\nint styleable MenuItem_actionViewClass 2\nint styleable MenuItem_alphabeticModifiers 3\nint styleable MenuItem_android_alphabeticShortcut 4\nint styleable MenuItem_android_checkable 5\nint styleable MenuItem_android_checked 6\nint styleable MenuItem_android_enabled 7\nint styleable MenuItem_android_icon 8\nint styleable MenuItem_android_id 9\nint styleable MenuItem_android_menuCategory 10\nint styleable MenuItem_android_numericShortcut 11\nint styleable MenuItem_android_onClick 12\nint styleable MenuItem_android_orderInCategory 13\nint styleable MenuItem_android_title 14\nint styleable MenuItem_android_titleCondensed 15\nint styleable MenuItem_android_visible 16\nint styleable MenuItem_contentDescription 17\nint styleable MenuItem_iconTint 18\nint styleable MenuItem_iconTintMode 19\nint styleable MenuItem_numericModifiers 20\nint styleable MenuItem_showAsAction 21\nint styleable MenuItem_tooltipText 22\nint[] styleable MenuView { 0x101012f, 0x101012d, 0x1010130, 0x1010131, 0x101012c, 0x101012e, 0x10100ae, 0x0, 0x0 }\nint styleable MenuView_android_headerBackground 0\nint styleable MenuView_android_horizontalDivider 1\nint styleable MenuView_android_itemBackground 2\nint styleable MenuView_android_itemIconDisabledAlpha 3\nint styleable MenuView_android_itemTextAppearance 4\nint styleable MenuView_android_verticalDivider 5\nint styleable MenuView_android_windowAnimationStyle 6\nint styleable MenuView_preserveIconSpacing 7\nint styleable MenuView_subMenuArrow 8\nint[] styleable MockView { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable MockView_mock_diagonalsColor 0\nint styleable MockView_mock_label 1\nint styleable MockView_mock_labelBackgroundColor 2\nint styleable MockView_mock_labelColor 3\nint styleable MockView_mock_showDiagonals 4\nint styleable MockView_mock_showLabel 5\nint[] styleable Motion { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable Motion_animate_relativeTo 0\nint styleable Motion_drawPath 1\nint styleable Motion_motionPathRotate 2\nint styleable Motion_motionStagger 3\nint styleable Motion_pathMotionArc 4\nint styleable Motion_transitionEasing 5\nint[] styleable MotionHelper { 0x0, 0x0 }\nint styleable MotionHelper_onHide 0\nint styleable MotionHelper_onShow 1\nint[] styleable MotionLayout { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable MotionLayout_applyMotionScene 0\nint styleable MotionLayout_currentState 1\nint styleable MotionLayout_layoutDescription 2\nint styleable MotionLayout_motionDebug 3\nint styleable MotionLayout_motionProgress 4\nint styleable MotionLayout_showPaths 5\nint[] styleable MotionScene { 0x0, 0x0 }\nint styleable MotionScene_defaultDuration 0\nint styleable MotionScene_layoutDuringTransition 1\nint[] styleable MotionTelltales { 0x0, 0x0, 0x0 }\nint styleable MotionTelltales_telltales_tailColor 0\nint styleable MotionTelltales_telltales_tailScale 1\nint styleable MotionTelltales_telltales_velocityMode 2\nint[] styleable NavigationView { 0x10100d4, 0x10100dd, 0x101011f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable NavigationView_android_background 0\nint styleable NavigationView_android_fitsSystemWindows 1\nint styleable NavigationView_android_maxWidth 2\nint styleable NavigationView_elevation 3\nint styleable NavigationView_headerLayout 4\nint styleable NavigationView_itemBackground 5\nint styleable NavigationView_itemHorizontalPadding 6\nint styleable NavigationView_itemIconPadding 7\nint styleable NavigationView_itemIconSize 8\nint styleable NavigationView_itemIconTint 9\nint styleable NavigationView_itemMaxLines 10\nint styleable NavigationView_itemShapeAppearance 11\nint styleable NavigationView_itemShapeAppearanceOverlay 12\nint styleable NavigationView_itemShapeFillColor 13\nint styleable NavigationView_itemShapeInsetBottom 14\nint styleable NavigationView_itemShapeInsetEnd 15\nint styleable NavigationView_itemShapeInsetStart 16\nint styleable NavigationView_itemShapeInsetTop 17\nint styleable NavigationView_itemTextAppearance 18\nint styleable NavigationView_itemTextColor 19\nint styleable NavigationView_menu 20\nint styleable NavigationView_shapeAppearance 21\nint styleable NavigationView_shapeAppearanceOverlay 22\nint[] styleable OnClick { 0x0, 0x0 }\nint styleable OnClick_clickAction 0\nint styleable OnClick_targetId 1\nint[] styleable OnSwipe { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable OnSwipe_dragDirection 0\nint styleable OnSwipe_dragScale 1\nint styleable OnSwipe_dragThreshold 2\nint styleable OnSwipe_limitBoundsTo 3\nint styleable OnSwipe_maxAcceleration 4\nint styleable OnSwipe_maxVelocity 5\nint styleable OnSwipe_moveWhenScrollAtTop 6\nint styleable OnSwipe_nestedScrollFlags 7\nint styleable OnSwipe_onTouchUp 8\nint styleable OnSwipe_touchAnchorId 9\nint styleable OnSwipe_touchAnchorSide 10\nint styleable OnSwipe_touchRegionId 11\nint[] styleable PopupWindow { 0x10102c9, 0x1010176, 0x0 }\nint styleable PopupWindow_android_popupAnimationStyle 0\nint styleable PopupWindow_android_popupBackground 1\nint styleable PopupWindow_overlapAnchor 2\nint[] styleable PopupWindowBackgroundState { 0x0 }\nint styleable PopupWindowBackgroundState_state_above_anchor 0\nint[] styleable PropertySet { 0x101031f, 0x10100dc, 0x0, 0x0, 0x0 }\nint styleable PropertySet_android_alpha 0\nint styleable PropertySet_android_visibility 1\nint styleable PropertySet_layout_constraintTag 2\nint styleable PropertySet_motionProgress 3\nint styleable PropertySet_visibilityMode 4\nint[] styleable RadialViewGroup { 0x0 }\nint styleable RadialViewGroup_materialCircleRadius 0\nint[] styleable RangeSlider { 0x0, 0x0 }\nint styleable RangeSlider_minSeparation 0\nint styleable RangeSlider_values 1\nint[] styleable RecycleListView { 0x0, 0x0 }\nint styleable RecycleListView_paddingBottomNoButtons 0\nint styleable RecycleListView_paddingTopNoTitle 1\nint[] styleable RecyclerView { 0x10100eb, 0x10100f1, 0x10100c4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable RecyclerView_android_clipToPadding 0\nint styleable RecyclerView_android_descendantFocusability 1\nint styleable RecyclerView_android_orientation 2\nint styleable RecyclerView_fastScrollEnabled 3\nint styleable RecyclerView_fastScrollHorizontalThumbDrawable 4\nint styleable RecyclerView_fastScrollHorizontalTrackDrawable 5\nint styleable RecyclerView_fastScrollVerticalThumbDrawable 6\nint styleable RecyclerView_fastScrollVerticalTrackDrawable 7\nint styleable RecyclerView_layoutManager 8\nint styleable RecyclerView_reverseLayout 9\nint styleable RecyclerView_spanCount 10\nint styleable RecyclerView_stackFromEnd 11\nint[] styleable ScrimInsetsFrameLayout { 0x0 }\nint styleable ScrimInsetsFrameLayout_insetForeground 0\nint[] styleable ScrollingViewBehavior_Layout { 0x0 }\nint styleable ScrollingViewBehavior_Layout_behavior_overlapTop 0\nint[] styleable SearchView { 0x10100da, 0x1010264, 0x1010220, 0x101011f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable SearchView_android_focusable 0\nint styleable SearchView_android_imeOptions 1\nint styleable SearchView_android_inputType 2\nint styleable SearchView_android_maxWidth 3\nint styleable SearchView_closeIcon 4\nint styleable SearchView_commitIcon 5\nint styleable SearchView_defaultQueryHint 6\nint styleable SearchView_goIcon 7\nint styleable SearchView_iconifiedByDefault 8\nint styleable SearchView_layout 9\nint styleable SearchView_queryBackground 10\nint styleable SearchView_queryHint 11\nint styleable SearchView_searchHintIcon 12\nint styleable SearchView_searchIcon 13\nint styleable SearchView_submitBackground 14\nint styleable SearchView_suggestionRowLayout 15\nint styleable SearchView_voiceIcon 16\nint[] styleable ShapeAppearance { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable ShapeAppearance_cornerFamily 0\nint styleable ShapeAppearance_cornerFamilyBottomLeft 1\nint styleable ShapeAppearance_cornerFamilyBottomRight 2\nint styleable ShapeAppearance_cornerFamilyTopLeft 3\nint styleable ShapeAppearance_cornerFamilyTopRight 4\nint styleable ShapeAppearance_cornerSize 5\nint styleable ShapeAppearance_cornerSizeBottomLeft 6\nint styleable ShapeAppearance_cornerSizeBottomRight 7\nint styleable ShapeAppearance_cornerSizeTopLeft 8\nint styleable ShapeAppearance_cornerSizeTopRight 9\nint[] styleable ShapeableImageView { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable ShapeableImageView_contentPadding 0\nint styleable ShapeableImageView_contentPaddingBottom 1\nint styleable ShapeableImageView_contentPaddingEnd 2\nint styleable ShapeableImageView_contentPaddingLeft 3\nint styleable ShapeableImageView_contentPaddingRight 4\nint styleable ShapeableImageView_contentPaddingStart 5\nint styleable ShapeableImageView_contentPaddingTop 6\nint styleable ShapeableImageView_shapeAppearance 7\nint styleable ShapeableImageView_shapeAppearanceOverlay 8\nint styleable ShapeableImageView_strokeColor 9\nint styleable ShapeableImageView_strokeWidth 10\nint[] styleable Slider { 0x101000e, 0x1010146, 0x1010024, 0x10102de, 0x10102df, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable Slider_android_enabled 0\nint styleable Slider_android_stepSize 1\nint styleable Slider_android_value 2\nint styleable Slider_android_valueFrom 3\nint styleable Slider_android_valueTo 4\nint styleable Slider_haloColor 5\nint styleable Slider_haloRadius 6\nint styleable Slider_labelBehavior 7\nint styleable Slider_labelStyle 8\nint styleable Slider_thumbColor 9\nint styleable Slider_thumbElevation 10\nint styleable Slider_thumbRadius 11\nint styleable Slider_thumbStrokeColor 12\nint styleable Slider_thumbStrokeWidth 13\nint styleable Slider_tickColor 14\nint styleable Slider_tickColorActive 15\nint styleable Slider_tickColorInactive 16\nint styleable Slider_tickVisible 17\nint styleable Slider_trackColor 18\nint styleable Slider_trackColorActive 19\nint styleable Slider_trackColorInactive 20\nint styleable Slider_trackHeight 21\nint[] styleable Snackbar { 0x0, 0x0, 0x0 }\nint styleable Snackbar_snackbarButtonStyle 0\nint styleable Snackbar_snackbarStyle 1\nint styleable Snackbar_snackbarTextViewStyle 2\nint[] styleable SnackbarLayout { 0x0, 0x101011f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable SnackbarLayout_actionTextColorAlpha 0\nint styleable SnackbarLayout_android_maxWidth 1\nint styleable SnackbarLayout_animationMode 2\nint styleable SnackbarLayout_backgroundOverlayColorAlpha 3\nint styleable SnackbarLayout_backgroundTint 4\nint styleable SnackbarLayout_backgroundTintMode 5\nint styleable SnackbarLayout_elevation 6\nint styleable SnackbarLayout_maxActionInlineWidth 7\nint[] styleable Spinner { 0x1010262, 0x10100b2, 0x1010176, 0x101017b, 0x0 }\nint styleable Spinner_android_dropDownWidth 0\nint styleable Spinner_android_entries 1\nint styleable Spinner_android_popupBackground 2\nint styleable Spinner_android_prompt 3\nint styleable Spinner_popupTheme 4\nint[] styleable State { 0x10100d0, 0x0 }\nint styleable State_android_id 0\nint styleable State_constraints 1\nint[] styleable StateListDrawable { 0x1010196, 0x101011c, 0x101030c, 0x101030d, 0x1010195, 0x1010194 }\nint styleable StateListDrawable_android_constantSize 0\nint styleable StateListDrawable_android_dither 1\nint styleable StateListDrawable_android_enterFadeDuration 2\nint styleable StateListDrawable_android_exitFadeDuration 3\nint styleable StateListDrawable_android_variablePadding 4\nint styleable StateListDrawable_android_visible 5\nint[] styleable StateListDrawableItem { 0x1010199 }\nint styleable StateListDrawableItem_android_drawable 0\nint[] styleable StateSet { 0x0 }\nint styleable StateSet_defaultState 0\nint[] styleable SwitchCompat { 0x1010125, 0x1010124, 0x1010142, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable SwitchCompat_android_textOff 0\nint styleable SwitchCompat_android_textOn 1\nint styleable SwitchCompat_android_thumb 2\nint styleable SwitchCompat_showText 3\nint styleable SwitchCompat_splitTrack 4\nint styleable SwitchCompat_switchMinWidth 5\nint styleable SwitchCompat_switchPadding 6\nint styleable SwitchCompat_switchTextAppearance 7\nint styleable SwitchCompat_thumbTextPadding 8\nint styleable SwitchCompat_thumbTint 9\nint styleable SwitchCompat_thumbTintMode 10\nint styleable SwitchCompat_track 11\nint styleable SwitchCompat_trackTint 12\nint styleable SwitchCompat_trackTintMode 13\nint[] styleable SwitchMaterial { 0x0 }\nint styleable SwitchMaterial_useMaterialThemeColors 0\nint[] styleable TabItem { 0x1010002, 0x10100f2, 0x101014f }\nint styleable TabItem_android_icon 0\nint styleable TabItem_android_layout 1\nint styleable TabItem_android_text 2\nint[] styleable TabLayout { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable TabLayout_tabBackground 0\nint styleable TabLayout_tabContentStart 1\nint styleable TabLayout_tabGravity 2\nint styleable TabLayout_tabIconTint 3\nint styleable TabLayout_tabIconTintMode 4\nint styleable TabLayout_tabIndicator 5\nint styleable TabLayout_tabIndicatorAnimationDuration 6\nint styleable TabLayout_tabIndicatorAnimationMode 7\nint styleable TabLayout_tabIndicatorColor 8\nint styleable TabLayout_tabIndicatorFullWidth 9\nint styleable TabLayout_tabIndicatorGravity 10\nint styleable TabLayout_tabIndicatorHeight 11\nint styleable TabLayout_tabInlineLabel 12\nint styleable TabLayout_tabMaxWidth 13\nint styleable TabLayout_tabMinWidth 14\nint styleable TabLayout_tabMode 15\nint styleable TabLayout_tabPadding 16\nint styleable TabLayout_tabPaddingBottom 17\nint styleable TabLayout_tabPaddingEnd 18\nint styleable TabLayout_tabPaddingStart 19\nint styleable TabLayout_tabPaddingTop 20\nint styleable TabLayout_tabRippleColor 21\nint styleable TabLayout_tabSelectedTextColor 22\nint styleable TabLayout_tabTextAppearance 23\nint styleable TabLayout_tabTextColor 24\nint styleable TabLayout_tabUnboundedRipple 25\nint[] styleable TextAppearance { 0x10103ac, 0x1010161, 0x1010162, 0x1010163, 0x1010164, 0x1010098, 0x101009a, 0x101009b, 0x1010585, 0x1010095, 0x1010097, 0x1010096, 0x0, 0x0, 0x0, 0x0 }\nint styleable TextAppearance_android_fontFamily 0\nint styleable TextAppearance_android_shadowColor 1\nint styleable TextAppearance_android_shadowDx 2\nint styleable TextAppearance_android_shadowDy 3\nint styleable TextAppearance_android_shadowRadius 4\nint styleable TextAppearance_android_textColor 5\nint styleable TextAppearance_android_textColorHint 6\nint styleable TextAppearance_android_textColorLink 7\nint styleable TextAppearance_android_textFontWeight 8\nint styleable TextAppearance_android_textSize 9\nint styleable TextAppearance_android_textStyle 10\nint styleable TextAppearance_android_typeface 11\nint styleable TextAppearance_fontFamily 12\nint styleable TextAppearance_fontVariationSettings 13\nint styleable TextAppearance_textAllCaps 14\nint styleable TextAppearance_textLocale 15\nint[] styleable TextInputEditText { 0x0 }\nint styleable TextInputEditText_textInputLayoutFocusedRectEnabled 0\nint[] styleable TextInputLayout { 0x101000e, 0x1010150, 0x101009a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable TextInputLayout_android_enabled 0\nint styleable TextInputLayout_android_hint 1\nint styleable TextInputLayout_android_textColorHint 2\nint styleable TextInputLayout_boxBackgroundColor 3\nint styleable TextInputLayout_boxBackgroundMode 4\nint styleable TextInputLayout_boxCollapsedPaddingTop 5\nint styleable TextInputLayout_boxCornerRadiusBottomEnd 6\nint styleable TextInputLayout_boxCornerRadiusBottomStart 7\nint styleable TextInputLayout_boxCornerRadiusTopEnd 8\nint styleable TextInputLayout_boxCornerRadiusTopStart 9\nint styleable TextInputLayout_boxStrokeColor 10\nint styleable TextInputLayout_boxStrokeErrorColor 11\nint styleable TextInputLayout_boxStrokeWidth 12\nint styleable TextInputLayout_boxStrokeWidthFocused 13\nint styleable TextInputLayout_counterEnabled 14\nint styleable TextInputLayout_counterMaxLength 15\nint styleable TextInputLayout_counterOverflowTextAppearance 16\nint styleable TextInputLayout_counterOverflowTextColor 17\nint styleable TextInputLayout_counterTextAppearance 18\nint styleable TextInputLayout_counterTextColor 19\nint styleable TextInputLayout_endIconCheckable 20\nint styleable TextInputLayout_endIconContentDescription 21\nint styleable TextInputLayout_endIconDrawable 22\nint styleable TextInputLayout_endIconMode 23\nint styleable TextInputLayout_endIconTint 24\nint styleable TextInputLayout_endIconTintMode 25\nint styleable TextInputLayout_errorContentDescription 26\nint styleable TextInputLayout_errorEnabled 27\nint styleable TextInputLayout_errorIconDrawable 28\nint styleable TextInputLayout_errorIconTint 29\nint styleable TextInputLayout_errorIconTintMode 30\nint styleable TextInputLayout_errorTextAppearance 31\nint styleable TextInputLayout_errorTextColor 32\nint styleable TextInputLayout_expandedHintEnabled 33\nint styleable TextInputLayout_helperText 34\nint styleable TextInputLayout_helperTextEnabled 35\nint styleable TextInputLayout_helperTextTextAppearance 36\nint styleable TextInputLayout_helperTextTextColor 37\nint styleable TextInputLayout_hintAnimationEnabled 38\nint styleable TextInputLayout_hintEnabled 39\nint styleable TextInputLayout_hintTextAppearance 40\nint styleable TextInputLayout_hintTextColor 41\nint styleable TextInputLayout_passwordToggleContentDescription 42\nint styleable TextInputLayout_passwordToggleDrawable 43\nint styleable TextInputLayout_passwordToggleEnabled 44\nint styleable TextInputLayout_passwordToggleTint 45\nint styleable TextInputLayout_passwordToggleTintMode 46\nint styleable TextInputLayout_placeholderText 47\nint styleable TextInputLayout_placeholderTextAppearance 48\nint styleable TextInputLayout_placeholderTextColor 49\nint styleable TextInputLayout_prefixText 50\nint styleable TextInputLayout_prefixTextAppearance 51\nint styleable TextInputLayout_prefixTextColor 52\nint styleable TextInputLayout_shapeAppearance 53\nint styleable TextInputLayout_shapeAppearanceOverlay 54\nint styleable TextInputLayout_startIconCheckable 55\nint styleable TextInputLayout_startIconContentDescription 56\nint styleable TextInputLayout_startIconDrawable 57\nint styleable TextInputLayout_startIconTint 58\nint styleable TextInputLayout_startIconTintMode 59\nint styleable TextInputLayout_suffixText 60\nint styleable TextInputLayout_suffixTextAppearance 61\nint styleable TextInputLayout_suffixTextColor 62\nint[] styleable ThemeEnforcement { 0x1010034, 0x0, 0x0 }\nint styleable ThemeEnforcement_android_textAppearance 0\nint styleable ThemeEnforcement_enforceMaterialTheme 1\nint styleable ThemeEnforcement_enforceTextAppearance 2\nint[] styleable Toolbar { 0x10100af, 0x1010140, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable Toolbar_android_gravity 0\nint styleable Toolbar_android_minHeight 1\nint styleable Toolbar_buttonGravity 2\nint styleable Toolbar_collapseContentDescription 3\nint styleable Toolbar_collapseIcon 4\nint styleable Toolbar_contentInsetEnd 5\nint styleable Toolbar_contentInsetEndWithActions 6\nint styleable Toolbar_contentInsetLeft 7\nint styleable Toolbar_contentInsetRight 8\nint styleable Toolbar_contentInsetStart 9\nint styleable Toolbar_contentInsetStartWithNavigation 10\nint styleable Toolbar_logo 11\nint styleable Toolbar_logoDescription 12\nint styleable Toolbar_maxButtonHeight 13\nint styleable Toolbar_menu 14\nint styleable Toolbar_navigationContentDescription 15\nint styleable Toolbar_navigationIcon 16\nint styleable Toolbar_popupTheme 17\nint styleable Toolbar_subtitle 18\nint styleable Toolbar_subtitleTextAppearance 19\nint styleable Toolbar_subtitleTextColor 20\nint styleable Toolbar_title 21\nint styleable Toolbar_titleMargin 22\nint styleable Toolbar_titleMarginBottom 23\nint styleable Toolbar_titleMarginEnd 24\nint styleable Toolbar_titleMarginStart 25\nint styleable Toolbar_titleMarginTop 26\nint styleable Toolbar_titleMargins 27\nint styleable Toolbar_titleTextAppearance 28\nint styleable Toolbar_titleTextColor 29\nint[] styleable Tooltip { 0x10100f6, 0x1010140, 0x101013f, 0x10100d5, 0x101014f, 0x1010034, 0x0 }\nint styleable Tooltip_android_layout_margin 0\nint styleable Tooltip_android_minHeight 1\nint styleable Tooltip_android_minWidth 2\nint styleable Tooltip_android_padding 3\nint styleable Tooltip_android_text 4\nint styleable Tooltip_android_textAppearance 5\nint styleable Tooltip_backgroundTint 6\nint[] styleable Transform { 0x1010440, 0x1010326, 0x1010327, 0x1010328, 0x1010324, 0x1010325, 0x1010320, 0x1010321, 0x1010322, 0x1010323, 0x10103fa }\nint styleable Transform_android_elevation 0\nint styleable Transform_android_rotation 1\nint styleable Transform_android_rotationX 2\nint styleable Transform_android_rotationY 3\nint styleable Transform_android_scaleX 4\nint styleable Transform_android_scaleY 5\nint styleable Transform_android_transformPivotX 6\nint styleable Transform_android_transformPivotY 7\nint styleable Transform_android_translationX 8\nint styleable Transform_android_translationY 9\nint styleable Transform_android_translationZ 10\nint[] styleable Transition { 0x10100d0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable Transition_android_id 0\nint styleable Transition_autoTransition 1\nint styleable Transition_constraintSetEnd 2\nint styleable Transition_constraintSetStart 3\nint styleable Transition_duration 4\nint styleable Transition_layoutDuringTransition 5\nint styleable Transition_motionInterpolator 6\nint styleable Transition_pathMotionArc 7\nint styleable Transition_staggered 8\nint styleable Transition_transitionDisable 9\nint styleable Transition_transitionFlags 10\nint[] styleable Variant { 0x0, 0x0, 0x0, 0x0, 0x0 }\nint styleable Variant_constraints 0\nint styleable Variant_region_heightLessThan 1\nint styleable Variant_region_heightMoreThan 2\nint styleable Variant_region_widthLessThan 3\nint styleable Variant_region_widthMoreThan 4\nint[] styleable View { 0x10100da, 0x1010000, 0x0, 0x0, 0x0 }\nint styleable View_android_focusable 0\nint styleable View_android_theme 1\nint styleable View_paddingEnd 2\nint styleable View_paddingStart 3\nint styleable View_theme 4\nint[] styleable ViewBackgroundHelper { 0x10100d4, 0x0, 0x0 }\nint styleable ViewBackgroundHelper_android_background 0\nint styleable ViewBackgroundHelper_backgroundTint 1\nint styleable ViewBackgroundHelper_backgroundTintMode 2\nint[] styleable ViewPager2 { 0x10100c4 }\nint styleable ViewPager2_android_orientation 0\nint[] styleable ViewStubCompat { 0x10100d0, 0x10100f3, 0x10100f2 }\nint styleable ViewStubCompat_android_id 0\nint styleable ViewStubCompat_android_inflatedId 1\nint styleable ViewStubCompat_android_layout 2\nint xml standalone_badge 0x0\nint xml standalone_badge_gravity_bottom_end 0x0\nint xml standalone_badge_gravity_bottom_start 0x0\nint xml standalone_badge_gravity_top_start 0x0\nint xml standalone_badge_offset 0x0\n"
  },
  {
    "path": "privacy-ui/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<merger version=\"3\"><dataSet config=\"main\" ignore_pattern=\"!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~\"><source path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/jniLibs\"/></dataSet><dataSet config=\"debug\" ignore_pattern=\"!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~\"><source path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/debug/jniLibs\"/></dataSet></merger>"
  },
  {
    "path": "privacy-ui/build/intermediates/incremental/mergeDebugShaders/merger.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<merger version=\"3\"><dataSet config=\"main\" ignore_pattern=\"!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~\"><source path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/shaders\"/></dataSet><dataSet config=\"debug\" ignore_pattern=\"!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~\"><source path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/debug/shaders\"/></dataSet></merger>"
  },
  {
    "path": "privacy-ui/build/intermediates/incremental/packageDebugAssets/merger.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<merger version=\"3\"><dataSet config=\"main\" ignore_pattern=\"!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~\"><source path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/assets\"/><source path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/build/intermediates/shader_assets/debug/out\"/></dataSet><dataSet config=\"debug\" ignore_pattern=\"!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~\"><source path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/debug/assets\"/></dataSet></merger>"
  },
  {
    "path": "privacy-ui/build/intermediates/incremental/packageDebugResources/compile-file-map.properties",
    "content": "#Wed May 08 10:30:24 CST 2024\n/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/res/layout/permission_item_view.xml=/Users/yulun/GitHub/PrivacySentry/privacy-ui/build/intermediates/packaged_res/debug/layout/permission_item_view.xml\n/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/res/layout/activity_real_time_privacy_item.xml=/Users/yulun/GitHub/PrivacySentry/privacy-ui/build/intermediates/packaged_res/debug/layout/activity_real_time_privacy_item.xml\n/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/res/layout/activity_replace_list.xml=/Users/yulun/GitHub/PrivacySentry/privacy-ui/build/intermediates/packaged_res/debug/layout/activity_replace_list.xml\n/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/res/layout/activity_permission_list.xml=/Users/yulun/GitHub/PrivacySentry/privacy-ui/build/intermediates/packaged_res/debug/layout/activity_permission_list.xml\n/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/res/layout/real_tile_item_view.xml=/Users/yulun/GitHub/PrivacySentry/privacy-ui/build/intermediates/packaged_res/debug/layout/real_tile_item_view.xml\n/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/res/layout/replace_item_view.xml=/Users/yulun/GitHub/PrivacySentry/privacy-ui/build/intermediates/packaged_res/debug/layout/replace_item_view.xml\n"
  },
  {
    "path": "privacy-ui/build/intermediates/incremental/packageDebugResources/merger.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<merger version=\"3\"><dataSet aapt-namespace=\"http://schemas.android.com/apk/res-auto\" config=\"main$Generated\" generated=\"true\" ignore_pattern=\"!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~\"><source path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/res\"/><source path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/build/generated/res/rs/debug\"/><source path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/build/generated/res/resValues/debug\"/></dataSet><dataSet aapt-namespace=\"http://schemas.android.com/apk/res-auto\" config=\"main\" generated-set=\"main$Generated\" ignore_pattern=\"!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~\"><source path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/res\"><file name=\"activity_real_time_privacy_item\" path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/res/layout/activity_real_time_privacy_item.xml\" qualifiers=\"\" type=\"layout\"/><file name=\"activity_permission_list\" path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/res/layout/activity_permission_list.xml\" qualifiers=\"\" type=\"layout\"/><file name=\"permission_item_view\" path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/res/layout/permission_item_view.xml\" qualifiers=\"\" type=\"layout\"/><file name=\"replace_item_view\" path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/res/layout/replace_item_view.xml\" qualifiers=\"\" type=\"layout\"/><file name=\"activity_replace_list\" path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/res/layout/activity_replace_list.xml\" qualifiers=\"\" type=\"layout\"/><file name=\"real_tile_item_view\" path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/res/layout/real_tile_item_view.xml\" qualifiers=\"\" type=\"layout\"/><file path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/res/values/strings.xml\" qualifiers=\"\"/></source><source path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/build/generated/res/rs/debug\"/><source path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/build/generated/res/resValues/debug\"/></dataSet><dataSet aapt-namespace=\"http://schemas.android.com/apk/res-auto\" config=\"debug$Generated\" generated=\"true\" ignore_pattern=\"!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~\"><source path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/debug/res\"/></dataSet><dataSet aapt-namespace=\"http://schemas.android.com/apk/res-auto\" config=\"debug\" generated-set=\"debug$Generated\" ignore_pattern=\"!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~\"><source path=\"/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/debug/res\"/></dataSet><mergedItems/></merger>"
  },
  {
    "path": "privacy-ui/build/intermediates/library_manifest/debug/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.yl.lib.privacy_ui\"\n    android:versionCode=\"1\"\n    android:versionName=\"1.0\" >\n\n    <uses-sdk\n        android:minSdkVersion=\"19\"\n        android:targetSdkVersion=\"29\" />\n\n    <application>\n        <activity\n            android:name=\"com.yl.lib.privacy_ui.RealTimePrivacyItemActivity\"\n            android:exported=\"false\" />\n        <activity\n            android:name=\"com.yl.lib.privacy_ui.ReplaceListActivity\"\n            android:exported=\"false\"\n            android:theme=\"@style/Theme.AppCompat.DayNight.NoActionBar\" />\n        <activity\n            android:name=\"com.yl.lib.privacy_ui.PermissionListActivity\"\n            android:exported=\"false\"\n            android:theme=\"@style/Theme.AppCompat.DayNight.NoActionBar\" />\n    </application>\n\n</manifest>"
  },
  {
    "path": "privacy-ui/build/intermediates/local_only_symbol_list/debug/R-def.txt",
    "content": "R_DEF: Internal format may change without notice\nlocal\nid content\nid function_name_tv\nid origin_count_tv\nid origin_method_tv\nid permission_desc_tv\nid permission_tv\nid search_bar\nid time_tv\nlayout activity_permission_list\nlayout activity_real_time_privacy_item\nlayout activity_replace_list\nlayout permission_item_view\nlayout real_tile_item_view\nlayout replace_item_view\n"
  },
  {
    "path": "privacy-ui/build/intermediates/manifest_merge_blame_file/debug/manifest-merger-blame-debug-report.txt",
    "content": "1<?xml version=\"1.0\" encoding=\"utf-8\"?>\n2<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n3    package=\"com.yl.lib.privacy_ui\"\n4    android:versionCode=\"1\"\n5    android:versionName=\"1.0\" >\n6\n7    <uses-sdk\n8        android:minSdkVersion=\"19\"\n8-->/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml\n9        android:targetSdkVersion=\"29\" />\n9-->/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml\n10\n11    <application>\n11-->/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:5:5-17:19\n12        <activity\n12-->/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:6:9-8:40\n13            android:name=\"com.yl.lib.privacy_ui.RealTimePrivacyItemActivity\"\n13-->/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:7:13-56\n14            android:exported=\"false\" />\n14-->/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:8:13-37\n15        <activity\n15-->/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:9:9-12:75\n16            android:name=\"com.yl.lib.privacy_ui.ReplaceListActivity\"\n16-->/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:10:13-48\n17            android:exported=\"false\"\n17-->/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:11:13-37\n18            android:theme=\"@style/Theme.AppCompat.DayNight.NoActionBar\" />\n18-->/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:12:13-72\n19        <activity\n19-->/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:13:9-16:75\n20            android:name=\"com.yl.lib.privacy_ui.PermissionListActivity\"\n20-->/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:14:13-51\n21            android:exported=\"false\"\n21-->/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:15:13-37\n22            android:theme=\"@style/Theme.AppCompat.DayNight.NoActionBar\" />\n22-->/Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:16:13-72\n23    </application>\n24\n25</manifest>\n"
  },
  {
    "path": "privacy-ui/build/intermediates/navigation_json/debug/navigation.json",
    "content": "[]"
  },
  {
    "path": "privacy-ui/build/intermediates/packaged_manifests/debug/output-metadata.json",
    "content": "{\n  \"version\": 2,\n  \"artifactType\": {\n    \"type\": \"PACKAGED_MANIFESTS\",\n    \"kind\": \"Directory\"\n  },\n  \"applicationId\": \"com.yl.lib.privacy_ui\",\n  \"variantName\": \"debug\",\n  \"elements\": [\n    {\n      \"type\": \"SINGLE\",\n      \"filters\": [],\n      \"outputFile\": \"../../library_manifest/debug/AndroidManifest.xml\"\n    }\n  ]\n}"
  },
  {
    "path": "privacy-ui/build/intermediates/packaged_res/debug/layout/activity_permission_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:orientation=\"vertical\"\n    tools:context=\".PermissionListActivity\">\n\n    <androidx.appcompat.widget.SearchView\n        android:id=\"@+id/search_bar\"\n        android:layout_width=\"match_parent\"\n        app:queryHint=\"输入查找敏感方法\"\n        app:iconifiedByDefault=\"false\"\n        android:layout_height=\"50dp\" />\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/content\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" />\n</LinearLayout>"
  },
  {
    "path": "privacy-ui/build/intermediates/packaged_res/debug/layout/activity_real_time_privacy_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:orientation=\"vertical\"\n    tools:context=\".RealTimePrivacyItemActivity\">\n\n    <androidx.appcompat.widget.SearchView\n        android:id=\"@+id/search_bar\"\n        android:layout_width=\"match_parent\"\n        app:queryHint=\"输入查找敏感方法\"\n        app:iconifiedByDefault=\"false\"\n        android:layout_height=\"50dp\" />\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/content\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" />\n</LinearLayout>"
  },
  {
    "path": "privacy-ui/build/intermediates/packaged_res/debug/layout/activity_replace_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:orientation=\"vertical\"\n    tools:context=\".ReplaceListActivity\">\n\n    <androidx.appcompat.widget.SearchView\n        android:id=\"@+id/search_bar\"\n        android:layout_width=\"match_parent\"\n        app:queryHint=\"输入查找权限\"\n        app:iconifiedByDefault=\"false\"\n        android:layout_height=\"50dp\" />\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/content\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" />\n</LinearLayout>"
  },
  {
    "path": "privacy-ui/build/intermediates/packaged_res/debug/layout/permission_item_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"100dp\"\n    android:orientation=\"horizontal\">\n\n    <TextView\n        android:gravity=\"center\"\n        android:padding=\"10dp\"\n        android:id=\"@+id/permission_tv\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_weight=\"1\"/>\n\n    <View\n        android:layout_width=\"1px\"\n        android:layout_height=\"50dp\"\n        android:layout_gravity=\"center_vertical\"\n        android:background=\"@color/design_default_color_error\" />\n\n    <TextView\n        android:id=\"@+id/permission_desc_tv\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:gravity=\"center\"\n        android:layout_weight=\"1\"/>\n</LinearLayout>"
  },
  {
    "path": "privacy-ui/build/intermediates/packaged_res/debug/layout/real_tile_item_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"100dp\"\n    android:orientation=\"horizontal\">\n\n    <TextView\n        android:id=\"@+id/time_tv\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_weight=\"1\"\n        android:gravity=\"center\"\n        android:padding=\"10dp\" />\n\n    <View\n        android:layout_width=\"1px\"\n        android:layout_height=\"50dp\"\n        android:layout_gravity=\"center_vertical\"\n        android:background=\"@color/design_default_color_error\" />\n\n    <TextView\n        android:id=\"@+id/function_name_tv\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_weight=\"1\"\n        android:gravity=\"center\" />\n</LinearLayout>"
  },
  {
    "path": "privacy-ui/build/intermediates/packaged_res/debug/layout/replace_item_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"100dp\"\n    android:orientation=\"horizontal\">\n\n    <TextView\n        android:gravity=\"center\"\n        android:padding=\"10dp\"\n        android:id=\"@+id/origin_method_tv\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_weight=\"1\"/>\n\n    <View\n        android:layout_width=\"1px\"\n        android:layout_height=\"50dp\"\n        android:layout_gravity=\"center_vertical\"\n        android:background=\"@color/design_default_color_error\" />\n\n    <TextView\n        android:id=\"@+id/origin_count_tv\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:gravity=\"center\"\n        android:layout_weight=\"1\"/>\n</LinearLayout>"
  },
  {
    "path": "privacy-ui/build/intermediates/symbol_list_with_package_name/debug/package-aware-r.txt",
    "content": "com.yl.lib.privacy_ui\nanim abc_fade_in\nanim abc_fade_out\nanim abc_grow_fade_in_from_bottom\nanim abc_popup_enter\nanim abc_popup_exit\nanim abc_shrink_fade_out_from_bottom\nanim abc_slide_in_bottom\nanim abc_slide_in_top\nanim abc_slide_out_bottom\nanim abc_slide_out_top\nanim abc_tooltip_enter\nanim abc_tooltip_exit\nanim btn_checkbox_to_checked_box_inner_merged_animation\nanim btn_checkbox_to_checked_box_outer_merged_animation\nanim btn_checkbox_to_checked_icon_null_animation\nanim btn_checkbox_to_unchecked_box_inner_merged_animation\nanim btn_checkbox_to_unchecked_check_path_merged_animation\nanim btn_checkbox_to_unchecked_icon_null_animation\nanim btn_radio_to_off_mtrl_dot_group_animation\nanim btn_radio_to_off_mtrl_ring_outer_animation\nanim btn_radio_to_off_mtrl_ring_outer_path_animation\nanim btn_radio_to_on_mtrl_dot_group_animation\nanim btn_radio_to_on_mtrl_ring_outer_animation\nanim btn_radio_to_on_mtrl_ring_outer_path_animation\nanim design_bottom_sheet_slide_in\nanim design_bottom_sheet_slide_out\nanim design_snackbar_in\nanim design_snackbar_out\nanim mtrl_bottom_sheet_slide_in\nanim mtrl_bottom_sheet_slide_out\nanim mtrl_card_lowers_interpolator\nanimator design_appbar_state_list_animator\nanimator design_fab_hide_motion_spec\nanimator design_fab_show_motion_spec\nanimator linear_indeterminate_line1_head_interpolator\nanimator linear_indeterminate_line1_tail_interpolator\nanimator linear_indeterminate_line2_head_interpolator\nanimator linear_indeterminate_line2_tail_interpolator\nanimator mtrl_btn_state_list_anim\nanimator mtrl_btn_unelevated_state_list_anim\nanimator mtrl_card_state_list_anim\nanimator mtrl_chip_state_list_anim\nanimator mtrl_extended_fab_change_size_collapse_motion_spec\nanimator mtrl_extended_fab_change_size_expand_motion_spec\nanimator mtrl_extended_fab_hide_motion_spec\nanimator mtrl_extended_fab_show_motion_spec\nanimator mtrl_extended_fab_state_list_animator\nanimator mtrl_fab_hide_motion_spec\nanimator mtrl_fab_show_motion_spec\nanimator mtrl_fab_transformation_sheet_collapse_spec\nanimator mtrl_fab_transformation_sheet_expand_spec\nattr actionBarDivider\nattr actionBarItemBackground\nattr actionBarPopupTheme\nattr actionBarSize\nattr actionBarSplitStyle\nattr actionBarStyle\nattr actionBarTabBarStyle\nattr actionBarTabStyle\nattr actionBarTabTextStyle\nattr actionBarTheme\nattr actionBarWidgetTheme\nattr actionButtonStyle\nattr actionDropDownStyle\nattr actionLayout\nattr actionMenuTextAppearance\nattr actionMenuTextColor\nattr actionModeBackground\nattr actionModeCloseButtonStyle\nattr actionModeCloseDrawable\nattr actionModeCopyDrawable\nattr actionModeCutDrawable\nattr actionModeFindDrawable\nattr actionModePasteDrawable\nattr actionModePopupWindowStyle\nattr actionModeSelectAllDrawable\nattr actionModeShareDrawable\nattr actionModeSplitBackground\nattr actionModeStyle\nattr actionModeWebSearchDrawable\nattr actionOverflowButtonStyle\nattr actionOverflowMenuStyle\nattr actionProviderClass\nattr actionTextColorAlpha\nattr actionViewClass\nattr activityChooserViewStyle\nattr alertDialogButtonGroupStyle\nattr alertDialogCenterButtons\nattr alertDialogStyle\nattr alertDialogTheme\nattr allowStacking\nattr alpha\nattr alphabeticModifiers\nattr altSrc\nattr animate_relativeTo\nattr animationMode\nattr appBarLayoutStyle\nattr applyMotionScene\nattr arcMode\nattr arrowHeadLength\nattr arrowShaftLength\nattr attributeName\nattr autoCompleteTextViewStyle\nattr autoSizeMaxTextSize\nattr autoSizeMinTextSize\nattr autoSizePresetSizes\nattr autoSizeStepGranularity\nattr autoSizeTextType\nattr autoTransition\nattr background\nattr backgroundColor\nattr backgroundInsetBottom\nattr backgroundInsetEnd\nattr backgroundInsetStart\nattr backgroundInsetTop\nattr backgroundOverlayColorAlpha\nattr backgroundSplit\nattr backgroundStacked\nattr backgroundTint\nattr backgroundTintMode\nattr badgeGravity\nattr badgeStyle\nattr badgeTextColor\nattr barLength\nattr barrierAllowsGoneWidgets\nattr barrierDirection\nattr barrierMargin\nattr behavior_autoHide\nattr behavior_autoShrink\nattr behavior_draggable\nattr behavior_expandedOffset\nattr behavior_fitToContents\nattr behavior_halfExpandedRatio\nattr behavior_hideable\nattr behavior_overlapTop\nattr behavior_peekHeight\nattr behavior_saveFlags\nattr behavior_skipCollapsed\nattr borderWidth\nattr borderlessButtonStyle\nattr bottomAppBarStyle\nattr bottomNavigationStyle\nattr bottomSheetDialogTheme\nattr bottomSheetStyle\nattr boxBackgroundColor\nattr boxBackgroundMode\nattr boxCollapsedPaddingTop\nattr boxCornerRadiusBottomEnd\nattr boxCornerRadiusBottomStart\nattr boxCornerRadiusTopEnd\nattr boxCornerRadiusTopStart\nattr boxStrokeColor\nattr boxStrokeErrorColor\nattr boxStrokeWidth\nattr boxStrokeWidthFocused\nattr brightness\nattr buttonBarButtonStyle\nattr buttonBarNegativeButtonStyle\nattr buttonBarNeutralButtonStyle\nattr buttonBarPositiveButtonStyle\nattr buttonBarStyle\nattr buttonCompat\nattr buttonGravity\nattr buttonIconDimen\nattr buttonPanelSideLayout\nattr buttonStyle\nattr buttonStyleSmall\nattr buttonTint\nattr buttonTintMode\nattr cardBackgroundColor\nattr cardCornerRadius\nattr cardElevation\nattr cardForegroundColor\nattr cardMaxElevation\nattr cardPreventCornerOverlap\nattr cardUseCompatPadding\nattr cardViewStyle\nattr chainUseRtl\nattr checkboxStyle\nattr checkedButton\nattr checkedChip\nattr checkedIcon\nattr checkedIconEnabled\nattr checkedIconMargin\nattr checkedIconSize\nattr checkedIconTint\nattr checkedIconVisible\nattr checkedTextViewStyle\nattr chipBackgroundColor\nattr chipCornerRadius\nattr chipEndPadding\nattr chipGroupStyle\nattr chipIcon\nattr chipIconEnabled\nattr chipIconSize\nattr chipIconTint\nattr chipIconVisible\nattr chipMinHeight\nattr chipMinTouchTargetSize\nattr chipSpacing\nattr chipSpacingHorizontal\nattr chipSpacingVertical\nattr chipStandaloneStyle\nattr chipStartPadding\nattr chipStrokeColor\nattr chipStrokeWidth\nattr chipStyle\nattr chipSurfaceColor\nattr circleRadius\nattr circularProgressIndicatorStyle\nattr clickAction\nattr clockFaceBackgroundColor\nattr clockHandColor\nattr clockIcon\nattr clockNumberTextColor\nattr closeIcon\nattr closeIconEnabled\nattr closeIconEndPadding\nattr closeIconSize\nattr closeIconStartPadding\nattr closeIconTint\nattr closeIconVisible\nattr closeItemLayout\nattr collapseContentDescription\nattr collapseIcon\nattr collapsedSize\nattr collapsedTitleGravity\nattr collapsedTitleTextAppearance\nattr collapsingToolbarLayoutStyle\nattr color\nattr colorAccent\nattr colorBackgroundFloating\nattr colorButtonNormal\nattr colorControlActivated\nattr colorControlHighlight\nattr colorControlNormal\nattr colorError\nattr colorOnBackground\nattr colorOnError\nattr colorOnPrimary\nattr colorOnPrimarySurface\nattr colorOnSecondary\nattr colorOnSurface\nattr colorPrimary\nattr colorPrimaryDark\nattr colorPrimarySurface\nattr colorPrimaryVariant\nattr colorSecondary\nattr colorSecondaryVariant\nattr colorSurface\nattr colorSwitchThumbNormal\nattr commitIcon\nattr constraintSet\nattr constraintSetEnd\nattr constraintSetStart\nattr constraint_referenced_ids\nattr constraints\nattr content\nattr contentDescription\nattr contentInsetEnd\nattr contentInsetEndWithActions\nattr contentInsetLeft\nattr contentInsetRight\nattr contentInsetStart\nattr contentInsetStartWithNavigation\nattr contentPadding\nattr contentPaddingBottom\nattr contentPaddingEnd\nattr contentPaddingLeft\nattr contentPaddingRight\nattr contentPaddingStart\nattr contentPaddingTop\nattr contentScrim\nattr contrast\nattr controlBackground\nattr coordinatorLayoutStyle\nattr cornerFamily\nattr cornerFamilyBottomLeft\nattr cornerFamilyBottomRight\nattr cornerFamilyTopLeft\nattr cornerFamilyTopRight\nattr cornerRadius\nattr cornerSize\nattr cornerSizeBottomLeft\nattr cornerSizeBottomRight\nattr cornerSizeTopLeft\nattr cornerSizeTopRight\nattr counterEnabled\nattr counterMaxLength\nattr counterOverflowTextAppearance\nattr counterOverflowTextColor\nattr counterTextAppearance\nattr counterTextColor\nattr crossfade\nattr currentState\nattr curveFit\nattr customBoolean\nattr customColorDrawableValue\nattr customColorValue\nattr customDimension\nattr customFloatValue\nattr customIntegerValue\nattr customNavigationLayout\nattr customPixelDimension\nattr customStringValue\nattr dayInvalidStyle\nattr daySelectedStyle\nattr dayStyle\nattr dayTodayStyle\nattr defaultDuration\nattr defaultQueryHint\nattr defaultState\nattr deltaPolarAngle\nattr deltaPolarRadius\nattr deriveConstraintsFrom\nattr dialogCornerRadius\nattr dialogPreferredPadding\nattr dialogTheme\nattr displayOptions\nattr divider\nattr dividerHorizontal\nattr dividerPadding\nattr dividerVertical\nattr dragDirection\nattr dragScale\nattr dragThreshold\nattr drawPath\nattr drawableBottomCompat\nattr drawableEndCompat\nattr drawableLeftCompat\nattr drawableRightCompat\nattr drawableSize\nattr drawableStartCompat\nattr drawableTint\nattr drawableTintMode\nattr drawableTopCompat\nattr drawerArrowStyle\nattr dropDownListViewStyle\nattr dropdownListPreferredItemHeight\nattr duration\nattr editTextBackground\nattr editTextColor\nattr editTextStyle\nattr elevation\nattr elevationOverlayColor\nattr elevationOverlayEnabled\nattr endIconCheckable\nattr endIconContentDescription\nattr endIconDrawable\nattr endIconMode\nattr endIconTint\nattr endIconTintMode\nattr enforceMaterialTheme\nattr enforceTextAppearance\nattr ensureMinTouchTargetSize\nattr errorContentDescription\nattr errorEnabled\nattr errorIconDrawable\nattr errorIconTint\nattr errorIconTintMode\nattr errorTextAppearance\nattr errorTextColor\nattr expandActivityOverflowButtonDrawable\nattr expanded\nattr expandedHintEnabled\nattr expandedTitleGravity\nattr expandedTitleMargin\nattr expandedTitleMarginBottom\nattr expandedTitleMarginEnd\nattr expandedTitleMarginStart\nattr expandedTitleMarginTop\nattr expandedTitleTextAppearance\nattr extendMotionSpec\nattr extendedFloatingActionButtonStyle\nattr fabAlignmentMode\nattr fabAnimationMode\nattr fabCradleMargin\nattr fabCradleRoundedCornerRadius\nattr fabCradleVerticalOffset\nattr fabCustomSize\nattr fabSize\nattr fastScrollEnabled\nattr fastScrollHorizontalThumbDrawable\nattr fastScrollHorizontalTrackDrawable\nattr fastScrollVerticalThumbDrawable\nattr fastScrollVerticalTrackDrawable\nattr firstBaselineToTopHeight\nattr floatingActionButtonStyle\nattr flow_firstHorizontalBias\nattr flow_firstHorizontalStyle\nattr flow_firstVerticalBias\nattr flow_firstVerticalStyle\nattr flow_horizontalAlign\nattr flow_horizontalBias\nattr flow_horizontalGap\nattr flow_horizontalStyle\nattr flow_lastHorizontalBias\nattr flow_lastHorizontalStyle\nattr flow_lastVerticalBias\nattr flow_lastVerticalStyle\nattr flow_maxElementsWrap\nattr flow_padding\nattr flow_verticalAlign\nattr flow_verticalBias\nattr flow_verticalGap\nattr flow_verticalStyle\nattr flow_wrapMode\nattr font\nattr fontFamily\nattr fontProviderAuthority\nattr fontProviderCerts\nattr fontProviderFetchStrategy\nattr fontProviderFetchTimeout\nattr fontProviderPackage\nattr fontProviderQuery\nattr fontStyle\nattr fontVariationSettings\nattr fontWeight\nattr foregroundInsidePadding\nattr framePosition\nattr gapBetweenBars\nattr gestureInsetBottomIgnored\nattr goIcon\nattr haloColor\nattr haloRadius\nattr headerLayout\nattr height\nattr helperText\nattr helperTextEnabled\nattr helperTextTextAppearance\nattr helperTextTextColor\nattr hideAnimationBehavior\nattr hideMotionSpec\nattr hideOnContentScroll\nattr hideOnScroll\nattr hintAnimationEnabled\nattr hintEnabled\nattr hintTextAppearance\nattr hintTextColor\nattr homeAsUpIndicator\nattr homeLayout\nattr horizontalOffset\nattr hoveredFocusedTranslationZ\nattr icon\nattr iconEndPadding\nattr iconGravity\nattr iconPadding\nattr iconSize\nattr iconStartPadding\nattr iconTint\nattr iconTintMode\nattr iconifiedByDefault\nattr imageButtonStyle\nattr indeterminateAnimationType\nattr indeterminateProgressStyle\nattr indicatorColor\nattr indicatorDirectionCircular\nattr indicatorDirectionLinear\nattr indicatorInset\nattr indicatorSize\nattr initialActivityCount\nattr insetForeground\nattr isLightTheme\nattr isMaterialTheme\nattr itemBackground\nattr itemFillColor\nattr itemHorizontalPadding\nattr itemHorizontalTranslationEnabled\nattr itemIconPadding\nattr itemIconSize\nattr itemIconTint\nattr itemMaxLines\nattr itemPadding\nattr itemRippleColor\nattr itemShapeAppearance\nattr itemShapeAppearanceOverlay\nattr itemShapeFillColor\nattr itemShapeInsetBottom\nattr itemShapeInsetEnd\nattr itemShapeInsetStart\nattr itemShapeInsetTop\nattr itemSpacing\nattr itemStrokeColor\nattr itemStrokeWidth\nattr itemTextAppearance\nattr itemTextAppearanceActive\nattr itemTextAppearanceInactive\nattr itemTextColor\nattr keyPositionType\nattr keyboardIcon\nattr keylines\nattr labelBehavior\nattr labelStyle\nattr labelVisibilityMode\nattr lastBaselineToBottomHeight\nattr layout\nattr layoutDescription\nattr layoutDuringTransition\nattr layoutManager\nattr layout_anchor\nattr layout_anchorGravity\nattr layout_behavior\nattr layout_collapseMode\nattr layout_collapseParallaxMultiplier\nattr layout_constrainedHeight\nattr layout_constrainedWidth\nattr layout_constraintBaseline_creator\nattr layout_constraintBaseline_toBaselineOf\nattr layout_constraintBottom_creator\nattr layout_constraintBottom_toBottomOf\nattr layout_constraintBottom_toTopOf\nattr layout_constraintCircle\nattr layout_constraintCircleAngle\nattr layout_constraintCircleRadius\nattr layout_constraintDimensionRatio\nattr layout_constraintEnd_toEndOf\nattr layout_constraintEnd_toStartOf\nattr layout_constraintGuide_begin\nattr layout_constraintGuide_end\nattr layout_constraintGuide_percent\nattr layout_constraintHeight_default\nattr layout_constraintHeight_max\nattr layout_constraintHeight_min\nattr layout_constraintHeight_percent\nattr layout_constraintHorizontal_bias\nattr layout_constraintHorizontal_chainStyle\nattr layout_constraintHorizontal_weight\nattr layout_constraintLeft_creator\nattr layout_constraintLeft_toLeftOf\nattr layout_constraintLeft_toRightOf\nattr layout_constraintRight_creator\nattr layout_constraintRight_toLeftOf\nattr layout_constraintRight_toRightOf\nattr layout_constraintStart_toEndOf\nattr layout_constraintStart_toStartOf\nattr layout_constraintTag\nattr layout_constraintTop_creator\nattr layout_constraintTop_toBottomOf\nattr layout_constraintTop_toTopOf\nattr layout_constraintVertical_bias\nattr layout_constraintVertical_chainStyle\nattr layout_constraintVertical_weight\nattr layout_constraintWidth_default\nattr layout_constraintWidth_max\nattr layout_constraintWidth_min\nattr layout_constraintWidth_percent\nattr layout_dodgeInsetEdges\nattr layout_editor_absoluteX\nattr layout_editor_absoluteY\nattr layout_goneMarginBottom\nattr layout_goneMarginEnd\nattr layout_goneMarginLeft\nattr layout_goneMarginRight\nattr layout_goneMarginStart\nattr layout_goneMarginTop\nattr layout_insetEdge\nattr layout_keyline\nattr layout_optimizationLevel\nattr layout_scrollFlags\nattr layout_scrollInterpolator\nattr liftOnScroll\nattr liftOnScrollTargetViewId\nattr limitBoundsTo\nattr lineHeight\nattr lineSpacing\nattr linearProgressIndicatorStyle\nattr listChoiceBackgroundIndicator\nattr listChoiceIndicatorMultipleAnimated\nattr listChoiceIndicatorSingleAnimated\nattr listDividerAlertDialog\nattr listItemLayout\nattr listLayout\nattr listMenuViewStyle\nattr listPopupWindowStyle\nattr listPreferredItemHeight\nattr listPreferredItemHeightLarge\nattr listPreferredItemHeightSmall\nattr listPreferredItemPaddingEnd\nattr listPreferredItemPaddingLeft\nattr listPreferredItemPaddingRight\nattr listPreferredItemPaddingStart\nattr logo\nattr logoDescription\nattr materialAlertDialogBodyTextStyle\nattr materialAlertDialogTheme\nattr materialAlertDialogTitleIconStyle\nattr materialAlertDialogTitlePanelStyle\nattr materialAlertDialogTitleTextStyle\nattr materialButtonOutlinedStyle\nattr materialButtonStyle\nattr materialButtonToggleGroupStyle\nattr materialCalendarDay\nattr materialCalendarFullscreenTheme\nattr materialCalendarHeaderCancelButton\nattr materialCalendarHeaderConfirmButton\nattr materialCalendarHeaderDivider\nattr materialCalendarHeaderLayout\nattr materialCalendarHeaderSelection\nattr materialCalendarHeaderTitle\nattr materialCalendarHeaderToggleButton\nattr materialCalendarMonth\nattr materialCalendarMonthNavigationButton\nattr materialCalendarStyle\nattr materialCalendarTheme\nattr materialCalendarYearNavigationButton\nattr materialCardViewStyle\nattr materialCircleRadius\nattr materialClockStyle\nattr materialThemeOverlay\nattr materialTimePickerStyle\nattr materialTimePickerTheme\nattr maxAcceleration\nattr maxActionInlineWidth\nattr maxButtonHeight\nattr maxCharacterCount\nattr maxHeight\nattr maxImageSize\nattr maxLines\nattr maxVelocity\nattr maxWidth\nattr measureWithLargestChild\nattr menu\nattr minHeight\nattr minHideDelay\nattr minSeparation\nattr minTouchTargetSize\nattr minWidth\nattr mock_diagonalsColor\nattr mock_label\nattr mock_labelBackgroundColor\nattr mock_labelColor\nattr mock_showDiagonals\nattr mock_showLabel\nattr motionDebug\nattr motionInterpolator\nattr motionPathRotate\nattr motionProgress\nattr motionStagger\nattr motionTarget\nattr motion_postLayoutCollision\nattr motion_triggerOnCollision\nattr moveWhenScrollAtTop\nattr multiChoiceItemLayout\nattr navigationContentDescription\nattr navigationIcon\nattr navigationIconTint\nattr navigationMode\nattr navigationViewStyle\nattr nestedScrollFlags\nattr nestedScrollable\nattr number\nattr numericModifiers\nattr onCross\nattr onHide\nattr onNegativeCross\nattr onPositiveCross\nattr onShow\nattr onTouchUp\nattr overlapAnchor\nattr overlay\nattr paddingBottomNoButtons\nattr paddingBottomSystemWindowInsets\nattr paddingEnd\nattr paddingLeftSystemWindowInsets\nattr paddingRightSystemWindowInsets\nattr paddingStart\nattr paddingTopNoTitle\nattr panelBackground\nattr panelMenuListTheme\nattr panelMenuListWidth\nattr passwordToggleContentDescription\nattr passwordToggleDrawable\nattr passwordToggleEnabled\nattr passwordToggleTint\nattr passwordToggleTintMode\nattr pathMotionArc\nattr path_percent\nattr percentHeight\nattr percentWidth\nattr percentX\nattr percentY\nattr perpendicularPath_percent\nattr pivotAnchor\nattr placeholderText\nattr placeholderTextAppearance\nattr placeholderTextColor\nattr placeholder_emptyVisibility\nattr popupMenuBackground\nattr popupMenuStyle\nattr popupTheme\nattr popupWindowStyle\nattr prefixText\nattr prefixTextAppearance\nattr prefixTextColor\nattr preserveIconSpacing\nattr pressedTranslationZ\nattr progressBarPadding\nattr progressBarStyle\nattr queryBackground\nattr queryHint\nattr radioButtonStyle\nattr rangeFillColor\nattr ratingBarStyle\nattr ratingBarStyleIndicator\nattr ratingBarStyleSmall\nattr recyclerViewStyle\nattr region_heightLessThan\nattr region_heightMoreThan\nattr region_widthLessThan\nattr region_widthMoreThan\nattr reverseLayout\nattr rippleColor\nattr round\nattr roundPercent\nattr saturation\nattr scrimAnimationDuration\nattr scrimBackground\nattr scrimVisibleHeightTrigger\nattr searchHintIcon\nattr searchIcon\nattr searchViewStyle\nattr seekBarStyle\nattr selectableItemBackground\nattr selectableItemBackgroundBorderless\nattr selectionRequired\nattr selectorSize\nattr shapeAppearance\nattr shapeAppearanceLargeComponent\nattr shapeAppearanceMediumComponent\nattr shapeAppearanceOverlay\nattr shapeAppearanceSmallComponent\nattr showAnimationBehavior\nattr showAsAction\nattr showDelay\nattr showDividers\nattr showMotionSpec\nattr showPaths\nattr showText\nattr showTitle\nattr shrinkMotionSpec\nattr singleChoiceItemLayout\nattr singleLine\nattr singleSelection\nattr sizePercent\nattr sliderStyle\nattr snackbarButtonStyle\nattr snackbarStyle\nattr snackbarTextViewStyle\nattr spanCount\nattr spinBars\nattr spinnerDropDownItemStyle\nattr spinnerStyle\nattr splitTrack\nattr srcCompat\nattr stackFromEnd\nattr staggered\nattr startIconCheckable\nattr startIconContentDescription\nattr startIconDrawable\nattr startIconTint\nattr startIconTintMode\nattr state_above_anchor\nattr state_collapsed\nattr state_collapsible\nattr state_dragged\nattr state_liftable\nattr state_lifted\nattr statusBarBackground\nattr statusBarForeground\nattr statusBarScrim\nattr strokeColor\nattr strokeWidth\nattr subMenuArrow\nattr submitBackground\nattr subtitle\nattr subtitleTextAppearance\nattr subtitleTextColor\nattr subtitleTextStyle\nattr suffixText\nattr suffixTextAppearance\nattr suffixTextColor\nattr suggestionRowLayout\nattr switchMinWidth\nattr switchPadding\nattr switchStyle\nattr switchTextAppearance\nattr tabBackground\nattr tabContentStart\nattr tabGravity\nattr tabIconTint\nattr tabIconTintMode\nattr tabIndicator\nattr tabIndicatorAnimationDuration\nattr tabIndicatorAnimationMode\nattr tabIndicatorColor\nattr tabIndicatorFullWidth\nattr tabIndicatorGravity\nattr tabIndicatorHeight\nattr tabInlineLabel\nattr tabMaxWidth\nattr tabMinWidth\nattr tabMode\nattr tabPadding\nattr tabPaddingBottom\nattr tabPaddingEnd\nattr tabPaddingStart\nattr tabPaddingTop\nattr tabRippleColor\nattr tabSelectedTextColor\nattr tabStyle\nattr tabTextAppearance\nattr tabTextColor\nattr tabUnboundedRipple\nattr targetId\nattr telltales_tailColor\nattr telltales_tailScale\nattr telltales_velocityMode\nattr textAllCaps\nattr textAppearanceBody1\nattr textAppearanceBody2\nattr textAppearanceButton\nattr textAppearanceCaption\nattr textAppearanceHeadline1\nattr textAppearanceHeadline2\nattr textAppearanceHeadline3\nattr textAppearanceHeadline4\nattr textAppearanceHeadline5\nattr textAppearanceHeadline6\nattr textAppearanceLargePopupMenu\nattr textAppearanceLineHeightEnabled\nattr textAppearanceListItem\nattr textAppearanceListItemSecondary\nattr textAppearanceListItemSmall\nattr textAppearanceOverline\nattr textAppearancePopupMenuHeader\nattr textAppearanceSearchResultSubtitle\nattr textAppearanceSearchResultTitle\nattr textAppearanceSmallPopupMenu\nattr textAppearanceSubtitle1\nattr textAppearanceSubtitle2\nattr textColorAlertDialogListItem\nattr textColorSearchUrl\nattr textEndPadding\nattr textInputLayoutFocusedRectEnabled\nattr textInputStyle\nattr textLocale\nattr textStartPadding\nattr theme\nattr themeLineHeight\nattr thickness\nattr thumbColor\nattr thumbElevation\nattr thumbRadius\nattr thumbStrokeColor\nattr thumbStrokeWidth\nattr thumbTextPadding\nattr thumbTint\nattr thumbTintMode\nattr tickColor\nattr tickColorActive\nattr tickColorInactive\nattr tickMark\nattr tickMarkTint\nattr tickMarkTintMode\nattr tickVisible\nattr tint\nattr tintMode\nattr title\nattr titleEnabled\nattr titleMargin\nattr titleMarginBottom\nattr titleMarginEnd\nattr titleMarginStart\nattr titleMarginTop\nattr titleMargins\nattr titleTextAppearance\nattr titleTextColor\nattr titleTextStyle\nattr toolbarId\nattr toolbarNavigationButtonStyle\nattr toolbarStyle\nattr tooltipForegroundColor\nattr tooltipFrameBackground\nattr tooltipStyle\nattr tooltipText\nattr touchAnchorId\nattr touchAnchorSide\nattr touchRegionId\nattr track\nattr trackColor\nattr trackColorActive\nattr trackColorInactive\nattr trackCornerRadius\nattr trackHeight\nattr trackThickness\nattr trackTint\nattr trackTintMode\nattr transitionDisable\nattr transitionEasing\nattr transitionFlags\nattr transitionPathRotate\nattr transitionShapeAppearance\nattr triggerId\nattr triggerReceiver\nattr triggerSlack\nattr ttcIndex\nattr useCompatPadding\nattr useMaterialThemeColors\nattr values\nattr verticalOffset\nattr viewInflaterClass\nattr visibilityMode\nattr voiceIcon\nattr warmth\nattr waveDecay\nattr waveOffset\nattr wavePeriod\nattr waveShape\nattr waveVariesBy\nattr windowActionBar\nattr windowActionBarOverlay\nattr windowActionModeOverlay\nattr windowFixedHeightMajor\nattr windowFixedHeightMinor\nattr windowFixedWidthMajor\nattr windowFixedWidthMinor\nattr windowMinWidthMajor\nattr windowMinWidthMinor\nattr windowNoTitle\nattr yearSelectedStyle\nattr yearStyle\nattr yearTodayStyle\nbool abc_action_bar_embed_tabs\nbool abc_allow_stacked_button_bar\nbool abc_config_actionMenuItemAllCaps\nbool mtrl_btn_textappearance_all_caps\ncolor abc_background_cache_hint_selector_material_dark\ncolor abc_background_cache_hint_selector_material_light\ncolor abc_btn_colored_borderless_text_material\ncolor abc_btn_colored_text_material\ncolor abc_color_highlight_material\ncolor abc_decor_view_status_guard\ncolor abc_decor_view_status_guard_light\ncolor abc_hint_foreground_material_dark\ncolor abc_hint_foreground_material_light\ncolor abc_input_method_navigation_guard\ncolor abc_primary_text_disable_only_material_dark\ncolor abc_primary_text_disable_only_material_light\ncolor abc_primary_text_material_dark\ncolor abc_primary_text_material_light\ncolor abc_search_url_text\ncolor abc_search_url_text_normal\ncolor abc_search_url_text_pressed\ncolor abc_search_url_text_selected\ncolor abc_secondary_text_material_dark\ncolor abc_secondary_text_material_light\ncolor abc_tint_btn_checkable\ncolor abc_tint_default\ncolor abc_tint_edittext\ncolor abc_tint_seek_thumb\ncolor abc_tint_spinner\ncolor abc_tint_switch_track\ncolor accent_material_dark\ncolor accent_material_light\ncolor androidx_core_ripple_material_light\ncolor androidx_core_secondary_text_default_material_light\ncolor background_floating_material_dark\ncolor background_floating_material_light\ncolor background_material_dark\ncolor background_material_light\ncolor bright_foreground_disabled_material_dark\ncolor bright_foreground_disabled_material_light\ncolor bright_foreground_inverse_material_dark\ncolor bright_foreground_inverse_material_light\ncolor bright_foreground_material_dark\ncolor bright_foreground_material_light\ncolor button_material_dark\ncolor button_material_light\ncolor cardview_dark_background\ncolor cardview_light_background\ncolor cardview_shadow_end_color\ncolor cardview_shadow_start_color\ncolor checkbox_themeable_attribute_color\ncolor design_bottom_navigation_shadow_color\ncolor design_box_stroke_color\ncolor design_dark_default_color_background\ncolor design_dark_default_color_error\ncolor design_dark_default_color_on_background\ncolor design_dark_default_color_on_error\ncolor design_dark_default_color_on_primary\ncolor design_dark_default_color_on_secondary\ncolor design_dark_default_color_on_surface\ncolor design_dark_default_color_primary\ncolor design_dark_default_color_primary_dark\ncolor design_dark_default_color_primary_variant\ncolor design_dark_default_color_secondary\ncolor design_dark_default_color_secondary_variant\ncolor design_dark_default_color_surface\ncolor design_default_color_background\ncolor design_default_color_error\ncolor design_default_color_on_background\ncolor design_default_color_on_error\ncolor design_default_color_on_primary\ncolor design_default_color_on_secondary\ncolor design_default_color_on_surface\ncolor design_default_color_primary\ncolor design_default_color_primary_dark\ncolor design_default_color_primary_variant\ncolor design_default_color_secondary\ncolor design_default_color_secondary_variant\ncolor design_default_color_surface\ncolor design_error\ncolor design_fab_shadow_end_color\ncolor design_fab_shadow_mid_color\ncolor design_fab_shadow_start_color\ncolor design_fab_stroke_end_inner_color\ncolor design_fab_stroke_end_outer_color\ncolor design_fab_stroke_top_inner_color\ncolor design_fab_stroke_top_outer_color\ncolor design_icon_tint\ncolor design_snackbar_background_color\ncolor dim_foreground_disabled_material_dark\ncolor dim_foreground_disabled_material_light\ncolor dim_foreground_material_dark\ncolor dim_foreground_material_light\ncolor error_color_material_dark\ncolor error_color_material_light\ncolor foreground_material_dark\ncolor foreground_material_light\ncolor highlighted_text_material_dark\ncolor highlighted_text_material_light\ncolor material_blue_grey_800\ncolor material_blue_grey_900\ncolor material_blue_grey_950\ncolor material_cursor_color\ncolor material_deep_teal_200\ncolor material_deep_teal_500\ncolor material_grey_100\ncolor material_grey_300\ncolor material_grey_50\ncolor material_grey_600\ncolor material_grey_800\ncolor material_grey_850\ncolor material_grey_900\ncolor material_on_background_disabled\ncolor material_on_background_emphasis_high_type\ncolor material_on_background_emphasis_medium\ncolor material_on_primary_disabled\ncolor material_on_primary_emphasis_high_type\ncolor material_on_primary_emphasis_medium\ncolor material_on_surface_disabled\ncolor material_on_surface_emphasis_high_type\ncolor material_on_surface_emphasis_medium\ncolor material_on_surface_stroke\ncolor material_slider_active_tick_marks_color\ncolor material_slider_active_track_color\ncolor material_slider_halo_color\ncolor material_slider_inactive_tick_marks_color\ncolor material_slider_inactive_track_color\ncolor material_slider_thumb_color\ncolor material_timepicker_button_background\ncolor material_timepicker_button_stroke\ncolor material_timepicker_clock_text_color\ncolor material_timepicker_clockface\ncolor material_timepicker_modebutton_tint\ncolor mtrl_bottom_nav_colored_item_tint\ncolor mtrl_bottom_nav_colored_ripple_color\ncolor mtrl_bottom_nav_item_tint\ncolor mtrl_bottom_nav_ripple_color\ncolor mtrl_btn_bg_color_selector\ncolor mtrl_btn_ripple_color\ncolor mtrl_btn_stroke_color_selector\ncolor mtrl_btn_text_btn_bg_color_selector\ncolor mtrl_btn_text_btn_ripple_color\ncolor mtrl_btn_text_color_disabled\ncolor mtrl_btn_text_color_selector\ncolor mtrl_btn_transparent_bg_color\ncolor mtrl_calendar_item_stroke_color\ncolor mtrl_calendar_selected_range\ncolor mtrl_card_view_foreground\ncolor mtrl_card_view_ripple\ncolor mtrl_chip_background_color\ncolor mtrl_chip_close_icon_tint\ncolor mtrl_chip_surface_color\ncolor mtrl_chip_text_color\ncolor mtrl_choice_chip_background_color\ncolor mtrl_choice_chip_ripple_color\ncolor mtrl_choice_chip_text_color\ncolor mtrl_error\ncolor mtrl_fab_bg_color_selector\ncolor mtrl_fab_icon_text_color_selector\ncolor mtrl_fab_ripple_color\ncolor mtrl_filled_background_color\ncolor mtrl_filled_icon_tint\ncolor mtrl_filled_stroke_color\ncolor mtrl_indicator_text_color\ncolor mtrl_navigation_item_background_color\ncolor mtrl_navigation_item_icon_tint\ncolor mtrl_navigation_item_text_color\ncolor mtrl_on_primary_text_btn_text_color_selector\ncolor mtrl_on_surface_ripple_color\ncolor mtrl_outlined_icon_tint\ncolor mtrl_outlined_stroke_color\ncolor mtrl_popupmenu_overlay_color\ncolor mtrl_scrim_color\ncolor mtrl_tabs_colored_ripple_color\ncolor mtrl_tabs_icon_color_selector\ncolor mtrl_tabs_icon_color_selector_colored\ncolor mtrl_tabs_legacy_text_color_selector\ncolor mtrl_tabs_ripple_color\ncolor mtrl_text_btn_text_color_selector\ncolor mtrl_textinput_default_box_stroke_color\ncolor mtrl_textinput_disabled_color\ncolor mtrl_textinput_filled_box_default_background_color\ncolor mtrl_textinput_focused_box_stroke_color\ncolor mtrl_textinput_hovered_box_stroke_color\ncolor notification_action_color_filter\ncolor notification_icon_bg_color\ncolor primary_dark_material_dark\ncolor primary_dark_material_light\ncolor primary_material_dark\ncolor primary_material_light\ncolor primary_text_default_material_dark\ncolor primary_text_default_material_light\ncolor primary_text_disabled_material_dark\ncolor primary_text_disabled_material_light\ncolor radiobutton_themeable_attribute_color\ncolor ripple_material_dark\ncolor ripple_material_light\ncolor secondary_text_default_material_dark\ncolor secondary_text_default_material_light\ncolor secondary_text_disabled_material_dark\ncolor secondary_text_disabled_material_light\ncolor switch_thumb_disabled_material_dark\ncolor switch_thumb_disabled_material_light\ncolor switch_thumb_material_dark\ncolor switch_thumb_material_light\ncolor switch_thumb_normal_material_dark\ncolor switch_thumb_normal_material_light\ncolor test_mtrl_calendar_day\ncolor test_mtrl_calendar_day_selected\ncolor tooltip_background_dark\ncolor tooltip_background_light\ndimen abc_action_bar_content_inset_material\ndimen abc_action_bar_content_inset_with_nav\ndimen abc_action_bar_default_height_material\ndimen abc_action_bar_default_padding_end_material\ndimen abc_action_bar_default_padding_start_material\ndimen abc_action_bar_elevation_material\ndimen abc_action_bar_icon_vertical_padding_material\ndimen abc_action_bar_overflow_padding_end_material\ndimen abc_action_bar_overflow_padding_start_material\ndimen abc_action_bar_stacked_max_height\ndimen abc_action_bar_stacked_tab_max_width\ndimen abc_action_bar_subtitle_bottom_margin_material\ndimen abc_action_bar_subtitle_top_margin_material\ndimen abc_action_button_min_height_material\ndimen abc_action_button_min_width_material\ndimen abc_action_button_min_width_overflow_material\ndimen abc_alert_dialog_button_bar_height\ndimen abc_alert_dialog_button_dimen\ndimen abc_button_inset_horizontal_material\ndimen abc_button_inset_vertical_material\ndimen abc_button_padding_horizontal_material\ndimen abc_button_padding_vertical_material\ndimen abc_cascading_menus_min_smallest_width\ndimen abc_config_prefDialogWidth\ndimen abc_control_corner_material\ndimen abc_control_inset_material\ndimen abc_control_padding_material\ndimen abc_dialog_corner_radius_material\ndimen abc_dialog_fixed_height_major\ndimen abc_dialog_fixed_height_minor\ndimen abc_dialog_fixed_width_major\ndimen abc_dialog_fixed_width_minor\ndimen abc_dialog_list_padding_bottom_no_buttons\ndimen abc_dialog_list_padding_top_no_title\ndimen abc_dialog_min_width_major\ndimen abc_dialog_min_width_minor\ndimen abc_dialog_padding_material\ndimen abc_dialog_padding_top_material\ndimen abc_dialog_title_divider_material\ndimen abc_disabled_alpha_material_dark\ndimen abc_disabled_alpha_material_light\ndimen abc_dropdownitem_icon_width\ndimen abc_dropdownitem_text_padding_left\ndimen abc_dropdownitem_text_padding_right\ndimen abc_edit_text_inset_bottom_material\ndimen abc_edit_text_inset_horizontal_material\ndimen abc_edit_text_inset_top_material\ndimen abc_floating_window_z\ndimen abc_list_item_height_large_material\ndimen abc_list_item_height_material\ndimen abc_list_item_height_small_material\ndimen abc_list_item_padding_horizontal_material\ndimen abc_panel_menu_list_width\ndimen abc_progress_bar_height_material\ndimen abc_search_view_preferred_height\ndimen abc_search_view_preferred_width\ndimen abc_seekbar_track_background_height_material\ndimen abc_seekbar_track_progress_height_material\ndimen abc_select_dialog_padding_start_material\ndimen abc_switch_padding\ndimen abc_text_size_body_1_material\ndimen abc_text_size_body_2_material\ndimen abc_text_size_button_material\ndimen abc_text_size_caption_material\ndimen abc_text_size_display_1_material\ndimen abc_text_size_display_2_material\ndimen abc_text_size_display_3_material\ndimen abc_text_size_display_4_material\ndimen abc_text_size_headline_material\ndimen abc_text_size_large_material\ndimen abc_text_size_medium_material\ndimen abc_text_size_menu_header_material\ndimen abc_text_size_menu_material\ndimen abc_text_size_small_material\ndimen abc_text_size_subhead_material\ndimen abc_text_size_subtitle_material_toolbar\ndimen abc_text_size_title_material\ndimen abc_text_size_title_material_toolbar\ndimen action_bar_size\ndimen appcompat_dialog_background_inset\ndimen cardview_compat_inset_shadow\ndimen cardview_default_elevation\ndimen cardview_default_radius\ndimen clock_face_margin_start\ndimen compat_button_inset_horizontal_material\ndimen compat_button_inset_vertical_material\ndimen compat_button_padding_horizontal_material\ndimen compat_button_padding_vertical_material\ndimen compat_control_corner_material\ndimen compat_notification_large_icon_max_height\ndimen compat_notification_large_icon_max_width\ndimen default_dimension\ndimen design_appbar_elevation\ndimen design_bottom_navigation_active_item_max_width\ndimen design_bottom_navigation_active_item_min_width\ndimen design_bottom_navigation_active_text_size\ndimen design_bottom_navigation_elevation\ndimen design_bottom_navigation_height\ndimen design_bottom_navigation_icon_size\ndimen design_bottom_navigation_item_max_width\ndimen design_bottom_navigation_item_min_width\ndimen design_bottom_navigation_label_padding\ndimen design_bottom_navigation_margin\ndimen design_bottom_navigation_shadow_height\ndimen design_bottom_navigation_text_size\ndimen design_bottom_sheet_elevation\ndimen design_bottom_sheet_modal_elevation\ndimen design_bottom_sheet_peek_height_min\ndimen design_fab_border_width\ndimen design_fab_elevation\ndimen design_fab_image_size\ndimen design_fab_size_mini\ndimen design_fab_size_normal\ndimen design_fab_translation_z_hovered_focused\ndimen design_fab_translation_z_pressed\ndimen design_navigation_elevation\ndimen design_navigation_icon_padding\ndimen design_navigation_icon_size\ndimen design_navigation_item_horizontal_padding\ndimen design_navigation_item_icon_padding\ndimen design_navigation_max_width\ndimen design_navigation_padding_bottom\ndimen design_navigation_separator_vertical_padding\ndimen design_snackbar_action_inline_max_width\ndimen design_snackbar_action_text_color_alpha\ndimen design_snackbar_background_corner_radius\ndimen design_snackbar_elevation\ndimen design_snackbar_extra_spacing_horizontal\ndimen design_snackbar_max_width\ndimen design_snackbar_min_width\ndimen design_snackbar_padding_horizontal\ndimen design_snackbar_padding_vertical\ndimen design_snackbar_padding_vertical_2lines\ndimen design_snackbar_text_size\ndimen design_tab_max_width\ndimen design_tab_scrollable_min_width\ndimen design_tab_text_size\ndimen design_tab_text_size_2line\ndimen design_textinput_caption_translate_y\ndimen disabled_alpha_material_dark\ndimen disabled_alpha_material_light\ndimen fastscroll_default_thickness\ndimen fastscroll_margin\ndimen fastscroll_minimum_range\ndimen highlight_alpha_material_colored\ndimen highlight_alpha_material_dark\ndimen highlight_alpha_material_light\ndimen hint_alpha_material_dark\ndimen hint_alpha_material_light\ndimen hint_pressed_alpha_material_dark\ndimen hint_pressed_alpha_material_light\ndimen item_touch_helper_max_drag_scroll_per_frame\ndimen item_touch_helper_swipe_escape_max_velocity\ndimen item_touch_helper_swipe_escape_velocity\ndimen material_clock_display_padding\ndimen material_clock_face_margin_top\ndimen material_clock_hand_center_dot_radius\ndimen material_clock_hand_padding\ndimen material_clock_hand_stroke_width\ndimen material_clock_number_text_size\ndimen material_clock_period_toggle_height\ndimen material_clock_period_toggle_margin_left\ndimen material_clock_period_toggle_width\ndimen material_clock_size\ndimen material_cursor_inset_bottom\ndimen material_cursor_inset_top\ndimen material_cursor_width\ndimen material_emphasis_disabled\ndimen material_emphasis_high_type\ndimen material_emphasis_medium\ndimen material_filled_edittext_font_1_3_padding_bottom\ndimen material_filled_edittext_font_1_3_padding_top\ndimen material_filled_edittext_font_2_0_padding_bottom\ndimen material_filled_edittext_font_2_0_padding_top\ndimen material_font_1_3_box_collapsed_padding_top\ndimen material_font_2_0_box_collapsed_padding_top\ndimen material_helper_text_default_padding_top\ndimen material_helper_text_font_1_3_padding_horizontal\ndimen material_helper_text_font_1_3_padding_top\ndimen material_input_text_to_prefix_suffix_padding\ndimen material_text_view_test_line_height\ndimen material_text_view_test_line_height_override\ndimen material_timepicker_dialog_buttons_margin_top\ndimen mtrl_alert_dialog_background_inset_bottom\ndimen mtrl_alert_dialog_background_inset_end\ndimen mtrl_alert_dialog_background_inset_start\ndimen mtrl_alert_dialog_background_inset_top\ndimen mtrl_alert_dialog_picker_background_inset\ndimen mtrl_badge_horizontal_edge_offset\ndimen mtrl_badge_long_text_horizontal_padding\ndimen mtrl_badge_radius\ndimen mtrl_badge_text_horizontal_edge_offset\ndimen mtrl_badge_text_size\ndimen mtrl_badge_toolbar_action_menu_item_horizontal_offset\ndimen mtrl_badge_toolbar_action_menu_item_vertical_offset\ndimen mtrl_badge_with_text_radius\ndimen mtrl_bottomappbar_fabOffsetEndMode\ndimen mtrl_bottomappbar_fab_bottom_margin\ndimen mtrl_bottomappbar_fab_cradle_margin\ndimen mtrl_bottomappbar_fab_cradle_rounded_corner_radius\ndimen mtrl_bottomappbar_fab_cradle_vertical_offset\ndimen mtrl_bottomappbar_height\ndimen mtrl_btn_corner_radius\ndimen mtrl_btn_dialog_btn_min_width\ndimen mtrl_btn_disabled_elevation\ndimen mtrl_btn_disabled_z\ndimen mtrl_btn_elevation\ndimen mtrl_btn_focused_z\ndimen mtrl_btn_hovered_z\ndimen mtrl_btn_icon_btn_padding_left\ndimen mtrl_btn_icon_padding\ndimen mtrl_btn_inset\ndimen mtrl_btn_letter_spacing\ndimen mtrl_btn_padding_bottom\ndimen mtrl_btn_padding_left\ndimen mtrl_btn_padding_right\ndimen mtrl_btn_padding_top\ndimen mtrl_btn_pressed_z\ndimen mtrl_btn_snackbar_margin_horizontal\ndimen mtrl_btn_stroke_size\ndimen mtrl_btn_text_btn_icon_padding\ndimen mtrl_btn_text_btn_padding_left\ndimen mtrl_btn_text_btn_padding_right\ndimen mtrl_btn_text_size\ndimen mtrl_btn_z\ndimen mtrl_calendar_action_confirm_button_min_width\ndimen mtrl_calendar_action_height\ndimen mtrl_calendar_action_padding\ndimen mtrl_calendar_bottom_padding\ndimen mtrl_calendar_content_padding\ndimen mtrl_calendar_day_corner\ndimen mtrl_calendar_day_height\ndimen mtrl_calendar_day_horizontal_padding\ndimen mtrl_calendar_day_today_stroke\ndimen mtrl_calendar_day_vertical_padding\ndimen mtrl_calendar_day_width\ndimen mtrl_calendar_days_of_week_height\ndimen mtrl_calendar_dialog_background_inset\ndimen mtrl_calendar_header_content_padding\ndimen mtrl_calendar_header_content_padding_fullscreen\ndimen mtrl_calendar_header_divider_thickness\ndimen mtrl_calendar_header_height\ndimen mtrl_calendar_header_height_fullscreen\ndimen mtrl_calendar_header_selection_line_height\ndimen mtrl_calendar_header_text_padding\ndimen mtrl_calendar_header_toggle_margin_bottom\ndimen mtrl_calendar_header_toggle_margin_top\ndimen mtrl_calendar_landscape_header_width\ndimen mtrl_calendar_maximum_default_fullscreen_minor_axis\ndimen mtrl_calendar_month_horizontal_padding\ndimen mtrl_calendar_month_vertical_padding\ndimen mtrl_calendar_navigation_bottom_padding\ndimen mtrl_calendar_navigation_height\ndimen mtrl_calendar_navigation_top_padding\ndimen mtrl_calendar_pre_l_text_clip_padding\ndimen mtrl_calendar_selection_baseline_to_top_fullscreen\ndimen mtrl_calendar_selection_text_baseline_to_bottom\ndimen mtrl_calendar_selection_text_baseline_to_bottom_fullscreen\ndimen mtrl_calendar_selection_text_baseline_to_top\ndimen mtrl_calendar_text_input_padding_top\ndimen mtrl_calendar_title_baseline_to_top\ndimen mtrl_calendar_title_baseline_to_top_fullscreen\ndimen mtrl_calendar_year_corner\ndimen mtrl_calendar_year_height\ndimen mtrl_calendar_year_horizontal_padding\ndimen mtrl_calendar_year_vertical_padding\ndimen mtrl_calendar_year_width\ndimen mtrl_card_checked_icon_margin\ndimen mtrl_card_checked_icon_size\ndimen mtrl_card_corner_radius\ndimen mtrl_card_dragged_z\ndimen mtrl_card_elevation\ndimen mtrl_card_spacing\ndimen mtrl_chip_pressed_translation_z\ndimen mtrl_chip_text_size\ndimen mtrl_edittext_rectangle_top_offset\ndimen mtrl_exposed_dropdown_menu_popup_elevation\ndimen mtrl_exposed_dropdown_menu_popup_vertical_offset\ndimen mtrl_exposed_dropdown_menu_popup_vertical_padding\ndimen mtrl_extended_fab_bottom_padding\ndimen mtrl_extended_fab_corner_radius\ndimen mtrl_extended_fab_disabled_elevation\ndimen mtrl_extended_fab_disabled_translation_z\ndimen mtrl_extended_fab_elevation\ndimen mtrl_extended_fab_end_padding\ndimen mtrl_extended_fab_end_padding_icon\ndimen mtrl_extended_fab_icon_size\ndimen mtrl_extended_fab_icon_text_spacing\ndimen mtrl_extended_fab_min_height\ndimen mtrl_extended_fab_min_width\ndimen mtrl_extended_fab_start_padding\ndimen mtrl_extended_fab_start_padding_icon\ndimen mtrl_extended_fab_top_padding\ndimen mtrl_extended_fab_translation_z_base\ndimen mtrl_extended_fab_translation_z_hovered_focused\ndimen mtrl_extended_fab_translation_z_pressed\ndimen mtrl_fab_elevation\ndimen mtrl_fab_min_touch_target\ndimen mtrl_fab_translation_z_hovered_focused\ndimen mtrl_fab_translation_z_pressed\ndimen mtrl_high_ripple_default_alpha\ndimen mtrl_high_ripple_focused_alpha\ndimen mtrl_high_ripple_hovered_alpha\ndimen mtrl_high_ripple_pressed_alpha\ndimen mtrl_large_touch_target\ndimen mtrl_low_ripple_default_alpha\ndimen mtrl_low_ripple_focused_alpha\ndimen mtrl_low_ripple_hovered_alpha\ndimen mtrl_low_ripple_pressed_alpha\ndimen mtrl_min_touch_target_size\ndimen mtrl_navigation_elevation\ndimen mtrl_navigation_item_horizontal_padding\ndimen mtrl_navigation_item_icon_padding\ndimen mtrl_navigation_item_icon_size\ndimen mtrl_navigation_item_shape_horizontal_margin\ndimen mtrl_navigation_item_shape_vertical_margin\ndimen mtrl_progress_circular_inset\ndimen mtrl_progress_circular_inset_extra_small\ndimen mtrl_progress_circular_inset_medium\ndimen mtrl_progress_circular_inset_small\ndimen mtrl_progress_circular_radius\ndimen mtrl_progress_circular_size\ndimen mtrl_progress_circular_size_extra_small\ndimen mtrl_progress_circular_size_medium\ndimen mtrl_progress_circular_size_small\ndimen mtrl_progress_circular_track_thickness_extra_small\ndimen mtrl_progress_circular_track_thickness_medium\ndimen mtrl_progress_circular_track_thickness_small\ndimen mtrl_progress_indicator_full_rounded_corner_radius\ndimen mtrl_progress_track_thickness\ndimen mtrl_shape_corner_size_large_component\ndimen mtrl_shape_corner_size_medium_component\ndimen mtrl_shape_corner_size_small_component\ndimen mtrl_slider_halo_radius\ndimen mtrl_slider_label_padding\ndimen mtrl_slider_label_radius\ndimen mtrl_slider_label_square_side\ndimen mtrl_slider_thumb_elevation\ndimen mtrl_slider_thumb_radius\ndimen mtrl_slider_track_height\ndimen mtrl_slider_track_side_padding\ndimen mtrl_slider_track_top\ndimen mtrl_slider_widget_height\ndimen mtrl_snackbar_action_text_color_alpha\ndimen mtrl_snackbar_background_corner_radius\ndimen mtrl_snackbar_background_overlay_color_alpha\ndimen mtrl_snackbar_margin\ndimen mtrl_snackbar_message_margin_horizontal\ndimen mtrl_snackbar_padding_horizontal\ndimen mtrl_switch_thumb_elevation\ndimen mtrl_textinput_box_corner_radius_medium\ndimen mtrl_textinput_box_corner_radius_small\ndimen mtrl_textinput_box_label_cutout_padding\ndimen mtrl_textinput_box_stroke_width_default\ndimen mtrl_textinput_box_stroke_width_focused\ndimen mtrl_textinput_counter_margin_start\ndimen mtrl_textinput_end_icon_margin_start\ndimen mtrl_textinput_outline_box_expanded_padding\ndimen mtrl_textinput_start_icon_margin_end\ndimen mtrl_toolbar_default_height\ndimen mtrl_tooltip_arrowSize\ndimen mtrl_tooltip_cornerSize\ndimen mtrl_tooltip_minHeight\ndimen mtrl_tooltip_minWidth\ndimen mtrl_tooltip_padding\ndimen mtrl_transition_shared_axis_slide_distance\ndimen notification_action_icon_size\ndimen notification_action_text_size\ndimen notification_big_circle_margin\ndimen notification_content_margin_start\ndimen notification_large_icon_height\ndimen notification_large_icon_width\ndimen notification_main_column_padding_top\ndimen notification_media_narrow_margin\ndimen notification_right_icon_size\ndimen notification_right_side_padding_top\ndimen notification_small_icon_background_padding\ndimen notification_small_icon_size_as_large\ndimen notification_subtext_size\ndimen notification_top_pad\ndimen notification_top_pad_large_text\ndimen test_mtrl_calendar_day_cornerSize\ndimen tooltip_corner_radius\ndimen tooltip_horizontal_padding\ndimen tooltip_margin\ndimen tooltip_precise_anchor_extra_offset\ndimen tooltip_precise_anchor_threshold\ndimen tooltip_vertical_padding\ndimen tooltip_y_offset_non_touch\ndimen tooltip_y_offset_touch\ndrawable abc_ab_share_pack_mtrl_alpha\ndrawable abc_action_bar_item_background_material\ndrawable abc_btn_borderless_material\ndrawable abc_btn_check_material\ndrawable abc_btn_check_material_anim\ndrawable abc_btn_check_to_on_mtrl_000\ndrawable abc_btn_check_to_on_mtrl_015\ndrawable abc_btn_colored_material\ndrawable abc_btn_default_mtrl_shape\ndrawable abc_btn_radio_material\ndrawable abc_btn_radio_material_anim\ndrawable abc_btn_radio_to_on_mtrl_000\ndrawable abc_btn_radio_to_on_mtrl_015\ndrawable abc_btn_switch_to_on_mtrl_00001\ndrawable abc_btn_switch_to_on_mtrl_00012\ndrawable abc_cab_background_internal_bg\ndrawable abc_cab_background_top_material\ndrawable abc_cab_background_top_mtrl_alpha\ndrawable abc_control_background_material\ndrawable abc_dialog_material_background\ndrawable abc_edit_text_material\ndrawable abc_ic_ab_back_material\ndrawable abc_ic_arrow_drop_right_black_24dp\ndrawable abc_ic_clear_material\ndrawable abc_ic_commit_search_api_mtrl_alpha\ndrawable abc_ic_go_search_api_material\ndrawable abc_ic_menu_copy_mtrl_am_alpha\ndrawable abc_ic_menu_cut_mtrl_alpha\ndrawable abc_ic_menu_overflow_material\ndrawable abc_ic_menu_paste_mtrl_am_alpha\ndrawable abc_ic_menu_selectall_mtrl_alpha\ndrawable abc_ic_menu_share_mtrl_alpha\ndrawable abc_ic_search_api_material\ndrawable abc_ic_star_black_16dp\ndrawable abc_ic_star_black_36dp\ndrawable abc_ic_star_black_48dp\ndrawable abc_ic_star_half_black_16dp\ndrawable abc_ic_star_half_black_36dp\ndrawable abc_ic_star_half_black_48dp\ndrawable abc_ic_voice_search_api_material\ndrawable abc_item_background_holo_dark\ndrawable abc_item_background_holo_light\ndrawable abc_list_divider_material\ndrawable abc_list_divider_mtrl_alpha\ndrawable abc_list_focused_holo\ndrawable abc_list_longpressed_holo\ndrawable abc_list_pressed_holo_dark\ndrawable abc_list_pressed_holo_light\ndrawable abc_list_selector_background_transition_holo_dark\ndrawable abc_list_selector_background_transition_holo_light\ndrawable abc_list_selector_disabled_holo_dark\ndrawable abc_list_selector_disabled_holo_light\ndrawable abc_list_selector_holo_dark\ndrawable abc_list_selector_holo_light\ndrawable abc_menu_hardkey_panel_mtrl_mult\ndrawable abc_popup_background_mtrl_mult\ndrawable abc_ratingbar_indicator_material\ndrawable abc_ratingbar_material\ndrawable abc_ratingbar_small_material\ndrawable abc_scrubber_control_off_mtrl_alpha\ndrawable abc_scrubber_control_to_pressed_mtrl_000\ndrawable abc_scrubber_control_to_pressed_mtrl_005\ndrawable abc_scrubber_primary_mtrl_alpha\ndrawable abc_scrubber_track_mtrl_alpha\ndrawable abc_seekbar_thumb_material\ndrawable abc_seekbar_tick_mark_material\ndrawable abc_seekbar_track_material\ndrawable abc_spinner_mtrl_am_alpha\ndrawable abc_spinner_textfield_background_material\ndrawable abc_switch_thumb_material\ndrawable abc_switch_track_mtrl_alpha\ndrawable abc_tab_indicator_material\ndrawable abc_tab_indicator_mtrl_alpha\ndrawable abc_text_cursor_material\ndrawable abc_text_select_handle_left_mtrl_dark\ndrawable abc_text_select_handle_left_mtrl_light\ndrawable abc_text_select_handle_middle_mtrl_dark\ndrawable abc_text_select_handle_middle_mtrl_light\ndrawable abc_text_select_handle_right_mtrl_dark\ndrawable abc_text_select_handle_right_mtrl_light\ndrawable abc_textfield_activated_mtrl_alpha\ndrawable abc_textfield_default_mtrl_alpha\ndrawable abc_textfield_search_activated_mtrl_alpha\ndrawable abc_textfield_search_default_mtrl_alpha\ndrawable abc_textfield_search_material\ndrawable abc_vector_test\ndrawable avd_hide_password\ndrawable avd_show_password\ndrawable btn_checkbox_checked_mtrl\ndrawable btn_checkbox_checked_to_unchecked_mtrl_animation\ndrawable btn_checkbox_unchecked_mtrl\ndrawable btn_checkbox_unchecked_to_checked_mtrl_animation\ndrawable btn_radio_off_mtrl\ndrawable btn_radio_off_to_on_mtrl_animation\ndrawable btn_radio_on_mtrl\ndrawable btn_radio_on_to_off_mtrl_animation\ndrawable design_bottom_navigation_item_background\ndrawable design_fab_background\ndrawable design_ic_visibility\ndrawable design_ic_visibility_off\ndrawable design_password_eye\ndrawable design_snackbar_background\ndrawable ic_clock_black_24dp\ndrawable ic_keyboard_black_24dp\ndrawable ic_mtrl_checked_circle\ndrawable ic_mtrl_chip_checked_black\ndrawable ic_mtrl_chip_checked_circle\ndrawable ic_mtrl_chip_close_circle\ndrawable material_cursor_drawable\ndrawable material_ic_calendar_black_24dp\ndrawable material_ic_clear_black_24dp\ndrawable material_ic_edit_black_24dp\ndrawable material_ic_keyboard_arrow_left_black_24dp\ndrawable material_ic_keyboard_arrow_next_black_24dp\ndrawable material_ic_keyboard_arrow_previous_black_24dp\ndrawable material_ic_keyboard_arrow_right_black_24dp\ndrawable material_ic_menu_arrow_down_black_24dp\ndrawable material_ic_menu_arrow_up_black_24dp\ndrawable mtrl_dialog_background\ndrawable mtrl_dropdown_arrow\ndrawable mtrl_ic_arrow_drop_down\ndrawable mtrl_ic_arrow_drop_up\ndrawable mtrl_ic_cancel\ndrawable mtrl_ic_error\ndrawable mtrl_popupmenu_background\ndrawable mtrl_popupmenu_background_dark\ndrawable mtrl_tabs_default_indicator\ndrawable navigation_empty_icon\ndrawable notification_action_background\ndrawable notification_bg\ndrawable notification_bg_low\ndrawable notification_bg_low_normal\ndrawable notification_bg_low_pressed\ndrawable notification_bg_normal\ndrawable notification_bg_normal_pressed\ndrawable notification_icon_background\ndrawable notification_template_icon_bg\ndrawable notification_template_icon_low_bg\ndrawable notification_tile_bg\ndrawable notify_panel_notification_icon_bg\ndrawable test_custom_background\ndrawable tooltip_frame_dark\ndrawable tooltip_frame_light\nid BOTTOM_END\nid BOTTOM_START\nid NO_DEBUG\nid SHOW_ALL\nid SHOW_PATH\nid SHOW_PROGRESS\nid TOP_END\nid TOP_START\nid accelerate\nid accessibility_action_clickable_span\nid accessibility_custom_action_0\nid accessibility_custom_action_1\nid accessibility_custom_action_10\nid accessibility_custom_action_11\nid accessibility_custom_action_12\nid accessibility_custom_action_13\nid accessibility_custom_action_14\nid accessibility_custom_action_15\nid accessibility_custom_action_16\nid accessibility_custom_action_17\nid accessibility_custom_action_18\nid accessibility_custom_action_19\nid accessibility_custom_action_2\nid accessibility_custom_action_20\nid accessibility_custom_action_21\nid accessibility_custom_action_22\nid accessibility_custom_action_23\nid accessibility_custom_action_24\nid accessibility_custom_action_25\nid accessibility_custom_action_26\nid accessibility_custom_action_27\nid accessibility_custom_action_28\nid accessibility_custom_action_29\nid accessibility_custom_action_3\nid accessibility_custom_action_30\nid accessibility_custom_action_31\nid accessibility_custom_action_4\nid accessibility_custom_action_5\nid accessibility_custom_action_6\nid accessibility_custom_action_7\nid accessibility_custom_action_8\nid accessibility_custom_action_9\nid action_bar\nid action_bar_activity_content\nid action_bar_container\nid action_bar_root\nid action_bar_spinner\nid action_bar_subtitle\nid action_bar_title\nid action_container\nid action_context_bar\nid action_divider\nid action_image\nid action_menu_divider\nid action_menu_presenter\nid action_mode_bar\nid action_mode_bar_stub\nid action_mode_close_button\nid action_text\nid actions\nid activity_chooser_view_content\nid add\nid alertTitle\nid aligned\nid animateToEnd\nid animateToStart\nid asConfigured\nid async\nid auto\nid autoComplete\nid autoCompleteToEnd\nid autoCompleteToStart\nid barrier\nid baseline\nid blocking\nid bottom\nid bounce\nid buttonPanel\nid cancel_button\nid center\nid chain\nid checkbox\nid checked\nid chip\nid chip1\nid chip2\nid chip3\nid chip_group\nid chronometer\nid circle_center\nid clear_text\nid clockwise\nid confirm_button\nid container\nid content\nid contentPanel\nid contiguous\nid coordinator\nid cos\nid counterclockwise\nid custom\nid customPanel\nid cut\nid date_picker_actions\nid decelerate\nid decelerateAndComplete\nid decor_content_parent\nid default_activity_button\nid deltaRelative\nid design_bottom_sheet\nid design_menu_item_action_area\nid design_menu_item_action_area_stub\nid design_menu_item_text\nid design_navigation_view\nid dialog_button\nid disjoint\nid dragDown\nid dragEnd\nid dragLeft\nid dragRight\nid dragStart\nid dragUp\nid dropdown_menu\nid easeIn\nid easeInOut\nid easeOut\nid edit_query\nid elastic\nid end\nid endToStart\nid expand_activities_button\nid expanded_menu\nid fade\nid fill\nid filled\nid fixed\nid flip\nid floating\nid forever\nid function_name_tv\nid ghost_view\nid ghost_view_holder\nid gone\nid group_divider\nid guideline\nid header_title\nid home\nid honorRequest\nid icon\nid icon_group\nid ignore\nid ignoreRequest\nid image\nid info\nid invisible\nid inward\nid italic\nid item_touch_helper_previous_elevation\nid jumpToEnd\nid jumpToStart\nid labelGroup\nid labeled\nid largeLabel\nid layout\nid left\nid leftToRight\nid line1\nid line3\nid linear\nid listMode\nid list_item\nid masked\nid material_clock_display\nid material_clock_face\nid material_clock_hand\nid material_clock_period_am_button\nid material_clock_period_pm_button\nid material_clock_period_toggle\nid material_hour_text_input\nid material_hour_tv\nid material_label\nid material_minute_text_input\nid material_minute_tv\nid material_textinput_timepicker\nid material_timepicker_cancel_button\nid material_timepicker_container\nid material_timepicker_edit_text\nid material_timepicker_mode_button\nid material_timepicker_ok_button\nid material_timepicker_view\nid material_value_index\nid message\nid middle\nid mini\nid month_grid\nid month_navigation_bar\nid month_navigation_fragment_toggle\nid month_navigation_next\nid month_navigation_previous\nid month_title\nid motion_base\nid mtrl_anchor_parent\nid mtrl_calendar_day_selector_frame\nid mtrl_calendar_days_of_week\nid mtrl_calendar_frame\nid mtrl_calendar_main_pane\nid mtrl_calendar_months\nid mtrl_calendar_selection_frame\nid mtrl_calendar_text_input_frame\nid mtrl_calendar_year_selector_frame\nid mtrl_card_checked_layer_id\nid mtrl_child_content_container\nid mtrl_internal_children_alpha_tag\nid mtrl_motion_snapshot_view\nid mtrl_picker_fullscreen\nid mtrl_picker_header\nid mtrl_picker_header_selection_text\nid mtrl_picker_header_title_and_selection\nid mtrl_picker_header_toggle\nid mtrl_picker_text_input_date\nid mtrl_picker_text_input_range_end\nid mtrl_picker_text_input_range_start\nid mtrl_picker_title_text\nid mtrl_view_tag_bottom_padding\nid multiply\nid navigation_header_container\nid none\nid normal\nid notification_background\nid notification_main_column\nid notification_main_column_container\nid off\nid on\nid origin_count_tv\nid origin_method_tv\nid outline\nid outward\nid packed\nid parallax\nid parent\nid parentPanel\nid parentRelative\nid parent_matrix\nid password_toggle\nid path\nid pathRelative\nid percent\nid permission_desc_tv\nid permission_tv\nid pin\nid position\nid postLayout\nid progress_circular\nid progress_horizontal\nid radio\nid rectangles\nid reverseSawtooth\nid right\nid rightToLeft\nid right_icon\nid right_side\nid rounded\nid row_index_key\nid save_non_transition_alpha\nid save_overlay_view\nid sawtooth\nid scale\nid screen\nid scrollIndicatorDown\nid scrollIndicatorUp\nid scrollView\nid scrollable\nid search_badge\nid search_bar\nid search_button\nid search_close_btn\nid search_edit_frame\nid search_go_btn\nid search_mag_icon\nid search_plate\nid search_src_text\nid search_voice_btn\nid select_dialog_listview\nid selected\nid selection_type\nid shortcut\nid sin\nid slide\nid smallLabel\nid snackbar_action\nid snackbar_text\nid spacer\nid spline\nid split_action_bar\nid spread\nid spread_inside\nid square\nid src_atop\nid src_in\nid src_over\nid standard\nid start\nid startHorizontal\nid startToEnd\nid startVertical\nid staticLayout\nid staticPostLayout\nid stop\nid stretch\nid submenuarrow\nid submit_area\nid tabMode\nid tag_accessibility_actions\nid tag_accessibility_clickable_spans\nid tag_accessibility_heading\nid tag_accessibility_pane_title\nid tag_screen_reader_focusable\nid tag_transition_group\nid tag_unhandled_key_event_manager\nid tag_unhandled_key_listeners\nid test_checkbox_android_button_tint\nid test_checkbox_app_button_tint\nid test_radiobutton_android_button_tint\nid test_radiobutton_app_button_tint\nid text\nid text2\nid textSpacerNoButtons\nid textSpacerNoTitle\nid text_input_end_icon\nid text_input_error_icon\nid text_input_start_icon\nid textinput_counter\nid textinput_error\nid textinput_helper_text\nid textinput_placeholder\nid textinput_prefix_text\nid textinput_suffix_text\nid time\nid time_tv\nid title\nid titleDividerNoCustom\nid title_template\nid top\nid topPanel\nid touch_outside\nid transition_current_scene\nid transition_layout_save\nid transition_position\nid transition_scene_layoutid_cache\nid transition_transform\nid triangle\nid unchecked\nid uniform\nid unlabeled\nid up\nid view_offset_helper\nid visible\nid withinBounds\nid wrap\nid wrap_content\nid zero_corner_chip\ninteger abc_config_activityDefaultDur\ninteger abc_config_activityShortDur\ninteger app_bar_elevation_anim_duration\ninteger bottom_sheet_slide_duration\ninteger cancel_button_image_alpha\ninteger config_tooltipAnimTime\ninteger design_snackbar_text_max_lines\ninteger design_tab_indicator_anim_duration_ms\ninteger hide_password_duration\ninteger mtrl_badge_max_character_count\ninteger mtrl_btn_anim_delay_ms\ninteger mtrl_btn_anim_duration_ms\ninteger mtrl_calendar_header_orientation\ninteger mtrl_calendar_selection_text_lines\ninteger mtrl_calendar_year_selector_span\ninteger mtrl_card_anim_delay_ms\ninteger mtrl_card_anim_duration_ms\ninteger mtrl_chip_anim_duration\ninteger mtrl_tab_indicator_anim_duration_ms\ninteger show_password_duration\ninteger status_bar_notification_info_maxnum\ninterpolator btn_checkbox_checked_mtrl_animation_interpolator_0\ninterpolator btn_checkbox_checked_mtrl_animation_interpolator_1\ninterpolator btn_checkbox_unchecked_mtrl_animation_interpolator_0\ninterpolator btn_checkbox_unchecked_mtrl_animation_interpolator_1\ninterpolator btn_radio_to_off_mtrl_animation_interpolator_0\ninterpolator btn_radio_to_on_mtrl_animation_interpolator_0\ninterpolator fast_out_slow_in\ninterpolator mtrl_fast_out_linear_in\ninterpolator mtrl_fast_out_slow_in\ninterpolator mtrl_linear\ninterpolator mtrl_linear_out_slow_in\nlayout abc_action_bar_title_item\nlayout abc_action_bar_up_container\nlayout abc_action_menu_item_layout\nlayout abc_action_menu_layout\nlayout abc_action_mode_bar\nlayout abc_action_mode_close_item_material\nlayout abc_activity_chooser_view\nlayout abc_activity_chooser_view_list_item\nlayout abc_alert_dialog_button_bar_material\nlayout abc_alert_dialog_material\nlayout abc_alert_dialog_title_material\nlayout abc_cascading_menu_item_layout\nlayout abc_dialog_title_material\nlayout abc_expanded_menu_layout\nlayout abc_list_menu_item_checkbox\nlayout abc_list_menu_item_icon\nlayout abc_list_menu_item_layout\nlayout abc_list_menu_item_radio\nlayout abc_popup_menu_header_item_layout\nlayout abc_popup_menu_item_layout\nlayout abc_screen_content_include\nlayout abc_screen_simple\nlayout abc_screen_simple_overlay_action_mode\nlayout abc_screen_toolbar\nlayout abc_search_dropdown_item_icons_2line\nlayout abc_search_view\nlayout abc_select_dialog_material\nlayout abc_tooltip\nlayout activity_permission_list\nlayout activity_real_time_privacy_item\nlayout activity_replace_list\nlayout custom_dialog\nlayout design_bottom_navigation_item\nlayout design_bottom_sheet_dialog\nlayout design_layout_snackbar\nlayout design_layout_snackbar_include\nlayout design_layout_tab_icon\nlayout design_layout_tab_text\nlayout design_menu_item_action_area\nlayout design_navigation_item\nlayout design_navigation_item_header\nlayout design_navigation_item_separator\nlayout design_navigation_item_subheader\nlayout design_navigation_menu\nlayout design_navigation_menu_item\nlayout design_text_input_end_icon\nlayout design_text_input_start_icon\nlayout material_chip_input_combo\nlayout material_clock_display\nlayout material_clock_display_divider\nlayout material_clock_period_toggle\nlayout material_clock_period_toggle_land\nlayout material_clockface_textview\nlayout material_clockface_view\nlayout material_radial_view_group\nlayout material_textinput_timepicker\nlayout material_time_chip\nlayout material_time_input\nlayout material_timepicker\nlayout material_timepicker_dialog\nlayout material_timepicker_textinput_display\nlayout mtrl_alert_dialog\nlayout mtrl_alert_dialog_actions\nlayout mtrl_alert_dialog_title\nlayout mtrl_alert_select_dialog_item\nlayout mtrl_alert_select_dialog_multichoice\nlayout mtrl_alert_select_dialog_singlechoice\nlayout mtrl_calendar_day\nlayout mtrl_calendar_day_of_week\nlayout mtrl_calendar_days_of_week\nlayout mtrl_calendar_horizontal\nlayout mtrl_calendar_month\nlayout mtrl_calendar_month_labeled\nlayout mtrl_calendar_month_navigation\nlayout mtrl_calendar_months\nlayout mtrl_calendar_vertical\nlayout mtrl_calendar_year\nlayout mtrl_layout_snackbar\nlayout mtrl_layout_snackbar_include\nlayout mtrl_picker_actions\nlayout mtrl_picker_dialog\nlayout mtrl_picker_fullscreen\nlayout mtrl_picker_header_dialog\nlayout mtrl_picker_header_fullscreen\nlayout mtrl_picker_header_selection_text\nlayout mtrl_picker_header_title_text\nlayout mtrl_picker_header_toggle\nlayout mtrl_picker_text_input_date\nlayout mtrl_picker_text_input_date_range\nlayout notification_action\nlayout notification_action_tombstone\nlayout notification_template_custom_big\nlayout notification_template_icon_group\nlayout notification_template_part_chronometer\nlayout notification_template_part_time\nlayout permission_item_view\nlayout real_tile_item_view\nlayout replace_item_view\nlayout select_dialog_item_material\nlayout select_dialog_multichoice_material\nlayout select_dialog_singlechoice_material\nlayout support_simple_spinner_dropdown_item\nlayout test_action_chip\nlayout test_chip_zero_corner_radius\nlayout test_design_checkbox\nlayout test_design_radiobutton\nlayout test_reflow_chipgroup\nlayout test_toolbar\nlayout test_toolbar_custom_background\nlayout test_toolbar_elevation\nlayout test_toolbar_surface\nlayout text_view_with_line_height_from_appearance\nlayout text_view_with_line_height_from_layout\nlayout text_view_with_line_height_from_style\nlayout text_view_with_theme_line_height\nlayout text_view_without_line_height\nplurals mtrl_badge_content_description\nstring abc_action_bar_home_description\nstring abc_action_bar_up_description\nstring abc_action_menu_overflow_description\nstring abc_action_mode_done\nstring abc_activity_chooser_view_see_all\nstring abc_activitychooserview_choose_application\nstring abc_capital_off\nstring abc_capital_on\nstring abc_menu_alt_shortcut_label\nstring abc_menu_ctrl_shortcut_label\nstring abc_menu_delete_shortcut_label\nstring abc_menu_enter_shortcut_label\nstring abc_menu_function_shortcut_label\nstring abc_menu_meta_shortcut_label\nstring abc_menu_shift_shortcut_label\nstring abc_menu_space_shortcut_label\nstring abc_menu_sym_shortcut_label\nstring abc_prepend_shortcut_label\nstring abc_search_hint\nstring abc_searchview_description_clear\nstring abc_searchview_description_query\nstring abc_searchview_description_search\nstring abc_searchview_description_submit\nstring abc_searchview_description_voice\nstring abc_shareactionprovider_share_with\nstring abc_shareactionprovider_share_with_application\nstring abc_toolbar_collapse_description\nstring appbar_scrolling_view_behavior\nstring bottom_sheet_behavior\nstring bottomsheet_action_expand_halfway\nstring character_counter_content_description\nstring character_counter_overflowed_content_description\nstring character_counter_pattern\nstring chip_text\nstring clear_text_end_icon_content_description\nstring error_icon_content_description\nstring exposed_dropdown_menu_content_description\nstring fab_transformation_scrim_behavior\nstring fab_transformation_sheet_behavior\nstring hide_bottom_view_on_scroll_behavior\nstring icon_content_description\nstring item_view_role_description\nstring material_clock_display_divider\nstring material_clock_toggle_content_description\nstring material_hour_selection\nstring material_hour_suffix\nstring material_minute_selection\nstring material_minute_suffix\nstring material_slider_range_end\nstring material_slider_range_start\nstring material_timepicker_am\nstring material_timepicker_clock_mode_description\nstring material_timepicker_hour\nstring material_timepicker_minute\nstring material_timepicker_pm\nstring material_timepicker_select_time\nstring material_timepicker_text_input_mode_description\nstring mtrl_badge_numberless_content_description\nstring mtrl_chip_close_icon_content_description\nstring mtrl_exceed_max_badge_number_content_description\nstring mtrl_exceed_max_badge_number_suffix\nstring mtrl_picker_a11y_next_month\nstring mtrl_picker_a11y_prev_month\nstring mtrl_picker_announce_current_selection\nstring mtrl_picker_cancel\nstring mtrl_picker_confirm\nstring mtrl_picker_date_header_selected\nstring mtrl_picker_date_header_title\nstring mtrl_picker_date_header_unselected\nstring mtrl_picker_day_of_week_column_header\nstring mtrl_picker_invalid_format\nstring mtrl_picker_invalid_format_example\nstring mtrl_picker_invalid_format_use\nstring mtrl_picker_invalid_range\nstring mtrl_picker_navigate_to_year_description\nstring mtrl_picker_out_of_range\nstring mtrl_picker_range_header_only_end_selected\nstring mtrl_picker_range_header_only_start_selected\nstring mtrl_picker_range_header_selected\nstring mtrl_picker_range_header_title\nstring mtrl_picker_range_header_unselected\nstring mtrl_picker_save\nstring mtrl_picker_text_input_date_hint\nstring mtrl_picker_text_input_date_range_end_hint\nstring mtrl_picker_text_input_date_range_start_hint\nstring mtrl_picker_text_input_day_abbr\nstring mtrl_picker_text_input_month_abbr\nstring mtrl_picker_text_input_year_abbr\nstring mtrl_picker_toggle_to_calendar_input_mode\nstring mtrl_picker_toggle_to_day_selection\nstring mtrl_picker_toggle_to_text_input_mode\nstring mtrl_picker_toggle_to_year_selection\nstring password_toggle_content_description\nstring path_password_eye\nstring path_password_eye_mask_strike_through\nstring path_password_eye_mask_visible\nstring path_password_strike_through\nstring search_menu_title\nstring status_bar_notification_info_overflow\nstyle AlertDialog_AppCompat\nstyle AlertDialog_AppCompat_Light\nstyle AndroidThemeColorAccentYellow\nstyle Animation_AppCompat_Dialog\nstyle Animation_AppCompat_DropDownUp\nstyle Animation_AppCompat_Tooltip\nstyle Animation_Design_BottomSheetDialog\nstyle Animation_MaterialComponents_BottomSheetDialog\nstyle Base_AlertDialog_AppCompat\nstyle Base_AlertDialog_AppCompat_Light\nstyle Base_Animation_AppCompat_Dialog\nstyle Base_Animation_AppCompat_DropDownUp\nstyle Base_Animation_AppCompat_Tooltip\nstyle Base_CardView\nstyle Base_DialogWindowTitleBackground_AppCompat\nstyle Base_DialogWindowTitle_AppCompat\nstyle Base_MaterialAlertDialog_MaterialComponents_Title_Icon\nstyle Base_MaterialAlertDialog_MaterialComponents_Title_Panel\nstyle Base_MaterialAlertDialog_MaterialComponents_Title_Text\nstyle Base_TextAppearance_AppCompat\nstyle Base_TextAppearance_AppCompat_Body1\nstyle Base_TextAppearance_AppCompat_Body2\nstyle Base_TextAppearance_AppCompat_Button\nstyle Base_TextAppearance_AppCompat_Caption\nstyle Base_TextAppearance_AppCompat_Display1\nstyle Base_TextAppearance_AppCompat_Display2\nstyle Base_TextAppearance_AppCompat_Display3\nstyle Base_TextAppearance_AppCompat_Display4\nstyle Base_TextAppearance_AppCompat_Headline\nstyle Base_TextAppearance_AppCompat_Inverse\nstyle Base_TextAppearance_AppCompat_Large\nstyle Base_TextAppearance_AppCompat_Large_Inverse\nstyle Base_TextAppearance_AppCompat_Light_Widget_PopupMenu_Large\nstyle Base_TextAppearance_AppCompat_Light_Widget_PopupMenu_Small\nstyle Base_TextAppearance_AppCompat_Medium\nstyle Base_TextAppearance_AppCompat_Medium_Inverse\nstyle Base_TextAppearance_AppCompat_Menu\nstyle Base_TextAppearance_AppCompat_SearchResult\nstyle Base_TextAppearance_AppCompat_SearchResult_Subtitle\nstyle Base_TextAppearance_AppCompat_SearchResult_Title\nstyle Base_TextAppearance_AppCompat_Small\nstyle Base_TextAppearance_AppCompat_Small_Inverse\nstyle Base_TextAppearance_AppCompat_Subhead\nstyle Base_TextAppearance_AppCompat_Subhead_Inverse\nstyle Base_TextAppearance_AppCompat_Title\nstyle Base_TextAppearance_AppCompat_Title_Inverse\nstyle Base_TextAppearance_AppCompat_Tooltip\nstyle Base_TextAppearance_AppCompat_Widget_ActionBar_Menu\nstyle Base_TextAppearance_AppCompat_Widget_ActionBar_Subtitle\nstyle Base_TextAppearance_AppCompat_Widget_ActionBar_Subtitle_Inverse\nstyle Base_TextAppearance_AppCompat_Widget_ActionBar_Title\nstyle Base_TextAppearance_AppCompat_Widget_ActionBar_Title_Inverse\nstyle Base_TextAppearance_AppCompat_Widget_ActionMode_Subtitle\nstyle Base_TextAppearance_AppCompat_Widget_ActionMode_Title\nstyle Base_TextAppearance_AppCompat_Widget_Button\nstyle Base_TextAppearance_AppCompat_Widget_Button_Borderless_Colored\nstyle Base_TextAppearance_AppCompat_Widget_Button_Colored\nstyle Base_TextAppearance_AppCompat_Widget_Button_Inverse\nstyle Base_TextAppearance_AppCompat_Widget_DropDownItem\nstyle Base_TextAppearance_AppCompat_Widget_PopupMenu_Header\nstyle Base_TextAppearance_AppCompat_Widget_PopupMenu_Large\nstyle Base_TextAppearance_AppCompat_Widget_PopupMenu_Small\nstyle Base_TextAppearance_AppCompat_Widget_Switch\nstyle Base_TextAppearance_AppCompat_Widget_TextView_SpinnerItem\nstyle Base_TextAppearance_MaterialComponents_Badge\nstyle Base_TextAppearance_MaterialComponents_Button\nstyle Base_TextAppearance_MaterialComponents_Headline6\nstyle Base_TextAppearance_MaterialComponents_Subtitle2\nstyle Base_TextAppearance_Widget_AppCompat_ExpandedMenu_Item\nstyle Base_TextAppearance_Widget_AppCompat_Toolbar_Subtitle\nstyle Base_TextAppearance_Widget_AppCompat_Toolbar_Title\nstyle Base_ThemeOverlay_AppCompat\nstyle Base_ThemeOverlay_AppCompat_ActionBar\nstyle Base_ThemeOverlay_AppCompat_Dark\nstyle Base_ThemeOverlay_AppCompat_Dark_ActionBar\nstyle Base_ThemeOverlay_AppCompat_Dialog\nstyle Base_ThemeOverlay_AppCompat_Dialog_Alert\nstyle Base_ThemeOverlay_AppCompat_Light\nstyle Base_ThemeOverlay_MaterialComponents_Dialog\nstyle Base_ThemeOverlay_MaterialComponents_Dialog_Alert\nstyle Base_ThemeOverlay_MaterialComponents_Dialog_Alert_Framework\nstyle Base_ThemeOverlay_MaterialComponents_Light_Dialog_Alert_Framework\nstyle Base_ThemeOverlay_MaterialComponents_MaterialAlertDialog\nstyle Base_Theme_AppCompat\nstyle Base_Theme_AppCompat_CompactMenu\nstyle Base_Theme_AppCompat_Dialog\nstyle Base_Theme_AppCompat_DialogWhenLarge\nstyle Base_Theme_AppCompat_Dialog_Alert\nstyle Base_Theme_AppCompat_Dialog_FixedSize\nstyle Base_Theme_AppCompat_Dialog_MinWidth\nstyle Base_Theme_AppCompat_Light\nstyle Base_Theme_AppCompat_Light_DarkActionBar\nstyle Base_Theme_AppCompat_Light_Dialog\nstyle Base_Theme_AppCompat_Light_DialogWhenLarge\nstyle Base_Theme_AppCompat_Light_Dialog_Alert\nstyle Base_Theme_AppCompat_Light_Dialog_FixedSize\nstyle Base_Theme_AppCompat_Light_Dialog_MinWidth\nstyle Base_Theme_MaterialComponents\nstyle Base_Theme_MaterialComponents_Bridge\nstyle Base_Theme_MaterialComponents_CompactMenu\nstyle Base_Theme_MaterialComponents_Dialog\nstyle Base_Theme_MaterialComponents_DialogWhenLarge\nstyle Base_Theme_MaterialComponents_Dialog_Alert\nstyle Base_Theme_MaterialComponents_Dialog_Bridge\nstyle Base_Theme_MaterialComponents_Dialog_FixedSize\nstyle Base_Theme_MaterialComponents_Dialog_MinWidth\nstyle Base_Theme_MaterialComponents_Light\nstyle Base_Theme_MaterialComponents_Light_Bridge\nstyle Base_Theme_MaterialComponents_Light_DarkActionBar\nstyle Base_Theme_MaterialComponents_Light_DarkActionBar_Bridge\nstyle Base_Theme_MaterialComponents_Light_Dialog\nstyle Base_Theme_MaterialComponents_Light_DialogWhenLarge\nstyle Base_Theme_MaterialComponents_Light_Dialog_Alert\nstyle Base_Theme_MaterialComponents_Light_Dialog_Bridge\nstyle Base_Theme_MaterialComponents_Light_Dialog_FixedSize\nstyle Base_Theme_MaterialComponents_Light_Dialog_MinWidth\nstyle Base_V14_ThemeOverlay_MaterialComponents_Dialog\nstyle Base_V14_ThemeOverlay_MaterialComponents_Dialog_Alert\nstyle Base_V14_ThemeOverlay_MaterialComponents_MaterialAlertDialog\nstyle Base_V14_Theme_MaterialComponents\nstyle Base_V14_Theme_MaterialComponents_Bridge\nstyle Base_V14_Theme_MaterialComponents_Dialog\nstyle Base_V14_Theme_MaterialComponents_Dialog_Bridge\nstyle Base_V14_Theme_MaterialComponents_Light\nstyle Base_V14_Theme_MaterialComponents_Light_Bridge\nstyle Base_V14_Theme_MaterialComponents_Light_DarkActionBar_Bridge\nstyle Base_V14_Theme_MaterialComponents_Light_Dialog\nstyle Base_V14_Theme_MaterialComponents_Light_Dialog_Bridge\nstyle Base_V21_ThemeOverlay_AppCompat_Dialog\nstyle Base_V21_Theme_AppCompat\nstyle Base_V21_Theme_AppCompat_Dialog\nstyle Base_V21_Theme_AppCompat_Light\nstyle Base_V21_Theme_AppCompat_Light_Dialog\nstyle Base_V21_Theme_MaterialComponents\nstyle Base_V21_Theme_MaterialComponents_Dialog\nstyle Base_V21_Theme_MaterialComponents_Light\nstyle Base_V21_Theme_MaterialComponents_Light_Dialog\nstyle Base_V22_Theme_AppCompat\nstyle Base_V22_Theme_AppCompat_Light\nstyle Base_V23_Theme_AppCompat\nstyle Base_V23_Theme_AppCompat_Light\nstyle Base_V26_Theme_AppCompat\nstyle Base_V26_Theme_AppCompat_Light\nstyle Base_V26_Widget_AppCompat_Toolbar\nstyle Base_V28_Theme_AppCompat\nstyle Base_V28_Theme_AppCompat_Light\nstyle Base_V7_ThemeOverlay_AppCompat_Dialog\nstyle Base_V7_Theme_AppCompat\nstyle Base_V7_Theme_AppCompat_Dialog\nstyle Base_V7_Theme_AppCompat_Light\nstyle Base_V7_Theme_AppCompat_Light_Dialog\nstyle Base_V7_Widget_AppCompat_AutoCompleteTextView\nstyle Base_V7_Widget_AppCompat_EditText\nstyle Base_V7_Widget_AppCompat_Toolbar\nstyle Base_Widget_AppCompat_ActionBar\nstyle Base_Widget_AppCompat_ActionBar_Solid\nstyle Base_Widget_AppCompat_ActionBar_TabBar\nstyle Base_Widget_AppCompat_ActionBar_TabText\nstyle Base_Widget_AppCompat_ActionBar_TabView\nstyle Base_Widget_AppCompat_ActionButton\nstyle Base_Widget_AppCompat_ActionButton_CloseMode\nstyle Base_Widget_AppCompat_ActionButton_Overflow\nstyle Base_Widget_AppCompat_ActionMode\nstyle Base_Widget_AppCompat_ActivityChooserView\nstyle Base_Widget_AppCompat_AutoCompleteTextView\nstyle Base_Widget_AppCompat_Button\nstyle Base_Widget_AppCompat_ButtonBar\nstyle Base_Widget_AppCompat_ButtonBar_AlertDialog\nstyle Base_Widget_AppCompat_Button_Borderless\nstyle Base_Widget_AppCompat_Button_Borderless_Colored\nstyle Base_Widget_AppCompat_Button_ButtonBar_AlertDialog\nstyle Base_Widget_AppCompat_Button_Colored\nstyle Base_Widget_AppCompat_Button_Small\nstyle Base_Widget_AppCompat_CompoundButton_CheckBox\nstyle Base_Widget_AppCompat_CompoundButton_RadioButton\nstyle Base_Widget_AppCompat_CompoundButton_Switch\nstyle Base_Widget_AppCompat_DrawerArrowToggle\nstyle Base_Widget_AppCompat_DrawerArrowToggle_Common\nstyle Base_Widget_AppCompat_DropDownItem_Spinner\nstyle Base_Widget_AppCompat_EditText\nstyle Base_Widget_AppCompat_ImageButton\nstyle Base_Widget_AppCompat_Light_ActionBar\nstyle Base_Widget_AppCompat_Light_ActionBar_Solid\nstyle Base_Widget_AppCompat_Light_ActionBar_TabBar\nstyle Base_Widget_AppCompat_Light_ActionBar_TabText\nstyle Base_Widget_AppCompat_Light_ActionBar_TabText_Inverse\nstyle Base_Widget_AppCompat_Light_ActionBar_TabView\nstyle Base_Widget_AppCompat_Light_PopupMenu\nstyle Base_Widget_AppCompat_Light_PopupMenu_Overflow\nstyle Base_Widget_AppCompat_ListMenuView\nstyle Base_Widget_AppCompat_ListPopupWindow\nstyle Base_Widget_AppCompat_ListView\nstyle Base_Widget_AppCompat_ListView_DropDown\nstyle Base_Widget_AppCompat_ListView_Menu\nstyle Base_Widget_AppCompat_PopupMenu\nstyle Base_Widget_AppCompat_PopupMenu_Overflow\nstyle Base_Widget_AppCompat_PopupWindow\nstyle Base_Widget_AppCompat_ProgressBar\nstyle Base_Widget_AppCompat_ProgressBar_Horizontal\nstyle Base_Widget_AppCompat_RatingBar\nstyle Base_Widget_AppCompat_RatingBar_Indicator\nstyle Base_Widget_AppCompat_RatingBar_Small\nstyle Base_Widget_AppCompat_SearchView\nstyle Base_Widget_AppCompat_SearchView_ActionBar\nstyle Base_Widget_AppCompat_SeekBar\nstyle Base_Widget_AppCompat_SeekBar_Discrete\nstyle Base_Widget_AppCompat_Spinner\nstyle Base_Widget_AppCompat_Spinner_Underlined\nstyle Base_Widget_AppCompat_TextView\nstyle Base_Widget_AppCompat_TextView_SpinnerItem\nstyle Base_Widget_AppCompat_Toolbar\nstyle Base_Widget_AppCompat_Toolbar_Button_Navigation\nstyle Base_Widget_Design_TabLayout\nstyle Base_Widget_MaterialComponents_AutoCompleteTextView\nstyle Base_Widget_MaterialComponents_CheckedTextView\nstyle Base_Widget_MaterialComponents_Chip\nstyle Base_Widget_MaterialComponents_MaterialCalendar_NavigationButton\nstyle Base_Widget_MaterialComponents_PopupMenu\nstyle Base_Widget_MaterialComponents_PopupMenu_ContextMenu\nstyle Base_Widget_MaterialComponents_PopupMenu_ListPopupWindow\nstyle Base_Widget_MaterialComponents_PopupMenu_Overflow\nstyle Base_Widget_MaterialComponents_Slider\nstyle Base_Widget_MaterialComponents_Snackbar\nstyle Base_Widget_MaterialComponents_TextInputEditText\nstyle Base_Widget_MaterialComponents_TextInputLayout\nstyle Base_Widget_MaterialComponents_TextView\nstyle CardView\nstyle CardView_Dark\nstyle CardView_Light\nstyle EmptyTheme\nstyle MaterialAlertDialog_MaterialComponents\nstyle MaterialAlertDialog_MaterialComponents_Body_Text\nstyle MaterialAlertDialog_MaterialComponents_Picker_Date_Calendar\nstyle MaterialAlertDialog_MaterialComponents_Picker_Date_Spinner\nstyle MaterialAlertDialog_MaterialComponents_Title_Icon\nstyle MaterialAlertDialog_MaterialComponents_Title_Icon_CenterStacked\nstyle MaterialAlertDialog_MaterialComponents_Title_Panel\nstyle MaterialAlertDialog_MaterialComponents_Title_Panel_CenterStacked\nstyle MaterialAlertDialog_MaterialComponents_Title_Text\nstyle MaterialAlertDialog_MaterialComponents_Title_Text_CenterStacked\nstyle Platform_AppCompat\nstyle Platform_AppCompat_Light\nstyle Platform_MaterialComponents\nstyle Platform_MaterialComponents_Dialog\nstyle Platform_MaterialComponents_Light\nstyle Platform_MaterialComponents_Light_Dialog\nstyle Platform_ThemeOverlay_AppCompat\nstyle Platform_ThemeOverlay_AppCompat_Dark\nstyle Platform_ThemeOverlay_AppCompat_Light\nstyle Platform_V21_AppCompat\nstyle Platform_V21_AppCompat_Light\nstyle Platform_V25_AppCompat\nstyle Platform_V25_AppCompat_Light\nstyle Platform_Widget_AppCompat_Spinner\nstyle RtlOverlay_DialogWindowTitle_AppCompat\nstyle RtlOverlay_Widget_AppCompat_ActionBar_TitleItem\nstyle RtlOverlay_Widget_AppCompat_DialogTitle_Icon\nstyle RtlOverlay_Widget_AppCompat_PopupMenuItem\nstyle RtlOverlay_Widget_AppCompat_PopupMenuItem_InternalGroup\nstyle RtlOverlay_Widget_AppCompat_PopupMenuItem_Shortcut\nstyle RtlOverlay_Widget_AppCompat_PopupMenuItem_SubmenuArrow\nstyle RtlOverlay_Widget_AppCompat_PopupMenuItem_Text\nstyle RtlOverlay_Widget_AppCompat_PopupMenuItem_Title\nstyle RtlOverlay_Widget_AppCompat_SearchView_MagIcon\nstyle RtlOverlay_Widget_AppCompat_Search_DropDown\nstyle RtlOverlay_Widget_AppCompat_Search_DropDown_Icon1\nstyle RtlOverlay_Widget_AppCompat_Search_DropDown_Icon2\nstyle RtlOverlay_Widget_AppCompat_Search_DropDown_Query\nstyle RtlOverlay_Widget_AppCompat_Search_DropDown_Text\nstyle RtlUnderlay_Widget_AppCompat_ActionButton\nstyle RtlUnderlay_Widget_AppCompat_ActionButton_Overflow\nstyle ShapeAppearanceOverlay\nstyle ShapeAppearanceOverlay_BottomLeftDifferentCornerSize\nstyle ShapeAppearanceOverlay_BottomRightCut\nstyle ShapeAppearanceOverlay_Cut\nstyle ShapeAppearanceOverlay_DifferentCornerSize\nstyle ShapeAppearanceOverlay_MaterialComponents_BottomSheet\nstyle ShapeAppearanceOverlay_MaterialComponents_Chip\nstyle ShapeAppearanceOverlay_MaterialComponents_ExtendedFloatingActionButton\nstyle ShapeAppearanceOverlay_MaterialComponents_FloatingActionButton\nstyle ShapeAppearanceOverlay_MaterialComponents_MaterialCalendar_Day\nstyle ShapeAppearanceOverlay_MaterialComponents_MaterialCalendar_Window_Fullscreen\nstyle ShapeAppearanceOverlay_MaterialComponents_MaterialCalendar_Year\nstyle ShapeAppearanceOverlay_MaterialComponents_TextInputLayout_FilledBox\nstyle ShapeAppearanceOverlay_TopLeftCut\nstyle ShapeAppearanceOverlay_TopRightDifferentCornerSize\nstyle ShapeAppearance_MaterialComponents\nstyle ShapeAppearance_MaterialComponents_LargeComponent\nstyle ShapeAppearance_MaterialComponents_MediumComponent\nstyle ShapeAppearance_MaterialComponents_SmallComponent\nstyle ShapeAppearance_MaterialComponents_Test\nstyle ShapeAppearance_MaterialComponents_Tooltip\nstyle TestStyleWithLineHeight\nstyle TestStyleWithLineHeightAppearance\nstyle TestStyleWithThemeLineHeightAttribute\nstyle TestStyleWithoutLineHeight\nstyle TestThemeWithLineHeight\nstyle TestThemeWithLineHeightDisabled\nstyle Test_ShapeAppearanceOverlay_MaterialComponents_MaterialCalendar_Day\nstyle Test_Theme_MaterialComponents_MaterialCalendar\nstyle Test_Widget_MaterialComponents_MaterialCalendar\nstyle Test_Widget_MaterialComponents_MaterialCalendar_Day\nstyle Test_Widget_MaterialComponents_MaterialCalendar_Day_Selected\nstyle TextAppearance_AppCompat\nstyle TextAppearance_AppCompat_Body1\nstyle TextAppearance_AppCompat_Body2\nstyle TextAppearance_AppCompat_Button\nstyle TextAppearance_AppCompat_Caption\nstyle TextAppearance_AppCompat_Display1\nstyle TextAppearance_AppCompat_Display2\nstyle TextAppearance_AppCompat_Display3\nstyle TextAppearance_AppCompat_Display4\nstyle TextAppearance_AppCompat_Headline\nstyle TextAppearance_AppCompat_Inverse\nstyle TextAppearance_AppCompat_Large\nstyle TextAppearance_AppCompat_Large_Inverse\nstyle TextAppearance_AppCompat_Light_SearchResult_Subtitle\nstyle TextAppearance_AppCompat_Light_SearchResult_Title\nstyle TextAppearance_AppCompat_Light_Widget_PopupMenu_Large\nstyle TextAppearance_AppCompat_Light_Widget_PopupMenu_Small\nstyle TextAppearance_AppCompat_Medium\nstyle TextAppearance_AppCompat_Medium_Inverse\nstyle TextAppearance_AppCompat_Menu\nstyle TextAppearance_AppCompat_SearchResult_Subtitle\nstyle TextAppearance_AppCompat_SearchResult_Title\nstyle TextAppearance_AppCompat_Small\nstyle TextAppearance_AppCompat_Small_Inverse\nstyle TextAppearance_AppCompat_Subhead\nstyle TextAppearance_AppCompat_Subhead_Inverse\nstyle TextAppearance_AppCompat_Title\nstyle TextAppearance_AppCompat_Title_Inverse\nstyle TextAppearance_AppCompat_Tooltip\nstyle TextAppearance_AppCompat_Widget_ActionBar_Menu\nstyle TextAppearance_AppCompat_Widget_ActionBar_Subtitle\nstyle TextAppearance_AppCompat_Widget_ActionBar_Subtitle_Inverse\nstyle TextAppearance_AppCompat_Widget_ActionBar_Title\nstyle TextAppearance_AppCompat_Widget_ActionBar_Title_Inverse\nstyle TextAppearance_AppCompat_Widget_ActionMode_Subtitle\nstyle TextAppearance_AppCompat_Widget_ActionMode_Subtitle_Inverse\nstyle TextAppearance_AppCompat_Widget_ActionMode_Title\nstyle TextAppearance_AppCompat_Widget_ActionMode_Title_Inverse\nstyle TextAppearance_AppCompat_Widget_Button\nstyle TextAppearance_AppCompat_Widget_Button_Borderless_Colored\nstyle TextAppearance_AppCompat_Widget_Button_Colored\nstyle TextAppearance_AppCompat_Widget_Button_Inverse\nstyle TextAppearance_AppCompat_Widget_DropDownItem\nstyle TextAppearance_AppCompat_Widget_PopupMenu_Header\nstyle TextAppearance_AppCompat_Widget_PopupMenu_Large\nstyle TextAppearance_AppCompat_Widget_PopupMenu_Small\nstyle TextAppearance_AppCompat_Widget_Switch\nstyle TextAppearance_AppCompat_Widget_TextView_SpinnerItem\nstyle TextAppearance_Compat_Notification\nstyle TextAppearance_Compat_Notification_Info\nstyle TextAppearance_Compat_Notification_Line2\nstyle TextAppearance_Compat_Notification_Time\nstyle TextAppearance_Compat_Notification_Title\nstyle TextAppearance_Design_CollapsingToolbar_Expanded\nstyle TextAppearance_Design_Counter\nstyle TextAppearance_Design_Counter_Overflow\nstyle TextAppearance_Design_Error\nstyle TextAppearance_Design_HelperText\nstyle TextAppearance_Design_Hint\nstyle TextAppearance_Design_Placeholder\nstyle TextAppearance_Design_Prefix\nstyle TextAppearance_Design_Snackbar_Message\nstyle TextAppearance_Design_Suffix\nstyle TextAppearance_Design_Tab\nstyle TextAppearance_MaterialComponents_Badge\nstyle TextAppearance_MaterialComponents_Body1\nstyle TextAppearance_MaterialComponents_Body2\nstyle TextAppearance_MaterialComponents_Button\nstyle TextAppearance_MaterialComponents_Caption\nstyle TextAppearance_MaterialComponents_Chip\nstyle TextAppearance_MaterialComponents_Headline1\nstyle TextAppearance_MaterialComponents_Headline2\nstyle TextAppearance_MaterialComponents_Headline3\nstyle TextAppearance_MaterialComponents_Headline4\nstyle TextAppearance_MaterialComponents_Headline5\nstyle TextAppearance_MaterialComponents_Headline6\nstyle TextAppearance_MaterialComponents_Overline\nstyle TextAppearance_MaterialComponents_Subtitle1\nstyle TextAppearance_MaterialComponents_Subtitle2\nstyle TextAppearance_MaterialComponents_TimePicker_Title\nstyle TextAppearance_MaterialComponents_Tooltip\nstyle TextAppearance_Widget_AppCompat_ExpandedMenu_Item\nstyle TextAppearance_Widget_AppCompat_Toolbar_Subtitle\nstyle TextAppearance_Widget_AppCompat_Toolbar_Title\nstyle ThemeOverlayColorAccentRed\nstyle ThemeOverlay_AppCompat\nstyle ThemeOverlay_AppCompat_ActionBar\nstyle ThemeOverlay_AppCompat_Dark\nstyle ThemeOverlay_AppCompat_Dark_ActionBar\nstyle ThemeOverlay_AppCompat_DayNight\nstyle ThemeOverlay_AppCompat_DayNight_ActionBar\nstyle ThemeOverlay_AppCompat_Dialog\nstyle ThemeOverlay_AppCompat_Dialog_Alert\nstyle ThemeOverlay_AppCompat_Light\nstyle ThemeOverlay_Design_TextInputEditText\nstyle ThemeOverlay_MaterialComponents\nstyle ThemeOverlay_MaterialComponents_ActionBar\nstyle ThemeOverlay_MaterialComponents_ActionBar_Primary\nstyle ThemeOverlay_MaterialComponents_ActionBar_Surface\nstyle ThemeOverlay_MaterialComponents_AutoCompleteTextView\nstyle ThemeOverlay_MaterialComponents_AutoCompleteTextView_FilledBox\nstyle ThemeOverlay_MaterialComponents_AutoCompleteTextView_FilledBox_Dense\nstyle ThemeOverlay_MaterialComponents_AutoCompleteTextView_OutlinedBox\nstyle ThemeOverlay_MaterialComponents_AutoCompleteTextView_OutlinedBox_Dense\nstyle ThemeOverlay_MaterialComponents_BottomAppBar_Primary\nstyle ThemeOverlay_MaterialComponents_BottomAppBar_Surface\nstyle ThemeOverlay_MaterialComponents_BottomSheetDialog\nstyle ThemeOverlay_MaterialComponents_Dark\nstyle ThemeOverlay_MaterialComponents_Dark_ActionBar\nstyle ThemeOverlay_MaterialComponents_DayNight_BottomSheetDialog\nstyle ThemeOverlay_MaterialComponents_Dialog\nstyle ThemeOverlay_MaterialComponents_Dialog_Alert\nstyle ThemeOverlay_MaterialComponents_Dialog_Alert_Framework\nstyle ThemeOverlay_MaterialComponents_Light\nstyle ThemeOverlay_MaterialComponents_Light_BottomSheetDialog\nstyle ThemeOverlay_MaterialComponents_Light_Dialog_Alert_Framework\nstyle ThemeOverlay_MaterialComponents_MaterialAlertDialog\nstyle ThemeOverlay_MaterialComponents_MaterialAlertDialog_Centered\nstyle ThemeOverlay_MaterialComponents_MaterialAlertDialog_Picker_Date\nstyle ThemeOverlay_MaterialComponents_MaterialAlertDialog_Picker_Date_Calendar\nstyle ThemeOverlay_MaterialComponents_MaterialAlertDialog_Picker_Date_Header_Text\nstyle ThemeOverlay_MaterialComponents_MaterialAlertDialog_Picker_Date_Header_Text_Day\nstyle ThemeOverlay_MaterialComponents_MaterialAlertDialog_Picker_Date_Spinner\nstyle ThemeOverlay_MaterialComponents_MaterialCalendar\nstyle ThemeOverlay_MaterialComponents_MaterialCalendar_Fullscreen\nstyle ThemeOverlay_MaterialComponents_TextInputEditText\nstyle ThemeOverlay_MaterialComponents_TextInputEditText_FilledBox\nstyle ThemeOverlay_MaterialComponents_TextInputEditText_FilledBox_Dense\nstyle ThemeOverlay_MaterialComponents_TextInputEditText_OutlinedBox\nstyle ThemeOverlay_MaterialComponents_TextInputEditText_OutlinedBox_Dense\nstyle ThemeOverlay_MaterialComponents_TimePicker\nstyle ThemeOverlay_MaterialComponents_TimePicker_Display\nstyle ThemeOverlay_MaterialComponents_Toolbar_Primary\nstyle ThemeOverlay_MaterialComponents_Toolbar_Surface\nstyle Theme_AppCompat\nstyle Theme_AppCompat_CompactMenu\nstyle Theme_AppCompat_DayNight\nstyle Theme_AppCompat_DayNight_DarkActionBar\nstyle Theme_AppCompat_DayNight_Dialog\nstyle Theme_AppCompat_DayNight_DialogWhenLarge\nstyle Theme_AppCompat_DayNight_Dialog_Alert\nstyle Theme_AppCompat_DayNight_Dialog_MinWidth\nstyle Theme_AppCompat_DayNight_NoActionBar\nstyle Theme_AppCompat_Dialog\nstyle Theme_AppCompat_DialogWhenLarge\nstyle Theme_AppCompat_Dialog_Alert\nstyle Theme_AppCompat_Dialog_MinWidth\nstyle Theme_AppCompat_Empty\nstyle Theme_AppCompat_Light\nstyle Theme_AppCompat_Light_DarkActionBar\nstyle Theme_AppCompat_Light_Dialog\nstyle Theme_AppCompat_Light_DialogWhenLarge\nstyle Theme_AppCompat_Light_Dialog_Alert\nstyle Theme_AppCompat_Light_Dialog_MinWidth\nstyle Theme_AppCompat_Light_NoActionBar\nstyle Theme_AppCompat_NoActionBar\nstyle Theme_Design\nstyle Theme_Design_BottomSheetDialog\nstyle Theme_Design_Light\nstyle Theme_Design_Light_BottomSheetDialog\nstyle Theme_Design_Light_NoActionBar\nstyle Theme_Design_NoActionBar\nstyle Theme_MaterialComponents\nstyle Theme_MaterialComponents_BottomSheetDialog\nstyle Theme_MaterialComponents_Bridge\nstyle Theme_MaterialComponents_CompactMenu\nstyle Theme_MaterialComponents_DayNight\nstyle Theme_MaterialComponents_DayNight_BottomSheetDialog\nstyle Theme_MaterialComponents_DayNight_Bridge\nstyle Theme_MaterialComponents_DayNight_DarkActionBar\nstyle Theme_MaterialComponents_DayNight_DarkActionBar_Bridge\nstyle Theme_MaterialComponents_DayNight_Dialog\nstyle Theme_MaterialComponents_DayNight_DialogWhenLarge\nstyle Theme_MaterialComponents_DayNight_Dialog_Alert\nstyle Theme_MaterialComponents_DayNight_Dialog_Alert_Bridge\nstyle Theme_MaterialComponents_DayNight_Dialog_Bridge\nstyle Theme_MaterialComponents_DayNight_Dialog_FixedSize\nstyle Theme_MaterialComponents_DayNight_Dialog_FixedSize_Bridge\nstyle Theme_MaterialComponents_DayNight_Dialog_MinWidth\nstyle Theme_MaterialComponents_DayNight_Dialog_MinWidth_Bridge\nstyle Theme_MaterialComponents_DayNight_NoActionBar\nstyle Theme_MaterialComponents_DayNight_NoActionBar_Bridge\nstyle Theme_MaterialComponents_Dialog\nstyle Theme_MaterialComponents_DialogWhenLarge\nstyle Theme_MaterialComponents_Dialog_Alert\nstyle Theme_MaterialComponents_Dialog_Alert_Bridge\nstyle Theme_MaterialComponents_Dialog_Bridge\nstyle Theme_MaterialComponents_Dialog_FixedSize\nstyle Theme_MaterialComponents_Dialog_FixedSize_Bridge\nstyle Theme_MaterialComponents_Dialog_MinWidth\nstyle Theme_MaterialComponents_Dialog_MinWidth_Bridge\nstyle Theme_MaterialComponents_Light\nstyle Theme_MaterialComponents_Light_BarSize\nstyle Theme_MaterialComponents_Light_BottomSheetDialog\nstyle Theme_MaterialComponents_Light_Bridge\nstyle Theme_MaterialComponents_Light_DarkActionBar\nstyle Theme_MaterialComponents_Light_DarkActionBar_Bridge\nstyle Theme_MaterialComponents_Light_Dialog\nstyle Theme_MaterialComponents_Light_DialogWhenLarge\nstyle Theme_MaterialComponents_Light_Dialog_Alert\nstyle Theme_MaterialComponents_Light_Dialog_Alert_Bridge\nstyle Theme_MaterialComponents_Light_Dialog_Bridge\nstyle Theme_MaterialComponents_Light_Dialog_FixedSize\nstyle Theme_MaterialComponents_Light_Dialog_FixedSize_Bridge\nstyle Theme_MaterialComponents_Light_Dialog_MinWidth\nstyle Theme_MaterialComponents_Light_Dialog_MinWidth_Bridge\nstyle Theme_MaterialComponents_Light_LargeTouch\nstyle Theme_MaterialComponents_Light_NoActionBar\nstyle Theme_MaterialComponents_Light_NoActionBar_Bridge\nstyle Theme_MaterialComponents_NoActionBar\nstyle Theme_MaterialComponents_NoActionBar_Bridge\nstyle Widget_AppCompat_ActionBar\nstyle Widget_AppCompat_ActionBar_Solid\nstyle Widget_AppCompat_ActionBar_TabBar\nstyle Widget_AppCompat_ActionBar_TabText\nstyle Widget_AppCompat_ActionBar_TabView\nstyle Widget_AppCompat_ActionButton\nstyle Widget_AppCompat_ActionButton_CloseMode\nstyle Widget_AppCompat_ActionButton_Overflow\nstyle Widget_AppCompat_ActionMode\nstyle Widget_AppCompat_ActivityChooserView\nstyle Widget_AppCompat_AutoCompleteTextView\nstyle Widget_AppCompat_Button\nstyle Widget_AppCompat_ButtonBar\nstyle Widget_AppCompat_ButtonBar_AlertDialog\nstyle Widget_AppCompat_Button_Borderless\nstyle Widget_AppCompat_Button_Borderless_Colored\nstyle Widget_AppCompat_Button_ButtonBar_AlertDialog\nstyle Widget_AppCompat_Button_Colored\nstyle Widget_AppCompat_Button_Small\nstyle Widget_AppCompat_CompoundButton_CheckBox\nstyle Widget_AppCompat_CompoundButton_RadioButton\nstyle Widget_AppCompat_CompoundButton_Switch\nstyle Widget_AppCompat_DrawerArrowToggle\nstyle Widget_AppCompat_DropDownItem_Spinner\nstyle Widget_AppCompat_EditText\nstyle Widget_AppCompat_ImageButton\nstyle Widget_AppCompat_Light_ActionBar\nstyle Widget_AppCompat_Light_ActionBar_Solid\nstyle Widget_AppCompat_Light_ActionBar_Solid_Inverse\nstyle Widget_AppCompat_Light_ActionBar_TabBar\nstyle Widget_AppCompat_Light_ActionBar_TabBar_Inverse\nstyle Widget_AppCompat_Light_ActionBar_TabText\nstyle Widget_AppCompat_Light_ActionBar_TabText_Inverse\nstyle Widget_AppCompat_Light_ActionBar_TabView\nstyle Widget_AppCompat_Light_ActionBar_TabView_Inverse\nstyle Widget_AppCompat_Light_ActionButton\nstyle Widget_AppCompat_Light_ActionButton_CloseMode\nstyle Widget_AppCompat_Light_ActionButton_Overflow\nstyle Widget_AppCompat_Light_ActionMode_Inverse\nstyle Widget_AppCompat_Light_ActivityChooserView\nstyle Widget_AppCompat_Light_AutoCompleteTextView\nstyle Widget_AppCompat_Light_DropDownItem_Spinner\nstyle Widget_AppCompat_Light_ListPopupWindow\nstyle Widget_AppCompat_Light_ListView_DropDown\nstyle Widget_AppCompat_Light_PopupMenu\nstyle Widget_AppCompat_Light_PopupMenu_Overflow\nstyle Widget_AppCompat_Light_SearchView\nstyle Widget_AppCompat_Light_Spinner_DropDown_ActionBar\nstyle Widget_AppCompat_ListMenuView\nstyle Widget_AppCompat_ListPopupWindow\nstyle Widget_AppCompat_ListView\nstyle Widget_AppCompat_ListView_DropDown\nstyle Widget_AppCompat_ListView_Menu\nstyle Widget_AppCompat_PopupMenu\nstyle Widget_AppCompat_PopupMenu_Overflow\nstyle Widget_AppCompat_PopupWindow\nstyle Widget_AppCompat_ProgressBar\nstyle Widget_AppCompat_ProgressBar_Horizontal\nstyle Widget_AppCompat_RatingBar\nstyle Widget_AppCompat_RatingBar_Indicator\nstyle Widget_AppCompat_RatingBar_Small\nstyle Widget_AppCompat_SearchView\nstyle Widget_AppCompat_SearchView_ActionBar\nstyle Widget_AppCompat_SeekBar\nstyle Widget_AppCompat_SeekBar_Discrete\nstyle Widget_AppCompat_Spinner\nstyle Widget_AppCompat_Spinner_DropDown\nstyle Widget_AppCompat_Spinner_DropDown_ActionBar\nstyle Widget_AppCompat_Spinner_Underlined\nstyle Widget_AppCompat_TextView\nstyle Widget_AppCompat_TextView_SpinnerItem\nstyle Widget_AppCompat_Toolbar\nstyle Widget_AppCompat_Toolbar_Button_Navigation\nstyle Widget_Compat_NotificationActionContainer\nstyle Widget_Compat_NotificationActionText\nstyle Widget_Design_AppBarLayout\nstyle Widget_Design_BottomNavigationView\nstyle Widget_Design_BottomSheet_Modal\nstyle Widget_Design_CollapsingToolbar\nstyle Widget_Design_FloatingActionButton\nstyle Widget_Design_NavigationView\nstyle Widget_Design_ScrimInsetsFrameLayout\nstyle Widget_Design_Snackbar\nstyle Widget_Design_TabLayout\nstyle Widget_Design_TextInputEditText\nstyle Widget_Design_TextInputLayout\nstyle Widget_MaterialComponents_ActionBar_Primary\nstyle Widget_MaterialComponents_ActionBar_PrimarySurface\nstyle Widget_MaterialComponents_ActionBar_Solid\nstyle Widget_MaterialComponents_ActionBar_Surface\nstyle Widget_MaterialComponents_AppBarLayout_Primary\nstyle Widget_MaterialComponents_AppBarLayout_PrimarySurface\nstyle Widget_MaterialComponents_AppBarLayout_Surface\nstyle Widget_MaterialComponents_AutoCompleteTextView_FilledBox\nstyle Widget_MaterialComponents_AutoCompleteTextView_FilledBox_Dense\nstyle Widget_MaterialComponents_AutoCompleteTextView_OutlinedBox\nstyle Widget_MaterialComponents_AutoCompleteTextView_OutlinedBox_Dense\nstyle Widget_MaterialComponents_Badge\nstyle Widget_MaterialComponents_BottomAppBar\nstyle Widget_MaterialComponents_BottomAppBar_Colored\nstyle Widget_MaterialComponents_BottomAppBar_PrimarySurface\nstyle Widget_MaterialComponents_BottomNavigationView\nstyle Widget_MaterialComponents_BottomNavigationView_Colored\nstyle Widget_MaterialComponents_BottomNavigationView_PrimarySurface\nstyle Widget_MaterialComponents_BottomSheet\nstyle Widget_MaterialComponents_BottomSheet_Modal\nstyle Widget_MaterialComponents_Button\nstyle Widget_MaterialComponents_Button_Icon\nstyle Widget_MaterialComponents_Button_OutlinedButton\nstyle Widget_MaterialComponents_Button_OutlinedButton_Icon\nstyle Widget_MaterialComponents_Button_TextButton\nstyle Widget_MaterialComponents_Button_TextButton_Dialog\nstyle Widget_MaterialComponents_Button_TextButton_Dialog_Flush\nstyle Widget_MaterialComponents_Button_TextButton_Dialog_Icon\nstyle Widget_MaterialComponents_Button_TextButton_Icon\nstyle Widget_MaterialComponents_Button_TextButton_Snackbar\nstyle Widget_MaterialComponents_Button_UnelevatedButton\nstyle Widget_MaterialComponents_Button_UnelevatedButton_Icon\nstyle Widget_MaterialComponents_CardView\nstyle Widget_MaterialComponents_CheckedTextView\nstyle Widget_MaterialComponents_ChipGroup\nstyle Widget_MaterialComponents_Chip_Action\nstyle Widget_MaterialComponents_Chip_Choice\nstyle Widget_MaterialComponents_Chip_Entry\nstyle Widget_MaterialComponents_Chip_Filter\nstyle Widget_MaterialComponents_CircularProgressIndicator\nstyle Widget_MaterialComponents_CircularProgressIndicator_ExtraSmall\nstyle Widget_MaterialComponents_CircularProgressIndicator_Medium\nstyle Widget_MaterialComponents_CircularProgressIndicator_Small\nstyle Widget_MaterialComponents_CollapsingToolbar\nstyle Widget_MaterialComponents_CompoundButton_CheckBox\nstyle Widget_MaterialComponents_CompoundButton_RadioButton\nstyle Widget_MaterialComponents_CompoundButton_Switch\nstyle Widget_MaterialComponents_ExtendedFloatingActionButton\nstyle Widget_MaterialComponents_ExtendedFloatingActionButton_Icon\nstyle Widget_MaterialComponents_FloatingActionButton\nstyle Widget_MaterialComponents_Light_ActionBar_Solid\nstyle Widget_MaterialComponents_LinearProgressIndicator\nstyle Widget_MaterialComponents_MaterialButtonToggleGroup\nstyle Widget_MaterialComponents_MaterialCalendar\nstyle Widget_MaterialComponents_MaterialCalendar_Day\nstyle Widget_MaterialComponents_MaterialCalendar_DayTextView\nstyle Widget_MaterialComponents_MaterialCalendar_Day_Invalid\nstyle Widget_MaterialComponents_MaterialCalendar_Day_Selected\nstyle Widget_MaterialComponents_MaterialCalendar_Day_Today\nstyle Widget_MaterialComponents_MaterialCalendar_Fullscreen\nstyle Widget_MaterialComponents_MaterialCalendar_HeaderCancelButton\nstyle Widget_MaterialComponents_MaterialCalendar_HeaderConfirmButton\nstyle Widget_MaterialComponents_MaterialCalendar_HeaderDivider\nstyle Widget_MaterialComponents_MaterialCalendar_HeaderLayout\nstyle Widget_MaterialComponents_MaterialCalendar_HeaderSelection\nstyle Widget_MaterialComponents_MaterialCalendar_HeaderSelection_Fullscreen\nstyle Widget_MaterialComponents_MaterialCalendar_HeaderTitle\nstyle Widget_MaterialComponents_MaterialCalendar_HeaderToggleButton\nstyle Widget_MaterialComponents_MaterialCalendar_Item\nstyle Widget_MaterialComponents_MaterialCalendar_MonthNavigationButton\nstyle Widget_MaterialComponents_MaterialCalendar_MonthTextView\nstyle Widget_MaterialComponents_MaterialCalendar_Year\nstyle Widget_MaterialComponents_MaterialCalendar_YearNavigationButton\nstyle Widget_MaterialComponents_MaterialCalendar_Year_Selected\nstyle Widget_MaterialComponents_MaterialCalendar_Year_Today\nstyle Widget_MaterialComponents_NavigationView\nstyle Widget_MaterialComponents_PopupMenu\nstyle Widget_MaterialComponents_PopupMenu_ContextMenu\nstyle Widget_MaterialComponents_PopupMenu_ListPopupWindow\nstyle Widget_MaterialComponents_PopupMenu_Overflow\nstyle Widget_MaterialComponents_ProgressIndicator\nstyle Widget_MaterialComponents_ShapeableImageView\nstyle Widget_MaterialComponents_Slider\nstyle Widget_MaterialComponents_Snackbar\nstyle Widget_MaterialComponents_Snackbar_FullWidth\nstyle Widget_MaterialComponents_Snackbar_TextView\nstyle Widget_MaterialComponents_TabLayout\nstyle Widget_MaterialComponents_TabLayout_Colored\nstyle Widget_MaterialComponents_TabLayout_PrimarySurface\nstyle Widget_MaterialComponents_TextInputEditText_FilledBox\nstyle Widget_MaterialComponents_TextInputEditText_FilledBox_Dense\nstyle Widget_MaterialComponents_TextInputEditText_OutlinedBox\nstyle Widget_MaterialComponents_TextInputEditText_OutlinedBox_Dense\nstyle Widget_MaterialComponents_TextInputLayout_FilledBox\nstyle Widget_MaterialComponents_TextInputLayout_FilledBox_Dense\nstyle Widget_MaterialComponents_TextInputLayout_FilledBox_Dense_ExposedDropdownMenu\nstyle Widget_MaterialComponents_TextInputLayout_FilledBox_ExposedDropdownMenu\nstyle Widget_MaterialComponents_TextInputLayout_OutlinedBox\nstyle Widget_MaterialComponents_TextInputLayout_OutlinedBox_Dense\nstyle Widget_MaterialComponents_TextInputLayout_OutlinedBox_Dense_ExposedDropdownMenu\nstyle Widget_MaterialComponents_TextInputLayout_OutlinedBox_ExposedDropdownMenu\nstyle Widget_MaterialComponents_TextView\nstyle Widget_MaterialComponents_TimePicker\nstyle Widget_MaterialComponents_TimePicker_Button\nstyle Widget_MaterialComponents_TimePicker_Clock\nstyle Widget_MaterialComponents_TimePicker_Display\nstyle Widget_MaterialComponents_TimePicker_Display_TextInputEditText\nstyle Widget_MaterialComponents_TimePicker_ImageButton\nstyle Widget_MaterialComponents_TimePicker_ImageButton_ShapeAppearance\nstyle Widget_MaterialComponents_Toolbar\nstyle Widget_MaterialComponents_Toolbar_Primary\nstyle Widget_MaterialComponents_Toolbar_PrimarySurface\nstyle Widget_MaterialComponents_Toolbar_Surface\nstyle Widget_MaterialComponents_Tooltip\nstyle Widget_Support_CoordinatorLayout\nstyleable ActionBar background backgroundSplit backgroundStacked contentInsetEnd contentInsetEndWithActions contentInsetLeft contentInsetRight contentInsetStart contentInsetStartWithNavigation customNavigationLayout displayOptions divider elevation height hideOnContentScroll homeAsUpIndicator homeLayout icon indeterminateProgressStyle itemPadding logo navigationMode popupTheme progressBarPadding progressBarStyle subtitle subtitleTextStyle title titleTextStyle\nstyleable ActionBarLayout android_layout_gravity\nstyleable ActionMenuItemView android_minWidth\nstyleable ActionMenuView\nstyleable ActionMode background backgroundSplit closeItemLayout height subtitleTextStyle titleTextStyle\nstyleable ActivityChooserView expandActivityOverflowButtonDrawable initialActivityCount\nstyleable AlertDialog android_layout buttonIconDimen buttonPanelSideLayout listItemLayout listLayout multiChoiceItemLayout showTitle singleChoiceItemLayout\nstyleable AnimatedStateListDrawableCompat android_constantSize android_dither android_enterFadeDuration android_exitFadeDuration android_variablePadding android_visible\nstyleable AnimatedStateListDrawableItem android_drawable android_id\nstyleable AnimatedStateListDrawableTransition android_drawable android_fromId android_reversible android_toId\nstyleable AppBarLayout android_background android_keyboardNavigationCluster android_touchscreenBlocksFocus elevation expanded liftOnScroll liftOnScrollTargetViewId statusBarForeground\nstyleable AppBarLayoutStates state_collapsed state_collapsible state_liftable state_lifted\nstyleable AppBarLayout_Layout layout_scrollFlags layout_scrollInterpolator\nstyleable AppCompatImageView android_src srcCompat tint tintMode\nstyleable AppCompatSeekBar android_thumb tickMark tickMarkTint tickMarkTintMode\nstyleable AppCompatTextHelper android_drawableBottom android_drawableEnd android_drawableLeft android_drawableRight android_drawableStart android_drawableTop android_textAppearance\nstyleable AppCompatTextView android_textAppearance autoSizeMaxTextSize autoSizeMinTextSize autoSizePresetSizes autoSizeStepGranularity autoSizeTextType drawableBottomCompat drawableEndCompat drawableLeftCompat drawableRightCompat drawableStartCompat drawableTint drawableTintMode drawableTopCompat firstBaselineToTopHeight fontFamily fontVariationSettings lastBaselineToBottomHeight lineHeight textAllCaps textLocale\nstyleable AppCompatTheme actionBarDivider actionBarItemBackground actionBarPopupTheme actionBarSize actionBarSplitStyle actionBarStyle actionBarTabBarStyle actionBarTabStyle actionBarTabTextStyle actionBarTheme actionBarWidgetTheme actionButtonStyle actionDropDownStyle actionMenuTextAppearance actionMenuTextColor actionModeBackground actionModeCloseButtonStyle actionModeCloseDrawable actionModeCopyDrawable actionModeCutDrawable actionModeFindDrawable actionModePasteDrawable actionModePopupWindowStyle actionModeSelectAllDrawable actionModeShareDrawable actionModeSplitBackground actionModeStyle actionModeWebSearchDrawable actionOverflowButtonStyle actionOverflowMenuStyle activityChooserViewStyle alertDialogButtonGroupStyle alertDialogCenterButtons alertDialogStyle alertDialogTheme android_windowAnimationStyle android_windowIsFloating autoCompleteTextViewStyle borderlessButtonStyle buttonBarButtonStyle buttonBarNegativeButtonStyle buttonBarNeutralButtonStyle buttonBarPositiveButtonStyle buttonBarStyle buttonStyle buttonStyleSmall checkboxStyle checkedTextViewStyle colorAccent colorBackgroundFloating colorButtonNormal colorControlActivated colorControlHighlight colorControlNormal colorError colorPrimary colorPrimaryDark colorSwitchThumbNormal controlBackground dialogCornerRadius dialogPreferredPadding dialogTheme dividerHorizontal dividerVertical dropDownListViewStyle dropdownListPreferredItemHeight editTextBackground editTextColor editTextStyle homeAsUpIndicator imageButtonStyle listChoiceBackgroundIndicator listChoiceIndicatorMultipleAnimated listChoiceIndicatorSingleAnimated listDividerAlertDialog listMenuViewStyle listPopupWindowStyle listPreferredItemHeight listPreferredItemHeightLarge listPreferredItemHeightSmall listPreferredItemPaddingEnd listPreferredItemPaddingLeft listPreferredItemPaddingRight listPreferredItemPaddingStart panelBackground panelMenuListTheme panelMenuListWidth popupMenuStyle popupWindowStyle radioButtonStyle ratingBarStyle ratingBarStyleIndicator ratingBarStyleSmall searchViewStyle seekBarStyle selectableItemBackground selectableItemBackgroundBorderless spinnerDropDownItemStyle spinnerStyle switchStyle textAppearanceLargePopupMenu textAppearanceListItem textAppearanceListItemSecondary textAppearanceListItemSmall textAppearancePopupMenuHeader textAppearanceSearchResultSubtitle textAppearanceSearchResultTitle textAppearanceSmallPopupMenu textColorAlertDialogListItem textColorSearchUrl toolbarNavigationButtonStyle toolbarStyle tooltipForegroundColor tooltipFrameBackground viewInflaterClass windowActionBar windowActionBarOverlay windowActionModeOverlay windowFixedHeightMajor windowFixedHeightMinor windowFixedWidthMajor windowFixedWidthMinor windowMinWidthMajor windowMinWidthMinor windowNoTitle\nstyleable Badge backgroundColor badgeGravity badgeTextColor horizontalOffset maxCharacterCount number verticalOffset\nstyleable BaseProgressIndicator android_indeterminate hideAnimationBehavior indicatorColor minHideDelay showAnimationBehavior showDelay trackColor trackCornerRadius trackThickness\nstyleable BottomAppBar backgroundTint elevation fabAlignmentMode fabAnimationMode fabCradleMargin fabCradleRoundedCornerRadius fabCradleVerticalOffset hideOnScroll paddingBottomSystemWindowInsets paddingLeftSystemWindowInsets paddingRightSystemWindowInsets\nstyleable BottomNavigationView backgroundTint elevation itemBackground itemHorizontalTranslationEnabled itemIconSize itemIconTint itemRippleColor itemTextAppearanceActive itemTextAppearanceInactive itemTextColor labelVisibilityMode menu\nstyleable BottomSheetBehavior_Layout android_elevation backgroundTint behavior_draggable behavior_expandedOffset behavior_fitToContents behavior_halfExpandedRatio behavior_hideable behavior_peekHeight behavior_saveFlags behavior_skipCollapsed gestureInsetBottomIgnored shapeAppearance shapeAppearanceOverlay\nstyleable ButtonBarLayout allowStacking\nstyleable CardView android_minHeight android_minWidth cardBackgroundColor cardCornerRadius cardElevation cardMaxElevation cardPreventCornerOverlap cardUseCompatPadding contentPadding contentPaddingBottom contentPaddingLeft contentPaddingRight contentPaddingTop\nstyleable Chip android_checkable android_ellipsize android_maxWidth android_text android_textAppearance android_textColor android_textSize checkedIcon checkedIconEnabled checkedIconTint checkedIconVisible chipBackgroundColor chipCornerRadius chipEndPadding chipIcon chipIconEnabled chipIconSize chipIconTint chipIconVisible chipMinHeight chipMinTouchTargetSize chipStartPadding chipStrokeColor chipStrokeWidth chipSurfaceColor closeIcon closeIconEnabled closeIconEndPadding closeIconSize closeIconStartPadding closeIconTint closeIconVisible ensureMinTouchTargetSize hideMotionSpec iconEndPadding iconStartPadding rippleColor shapeAppearance shapeAppearanceOverlay showMotionSpec textEndPadding textStartPadding\nstyleable ChipGroup checkedChip chipSpacing chipSpacingHorizontal chipSpacingVertical selectionRequired singleLine singleSelection\nstyleable CircularProgressIndicator indicatorDirectionCircular indicatorInset indicatorSize\nstyleable ClockFaceView clockFaceBackgroundColor clockNumberTextColor\nstyleable ClockHandView clockHandColor materialCircleRadius selectorSize\nstyleable CollapsingToolbarLayout collapsedTitleGravity collapsedTitleTextAppearance contentScrim expandedTitleGravity expandedTitleMargin expandedTitleMarginBottom expandedTitleMarginEnd expandedTitleMarginStart expandedTitleMarginTop expandedTitleTextAppearance maxLines scrimAnimationDuration scrimVisibleHeightTrigger statusBarScrim title titleEnabled toolbarId\nstyleable CollapsingToolbarLayout_Layout layout_collapseMode layout_collapseParallaxMultiplier\nstyleable ColorStateListItem alpha android_alpha android_color\nstyleable CompoundButton android_button buttonCompat buttonTint buttonTintMode\nstyleable Constraint android_alpha android_elevation android_id android_layout_height android_layout_marginBottom android_layout_marginEnd android_layout_marginLeft android_layout_marginRight android_layout_marginStart android_layout_marginTop android_layout_width android_maxHeight android_maxWidth android_minHeight android_minWidth android_orientation android_rotation android_rotationX android_rotationY android_scaleX android_scaleY android_transformPivotX android_transformPivotY android_translationX android_translationY android_translationZ android_visibility animate_relativeTo barrierAllowsGoneWidgets barrierDirection barrierMargin chainUseRtl constraint_referenced_ids drawPath flow_firstHorizontalBias flow_firstHorizontalStyle flow_firstVerticalBias flow_firstVerticalStyle flow_horizontalAlign flow_horizontalBias flow_horizontalGap flow_horizontalStyle flow_lastHorizontalBias flow_lastHorizontalStyle flow_lastVerticalBias flow_lastVerticalStyle flow_maxElementsWrap flow_verticalAlign flow_verticalBias flow_verticalGap flow_verticalStyle flow_wrapMode layout_constrainedHeight layout_constrainedWidth layout_constraintBaseline_creator layout_constraintBaseline_toBaselineOf layout_constraintBottom_creator layout_constraintBottom_toBottomOf layout_constraintBottom_toTopOf layout_constraintCircle layout_constraintCircleAngle layout_constraintCircleRadius layout_constraintDimensionRatio layout_constraintEnd_toEndOf layout_constraintEnd_toStartOf layout_constraintGuide_begin layout_constraintGuide_end layout_constraintGuide_percent layout_constraintHeight_default layout_constraintHeight_max layout_constraintHeight_min layout_constraintHeight_percent layout_constraintHorizontal_bias layout_constraintHorizontal_chainStyle layout_constraintHorizontal_weight layout_constraintLeft_creator layout_constraintLeft_toLeftOf layout_constraintLeft_toRightOf layout_constraintRight_creator layout_constraintRight_toLeftOf layout_constraintRight_toRightOf layout_constraintStart_toEndOf layout_constraintStart_toStartOf layout_constraintTag layout_constraintTop_creator layout_constraintTop_toBottomOf layout_constraintTop_toTopOf layout_constraintVertical_bias layout_constraintVertical_chainStyle layout_constraintVertical_weight layout_constraintWidth_default layout_constraintWidth_max layout_constraintWidth_min layout_constraintWidth_percent layout_editor_absoluteX layout_editor_absoluteY layout_goneMarginBottom layout_goneMarginEnd layout_goneMarginLeft layout_goneMarginRight layout_goneMarginStart layout_goneMarginTop motionProgress motionStagger pathMotionArc pivotAnchor transitionEasing transitionPathRotate visibilityMode\nstyleable ConstraintLayout_Layout android_elevation android_maxHeight android_maxWidth android_minHeight android_minWidth android_orientation android_padding android_paddingBottom android_paddingEnd android_paddingLeft android_paddingRight android_paddingStart android_paddingTop android_visibility barrierAllowsGoneWidgets barrierDirection barrierMargin chainUseRtl constraintSet constraint_referenced_ids flow_firstHorizontalBias flow_firstHorizontalStyle flow_firstVerticalBias flow_firstVerticalStyle flow_horizontalAlign flow_horizontalBias flow_horizontalGap flow_horizontalStyle flow_lastHorizontalBias flow_lastHorizontalStyle flow_lastVerticalBias flow_lastVerticalStyle flow_maxElementsWrap flow_verticalAlign flow_verticalBias flow_verticalGap flow_verticalStyle flow_wrapMode layoutDescription layout_constrainedHeight layout_constrainedWidth layout_constraintBaseline_creator layout_constraintBaseline_toBaselineOf layout_constraintBottom_creator layout_constraintBottom_toBottomOf layout_constraintBottom_toTopOf layout_constraintCircle layout_constraintCircleAngle layout_constraintCircleRadius layout_constraintDimensionRatio layout_constraintEnd_toEndOf layout_constraintEnd_toStartOf layout_constraintGuide_begin layout_constraintGuide_end layout_constraintGuide_percent layout_constraintHeight_default layout_constraintHeight_max layout_constraintHeight_min layout_constraintHeight_percent layout_constraintHorizontal_bias layout_constraintHorizontal_chainStyle layout_constraintHorizontal_weight layout_constraintLeft_creator layout_constraintLeft_toLeftOf layout_constraintLeft_toRightOf layout_constraintRight_creator layout_constraintRight_toLeftOf layout_constraintRight_toRightOf layout_constraintStart_toEndOf layout_constraintStart_toStartOf layout_constraintTag layout_constraintTop_creator layout_constraintTop_toBottomOf layout_constraintTop_toTopOf layout_constraintVertical_bias layout_constraintVertical_chainStyle layout_constraintVertical_weight layout_constraintWidth_default layout_constraintWidth_max layout_constraintWidth_min layout_constraintWidth_percent layout_editor_absoluteX layout_editor_absoluteY layout_goneMarginBottom layout_goneMarginEnd layout_goneMarginLeft layout_goneMarginRight layout_goneMarginStart layout_goneMarginTop layout_optimizationLevel\nstyleable ConstraintLayout_placeholder content placeholder_emptyVisibility\nstyleable ConstraintSet android_alpha android_elevation android_id android_layout_height android_layout_marginBottom android_layout_marginEnd android_layout_marginLeft android_layout_marginRight android_layout_marginStart android_layout_marginTop android_layout_width android_maxHeight android_maxWidth android_minHeight android_minWidth android_orientation android_pivotX android_pivotY android_rotation android_rotationX android_rotationY android_scaleX android_scaleY android_transformPivotX android_transformPivotY android_translationX android_translationY android_translationZ android_visibility animate_relativeTo barrierAllowsGoneWidgets barrierDirection barrierMargin chainUseRtl constraint_referenced_ids deriveConstraintsFrom drawPath flow_firstHorizontalBias flow_firstHorizontalStyle flow_firstVerticalBias flow_firstVerticalStyle flow_horizontalAlign flow_horizontalBias flow_horizontalGap flow_horizontalStyle flow_lastHorizontalBias flow_lastHorizontalStyle flow_lastVerticalBias flow_lastVerticalStyle flow_maxElementsWrap flow_verticalAlign flow_verticalBias flow_verticalGap flow_verticalStyle flow_wrapMode layout_constrainedHeight layout_constrainedWidth layout_constraintBaseline_creator layout_constraintBaseline_toBaselineOf layout_constraintBottom_creator layout_constraintBottom_toBottomOf layout_constraintBottom_toTopOf layout_constraintCircle layout_constraintCircleAngle layout_constraintCircleRadius layout_constraintDimensionRatio layout_constraintEnd_toEndOf layout_constraintEnd_toStartOf layout_constraintGuide_begin layout_constraintGuide_end layout_constraintGuide_percent layout_constraintHeight_default layout_constraintHeight_max layout_constraintHeight_min layout_constraintHeight_percent layout_constraintHorizontal_bias layout_constraintHorizontal_chainStyle layout_constraintHorizontal_weight layout_constraintLeft_creator layout_constraintLeft_toLeftOf layout_constraintLeft_toRightOf layout_constraintRight_creator layout_constraintRight_toLeftOf layout_constraintRight_toRightOf layout_constraintStart_toEndOf layout_constraintStart_toStartOf layout_constraintTag layout_constraintTop_creator layout_constraintTop_toBottomOf layout_constraintTop_toTopOf layout_constraintVertical_bias layout_constraintVertical_chainStyle layout_constraintVertical_weight layout_constraintWidth_default layout_constraintWidth_max layout_constraintWidth_min layout_constraintWidth_percent layout_editor_absoluteX layout_editor_absoluteY layout_goneMarginBottom layout_goneMarginEnd layout_goneMarginLeft layout_goneMarginRight layout_goneMarginStart layout_goneMarginTop motionProgress motionStagger pathMotionArc pivotAnchor transitionEasing transitionPathRotate\nstyleable CoordinatorLayout keylines statusBarBackground\nstyleable CoordinatorLayout_Layout android_layout_gravity layout_anchor layout_anchorGravity layout_behavior layout_dodgeInsetEdges layout_insetEdge layout_keyline\nstyleable CustomAttribute attributeName customBoolean customColorDrawableValue customColorValue customDimension customFloatValue customIntegerValue customPixelDimension customStringValue\nstyleable DrawerArrowToggle arrowHeadLength arrowShaftLength barLength color drawableSize gapBetweenBars spinBars thickness\nstyleable ExtendedFloatingActionButton collapsedSize elevation extendMotionSpec hideMotionSpec showMotionSpec shrinkMotionSpec\nstyleable ExtendedFloatingActionButton_Behavior_Layout behavior_autoHide behavior_autoShrink\nstyleable FloatingActionButton android_enabled backgroundTint backgroundTintMode borderWidth elevation ensureMinTouchTargetSize fabCustomSize fabSize hideMotionSpec hoveredFocusedTranslationZ maxImageSize pressedTranslationZ rippleColor shapeAppearance shapeAppearanceOverlay showMotionSpec useCompatPadding\nstyleable FloatingActionButton_Behavior_Layout behavior_autoHide\nstyleable FlowLayout itemSpacing lineSpacing\nstyleable FontFamily fontProviderAuthority fontProviderCerts fontProviderFetchStrategy fontProviderFetchTimeout fontProviderPackage fontProviderQuery\nstyleable FontFamilyFont android_font android_fontStyle android_fontVariationSettings android_fontWeight android_ttcIndex font fontStyle fontVariationSettings fontWeight ttcIndex\nstyleable ForegroundLinearLayout android_foreground android_foregroundGravity foregroundInsidePadding\nstyleable GradientColor android_centerColor android_centerX android_centerY android_endColor android_endX android_endY android_gradientRadius android_startColor android_startX android_startY android_tileMode android_type\nstyleable GradientColorItem android_color android_offset\nstyleable ImageFilterView altSrc brightness contrast crossfade overlay round roundPercent saturation warmth\nstyleable Insets paddingBottomSystemWindowInsets paddingLeftSystemWindowInsets paddingRightSystemWindowInsets\nstyleable KeyAttribute android_alpha android_elevation android_rotation android_rotationX android_rotationY android_scaleX android_scaleY android_transformPivotX android_transformPivotY android_translationX android_translationY android_translationZ curveFit framePosition motionProgress motionTarget transitionEasing transitionPathRotate\nstyleable KeyCycle android_alpha android_elevation android_rotation android_rotationX android_rotationY android_scaleX android_scaleY android_translationX android_translationY android_translationZ curveFit framePosition motionProgress motionTarget transitionEasing transitionPathRotate waveOffset wavePeriod waveShape waveVariesBy\nstyleable KeyPosition curveFit drawPath framePosition keyPositionType motionTarget pathMotionArc percentHeight percentWidth percentX percentY sizePercent transitionEasing\nstyleable KeyTimeCycle android_alpha android_elevation android_rotation android_rotationX android_rotationY android_scaleX android_scaleY android_translationX android_translationY android_translationZ curveFit framePosition motionProgress motionTarget transitionEasing transitionPathRotate waveDecay waveOffset wavePeriod waveShape\nstyleable KeyTrigger framePosition motionTarget motion_postLayoutCollision motion_triggerOnCollision onCross onNegativeCross onPositiveCross triggerId triggerReceiver triggerSlack\nstyleable Layout android_layout_height android_layout_marginBottom android_layout_marginEnd android_layout_marginLeft android_layout_marginRight android_layout_marginStart android_layout_marginTop android_layout_width android_orientation barrierAllowsGoneWidgets barrierDirection barrierMargin chainUseRtl constraint_referenced_ids layout_constrainedHeight layout_constrainedWidth layout_constraintBaseline_creator layout_constraintBaseline_toBaselineOf layout_constraintBottom_creator layout_constraintBottom_toBottomOf layout_constraintBottom_toTopOf layout_constraintCircle layout_constraintCircleAngle layout_constraintCircleRadius layout_constraintDimensionRatio layout_constraintEnd_toEndOf layout_constraintEnd_toStartOf layout_constraintGuide_begin layout_constraintGuide_end layout_constraintGuide_percent layout_constraintHeight_default layout_constraintHeight_max layout_constraintHeight_min layout_constraintHeight_percent layout_constraintHorizontal_bias layout_constraintHorizontal_chainStyle layout_constraintHorizontal_weight layout_constraintLeft_creator layout_constraintLeft_toLeftOf layout_constraintLeft_toRightOf layout_constraintRight_creator layout_constraintRight_toLeftOf layout_constraintRight_toRightOf layout_constraintStart_toEndOf layout_constraintStart_toStartOf layout_constraintTop_creator layout_constraintTop_toBottomOf layout_constraintTop_toTopOf layout_constraintVertical_bias layout_constraintVertical_chainStyle layout_constraintVertical_weight layout_constraintWidth_default layout_constraintWidth_max layout_constraintWidth_min layout_constraintWidth_percent layout_editor_absoluteX layout_editor_absoluteY layout_goneMarginBottom layout_goneMarginEnd layout_goneMarginLeft layout_goneMarginRight layout_goneMarginStart layout_goneMarginTop maxHeight maxWidth minHeight minWidth\nstyleable LinearLayoutCompat android_baselineAligned android_baselineAlignedChildIndex android_gravity android_orientation android_weightSum divider dividerPadding measureWithLargestChild showDividers\nstyleable LinearLayoutCompat_Layout android_layout_gravity android_layout_height android_layout_weight android_layout_width\nstyleable LinearProgressIndicator indeterminateAnimationType indicatorDirectionLinear\nstyleable ListPopupWindow android_dropDownHorizontalOffset android_dropDownVerticalOffset\nstyleable MaterialAlertDialog backgroundInsetBottom backgroundInsetEnd backgroundInsetStart backgroundInsetTop\nstyleable MaterialAlertDialogTheme materialAlertDialogBodyTextStyle materialAlertDialogTheme materialAlertDialogTitleIconStyle materialAlertDialogTitlePanelStyle materialAlertDialogTitleTextStyle\nstyleable MaterialAutoCompleteTextView android_inputType\nstyleable MaterialButton android_background android_checkable android_insetBottom android_insetLeft android_insetRight android_insetTop backgroundTint backgroundTintMode cornerRadius elevation icon iconGravity iconPadding iconSize iconTint iconTintMode rippleColor shapeAppearance shapeAppearanceOverlay strokeColor strokeWidth\nstyleable MaterialButtonToggleGroup checkedButton selectionRequired singleSelection\nstyleable MaterialCalendar android_windowFullscreen dayInvalidStyle daySelectedStyle dayStyle dayTodayStyle nestedScrollable rangeFillColor yearSelectedStyle yearStyle yearTodayStyle\nstyleable MaterialCalendarItem android_insetBottom android_insetLeft android_insetRight android_insetTop itemFillColor itemShapeAppearance itemShapeAppearanceOverlay itemStrokeColor itemStrokeWidth itemTextColor\nstyleable MaterialCardView android_checkable cardForegroundColor checkedIcon checkedIconMargin checkedIconSize checkedIconTint rippleColor shapeAppearance shapeAppearanceOverlay state_dragged strokeColor strokeWidth\nstyleable MaterialCheckBox buttonTint useMaterialThemeColors\nstyleable MaterialRadioButton buttonTint useMaterialThemeColors\nstyleable MaterialShape shapeAppearance shapeAppearanceOverlay\nstyleable MaterialTextAppearance android_letterSpacing android_lineHeight lineHeight\nstyleable MaterialTextView android_lineHeight android_textAppearance lineHeight\nstyleable MaterialTimePicker clockIcon keyboardIcon\nstyleable MaterialToolbar navigationIconTint\nstyleable MenuGroup android_checkableBehavior android_enabled android_id android_menuCategory android_orderInCategory android_visible\nstyleable MenuItem actionLayout actionProviderClass actionViewClass alphabeticModifiers android_alphabeticShortcut android_checkable android_checked android_enabled android_icon android_id android_menuCategory android_numericShortcut android_onClick android_orderInCategory android_title android_titleCondensed android_visible contentDescription iconTint iconTintMode numericModifiers showAsAction tooltipText\nstyleable MenuView android_headerBackground android_horizontalDivider android_itemBackground android_itemIconDisabledAlpha android_itemTextAppearance android_verticalDivider android_windowAnimationStyle preserveIconSpacing subMenuArrow\nstyleable MockView mock_diagonalsColor mock_label mock_labelBackgroundColor mock_labelColor mock_showDiagonals mock_showLabel\nstyleable Motion animate_relativeTo drawPath motionPathRotate motionStagger pathMotionArc transitionEasing\nstyleable MotionHelper onHide onShow\nstyleable MotionLayout applyMotionScene currentState layoutDescription motionDebug motionProgress showPaths\nstyleable MotionScene defaultDuration layoutDuringTransition\nstyleable MotionTelltales telltales_tailColor telltales_tailScale telltales_velocityMode\nstyleable NavigationView android_background android_fitsSystemWindows android_maxWidth elevation headerLayout itemBackground itemHorizontalPadding itemIconPadding itemIconSize itemIconTint itemMaxLines itemShapeAppearance itemShapeAppearanceOverlay itemShapeFillColor itemShapeInsetBottom itemShapeInsetEnd itemShapeInsetStart itemShapeInsetTop itemTextAppearance itemTextColor menu shapeAppearance shapeAppearanceOverlay\nstyleable OnClick clickAction targetId\nstyleable OnSwipe dragDirection dragScale dragThreshold limitBoundsTo maxAcceleration maxVelocity moveWhenScrollAtTop nestedScrollFlags onTouchUp touchAnchorId touchAnchorSide touchRegionId\nstyleable PopupWindow android_popupAnimationStyle android_popupBackground overlapAnchor\nstyleable PopupWindowBackgroundState state_above_anchor\nstyleable PropertySet android_alpha android_visibility layout_constraintTag motionProgress visibilityMode\nstyleable RadialViewGroup materialCircleRadius\nstyleable RangeSlider minSeparation values\nstyleable RecycleListView paddingBottomNoButtons paddingTopNoTitle\nstyleable RecyclerView android_clipToPadding android_descendantFocusability android_orientation fastScrollEnabled fastScrollHorizontalThumbDrawable fastScrollHorizontalTrackDrawable fastScrollVerticalThumbDrawable fastScrollVerticalTrackDrawable layoutManager reverseLayout spanCount stackFromEnd\nstyleable ScrimInsetsFrameLayout insetForeground\nstyleable ScrollingViewBehavior_Layout behavior_overlapTop\nstyleable SearchView android_focusable android_imeOptions android_inputType android_maxWidth closeIcon commitIcon defaultQueryHint goIcon iconifiedByDefault layout queryBackground queryHint searchHintIcon searchIcon submitBackground suggestionRowLayout voiceIcon\nstyleable ShapeAppearance cornerFamily cornerFamilyBottomLeft cornerFamilyBottomRight cornerFamilyTopLeft cornerFamilyTopRight cornerSize cornerSizeBottomLeft cornerSizeBottomRight cornerSizeTopLeft cornerSizeTopRight\nstyleable ShapeableImageView contentPadding contentPaddingBottom contentPaddingEnd contentPaddingLeft contentPaddingRight contentPaddingStart contentPaddingTop shapeAppearance shapeAppearanceOverlay strokeColor strokeWidth\nstyleable Slider android_enabled android_stepSize android_value android_valueFrom android_valueTo haloColor haloRadius labelBehavior labelStyle thumbColor thumbElevation thumbRadius thumbStrokeColor thumbStrokeWidth tickColor tickColorActive tickColorInactive tickVisible trackColor trackColorActive trackColorInactive trackHeight\nstyleable Snackbar snackbarButtonStyle snackbarStyle snackbarTextViewStyle\nstyleable SnackbarLayout actionTextColorAlpha android_maxWidth animationMode backgroundOverlayColorAlpha backgroundTint backgroundTintMode elevation maxActionInlineWidth\nstyleable Spinner android_dropDownWidth android_entries android_popupBackground android_prompt popupTheme\nstyleable State android_id constraints\nstyleable StateListDrawable android_constantSize android_dither android_enterFadeDuration android_exitFadeDuration android_variablePadding android_visible\nstyleable StateListDrawableItem android_drawable\nstyleable StateSet defaultState\nstyleable SwitchCompat android_textOff android_textOn android_thumb showText splitTrack switchMinWidth switchPadding switchTextAppearance thumbTextPadding thumbTint thumbTintMode track trackTint trackTintMode\nstyleable SwitchMaterial useMaterialThemeColors\nstyleable TabItem android_icon android_layout android_text\nstyleable TabLayout tabBackground tabContentStart tabGravity tabIconTint tabIconTintMode tabIndicator tabIndicatorAnimationDuration tabIndicatorAnimationMode tabIndicatorColor tabIndicatorFullWidth tabIndicatorGravity tabIndicatorHeight tabInlineLabel tabMaxWidth tabMinWidth tabMode tabPadding tabPaddingBottom tabPaddingEnd tabPaddingStart tabPaddingTop tabRippleColor tabSelectedTextColor tabTextAppearance tabTextColor tabUnboundedRipple\nstyleable TextAppearance android_fontFamily android_shadowColor android_shadowDx android_shadowDy android_shadowRadius android_textColor android_textColorHint android_textColorLink android_textFontWeight android_textSize android_textStyle android_typeface fontFamily fontVariationSettings textAllCaps textLocale\nstyleable TextInputEditText textInputLayoutFocusedRectEnabled\nstyleable TextInputLayout android_enabled android_hint android_textColorHint boxBackgroundColor boxBackgroundMode boxCollapsedPaddingTop boxCornerRadiusBottomEnd boxCornerRadiusBottomStart boxCornerRadiusTopEnd boxCornerRadiusTopStart boxStrokeColor boxStrokeErrorColor boxStrokeWidth boxStrokeWidthFocused counterEnabled counterMaxLength counterOverflowTextAppearance counterOverflowTextColor counterTextAppearance counterTextColor endIconCheckable endIconContentDescription endIconDrawable endIconMode endIconTint endIconTintMode errorContentDescription errorEnabled errorIconDrawable errorIconTint errorIconTintMode errorTextAppearance errorTextColor expandedHintEnabled helperText helperTextEnabled helperTextTextAppearance helperTextTextColor hintAnimationEnabled hintEnabled hintTextAppearance hintTextColor passwordToggleContentDescription passwordToggleDrawable passwordToggleEnabled passwordToggleTint passwordToggleTintMode placeholderText placeholderTextAppearance placeholderTextColor prefixText prefixTextAppearance prefixTextColor shapeAppearance shapeAppearanceOverlay startIconCheckable startIconContentDescription startIconDrawable startIconTint startIconTintMode suffixText suffixTextAppearance suffixTextColor\nstyleable ThemeEnforcement android_textAppearance enforceMaterialTheme enforceTextAppearance\nstyleable Toolbar android_gravity android_minHeight buttonGravity collapseContentDescription collapseIcon contentInsetEnd contentInsetEndWithActions contentInsetLeft contentInsetRight contentInsetStart contentInsetStartWithNavigation logo logoDescription maxButtonHeight menu navigationContentDescription navigationIcon popupTheme subtitle subtitleTextAppearance subtitleTextColor title titleMargin titleMarginBottom titleMarginEnd titleMarginStart titleMarginTop titleMargins titleTextAppearance titleTextColor\nstyleable Tooltip android_layout_margin android_minHeight android_minWidth android_padding android_text android_textAppearance backgroundTint\nstyleable Transform android_elevation android_rotation android_rotationX android_rotationY android_scaleX android_scaleY android_transformPivotX android_transformPivotY android_translationX android_translationY android_translationZ\nstyleable Transition android_id autoTransition constraintSetEnd constraintSetStart duration layoutDuringTransition motionInterpolator pathMotionArc staggered transitionDisable transitionFlags\nstyleable Variant constraints region_heightLessThan region_heightMoreThan region_widthLessThan region_widthMoreThan\nstyleable View android_focusable android_theme paddingEnd paddingStart theme\nstyleable ViewBackgroundHelper android_background backgroundTint backgroundTintMode\nstyleable ViewPager2 android_orientation\nstyleable ViewStubCompat android_id android_inflatedId android_layout\nxml standalone_badge\nxml standalone_badge_gravity_bottom_end\nxml standalone_badge_gravity_bottom_start\nxml standalone_badge_gravity_top_start\nxml standalone_badge_offset\n"
  },
  {
    "path": "privacy-ui/build/kotlin/compileDebugKotlin/caches-jvm/lookups/counters.tab",
    "content": "11\n0"
  },
  {
    "path": "privacy-ui/build/outputs/logs/manifest-merger-debug-report.txt",
    "content": "-- Merging decision tree log ---\nmanifest\nADDED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:2:1-19:12\nINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:2:1-19:12\nINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:2:1-19:12\nINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:2:1-19:12\nINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:2:1-19:12\nINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:2:1-19:12\nINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:2:1-19:12\n\tpackage\n\t\tADDED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:3:5-36\n\t\tINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml\n\t\tINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml\n\tandroid:versionName\n\t\tINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml\n\t\tADDED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:2:1-19:12\n\t\tINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml\n\tandroid:versionCode\n\t\tINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml\n\t\tADDED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:2:1-19:12\n\t\tINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml\n\txmlns:android\n\t\tADDED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:2:11-69\napplication\nADDED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:5:5-17:19\nactivity#com.yl.lib.privacy_ui.RealTimePrivacyItemActivity\nADDED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:6:9-8:40\n\tandroid:exported\n\t\tADDED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:8:13-37\n\tandroid:name\n\t\tADDED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:7:13-56\nactivity#com.yl.lib.privacy_ui.ReplaceListActivity\nADDED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:9:9-12:75\n\tandroid:exported\n\t\tADDED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:11:13-37\n\tandroid:theme\n\t\tADDED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:12:13-72\n\tandroid:name\n\t\tADDED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:10:13-48\nactivity#com.yl.lib.privacy_ui.PermissionListActivity\nADDED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:13:9-16:75\n\tandroid:exported\n\t\tADDED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:15:13-37\n\tandroid:theme\n\t\tADDED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:16:13-72\n\tandroid:name\n\t\tADDED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml:14:13-51\nuses-sdk\nINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml reason: use-sdk injection requested\nINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml\nINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml\nINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml\nINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml\n\tandroid:targetSdkVersion\n\t\tINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml\n\t\tADDED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml\n\t\tINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml\n\tandroid:minSdkVersion\n\t\tINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml\n\t\tADDED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml\n\t\tINJECTED from /Users/yulun/GitHub/PrivacySentry/privacy-ui/src/main/AndroidManifest.xml\n"
  },
  {
    "path": "privacy-ui/build/tmp/compileDebugJavaWithJavac/source-classes-mapping.txt",
    "content": "com/yl/lib/privacy_ui/BuildConfig.java\n com.yl.lib.privacy_ui.BuildConfig\n"
  },
  {
    "path": "privacy_hook.json",
    "content": "{\n\t\"hookServiceList\":[\n\t\t\"com.yl.lib.privacysentry.test.TestService\",\n\t\t\"com.yl.lib.privacysentry.test.TestWhiteService\"\n\t],\n\t\"replaceMethodMap\":{\n\t\t\"android.app.ActivityManager.getRunningAppProcesses\":{\n\t\t\t\"count\":3,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacy_test.TestMethodInJava\",\n\t\t\t\t\t\"originMethodName\":\"getRunningAppProcesses\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacy_test.TestMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getRunningAppProcesses\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getRunningAppProcesses\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.app.ActivityManager.getRunningTasks\":{\n\t\t\t\"count\":3,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacy_test.TestMethodInJava\",\n\t\t\t\t\t\"originMethodName\":\"getRunningTasks\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacy_test.TestMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getRunningTasks\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getRunningTasks\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.bluetooth.BluetoothAdapter.getAddress\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getAddress\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.content.ClipboardManager.getPrimaryClip\":{\n\t\t\t\"count\":2,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacy_test.TestMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getPrimaryClip\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getPrimaryClip\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.content.ClipboardManager.getPrimaryClipDescription\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getPrimaryClipDescription\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.content.ClipboardManager.getText\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getText\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.content.ClipboardManager.hasPrimaryClip\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"hasPrimaryClip\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.content.ClipboardManager.setPrimaryClip\":{\n\t\t\t\"count\":2,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacy_test.TestMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"setPrimaryClip\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"setPrimaryClip\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.content.ClipboardManager.setText\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"setText\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.content.ContentResolver.insert\":{\n\t\t\t\"count\":2,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.contact.ContactManager$Manager\",\n\t\t\t\t\t\"originMethodName\":\"insert\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.calendar.CalendarManager$Manager\",\n\t\t\t\t\t\"originMethodName\":\"insert\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.content.ContentResolver.query\":{\n\t\t\t\"count\":2,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.contact.ContactManager$Manager\",\n\t\t\t\t\t\"originMethodName\":\"query\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.calendar.CalendarManager$Manager\",\n\t\t\t\t\t\"originMethodName\":\"query\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.content.pm.PackageManager.getInstalledPackages\":{\n\t\t\t\"count\":2,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacy_test.TestMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getInstalledPackages\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getInstalledPackages\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.content.pm.PackageManager.getPackageInfo\":{\n\t\t\t\"count\":2,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacy_ui.permission.PermissionViewModel\",\n\t\t\t\t\t\"originMethodName\":\"getPackageInfo\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getPackageInfo\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.content.pm.PackageManager.queryIntentActivities\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"queryIntentActivities\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.content.pm.PackageManager.queryIntentActivityOptions\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"queryIntentActivityOptions\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.hardware.SensorManager.getSensorList\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getSensorList\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.hardware.SensorManager.registerListener\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"registerListener\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.location.LocationManager.getLastKnownLocation\":{\n\t\t\t\"count\":2,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.location.LocationTestActivity$3\",\n\t\t\t\t\t\"originMethodName\":\"getLastKnownLocation\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.location.LocationTestActivity\",\n\t\t\t\t\t\"originMethodName\":\"getLastKnownLocation\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.location.LocationManager.requestLocationUpdates\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.location.LocationTestActivity\",\n\t\t\t\t\t\"originMethodName\":\"requestLocationUpdates\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.net.wifi.WifiInfo.getMacAddress\":{\n\t\t\t\"count\":2,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacy_test.TestMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getMacAddress\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getMacAddress\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.net.wifi.WifiManager.getScanResults\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getScanResults\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.net.wifi.WifiManager.isWifiEnabled\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"isWifiEnabled\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.os.Build.getSerial\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getSerial\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.os.Environment.getExternalStorageDirectory\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getExternalStorageDirectory\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.provider.Settings$Secure.getString\":{\n\t\t\t\"count\":2,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacy_test.TestMethodInJava\",\n\t\t\t\t\t\"originMethodName\":\"getString\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getString\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.provider.Settings$System.getString\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacy_test.TestMethodInJava\",\n\t\t\t\t\t\"originMethodName\":\"getString\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.telephony.TelephonyManager.getDeviceId\":{\n\t\t\t\"count\":2,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacy_test.TestMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getDeviceId\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getDeviceId\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.telephony.TelephonyManager.getImei\":{\n\t\t\t\"count\":2,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacy_test.TestMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getImei\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getImei\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.telephony.TelephonyManager.getMeid\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getMeid\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.telephony.TelephonyManager.getNetworkOperator\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getNetworkOperator\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.telephony.TelephonyManager.getSimOperator\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getSimOperator\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.telephony.TelephonyManager.getSimSerialNumber\":{\n\t\t\t\"count\":2,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacy_test.TestMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getSimSerialNumber\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getSimSerialNumber\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.telephony.TelephonyManager.getSimState\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getSimState\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"android.telephony.TelephonyManager.getSubscriberId\":{\n\t\t\t\"count\":3,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacy_test.TestMethodInJava\",\n\t\t\t\t\t\"originMethodName\":\"getSubscriberId\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacy_test.TestMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getSubscriberId\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getSubscriberId\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"androidx.appcompat.app.AppCompatActivity.requestPermissions\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.contact.ContactActivity\",\n\t\t\t\t\t\"originMethodName\":\"requestPermissions\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"com.yl.lib.privacysentry.MainActivity.requestPermissions\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.MainActivity\",\n\t\t\t\t\t\"originMethodName\":\"requestPermissions\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"com.yl.lib.privacysentry.location.LocationTestActivity.requestPermissions\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.location.LocationTestActivity\",\n\t\t\t\t\t\"originMethodName\":\"requestPermissions\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"com.yl.lib.privacysentry.telephony.TelephonyTestActivity.requestPermissions\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.telephony.TelephonyTestActivity\",\n\t\t\t\t\t\"originMethodName\":\"requestPermissions\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"com.yl.lib.privacysentry.test.ui.main.TestPermissionFragment.requestPermissions\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.ui.main.TestPermissionFragment\",\n\t\t\t\t\t\"originMethodName\":\"requestPermissions\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"java.lang.reflect.Method.invoke\":{\n\t\t\t\"count\":2,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.TestReflexJava\",\n\t\t\t\t\t\"originMethodName\":\"invoke\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.TestReflex\",\n\t\t\t\t\t\"originMethodName\":\"invoke\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"java.net.HttpURLConnection.connect\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.TestInJava\",\n\t\t\t\t\t\"originMethodName\":\"connect\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"java.net.InetAddress.getHostAddress\":{\n\t\t\t\"count\":1,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.TestInJava\",\n\t\t\t\t\t\"originMethodName\":\"getHostAddress\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"java.net.NetworkInterface.getHardwareAddress\":{\n\t\t\t\"count\":2,\n\t\t\t\"originMethodList\":[\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacy_test.TestMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getHardwareAddress\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"originClassName\":\"com.yl.lib.privacysentry.test.PrivacyMethod$PrivacyMethod\",\n\t\t\t\t\t\"originMethodName\":\"getHardwareAddress\"\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t}\n}"
  },
  {
    "path": "publish.gradle",
    "content": "apply plugin: 'maven-publish'\npublishing {\n    publications {\n        release(MavenPublication) {\n            groupId = 'com.github.allenymt.PrivacySentry'\n            artifactId = project.ARTIFACT_ID\n            version = rootProject.ext.publish_config[\"version\"]\n            afterEvaluate {\n                if(project.ARTIFACT_ID == \"plugin-sentry\" || project.ARTIFACT_ID == \"privacy-annotation\") {\n                    from components.java\n                } else {\n                    from components.release\n                }\n            }\n        }\n    }\n    if (rootProject.ext.build.local_debug) {\n        repositories {\n            maven {\n                url = uri(rootProject.ext.build.local_debug_dir)\n            }\n        }\n    }\n}"
  },
  {
    "path": "settings.gradle.kts",
    "content": "rootProject.name = \"PrivacySentry\"\n\npluginManagement {\n    repositories {\n        mavenCentral()\n        google()\n        gradlePluginPortal()\n    }\n}\n\n//dependencyResolutionManagement {\n//    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)\n//    repositories {\n//        mavenCentral()\n//        google()\n//        maven { url = uri(\"https://jitpack.io\") }\n//    }\n//}\n\ninclude (\":app\")\ninclude (\":hook-sentry\")\ninclude (\":plugin-sentry\")\ninclude (\":privacy-test\")\ninclude (\":privacy-annotation\")\ninclude (\":privacy-proxy\")\ninclude (\":privacy-replace\")\n"
  },
  {
    "path": "upload_local.sh",
    "content": "#!/bin/bash\n\n#定义颜色的变量\nRED_COLOR=\"\\033[1;31m\"  #红\nGREEN_COLOR=\"\\033[1;32m\" #绿\nYELOW_COLOR=\"\\033[1;33m\" #黄\nBLUE_COLOR=\"\\033[1;34m\"  #蓝\nPINK=\"\\033[1;35m\"    #粉红\nRES=\"\\033[0m\"\n\n./gradlew clean\n./gradlew :plugin-sentry:assemble --stacktrace\n./gradlew :hook-sentry:assembleRelease --stacktrace\n./gradlew :privacy-annotation:assemble --stacktrace\n./gradlew :privacy-proxy:assembleRelease --stacktrace\n./gradlew :privacy-replace:assembleRelease --stacktrace\n#publish\n./gradlew :plugin-sentry:publish --stacktrace\n./gradlew :hook-sentry:publish --stacktrace\n./gradlew :privacy-annotation:publish --stacktrace\n./gradlew :privacy-proxy:publish --stacktrace\n./gradlew :privacy-replace:publish --stacktrace\necho -e \"${GREEN_COLOR}本地打包完成！！！${RES}\"\n"
  }
]