commit c458f3c70710b6a4d4fae033a499592b74996a3a Author: Joywayer Date: Mon Feb 16 18:24:19 2026 +0800 first commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0691144 --- /dev/null +++ b/.gitignore @@ -0,0 +1,87 @@ +# Mac 忽略文件 +.DS_Store +# Built application files +*.apk +*.aar +*.ap_ +*.aab + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ +# Uncomment the following line in case you need and you don't have the release build type files in your app +# release/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# IntelliJ +*.iml +.idea/workspace.xml +.idea/tasks.xml +.idea/gradle.xml +.idea/assetWizardSettings.xml +.idea/dictionaries +.idea/libraries +# Android Studio 3 in .gitignore file. +.idea/caches +.idea/modules.xml +# Comment next line if keeping position of elements in Navigation Editor is relevant for you +.idea/navEditor.xml + +# Keystore files +# Uncomment the following lines if you do not want to check your keystore files in. +#*.jks +#*.keystore + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild +.cxx/ + +# Google Services (e.g. APIs or Firebase) +# google-services.json + +# Freeline +freeline.py +freeline/ +freeline_project_description.json + +# fastlane +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output +fastlane/readme.md + +# Version control +vcs.xml + +# lint +lint/intermediates/ +lint/generated/ +lint/outputs/ +lint/tmp/ +# lint/reports/ \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000..4a53bee --- /dev/null +++ b/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..ae78c11 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,113 @@ + + + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
+
+
\ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..61a9130 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml new file mode 100644 index 0000000..0c0c338 --- /dev/null +++ b/.idea/deploymentTargetDropDown.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..5959e0b --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,18 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..c2bae49 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..e34606c --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..be6fe31 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/HarmonyOS_官方资源快速参考.md b/HarmonyOS_官方资源快速参考.md new file mode 100644 index 0000000..671a031 --- /dev/null +++ b/HarmonyOS_官方资源快速参考.md @@ -0,0 +1,236 @@ +# HarmonyOS 5.0 官方开发者资源快速参考手册 + +## 🎯 使用说明 + +本文档为"进贤聚友棋牌 (HarmonyOS版)"项目提供官方开发者资源的快速索引和使用指导。**开发过程中必须优先参考官方文档**,本文档仅作为导航和补充。 + +--- + +## 📚 一、核心官方文档(优先级排序) + +### ⭐⭐⭐⭐⭐ 最高优先级 - 日常开发必备 + +#### 1. **HarmonyOS API参考文档** +- **官方链接**: https://developer.huawei.com/consumer/cn/doc/harmonyos-references/development-intro-api +- **使用场景**: 所有API调用前必须查阅 +- **重点关注**: + - Web组件API: `ts-basic-components-web` + - WebviewController: `js-apis-webview` + - 文件管理: `js-apis-file-fs` + - 网络请求: `js-apis-http` +- **开发建议**: 收藏并设为浏览器首页,开发过程中随时查阅 + +#### 2. **HarmonyOS应用开发指南** +- **官方链接**: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/application-dev-guide +- **使用场景**: 项目架构设计、功能实现方案设计 +- **重点关注**: + - 应用工程结构: `application-project-structure` + - WebView开发: `webview-js-interaction` + - 数据管理: `data-mgmt-overview` + - 网络管理: `network-connection-overview` +- **开发建议**: 项目启动前通读相关章节,设计阶段重点参考 + +### ⭐⭐⭐⭐ 高优先级 - 技术决策参考 + +#### 3. **HarmonyOS最佳实践** +- **官方链接**: https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-best-practices-overview +- **使用场景**: 架构设计、性能优化、代码质量提升 +- **重点关注**: + - WebView性能优化: `bpta-webview-performance` + - 网络请求优化: `bpta-network-request` + - 内存管理: `bpta-memory-management` + - ArkTS开发规范: `bpta-arkts-guidelines` +- **开发建议**: 每个功能模块设计前查阅相关最佳实践 + +#### 4. **HarmonyOS版本发布说明** +- **官方链接**: https://developer.huawei.com/consumer/cn/doc/harmonyos-releases/overview-allversion +- **使用场景**: 版本兼容性确认、API变更跟踪 +- **重点关注**: + - API 12新特性和变更 + - 兼容性要求 + - 废弃API列表 +- **开发建议**: 项目开始前确认目标版本,定期检查更新 + +### ⭐⭐⭐ 中等优先级 - 问题解决工具 + +#### 5. **HarmonyOS开发FAQ** +- **官方链接**: https://developer.huawei.com/consumer/cn/doc/harmonyos-faqs/faqs-ux-design +- **使用场景**: 遇到问题时的第一参考资料 +- **重点关注**: + - WebView相关FAQ + - ArkTS编译错误FAQ + - 性能问题FAQ +- **开发建议**: 遇到问题先查FAQ,再搜索或提问 + +--- + +## 🛠️ 二、开发工具官方资源 + +### DevEco Studio +- **官方下载**: https://developer.huawei.com/consumer/cn/deveco-studio/ +- **文档**: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-guide +- **版本要求**: 支持HarmonyOS 5.0的最新版本 +- **关键功能**: 代码编辑、调试、模拟器、性能分析 + +### SDK管理 +- **官方指南**: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-sdk-manager +- **版本选择**: API 12+ for HarmonyOS 5.0 +- **更新策略**: 定期检查更新,关注兼容性变更 + +--- + +## 🎯 三、项目关键功能的官方资源映射 + +### WebView与JSBridge开发 +``` +功能需求 → 官方资源 +├── WebView基础配置 → Web组件API参考 +├── JSBridge通信 → JavaScript与应用交互指南 +├── WebView控制器 → WebviewController API参考 +├── 性能优化 → WebView性能优化最佳实践 +└── 问题排查 → WebView FAQ专区 +``` + +### 资源管理与文件操作 +``` +功能需求 → 官方资源 +├── 文件读写 → 文件管理API参考 +├── 网络下载 → 网络请求API + 最佳实践 +├── 资源解压 → 文件系统API + ZIP处理示例 +├── 缓存管理 → 数据管理指南 +└── 权限申请 → 权限管理指南 +``` + +### 应用架构与状态管理 +``` +功能需求 → 官方资源 +├── 页面导航 → 页面路由开发指南 +├── 状态管理 → ArkUI状态管理 +├── 组件通信 → 组件化开发指南 +├── 生命周期 → 应用/组件生命周期 +└── 数据持久化 → 数据管理overview +``` + +--- + +## 📋 四、开发阶段的官方资源使用计划 + +### 第一阶段:环境搭建 +**主要参考**: +1. DevEco Studio安装指南 +2. SDK管理文档 +3. 项目创建向导 +4. 开发环境配置FAQ + +**使用策略**: 严格按照官方指南操作,遇到问题优先查阅FAQ + +### 第二阶段:核心功能开发 +**主要参考**: +1. API参考文档(日常查阅) +2. 开发指南(设计参考) +3. 最佳实践(质量保证) +4. 示例代码(快速上手) + +**使用策略**: API文档作为编码标准,最佳实践指导架构设计 + +### 第三阶段:功能完善 +**主要参考**: +1. 性能优化最佳实践 +2. 用户体验设计指南 +3. 兼容性测试指南 +4. 错误处理最佳实践 + +**使用策略**: 对照最佳实践优化代码质量和用户体验 + +### 第四阶段:测试与优化 +**主要参考**: +1. 测试框架文档 +2. 性能分析工具指南 +3. 调试技巧文档 +4. 发布前检查清单 + +**使用策略**: 使用官方工具进行全面测试和性能优化 + +--- + +## 🔍 五、快速查找指南 + +### 常见问题快速定位 + +#### WebView相关问题 +``` +问题类型 → 查找路径 +├── 类型错误 → API参考文档 → WebviewController +├── 通信失败 → 开发指南 → JavaScript交互 +├── 性能问题 → 最佳实践 → WebView性能优化 +├── 兼容性 → 版本说明 → API变更列表 +└── 其他 → FAQ → WebView专区 +``` + +#### ArkTS编译错误 +``` +问题类型 → 查找路径 +├── 语法错误 → 开发指南 → ArkTS语法 +├── 类型错误 → API参考 → 具体API类型定义 +├── 装饰器错误 → 开发指南 → 状态管理 +├── 导入错误 → 开发指南 → 模块化开发 +└── 其他 → FAQ → 编译错误专区 +``` + +### 搜索关键词建议 + +#### 中文搜索 +- "HarmonyOS WebView" +- "ArkTS WebviewController" +- "HarmonyOS JSBridge" +- "HarmonyOS 文件管理" +- "ArkTS 类型检查" + +#### 英文搜索 +- "HarmonyOS Web Component" +- "ArkTS WebviewController API" +- "HarmonyOS JavaScript Proxy" +- "HarmonyOS File System" +- "ArkTS Type System" + +--- + +## ⚠️ 重要提醒 + +### 优先级原则 +1. **官方文档 > 第三方资料**:当存在冲突时,以官方文档为准 +2. **API参考 > 示例代码**:编码时优先查阅API文档确保参数正确 +3. **最新版本 > 历史版本**:确保使用与目标版本一致的文档 + +### 版本一致性 +- 确保查阅的文档版本与项目目标版本(HarmonyOS 5.0 API 12+)一致 +- 关注API变更和废弃通知 +- 定期检查文档更新 + +### 问题反馈 +- 通过官方开发者社区反馈技术问题 +- 利用DevEco Studio内置的问题报告功能 +- 参与官方技术交流群获得及时支持 + +--- + +## 📞 官方支持渠道 + +### 开发者社区 +- **HarmonyOS开发者论坛**: https://developer.huawei.com/consumer/cn/forum/block/harmonyos +- **用途**: 技术讨论、问题求助、经验分享 + +### 官方技术支持 +- **在线客服**: DevEco Studio → Help → Contact Support +- **用途**: 紧急技术问题、工具bug反馈 + +### 官方培训资源 +- **在线课程**: https://developer.huawei.com/consumer/cn/training/ +- **用途**: 系统学习HarmonyOS开发技能 + +--- + +**最后更新**: 2024年12月19日 +**文档版本**: v1.0 +**适用项目**: 进贤聚友棋牌 (HarmonyOS版) +**目标平台**: HarmonyOS 5.0 (API 12+) diff --git a/TSGame_HarmonyOS开发指南.md b/TSGame_HarmonyOS开发指南.md new file mode 100644 index 0000000..58d26e3 --- /dev/null +++ b/TSGame_HarmonyOS开发指南.md @@ -0,0 +1,1529 @@ +# TSGame HarmonyOS应用开发指南 + +## 项目概述 + +本文档提供了基于HarmonyOS平台开发TSGame棋牌游戏应用的完整技术指南,包括架构设计、开发环境搭建、核心功能实现、JS Bridge接口开发等详细内容。 + +### HarmonyOS 5.0新特性适配 + +本项目充分利用HarmonyOS 5.0的新特性和性能优化: + +#### 1. 增强的WebView引擎 +- **性能提升**: 利用5.0优化的WebView渲染引擎,提高H5游戏运行性能 +- **内存优化**: 改进的内存管理机制,减少WebView内存占用 +- **启动加速**: WebView初始化和页面加载速度显著提升 + +#### 2. 新的权限管理机制 +- **精细化权限**: 支持5.0的精细化权限控制 +- **动态权限**: 改进的运行时权限申请机制 +- **隐私保护**: 增强的用户隐私保护特性 + +#### 3. 文件系统API改进 +- **沙盒机制**: 适配5.0的新沙盒文件访问机制 +- **存储优化**: 利用改进的文件存储API提高I/O性能 +- **安全增强**: 文件访问安全性提升 + +#### 4. 应用启动优化 +- **冷启动**: 利用5.0的应用预加载机制 +- **热启动**: 优化的应用恢复机制 +- **资源预加载**: 智能资源预加载策略 + +#### 5. 向下兼容性 +- **API适配层**: 建立兼容性适配层支持HarmonyOS 4.0 +- **特性检测**: 运行时检测系统版本并启用对应特性 +- **降级策略**: 为不支持的特性提供降级方案 + +### 应用基本信息 +- **应用名称**: 进贤聚友棋牌 (HarmonyOS版) +- **Bundle名称**: `com.jx.jyhd.harmonyos` +- **目标API**: HarmonyOS API 12+ (支持HarmonyOS 5.0) +- **最低支持**: HarmonyOS API 11 (HarmonyOS 4.0) +- **开发语言**: ArkTS/TypeScript +- **应用模型**: Stage模型 +- **项目周期**: 8-10周 +- **团队规模**: 3-5人 + +## 1. 程序设计框架 + +### 1.1 整体架构设计 + +``` +┌─────────────────────────────────────────────────────────┐ +│ H5游戏前端层 │ +│ (HTML5 + CSS3 + JavaScript) │ +│ - 游戏逻辑实现 │ +│ - UI界面展示 │ +│ - 用户交互处理 │ +└─────────────────────────────────────────────────────────┘ + │ + JavaScript Bridge API + │ +┌─────────────────────────────────────────────────────────┐ +│ HarmonyOS Native层 │ +│ │ +│ ┌─────────────┬─────────────┬─────────────────────┐ │ +│ │ AbilityKit │ WebView组件 │ 系统服务集成 │ │ +│ │ 生命周期 │ JS Bridge │ - 位置服务 │ │ +│ │ 页面管理 │ 通信管理 │ - 多媒体服务 │ │ +│ │ 权限管理 │ 事件处理 │ - 网络服务 │ │ +│ └─────────────┴─────────────┴─────────────────────┘ │ +│ │ +│ ┌─────────────┬─────────────┬─────────────────────┐ │ +│ │ 第三方SDK集成│ 数据存储 │ 平台特性适配 │ │ +│ │ - 华为地图 │ - 本地存储 │ - 华为账号 │ │ +│ │ - 原生音频 │ - 文件管理 │ - 华为分享 │ │ +│ │ - 华为分析 │ - 配置管理 │ - HarmonyOS规范 │ │ +│ └─────────────┴─────────────┴─────────────────────┘ │ +└─────────────────────────────────────────────────────────┘ +``` + +### 1.2 双WebView架构设计 + +TSGame应用采用双WebView架构,实现大厅和子游戏的分离管理: + +``` +应用启动流程: +启动App → 加载远程配置 → 下载大厅ZIP包 → 解压大厅资源 → 显示大厅WebView + ↓ +用户点击子游戏 → 验证子游戏ZIP包 → 下载子游戏ZIP → 解压子游戏资源 → 显示子游戏WebView +``` + +#### 1.2.1 表现层 (UI Layer) +```typescript +// 双WebView UI组件层次结构 +EntryAbility +├── MainPage (应用主页面) +│ ├── HallWebView (大厅WebView) +│ │ ├── HallWebComponent (大厅Web组件) +│ │ ├── HallLoadingComponent (大厅加载组件) +│ │ └── HallErrorComponent (大厅错误处理) +│ ├── GameWebView (子游戏WebView) +│ │ ├── GameWebComponent (子游戏Web组件) +│ │ ├── GameLoadingComponent (子游戏加载组件) +│ │ └── GameErrorComponent (子游戏错误处理) +│ ├── NavigationController (WebView切换控制器) +│ ├── DownloadProgressView (下载进度显示) +│ └── GlobalLoadingView (全局加载组件) +└── SettingsPage (设置页面) + ├── PermissionSettings (权限设置) + ├── AboutPage (关于页面) + └── VersionCheck (版本检查) +``` + +#### 1.2.2 业务逻辑层 (Business Layer) +```typescript +// 核心业务模块 - 双WebView架构 +├── HallManager (大厅管理器) +│ ├── HallLauncher (大厅启动器) +│ ├── HallResourceManager (大厅资源管理器) +│ └── HallConfigManager (大厅配置管理器) +├── GameManager (子游戏管理器) +│ ├── GameLauncher (子游戏启动器) +│ ├── GameResourceManager (子游戏资源管理器) +│ ├── GameValidation (子游戏验证器) +│ └── GamePackageManager (子游戏包管理器) +├── WebViewManager (WebView管理器) +│ ├── HallWebViewController (大厅WebView控制器) +│ ├── GameWebViewController (子游戏WebView控制器) +│ └── WebViewSwitcher (WebView切换器) +├── BridgeManager (桥接管理器) +│ ├── JSBridgeService (JS桥接服务) +│ ├── APIDispatcher (API分发器) +│ └── MessageHandler (消息处理器) +├── ResourceManager (资源管理器) +│ ├── ZipDownloader (ZIP下载器) +│ ├── ZipExtractor (ZIP解压器) +│ ├── ResourceValidator (资源验证器) +│ └── CacheManager (缓存管理器) +├── UserManager (用户管理器) +│ ├── AuthService (认证服务) +│ ├── ProfileManager (用户档案管理) +│ └── SessionManager (会话管理) +└── MediaManager (多媒体管理器) + ├── AudioService (音频服务) + ├── VideoService (视频服务) + └── CameraService (相机服务) +``` + +#### 1.2.3 数据访问层 (Data Layer) +```typescript +// 数据管理模块 +├── LocalStorage (本地存储) +│ ├── PreferenceUtil (首选项工具) +│ ├── FileManager (文件管理) +│ └── DatabaseManager (数据库管理) +├── NetworkService (网络服务) +│ ├── HttpClient (HTTP客户端) +│ ├── DownloadManager (下载管理器) +│ └── UploadManager (上传管理器) +└── CacheManager (缓存管理) + ├── ImageCache (图片缓存) + ├── DataCache (数据缓存) + └── WebCache (Web缓存) +``` + +### 1.3 模块依赖关系 + +```typescript +// 双WebView架构模块依赖图 +HallManager +├── 依赖 → ResourceManager (ZIP下载解压) +├── 依赖 → ConfigManager (配置管理) +├── 依赖 → WebViewManager (大厅WebView控制) +└── 依赖 → NetworkService (网络服务) + +GameManager +├── 依赖 → ResourceManager (子游戏ZIP管理) +├── 依赖 → WebViewManager (子游戏WebView控制) +├── 依赖 → BridgeManager (JS桥接) +└── 依赖 → ValidationService (ZIP包验证) + +WebViewManager +├── 依赖 → BridgeManager (JS Bridge注册) +├── 依赖 → MediaManager (多媒体功能) +├── 依赖 → LocationService (定位服务) +└── 依赖 → UserManager (用户管理) + +ResourceManager +├── 依赖 → NetworkService (ZIP下载) +├── 依赖 → FileManager (文件解压) +├── 依赖 → CacheManager (资源缓存) +└── 依赖 → ValidationService (完整性验证) + +BridgeManager +├── 依赖 → MediaManager (音视频通话) +├── 依赖 → LocationService (定位功能) +├── 依赖 → UserManager (认证登录) +└── 依赖 → SystemService (系统功能) +``` + +## 2. 项目目录结构设计 + +### 2.1 标准HarmonyOS项目结构 (双WebView架构) +``` +tsgame_harmonyos/ +├── AppScope/ # 应用级配置 +│ └── app.json5 # 应用配置文件 +├── entry/ # 主模块 +│ ├── src/main/ +│ │ ├── ets/ # ArkTS源码 +│ │ │ ├── entryability/ # Ability入口 +│ │ │ │ └── EntryAbility.ts +│ │ │ ├── pages/ # 页面文件 +│ │ │ │ ├── MainPage.ets # 主页面(双WebView容器) +│ │ │ │ └── SettingsPage.ets # 设置页面 +│ │ │ ├── common/ # 通用工具类 +│ │ │ │ ├── constants/ # 常量定义 +│ │ │ │ │ ├── AppConstants.ts # 应用常量 +│ │ │ │ │ └── WebViewConstants.ts # WebView常量 +│ │ │ │ ├── utils/ # 工具类 +│ │ │ │ │ ├── ConfigParameterHelper.ts # 配置参数工具 +│ │ │ │ │ ├── ZipExtractor.ts # ZIP解压工具 +│ │ │ │ │ └── FileUtils.ts # 文件工具 +│ │ │ │ └── types/ # 类型定义 +│ │ │ │ ├── GameTypes.ts # 游戏类型定义 +│ │ │ │ ├── ConfigTypes.ts # 配置类型定义 +│ │ │ │ └── WebViewTypes.ts # WebView类型定义 +│ │ │ ├── manager/ # 管理器类 +│ │ │ │ ├── HallManager.ts # 大厅管理器 +│ │ │ │ ├── GameManager.ts # 子游戏管理器 +│ │ │ │ ├── WebViewManager.ts # WebView管理器 +│ │ │ │ ├── BridgeManager.ts # 桥接管理器 +│ │ │ │ ├── ResourceManager.ts # 资源管理器 +│ │ │ │ ├── MediaManager.ts # 多媒体管理器 +│ │ │ │ ├── UserManager.ts # 用户管理器 +│ │ │ │ └── StartupManager.ts # 启动管理器 +│ │ │ ├── service/ # 服务类 +│ │ │ │ ├── AuthService.ts # 认证服务 +│ │ │ │ ├── LocationService.ts # 定位服务 +│ │ │ │ ├── NetworkService.ts # 网络服务 +│ │ │ │ ├── MediaService.ts # 媒体服务 +│ │ │ │ ├── ConfigManager.ts # 配置管理服务 +│ │ │ │ └── DownloadService.ts # 下载服务 +│ │ │ ├── bridge/ # JS桥接实现 +│ │ │ │ ├── JSBridgeService.ts # 桥接核心服务 +│ │ │ │ ├── handlers/ # API处理器 +│ │ │ │ │ ├── AuthHandler.ts # 认证处理器 +│ │ │ │ │ ├── MediaHandler.ts# 媒体处理器 +│ │ │ │ │ ├── SystemHandler.ts# 系统处理器 +│ │ │ │ │ ├── LocationHandler.ts# 定位处理器 +│ │ │ │ │ ├── HallHandler.ts # 大厅处理器 +│ │ │ │ │ └── GameHandler.ts # 游戏处理器 +│ │ │ │ └── types/ # 桥接类型定义 +│ │ │ │ └── BridgeTypes.ts +│ │ │ └── components/ # 自定义组件 +│ │ │ ├── HallWebComponent.ets # 大厅Web组件 +│ │ │ ├── GameWebComponent.ets # 子游戏Web组件 +│ │ │ ├── LoadingComponent.ets # 加载组件 +│ │ │ ├── ProgressComponent.ets # 进度组件 +│ │ │ └── ErrorComponent.ets # 错误组件 +│ │ ├── resources/ # 资源文件 +│ │ │ ├── base/ # 基础资源 +│ │ │ │ ├── element/ # 元素资源 +│ │ │ │ ├── media/ # 媒体资源 +│ │ │ │ └── profile/ # 配置文件 +│ │ │ │ ├── main_pages.json # 页面路由配置 +│ │ │ │ └── startup_config.json # 启动配置 +│ │ │ ├── rawfile/ # 原始文件 +│ │ │ │ ├── default_hall/ # 默认大厅资源 +│ │ │ │ │ ├── index.html # 大厅入口页面 +│ │ │ │ │ ├── js/ # JavaScript文件 +│ │ │ │ │ ├── css/ # 样式文件 +│ │ │ │ │ └── images/ # 图片资源 +│ │ │ │ ├── default_games/ # 默认游戏资源 +│ │ │ │ │ └── placeholder/ # 占位游戏 +│ │ │ │ └── bridge/ # 桥接相关 +│ │ │ │ ├── hall_bridge.js # 大厅桥接JS +│ │ │ │ └── game_bridge.js # 游戏桥接JS +│ │ │ └── en_US/ # 英文资源 +│ │ └── module.json5 # 模块配置文件 +│ ├── build-profile.json5 # 构建配置 +│ ├── hvigorfile.ts # 构建脚本 +│ └── oh-package.json5 # 依赖配置 +├── har/ # HAR模块(可选) +│ └── common_lib/ # 通用库模块 +├── libs/ # 第三方库 +│ ├── huawei-map-sdk/ # 华为地图SDK +│ └── wechat-harmonyos-sdk/ # 微信SDK(如有) +├── docs/ # 文档目录 +│ ├── API_REFERENCE.md # API参考文档 +│ ├── DEPLOYMENT_GUIDE.md # 部署指南 +│ └── TROUBLESHOOTING.md # 故障排除 +├── build-profile.json5 # 项目构建配置 +├── hvigorfile.ts # 项目构建脚本 +└── oh-package.json5 # 项目依赖配置 +``` + +### 2.2 运行时资源目录结构 + +应用运行时会在设备上创建以下目录结构来管理动态下载的游戏资源: + +``` +/data/app/el2/100/base/com.jx.jyhd.harmonyos/haps/entry/files/ +├── game_resources/ # 游戏资源根目录 +│ ├── hall/ # 大厅资源目录 +│ │ ├── index.html # 大厅入口文件 +│ │ ├── js/ # 大厅JS文件 +│ │ ├── css/ # 大厅样式文件 +│ │ ├── images/ # 大厅图片资源 +│ │ └── version.txt # 大厅版本信息 +│ ├── games/ # 子游戏资源目录 +│ │ ├── game001/ # 斗地主游戏 +│ │ │ ├── index.html # 游戏入口文件 +│ │ │ ├── js/ # 游戏JS文件 +│ │ │ ├── css/ # 游戏样式文件 +│ │ │ ├── images/ # 游戏图片资源 +│ │ │ ├── audio/ # 游戏音频资源 +│ │ │ └── version.txt # 游戏版本信息 +│ │ ├── game002/ # 麻将游戏 +│ │ │ ├── index.html +│ │ │ ├── js/ +│ │ │ ├── css/ +│ │ │ ├── images/ +│ │ │ ├── audio/ +│ │ │ └── version.txt +│ │ └── ... # 其他子游戏 +│ ├── downloads/ # 临时下载目录 +│ │ ├── hall_temp.zip # 临时大厅ZIP包 +│ │ ├── game001_temp.zip # 临时游戏ZIP包 +│ │ └── ... +│ └── cache/ # 缓存目录 +│ ├── images/ # 图片缓存 +│ ├── config/ # 配置缓存 +│ └── temp/ # 临时文件 +├── config_cache/ # 配置缓存目录 +│ ├── remote_config.json # 远程配置缓存 +│ └── startup_config.json # 启动配置缓存 +└── logs/ # 日志目录 + ├── app.log # 应用日志 + ├── download.log # 下载日志 + └── error.log # 错误日志 +``` + +### 2.2 关键配置文件说明 + +#### 2.2.1 应用配置 (app.json5) +```json5 +{ + "app": { + "bundleName": "com.jx.jyhd.harmonyos", + "vendor": "YouleGames", + "versionCode": 1000360, + "versionName": "3.6.0", + "icon": "$media:app_icon", + "label": "$string:app_name", + "description": "$string:app_description", + "distributedNotificationEnabled": true, + "targetAPIVersion": 9, + "compatibleAPIVersion": 8 + } +} +``` + +#### 2.2.2 模块配置 (module.json5) +```json5 +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "phone", + "tablet", + "2in1" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ts", + "description": "$string:EntryAbility_desc", + "icon": "$media:icon", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:icon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "requestPermissions": [ + { + "name": "ohos.permission.INTERNET", + "reason": "$string:permission_internet_reason", + "usedScene": { + "abilities": ["EntryAbility"], + "when": "always" + } + }, + { + "name": "ohos.permission.LOCATION", + "reason": "$string:permission_location_reason", + "usedScene": { + "abilities": ["EntryAbility"], + "when": "inuse" + } + }, + { + "name": "ohos.permission.APPROXIMATELY_LOCATION", + "reason": "$string:permission_location_reason", + "usedScene": { + "abilities": ["EntryAbility"], + "when": "inuse" + } + }, + { + "name": "ohos.permission.CAMERA", + "reason": "$string:permission_camera_reason", + "usedScene": { + "abilities": ["EntryAbility"], + "when": "inuse" + } + }, + { + "name": "ohos.permission.MICROPHONE", + "reason": "$string:permission_microphone_reason", + "usedScene": { + "abilities": ["EntryAbility"], + "when": "inuse" + } + }, + { + "name": "ohos.permission.WRITE_MEDIA", + "reason": "$string:permission_storage_reason", + "usedScene": { + "abilities": ["EntryAbility"], + "when": "inuse" + } + }, + { + "name": "ohos.permission.READ_MEDIA", + "reason": "$string:permission_storage_reason", + "usedScene": { + "abilities": ["EntryAbility"], + "when": "inuse" + } + }, + { + "name": "ohos.permission.VIBRATE", + "reason": "$string:permission_vibrate_reason", + "usedScene": { + "abilities": ["EntryAbility"], + "when": "inuse" + } + } + ] + } +} +``` + +## 2. 应用启动流程设计 + +TSGame HarmonyOS应用采用分阶段启动流程,通过远程配置文件驱动,支持大厅和子游戏的动态资源管理。由于启动流程涉及多个复杂的组件和详细的配置参数,已将完整的启动逻辑分离到独立文档中。 + +### 2.1 启动流程文档 + +**📖 详细启动流程说明请参考:[TSGame_应用启动流程详解.md](./TSGame_应用启动流程详解.md)** + +该文档包含以下完整内容: + +#### 2.1.1 核心启动流程 +- **启动时序图**:从应用启动到大厅显示的完整流程 +- **阶段化启动**:EntryAbility.onCreate() → 配置检查 → 资源下载 → WebView初始化 +- **大厅启动逻辑**:大厅资源管理、WebView配置、页面加载 +- **子游戏跳转**:游戏资源检查、下载解压、WebView切换 + +#### 2.1.2 远程配置文件管理 +- **配置文件结构**:JSON格式的分层配置,存储在七牛云CDN +- **配置参数获取**:ConfigParameterHelper类的详细实现 +- **属性读取逻辑**:具体到每个配置属性的获取方法 +- **分层覆盖机制**:全局 → 代理商 → 渠道 → 市场的参数覆盖 + +#### 2.1.3 关键配置属性说明 +- `app_download`:应用下载地址,用于应用更新 +- `app_version`:应用版本号,用于版本比较 +- `game_download`:游戏ZIP包下载地址,用于游戏资源更新 +- `game_version`:游戏版本号,用于资源版本比较 +- `url`:API服务器地址,用于网络请求 +- `showmessage`:版本更新说明,用于用户提示 + +#### 2.1.4 ZIP包解压路径规范 +- **文件系统结构**:HarmonyOS应用的完整目录布局 +- **解压路径管理**:PathManager类的路径规范 +- **资源目录说明**:大厅、子游戏、缓存、配置等目录结构 + +#### 2.1.5 版本检查和更新 +- **版本检测流程**:启动时的版本比较逻辑 +- **更新策略**:应用更新vs资源更新的区别 +- **异常处理**:配置获取失败、下载失败等异常的降级处理 + +### 2.2 HarmonyOS适配要点 + +#### 2.2.1 启动性能优化 +- 利用HarmonyOS 5.0的应用预加载机制 +- 异步加载非关键资源 +- WebView初始化优化 + +#### 2.2.2 资源管理适配 +- 适配HarmonyOS的沙盒文件系统 +- 文件权限管理 +- 存储空间优化 + +#### 2.2.3 网络请求优化 +- 网络状态检测和适配 +- CDN加速配置 +- 下载断点续传支持 + +## 3. JavaScript与App双向调用接口 + +TSGame应用通过JS Bridge实现WebView(H5游戏)与原生Android/HarmonyOS应用之间的双向通信。由于接口数量众多且参数复杂,已将所有JavaScript与App双向调用的接口详细说明分离到独立文档中。 + +### 3.1 接口详解文档 + +**📖 详细接口说明请参考:[TSGame_JSBridge_接口详解.md](./TSGame_JSBridge_接口详解.md)** + +该文档包含以下完整内容: + +#### 3.1.1 WebView调用App接口 +- **游戏相关接口**:SwitchOverGameData、getGameinstall、downloadGame等 +- **用户信息接口**:getUserInfo、updateUserCoins等 +- **分享接口**:friendsSharetypeUrlToptitleDescript、getSharePlatforms等 +- **媒体播放接口**:mediaTypeAudio、mediaTypeVideo等 +- **设备信息接口**:getDeviceInfo、getPhoneInfo等 +- **网络请求接口**:httpRequest等 +- **系统功能接口**:showToast、showDialog、openUrl等 + +#### 3.1.2 App调用WebView接口 +- **页面生命周期**:onPageResume、onPagePause、onPageDestroy +- **网络状态通知**:onNetworkChanged +- **数据更新通知**:onUserDataChanged + +#### 3.1.3 数据结构定义 +- **基础数据结构**:BaseResponse、Position、Size等 +- **游戏数据结构**:GameInfo、GameProgress等 +- **分享数据结构**:ShareConfig、ShareResult等 +- **媒体数据结构**:AudioInfo、VideoInfo等 + +#### 3.1.4 完整的接口参考 +- 每个接口的作用、调用时机、参数结构、字段说明 +- TypeScript类型定义和JSON数据格式 +- 实际使用示例和错误处理 +- 错误码定义和注意事项 + +### 3.2 HarmonyOS适配要点 + +基于Android工程webviewActivity.java和NewwebviewActivity.java代码完整分析,HarmonyOS版本的JS Bridge实现需要注意以下几点: + +#### 3.2.1 接口兼容性 +- 所有接口方法名、参数格式与Android工程代码保持完全一致 +- 保持与现有H5游戏的无缝兼容 +- 接口调用方式和数据格式保持不变 + +#### 3.2.2 权限适配 +- 相机、定位、通讯录等接口需要动态申请权限 +- 适配HarmonyOS 5.0的精细化权限控制 +- 实现权限申请失败的降级处理 + +#### 3.2.3 性能优化 +- 避免频繁调用Bridge接口 +- 大量数据传输考虑分批处理 +- 适当使用本地缓存减少接口调用 + +#### 3.2.4 异常处理 +- 所有Bridge调用都是异步的,需要适当的超时处理 +- 网络中断时部分接口可能失效 +- 提供友好的错误提示和重试机制 + +## 4. 总结 + +TSGame HarmonyOS版本通过完整的JavaScript Bridge接口体系,实现了WebView与原生应用的深度集成。本文档详细说明了所有40多个双向接口的用法、参数格式和调用时机,为HarmonyOS版本的开发提供了完整的技术参考。 + +所有接口的方法名、参数格式均与Android工程保持完全一致,确保了跨平台的兼容性和一致性。开发者可以基于这些接口实现丰富的原生功能集成。 + +## 8. 应用和游戏更新机制 + +TSGame支持应用APK/APP和游戏ZIP资源的自动更新机制,确保用户始终使用最新版本的应用和游戏内容。HarmonyOS版本需要完全实现与Android一致的更新逻辑。 + +### 8.1 更新机制概述 + +#### 8.1.1 更新类型 + +**应用更新(APP级别):** +- 更新应用本身的代码和核心功能 +- 涉及应用包(.hap文件)的下载和安装 +- 需要用户确认和重启应用 +- 对应Android的APK更新 + +**游戏更新(资源级别):** +- 更新游戏资源文件(HTML、CSS、JS、图片等) +- 涉及ZIP包的下载、解压和替换 +- 支持静默更新,无需用户干预 +- 不需要重启应用,热更新生效 + +#### 8.1.2 版本控制策略 + +更新机制采用分层配置的版本控制策略: + +```typescript +interface VersionConfig { + // 应用版本信息 + app_version: string; // 应用版本号,如"3.6.3" + app_download: string; // 应用下载URL + app_size: string; // 应用包大小 + + // 游戏版本信息 + game_version: string; // 游戏版本号,如"2.1.0" + game_download: string; // 游戏ZIP包下载URL + game_size: string; // 游戏包大小 + + // 显示信息 + showmessage: string; // 版本更新说明文本 +} +``` + +### 8.2 版本检测流程 + +#### 8.2.1 启动时版本检测 + +```typescript +class VersionChecker { + + /** + * 启动时执行版本检测流程 + */ + public async checkVersionOnLaunch(): Promise { + try { + // 1. 获取本地版本信息 + const localVersions = await this.getLocalVersionInfo(); + + // 2. 获取服务器版本配置 + const serverConfig = await this.fetchServerVersionConfig(); + + // 3. 比较版本并决定更新策略 + const updatePlan = this.compareVersions(localVersions, serverConfig); + + // 4. 执行相应的更新流程 + await this.executeUpdatePlan(updatePlan); + + } catch (error) { + console.error('版本检测失败:', error); + // 失败时继续启动,使用本地版本 + this.startGameWithLocalVersion(); + } + } + + /** + * 获取本地版本信息 + */ + private async getLocalVersionInfo(): Promise { + const preferences = dataPreferences.getPreferences(getContext(), 'version_prefs'); + + return { + appVersion: await preferences.get('app_version', ''), + gameVersion: await preferences.get('game_version', ''), + gameId: await preferences.get('game_id', ''), + lastUpdateTime: await preferences.get('last_update_time', 0) + }; + } + + /** + * 获取服务器版本配置 + */ + private async fetchServerVersionConfig(): Promise { + const gameData = this.getCurrentGameData(); + const configUrl = this.buildConfigUrl(gameData); + + const response = await fetch(configUrl + '?t=' + Date.now()); + if (!response.ok) { + throw new Error(`配置获取失败: ${response.status}`); + } + + return response.json(); + } + + /** + * 比较版本并生成更新计划 + */ + private compareVersions(local: LocalVersionInfo, server: VersionConfig): UpdatePlan { + const plan: UpdatePlan = { + needAppUpdate: false, + needGameUpdate: false, + appUpdateInfo: null, + gameUpdateInfo: null + }; + + // 比较应用版本 + if (this.isVersionNewer(server.app_version, local.appVersion)) { + plan.needAppUpdate = true; + plan.appUpdateInfo = { + version: server.app_version, + downloadUrl: server.app_download, + size: server.app_size, + message: server.showmessage + }; + } + + // 比较游戏版本 + if (this.isVersionNewer(server.game_version, local.gameVersion)) { + plan.needGameUpdate = true; + plan.gameUpdateInfo = { + version: server.game_version, + downloadUrl: server.game_download, + size: server.game_size, + message: server.showmessage + }; + } + + return plan; + } +} +``` + +#### 8.2.2 版本比较逻辑 + +```typescript +class VersionComparator { + + /** + * 比较两个版本号,判断newVersion是否比oldVersion新 + */ + public static isVersionNewer(newVersion: string, oldVersion: string): boolean { + if (!newVersion || !oldVersion) { + return !!newVersion && !oldVersion; + } + + const newParts = newVersion.split('.').map(Number); + const oldParts = oldVersion.split('.').map(Number); + const maxLength = Math.max(newParts.length, oldParts.length); + + for (let i = 0; i < maxLength; i++) { + const newPart = newParts[i] || 0; + const oldPart = oldParts[i] || 0; + + if (newPart > oldPart) return true; + if (newPart < oldPart) return false; + } + + return false; + } + + /** + * 获取版本比较结果码(用于JS Bridge接口) + * @returns "1" - 本地版本高于服务器版本,"0" - 本地版本低于或等于服务器版本 + */ + public static getCompareCode(localVersion: string, serverVersion: string): string { + return this.isVersionNewer(localVersion, serverVersion) ? "1" : "0"; + } +} +``` + +### 8.3 应用更新实现 + +#### 8.3.1 应用更新流程 + +```typescript +class AppUpdater { + + /** + * 执行应用更新 + */ + public async updateApp(updateInfo: AppUpdateInfo): Promise { + try { + // 1. 显示更新确认对话框 + const userConfirmed = await this.showUpdateConfirmDialog(updateInfo); + if (!userConfirmed) { + return; + } + + // 2. 显示下载进度界面 + this.showDownloadProgress(); + + // 3. 下载应用包 + const appPackagePath = await this.downloadAppPackage(updateInfo.downloadUrl); + + // 4. 验证包完整性 + await this.verifyPackageIntegrity(appPackagePath); + + // 5. 启动安装流程 + await this.installAppPackage(appPackagePath); + + } catch (error) { + console.error('应用更新失败:', error); + this.showUpdateErrorDialog(error.message); + } + } + + /** + * 显示更新确认对话框 + */ + private async showUpdateConfirmDialog(updateInfo: AppUpdateInfo): Promise { + return new Promise((resolve) => { + AlertDialog.show({ + title: '发现新版本', + message: `版本 ${updateInfo.version}\n大小: ${updateInfo.size}\n\n${updateInfo.message}`, + primaryButton: { + value: '立即更新', + action: () => resolve(true) + }, + secondaryButton: { + value: '稍后更新', + action: () => resolve(false) + } + }); + }); + } + + /** + * 下载应用包 + */ + private async downloadAppPackage(downloadUrl: string): Promise { + const downloader = new FileDownloader(); + const fileName = `tsgame_update_${Date.now()}.hap`; + const downloadPath = getContext().filesDir + '/downloads/' + fileName; + + // 创建下载目录 + await fileIo.mkdir(downloadPath.substring(0, downloadPath.lastIndexOf('/'))); + + return new Promise((resolve, reject) => { + downloader.download(downloadUrl, downloadPath, { + onProgress: (progress: number, total: number) => { + this.updateDownloadProgress(progress, total); + }, + onSuccess: () => { + console.log('应用包下载完成:', downloadPath); + resolve(downloadPath); + }, + onError: (error: Error) => { + console.error('应用包下载失败:', error); + reject(error); + } + }); + }); + } + + /** + * 安装应用包 + */ + private async installAppPackage(packagePath: string): Promise { + try { + // HarmonyOS应用安装API调用 + const bundleInstaller = installer.getBundleInstaller(); + + await bundleInstaller.install([packagePath], { + userId: 100, + installFlag: installer.InstallFlag.REPLACE_EXISTING + }); + + console.log('应用安装成功'); + + // 安装成功后重启应用 + this.restartApp(); + + } catch (error) { + console.error('应用安装失败:', error); + throw new Error('安装失败,请手动安装'); + } + } +} +``` + +#### 8.3.2 下载进度管理 + +```typescript +class DownloadProgressManager { + private progressDialog: CustomDialogController | null = null; + + /** + * 显示下载进度界面 + */ + public showDownloadProgress(): void { + this.progressDialog = new CustomDialogController({ + builder: DownloadProgressDialog({ + progress: 0, + downloadedSize: '0 MB', + totalSize: '0 MB', + onCancel: () => this.cancelDownload() + }), + autoCancel: false, + customStyle: true + }); + + this.progressDialog.open(); + } + + /** + * 更新下载进度 + */ + public updateProgress(downloaded: number, total: number): void { + if (!this.progressDialog) return; + + const progress = Math.floor((downloaded / total) * 100); + const downloadedMB = (downloaded / 1024 / 1024).toFixed(2); + const totalMB = (total / 1024 / 1024).toFixed(2); + + // 更新进度界面显示 + this.progressDialog.update({ + progress: progress, + downloadedSize: `${downloadedMB} MB`, + totalSize: `${totalMB} MB` + }); + } + + /** + * 隐藏下载进度界面 + */ + public hideDownloadProgress(): void { + if (this.progressDialog) { + this.progressDialog.close(); + this.progressDialog = null; + } + } +} +``` + +### 8.4 游戏资源更新实现 + +#### 8.4.1 游戏资源更新流程 + +```typescript +class GameResourceUpdater { + + /** + * 执行游戏资源更新 + */ + public async updateGameResources(updateInfo: GameUpdateInfo): Promise { + try { + // 1. 静默下载游戏ZIP包 + this.showUpdateProgress('正在下载游戏资源...'); + const zipFilePath = await this.downloadGameZip(updateInfo.downloadUrl); + + // 2. 验证ZIP包完整性 + this.showUpdateProgress('正在验证资源包...'); + await this.verifyZipIntegrity(zipFilePath); + + // 3. 备份当前游戏资源 + this.showUpdateProgress('正在备份当前资源...'); + await this.backupCurrentGameResources(); + + // 4. 解压新的游戏资源 + this.showUpdateProgress('正在解压游戏资源...'); + await this.extractGameZip(zipFilePath); + + // 5. 更新本地版本信息 + await this.updateLocalVersionInfo(updateInfo.version); + + // 6. 清理临时文件 + await this.cleanupTempFiles(zipFilePath); + + console.log('游戏资源更新完成'); + this.hideUpdateProgress(); + + } catch (error) { + console.error('游戏资源更新失败:', error); + + // 失败时恢复备份 + await this.restoreBackupResources(); + this.showUpdateErrorDialog('游戏资源更新失败,已恢复原始资源'); + } + } + + /** + * 下载游戏ZIP包 + */ + private async downloadGameZip(downloadUrl: string): Promise { + const downloader = new FileDownloader(); + const fileName = `game_${Date.now()}.zip`; + const downloadPath = getContext().filesDir + '/temp/' + fileName; + + // 创建临时目录 + await fileIo.mkdir(downloadPath.substring(0, downloadPath.lastIndexOf('/'))); + + return new Promise((resolve, reject) => { + downloader.download(downloadUrl, downloadPath, { + onProgress: (progress: number, total: number) => { + const percent = Math.floor((progress / total) * 100); + this.updateProgressText(`下载进度: ${percent}%`); + }, + onSuccess: () => { + console.log('游戏ZIP包下载完成:', downloadPath); + resolve(downloadPath); + }, + onError: (error: Error) => { + console.error('游戏ZIP包下载失败:', error); + reject(error); + } + }); + }); + } + + /** + * 解压游戏ZIP包 + */ + private async extractGameZip(zipFilePath: string): Promise { + const gameResourceDir = this.getGameResourceDirectory(); + + // 删除旧的游戏资源 + if (await fileIo.access(gameResourceDir)) { + await fileIo.rmdir(gameResourceDir, true); + } + + // 创建游戏资源目录 + await fileIo.mkdir(gameResourceDir, true); + + // 解压ZIP包到游戏资源目录 + const zipExtractor = new ZipExtractor(); + await zipExtractor.extract(zipFilePath, gameResourceDir, { + onProgress: (extractedFiles: number, totalFiles: number) => { + const percent = Math.floor((extractedFiles / totalFiles) * 100); + this.updateProgressText(`解压进度: ${percent}%`); + } + }); + + console.log('游戏资源解压完成'); + } + + /** + * 备份当前游戏资源 + */ + private async backupCurrentGameResources(): Promise { + const gameResourceDir = this.getGameResourceDirectory(); + const backupDir = this.getGameBackupDirectory(); + + if (await fileIo.access(gameResourceDir)) { + // 删除旧备份 + if (await fileIo.access(backupDir)) { + await fileIo.rmdir(backupDir, true); + } + + // 创建新备份 + await this.copyDirectory(gameResourceDir, backupDir); + console.log('游戏资源备份完成'); + } + } + + /** + * 恢复备份资源 + */ + private async restoreBackupResources(): Promise { + const gameResourceDir = this.getGameResourceDirectory(); + const backupDir = this.getGameBackupDirectory(); + + if (await fileIo.access(backupDir)) { + // 删除损坏的资源 + if (await fileIo.access(gameResourceDir)) { + await fileIo.rmdir(gameResourceDir, true); + } + + // 恢复备份资源 + await this.copyDirectory(backupDir, gameResourceDir); + console.log('游戏资源恢复完成'); + } + } +} +``` + +#### 8.4.2 ZIP包处理工具 + +```typescript +class ZipExtractor { + + /** + * 解压ZIP文件 + */ + public async extract(zipPath: string, targetDir: string, options?: ExtractOptions): Promise { + return new Promise((resolve, reject) => { + // 使用HarmonyOS的压缩解压API + const decompressor = zlib.createDecompressor(); + + decompressor.decompress(zipPath, targetDir, (error, result) => { + if (error) { + reject(new Error(`解压失败: ${error.message}`)); + return; + } + + if (options?.onProgress) { + options.onProgress(result.extractedFiles, result.totalFiles); + } + + resolve(); + }); + }); + } + + /** + * 验证ZIP包完整性 + */ + public async verifyIntegrity(zipPath: string): Promise { + try { + const validator = zlib.createValidator(); + const result = await validator.validate(zipPath); + return result.isValid; + } catch (error) { + console.error('ZIP包验证失败:', error); + return false; + } + } +} +``` + +### 8.5 文件下载器实现 + +#### 8.5.1 网络下载管理 + +```typescript +class FileDownloader { + private downloadTask: request.DownloadTask | null = null; + + /** + * 下载文件 + */ + public download(url: string, filePath: string, callbacks: DownloadCallbacks): void { + const downloadConfig: request.DownloadConfig = { + url: url, + filePath: filePath, + enableMetered: true, + enableRoaming: true, + description: '正在下载更新包...', + networkType: request.NETWORK_WIFI | request.NETWORK_MOBILE + }; + + request.downloadFile(getContext(), downloadConfig).then((task) => { + this.downloadTask = task; + + // 监听下载进度 + task.on('progress', (receivedSize: number, totalSize: number) => { + callbacks.onProgress?.(receivedSize, totalSize); + }); + + // 监听下载完成 + task.on('complete', () => { + callbacks.onSuccess?.(); + this.downloadTask = null; + }); + + // 监听下载失败 + task.on('fail', (error: number) => { + const errorMsg = this.getDownloadErrorMessage(error); + callbacks.onError?.(new Error(errorMsg)); + this.downloadTask = null; + }); + + }).catch((error) => { + callbacks.onError?.(error); + }); + } + + /** + * 取消下载 + */ + public cancel(): void { + if (this.downloadTask) { + this.downloadTask.delete((error) => { + if (error) { + console.error('取消下载失败:', error); + } else { + console.log('下载已取消'); + } + }); + this.downloadTask = null; + } + } + + /** + * 获取下载错误信息 + */ + private getDownloadErrorMessage(errorCode: number): string { + const errorMessages = { + [request.ERROR_CANNOT_RESUME]: '无法恢复下载', + [request.ERROR_DEVICE_NOT_FOUND]: '设备未找到', + [request.ERROR_FILE_ALREADY_EXISTS]: '文件已存在', + [request.ERROR_FILE_ERROR]: '文件错误', + [request.ERROR_HTTP_DATA_ERROR]: 'HTTP数据错误', + [request.ERROR_INSUFFICIENT_SPACE]: '存储空间不足', + [request.ERROR_TOO_MANY_REDIRECTS]: '重定向次数过多', + [request.ERROR_UNHANDLED_HTTP_CODE]: '未处理的HTTP状态码', + [request.ERROR_UNKNOWN]: '未知错误' + }; + + return errorMessages[errorCode] || `下载失败,错误代码: ${errorCode}`; + } +} +``` + +### 8.6 更新状态管理 + +#### 8.6.1 更新进度界面 + +```typescript +@CustomDialog +struct DownloadProgressDialog { + @State progress: number = 0; + @State downloadedSize: string = '0 MB'; + @State totalSize: string = '0 MB'; + @State statusText: string = '正在下载...'; + @State errorMessage: string = ''; + onCancel?: () => void; + + build() { + Column({ space: 20 }) { + // 标题 + Text('更新下载') + .fontSize(18) + .fontWeight(FontWeight.Medium) + .fontColor(Color.Black) + + // 进度条 + Progress({ + value: this.progress, + total: 100, + type: ProgressType.Linear + }) + .width('100%') + .height(10) + .color(Color.Blue) + .backgroundColor(Color.Gray) + + // 进度文本 + Row() { + Text(`${this.progress}%`) + .fontSize(14) + .fontColor(Color.Gray) + + Spacer() + + Text(`${this.downloadedSize} / ${this.totalSize}`) + .fontSize(14) + .fontColor(Color.Gray) + } + .width('100%') + + // 状态文本 + Text(this.statusText) + .fontSize(14) + .fontColor(Color.Gray) + .textAlign(TextAlign.Center) + + // 错误信息 + if (this.errorMessage.trim() !== '') { + Text(this.errorMessage) + .fontSize(14) + .fontColor(Color.Red) + .textAlign(TextAlign.Center) + } + + // 取消按钮 + Button('取消下载') + .width('100%') + .height(40) + .backgroundColor(Color.Gray) + .onClick(() => { + this.onCancel?.(); + }) + } + .width('80%') + .padding(20) + .backgroundColor(Color.White) + .borderRadius(10) + } +} +``` + +## 9. 项目风险评估与解决方案 + +### 9.1 高风险项 + +#### 9.1.1 微信SDK集成 (风险等级: 高) +**问题描述**: 微信SDK可能不支持HarmonyOS平台 +**影响评估**: +- 微信登录功能无法实现 +- 微信分享功能受限 +- 用户体验下降 + +**解决方案**: +1. **WebView内嵌登录**: 使用WebView内嵌微信网页版登录 +2. **华为账号优先**: 将华为账号作为主要登录方式 +3. **预留接口**: 保留微信SDK接口,待官方支持后再集成 +4. **系统分享**: 使用HarmonyOS系统级分享功能替代 + +#### 9.1.2 双WebView架构性能 (风险等级: 中) +**问题描述**: 多个WebView可能导致内存占用过高 +**影响评估**: +- 应用内存占用增加 +- 系统性能下降 +- 可能出现OOM崩溃 + +**解决方案**: +1. **WebView复用机制**: 实现WebView池化管理 +2. **及时释放**: 及时释放不活跃的WebView资源 +3. **资源优化**: 优化H5资源加载策略 +4. **内存监控**: 建立内存使用监控机制 + +#### 9.1.3 HarmonyOS 5.0新API适配 (风险等级: 中) +**问题描述**: 新版本API可能存在兼容性问题或文档不完善 +**影响评估**: +- 新特性无法正常使用 +- 向下兼容性问题 +- 开发周期延长 + +**解决方案**: +1. **官方文档跟踪**: 及时关注华为官方文档更新 +2. **兼容性测试**: 建立API兼容性测试用例 +3. **技术支持**: 保持与华为技术支持的沟通 +4. **降级方案**: 准备API降级方案确保向下兼容 + +### 9.2 中风险项 + +#### 9.2.1 华为地图SDK集成 +**解决方案**: 参考华为官方文档,建立标准集成流程 + +#### 9.2.2 版本更新机制 +**解决方案**: 参考HarmonyOS应用更新最佳实践 + +#### 9.2.3 性能优化 +**解决方案**: 建立性能监控体系,持续优化 + +## 10. 团队分工与技能要求 + +### 10.1 核心开发团队 (3-5人) + +#### 10.1.1 架构师/技术负责人 (1人) +**职责**: +- 技术架构设计和决策 +- 核心模块开发 +- 代码审查和质量把控 +- 技术难点攻关 + +**技能要求**: +- 精通HarmonyOS开发 (熟悉5.0新特性) +- 丰富的移动应用架构经验 +- 熟悉WebView和JS Bridge技术 +- 了解HarmonyOS 5.0性能优化技术 + +#### 10.1.2 前端开发/UI开发 (1人) +**职责**: +- WebView组件开发 +- 用户界面实现 +- 用户体验优化 +- 前端性能优化 + +**技能要求**: +- 熟练掌握ArkTS/TypeScript +- 熟悉HarmonyOS UI框架 (包括5.0新特性) +- 有WebView开发经验 +- 了解HarmonyOS 5.0 UI渲染优化 + +#### 10.1.3 后端集成/API开发 (1-2人) +**职责**: +- JS Bridge API实现 +- 第三方SDK集成 +- 系统服务集成 +- 网络和存储功能 + +**技能要求**: +- 熟悉HarmonyOS系统API (特别是5.0新增API) +- 有移动应用API开发经验 +- 了解第三方SDK集成 +- 掌握HarmonyOS 5.0安全特性 + +#### 10.1.4 测试工程师 (1人) +**职责**: +- 功能测试和验证 +- 性能测试 +- 兼容性测试 +- Bug跟踪和质量保证 + +**技能要求**: +- 熟悉移动应用测试 +- 了解HarmonyOS测试工具 (包括5.0新测试框架) +- 有自动化测试经验更佳 +- 掌握跨版本兼容性测试方法 + +## 11. 开发里程碑与交付物 + +### 11.1 里程碑1: 基础框架完成 (第2周末) +**交付物**: +- 可运行的项目骨架 +- 双WebView容器实现 +- 基础目录结构 +- 开发环境文档 + +### 11.2 里程碑2: 核心功能完成 (第5周末) +**交付物**: +- 资源下载和管理功能 +- WebView加载和切换 +- 基础JS Bridge API +- 功能演示版本 + +### 11.3 里程碑3: 功能集成完成 (第7周末) +**交付物**: +- 所有第三方SDK集成 +- 完整的API接口 +- 媒体和定位功能 +- Beta测试版本 + +### 11.4 里程碑4: 产品就绪 (第10周末) +**交付物**: +- 完整功能的应用 +- 性能优化版本 +- 完整测试报告 +- 发布准备材料 + +## 12. Git版本管理规范 + +### 12.1 Git工作流策略 + +采用**Git Flow**工作流模式,确保代码管理的规范性和可追溯性。 + +#### 12.1.1 分支策略 + +``` +master (主分支) +├── develop (开发分支) +│ ├── feature/user-auth # 功能分支:用户认证 +│ ├── feature/webview-bridge # 功能分支:WebView桥接 +│ ├── feature/media-manager # 功能分支:媒体管理 +│ └── feature/location-service # 功能分支:定位服务 +├── release/v1.0.0 # 发布分支 +└── hotfix/critical-bug-fix # 热修复分支 +``` + +**分支说明**: +- **master**: 生产环境分支,只接受release和hotfix的合并 +- **develop**: 开发主分支,集成所有feature分支 +- **feature/***: 功能开发分支,从develop分出,完成后合并回develop +- **release/***: 发布准备分支,从develop分出,用于发布前的bug修复 +- **hotfix/***: 紧急修复分支,从master分出,修复后合并到master和develop + +#### 12.1.2 分支命名规范 + +```bash +# 功能分支 +feature/模块名-功能描述 +例:feature/auth-wechat-login + feature/webview-js-bridge + feature/media-audio-record + +# 发布分支 +release/版本号 +例:release/v1.0.0 + release/v1.1.0 + +# 热修复分支 +hotfix/问题描述 +例:hotfix/webview-crash-fix + hotfix/login-timeout-issue +``` + +#### 12.1.3 提交消息规范 + +```bash +(): + +# type类型: +feat: 新功能 +fix: 修复bug +docs: 文档更新 +style: 代码格式调整 +refactor: 代码重构 +test: 测试相关 +chore: 构建过程或辅助工具的变动 + +# 示例: +feat(webview): 实现双WebView架构 +fix(bridge): 修复JS Bridge通信异常 +docs(api): 更新API接口文档 +``` + +### 12.2 代码审查规范 + +1. **必须审查**: 所有PR必须经过代码审查 +2. **审查人员**: 至少需要一名高级开发人员审查 +3. **审查内容**: 代码质量、性能、安全性、规范性 +4. **合并条件**: 审查通过且CI/CD通过后方可合并 + +## 13. 最佳实践和注意事项 + +### 13.1 性能优化最佳实践 + +1. **WebView优化**: + - 使用WebView池化管理 + - 及时释放不使用的WebView + - 优化JS Bridge调用频率 + +2. **内存管理**: + - 监控内存使用情况 + - 及时清理缓存数据 + - 避免内存泄漏 + +3. **网络优化**: + - 使用CDN加速资源下载 + - 实现断点续传机制 + - 合理使用缓存策略 + +### 13.2 安全最佳实践 + +1. **数据安全**: + - 敏感数据加密存储 + - 网络传输使用HTTPS + - 验证下载包完整性 + +2. **权限管理**: + - 最小权限原则 + - 动态权限申请 + - 权限使用说明 + +3. **代码安全**: + - 代码混淆保护 + - 防止逆向工程 + - 安全审计 \ No newline at end of file diff --git a/TSGame_应用启动流程详解.md b/TSGame_应用启动流程详解.md new file mode 100644 index 0000000..b12d26e --- /dev/null +++ b/TSGame_应用启动流程详解.md @@ -0,0 +1,2535 @@ +# TSGame 应用启动流程详解 + +## 目录 + +1. [概述](#概述) +2. [启动流程时序](#启动流程时序) +3. [远程配置文件管理](#远程配置文件管理) + - [3.1 配置文件结构](#31-配置文件结构) + - [3.2 配置参数获取逻辑](#32-配置参数获取逻辑) + - [3.3 配置属性详解](#33-配置属性详解) + - [3.4 应用升级验证详解](#34-应用升级验证详解) + - [3.5 下载地址获取详解](#35-下载地址获取详解) + - [3.6 解压路径和启动路径详解](#36-解压路径和启动路径详解) + - [3.7 大厅跳转子游戏的具体逻辑详解](#37-大厅跳转子游戏的具体逻辑详解) +4. [资源目录和解压路径](#资源目录和解压路径) + - [4.1 文件系统结构](#41-文件系统结构) + - [4.2 ZIP包解压路径规范](#42-zip包解压路径规范) +5. [大厅启动逻辑](#大厅启动逻辑) + - [5.1 大厅资源初始化](#51-大厅资源初始化) + - [5.2 大厅WebView启动](#52-大厅webview启动) +6. [子游戏跳转启动逻辑](#子游戏跳转启动逻辑) + - [6.1 子游戏资源管理](#61-子游戏资源管理) + - [6.2 子游戏WebView切换](#62-子游戏webview切换) + - [6.3 子游戏启动流程的配置属性读取详解](#63-子游戏启动流程的配置属性读取详解) + - [6.4 子游戏启动路径的完整解析](#64-子游戏启动路径的完整解析) +7. [版本检查和更新流程](#版本检查和更新流程) +8. [启动异常处理](#启动异常处理) + +--- + +## 概述 + +TSGame HarmonyOS应用采用分阶段启动流程,通过远程配置文件驱动,支持大厅和子游戏的动态资源管理。应用启动过程包括配置文件获取、资源下载解压、WebView初始化和页面加载等关键步骤。 + +### 核心特性 + +- **远程配置驱动**:通过七牛云CDN获取分层配置 +- **双WebView架构**:大厅和子游戏独立管理 +- **动态资源更新**:支持ZIP包热更新 +- **版本检查机制**:自动检测和更新资源版本 +- **降级兼容**:配置获取失败时使用本地缓存 + +--- + +## 启动流程时序 + +### 完整启动时序图 + +``` +用户启动App + ↓ +EntryAbility.onCreate() + ↓ +初始化基础管理器 + ↓ +ConfigManager.loadStartupConfig() ←→ 加载本地启动配置 + ↓ +检测远程配置文件 ←→ 七牛云CDN + ↓ ↓ +配置文件存在? 下载配置文件 + ↓ (是) ↓ +解析远程配置 校验文件格式 + ↓ ↓ +获取大厅ZIP包URL 保存到本地缓存 + ↓ +下载大厅ZIP包 ←→ CDN服务器 + ↓ ↓ +解压大厅资源 验证ZIP包完整性 + ↓ +初始化大厅WebView + ↓ +加载大厅HTML页面 + ↓ +大厅显示完成 + ↓ +用户点击子游戏 + ↓ +获取子游戏ZIP包URL + ↓ +验证子游戏ZIP包有效性 + ↓ +下载子游戏ZIP包 ←→ CDN服务器 + ↓ ↓ +解压子游戏资源 验证ZIP包完整性 + ↓ +初始化子游戏WebView + ↓ +加载子游戏HTML页面 + ↓ +子游戏启动完成 +``` + +### 启动阶段详解 + +#### 阶段1:应用初始化 + +```typescript +class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + console.log('TSGame应用启动'); + + // 1. 初始化基础服务 + this.initBaseServices(); + + // 2. 加载启动配置 + this.loadStartupConfig(); + + // 3. 启动配置检查流程 + this.startConfigCheckFlow(); + } + + private async initBaseServices(): Promise { + // 初始化文件管理器 + await FileManager.initialize(); + + // 初始化网络管理器 + await NetworkManager.initialize(); + + // 初始化配置管理器 + await ConfigManager.initialize(); + + // 初始化资源管理器 + await ResourceManager.initialize(); + } +} +``` + +#### 阶段2:配置文件检查 + +```typescript +class ConfigManager { + + /** + * 启动配置检查流程 + */ + public async startConfigCheckFlow(): Promise { + try { + // 1. 加载本地启动配置 + const localConfig = await this.loadLocalStartupConfig(); + + // 2. 获取远程配置文件 + const remoteConfig = await this.fetchRemoteConfig(); + + // 3. 比较并更新配置 + const needUpdate = this.compareConfigs(localConfig, remoteConfig); + + if (needUpdate) { + // 4. 更新本地配置缓存 + await this.updateLocalConfig(remoteConfig); + } + + // 5. 启动大厅初始化流程 + await this.startHallInitialization(remoteConfig); + + } catch (error) { + console.error('配置检查失败:', error); + // 降级到本地配置 + await this.fallbackToLocalConfig(); + } + } + + /** + * 获取远程配置文件 + */ + private async fetchRemoteConfig(): Promise { + const gameData = await this.getCurrentGameData(); + const configUrl = this.buildConfigUrl(gameData); + + console.log('请求配置文件URL:', configUrl); + + const response = await fetch(configUrl + '?t=' + Date.now(), { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'Cache-Control': 'no-cache' + }, + timeout: 10000 + }); + + if (!response.ok) { + throw new Error(`配置文件获取失败: ${response.status}`); + } + + const configData = await response.json(); + console.log('远程配置获取成功:', configData); + + return configData; + } +} +``` + +--- + +## 远程配置文件管理 + +### 3.1 配置文件结构 + +#### 配置文件完整JSON结构 + +```json +{ + "configVersion": "1.0.0", + "timestamp": 1688544000000, + "data": { + "app_download": "https://cdn.jxjygame.com/app/tsgame_v3.6.3.apk", + "app_version": "3.6.3", + "app_size": "25.6MB", + "game_download": "https://cdn.jxjygame.com/games/default_game.zip", + "game_version": "1.0.0", + "game_size": "12.3MB", + "url": "https://api.jxjygame.com", + "showmessage": "欢迎使用进贤聚友棋牌", + "agentlist": [ + { + "agentid": "agent001", + "agentname": "代理商A", + "url": "https://api-agent001.jxjygame.com", + "app_download": "https://cdn.jxjygame.com/app/agent001_v3.6.3.apk", + "app_version": "3.6.3", + "app_size": "25.8MB", + "game_download": "https://cdn.jxjygame.com/games/agent001_games.zip", + "game_version": "2.1.0", + "game_size": "15.2MB", + "showmessage": "代理商A定制版本", + "channellist": [ + { + "channelid": "channel001", + "channelname": "华为渠道", + "app_download": "https://cdn.jxjygame.com/app/huawei_v3.6.3.apk", + "app_version": "3.6.3", + "app_size": "25.9MB", + "game_download": "https://cdn.jxjygame.com/games/huawei_games.zip", + "game_version": "2.1.1", + "game_size": "15.5MB", + "showmessage": "华为渠道专版", + "marketlist": [ + { + "marketid": "huawei_appgallery", + "marketname": "华为应用市场", + "app_download": "https://cdn.jxjygame.com/app/huawei_market_v3.6.4.apk", + "app_version": "3.6.4", + "app_size": "26.1MB", + "game_download": "https://cdn.jxjygame.com/games/huawei_market_games.zip", + "game_version": "2.1.2", + "game_size": "15.8MB", + "showmessage": "华为应用市场版本" + } + ] + } + ] + } + ] + } +} +``` + +#### 配置层级说明 + +配置文件采用四级层次结构,支持参数覆盖: + +1. **全局配置** (data根级别) - 最低优先级 +2. **代理商配置** (agentlist) - 覆盖全局配置 +3. **渠道配置** (channellist) - 覆盖代理商配置 +4. **市场配置** (marketlist) - 最高优先级,覆盖所有上级配置 + +### 3.2 配置参数获取逻辑 + +#### 核心参数获取类 + +```typescript +/** + * 配置参数获取工具类 + * 严格按照Android版本的逻辑实现,支持分层参数覆盖 + */ +export class ConfigParameterHelper { + + /** + * 根据层级结构获取配置参数值 + * @param config 配置对象 + * @param paramName 参数名称 + * @param gameData 游戏数据上下文 + * @returns 参数值 + */ + public static getParameterValue(config: any, paramName: string, gameData: GameData): any { + const agentId = gameData.agentId; + const channelId = gameData.channelId; + const marketId = gameData.marketId; + + let paramValue = null; + + // 内部函数:遍历数组匹配key获取参数值 + const getParameterFromList = (arrayList: any[], keyName: string, keyValue: string): any => { + if (arrayList && keyName && keyValue) { + for (let i = 0; i < arrayList.length; i++) { + if (arrayList[i][keyName] === keyValue) { + // 如果找到匹配项且包含目标参数,更新参数值 + if (arrayList[i][paramName] !== undefined) { + paramValue = arrayList[i][paramName]; + } + return arrayList[i]; + } + } + } + return null; + }; + + // 检查配置数据是否存在 + if (!config || !config.data) { + return paramValue; + } + + // 1. 首先检查全局配置(最低优先级) + if (config.data[paramName] !== undefined) { + paramValue = config.data[paramName]; + } + + // 2. 按层级查找,后面的层级覆盖前面的:代理商 -> 渠道 -> 市场 + + // 代理商级别配置 + const agentConfig = getParameterFromList(config.data.agentlist, "agentid", agentId); + if (!agentConfig) { + return paramValue; // 如果找不到代理商配置,返回全局配置值 + } + + // 渠道级别配置 + const channelConfig = getParameterFromList(agentConfig.channellist, "channelid", channelId); + if (!channelConfig) { + return paramValue; // 如果找不到渠道配置,返回当前参数值 + } + + // 市场级别配置(最高优先级) + const marketConfig = getParameterFromList(channelConfig.marketlist, "marketid", marketId); + // 不管是否找到市场配置,都返回当前参数值(可能已被前面层级更新) + + return paramValue; + } + + /** + * 获取应用下载地址 + * 对应配置文件中的 app_download 属性 + */ + public static getAppDownloadUrl(config: any, gameData: GameData): string { + return this.getParameterValue(config, "app_download", gameData) || ""; + } + + /** + * 获取应用版本号 + * 对应配置文件中的 app_version 属性 + */ + public static getAppVersion(config: any, gameData: GameData): string { + return this.getParameterValue(config, "app_version", gameData) || ""; + } + + /** + * 获取游戏ZIP包下载地址 + * 对应配置文件中的 game_download 属性 + */ + public static getGameDownloadUrl(config: any, gameData: GameData): string { + return this.getParameterValue(config, "game_download", gameData) || ""; + } + + /** + * 获取游戏版本号 + * 对应配置文件中的 game_version 属性 + */ + public static getGameVersion(config: any, gameData: GameData): string { + return this.getParameterValue(config, "game_version", gameData) || ""; + } + + /** + * 获取服务器地址 + * 对应配置文件中的 url 属性 + */ + public static getServerUrl(config: any, gameData: GameData): string { + return this.getParameterValue(config, "url", gameData) || ""; + } + + /** + * 获取显示消息 + * 对应配置文件中的 showmessage 属性 + */ + public static getShowMessage(config: any, gameData: GameData): string { + return this.getParameterValue(config, "showmessage", gameData) || ""; + } +} + +/** + * 游戏数据上下文 + */ +export interface GameData { + agentId: string; // 代理商ID,从本地配置或启动参数获取 + channelId: string; // 渠道ID,从本地配置或启动参数获取 + marketId: string; // 市场ID,从本地配置或启动参数获取 +} +``` + +#### 配置参数获取示例 + +```typescript +// 配置参数获取的实际使用示例 +export class ConfigUsageExample { + + public static async demonstrateConfigUsage(): Promise { + // 1. 获取当前游戏数据上下文 + const gameData: GameData = { + agentId: "agent001", // 从本地存储或启动参数获取 + channelId: "channel001", // 从本地存储或启动参数获取 + marketId: "huawei_appgallery" // 从本地存储或启动参数获取 + }; + + // 2. 加载远程配置 + const config = await ConfigManager.fetchRemoteConfig(); + + // 3. 获取各种配置参数 + const appDownloadUrl = ConfigParameterHelper.getAppDownloadUrl(config, gameData); + // 实际获取到: "https://cdn.jxjygame.com/app/huawei_market_v3.6.4.apk" + + const appVersion = ConfigParameterHelper.getAppVersion(config, gameData); + // 实际获取到: "3.6.4" (市场级配置覆盖) + + const gameDownloadUrl = ConfigParameterHelper.getGameDownloadUrl(config, gameData); + // 实际获取到: "https://cdn.jxjygame.com/games/huawei_market_games.zip" + + const gameVersion = ConfigParameterHelper.getGameVersion(config, gameData); + // 实际获取到: "2.1.2" (市场级配置覆盖) + + const serverUrl = ConfigParameterHelper.getServerUrl(config, gameData); + // 实际获取到: "https://api-agent001.jxjygame.com" (代理商级配置) + + const showMessage = ConfigParameterHelper.getShowMessage(config, gameData); + // 实际获取到: "华为应用市场版本" (市场级配置覆盖) + + console.log('配置参数获取结果:'); + console.log(`App Download URL: ${appDownloadUrl}`); + console.log(`App Version: ${appVersion}`); + console.log(`Game Download URL: ${gameDownloadUrl}`); + console.log(`Game Version: ${gameVersion}`); + console.log(`Server URL: ${serverUrl}`); + console.log(`Show Message: ${showMessage}`); + } +} +``` + +#### 配置获取的优先级规则 + +1. **全局配置** (`data`根级别):作为默认值,优先级最低 +2. **代理商配置** (`agentlist[].`):覆盖全局配置中的同名属性 +3. **渠道配置** (`channellist[].`):覆盖代理商和全局配置中的同名属性 +4. **市场配置** (`marketlist[].`):最高优先级,覆盖所有上级配置中的同名属性 + +### 3.4 应用升级验证详解 + +#### 升级验证的具体配置属性 + +TSGame应用的升级验证基于以下配置属性的组合判断: + +```typescript +interface AppUpgradeValidation { + // 主要验证属性 + app_version: string; // 远程应用版本号 - 核心验证属性 + app_download: string; // 应用下载URL - 升级时获取新版本 + app_size: string; // 应用包大小 - 用于下载进度显示 + showmessage: string; // 版本更新说明 - 用户升级提示 + + // 辅助验证属性 + force_update?: boolean; // 强制更新标志 - 是否必须升级 + min_version?: string; // 最低支持版本 - 低于此版本强制升级 + update_priority?: number; // 更新优先级 - 控制更新推送频率 +} +``` + +#### 具体的升级验证逻辑 + +```typescript +export class AppUpgradeValidator { + + /** + * 验证应用是否需要升级 + * 主要读取配置属性:app_version、force_update、min_version + */ + public static async validateAppUpgrade(config: any, gameData: any): Promise { + // 1. 获取远程版本号 - 读取 app_version 属性 + const remoteVersion = ConfigParameterHelper.getAppVersion(config, gameData); + console.log(`远程应用版本: ${remoteVersion}`); + + // 2. 获取本地应用版本 + const localVersion = await DeviceInfo.getAppVersion(); + console.log(`本地应用版本: ${localVersion}`); + + // 3. 版本比较 - 核心验证逻辑 + const needUpdate = VersionComparator.isVersionNewer(remoteVersion, localVersion); + + // 4. 检查是否强制更新 - 读取 force_update 属性 + const forceUpdate = ConfigParameterHelper.getBooleanValue(config, gameData, 'force_update', false); + + // 5. 检查最低版本要求 - 读取 min_version 属性 + const minVersion = ConfigParameterHelper.getString(config, gameData, 'min_version', '1.0.0'); + const belowMinVersion = VersionComparator.isVersionOlder(localVersion, minVersion); + + return { + needUpdate: needUpdate || belowMinVersion, + forceUpdate: forceUpdate || belowMinVersion, + remoteVersion, + localVersion, + upgradeType: belowMinVersion ? 'critical' : (forceUpdate ? 'force' : 'optional') + }; + } + + /** + * 获取应用下载信息 + * 主要读取配置属性:app_download、app_size、showmessage + */ + public static getAppDownloadInfo(config: any, gameData: any): AppDownloadInfo { + return { + // 读取 app_download 属性 - 应用下载地址 + downloadUrl: ConfigParameterHelper.getAppDownloadUrl(config, gameData), + + // 读取 app_size 属性 - 应用包大小 + packageSize: ConfigParameterHelper.getAppSize(config, gameData), + + // 读取 showmessage 属性 - 更新说明 + upgradeMessage: ConfigParameterHelper.getShowMessage(config, gameData), + + // 其他下载相关属性 + md5Hash: ConfigParameterHelper.getString(config, gameData, 'app_md5', ''), + timeout: ConfigParameterHelper.getNumber(config, gameData, 'download_timeout', 300000) + }; + } +} +``` + +### 3.5 下载地址获取详解 + +#### 应用下载地址的具体获取 + +```typescript +export class DownloadUrlResolver { + + /** + * 获取应用下载地址 + * 配置属性:app_download + */ + public static getAppDownloadUrl(config: any, gameData: any): string { + // 按优先级读取 app_download 属性 + const downloadUrl = ConfigParameterHelper.getAppDownloadUrl(config, gameData); + + console.log(`应用下载地址配置路径解析:`); + console.log(`1. 尝试读取市场级别: marketlist[${gameData.marketid}].app_download`); + console.log(`2. 尝试读取渠道级别: channellist[${gameData.channelid}].app_download`); + console.log(`3. 尝试读取代理商级别: agentlist[${gameData.agentid}].app_download`); + console.log(`4. 尝试读取全局级别: data.app_download`); + console.log(`最终获取到的下载地址: ${downloadUrl}`); + + return downloadUrl; + } + + /** + * 获取大厅ZIP包下载地址 + * 配置属性:game_download(大厅使用相同的配置) + */ + public static getHallZipDownloadUrl(config: any, gameData: any): string { + // 大厅ZIP包使用 game_download 属性 + const hallZipUrl = ConfigParameterHelper.getGameDownloadUrl(config, gameData); + + console.log(`大厅ZIP包下载地址: ${hallZipUrl}`); + return hallZipUrl; + } + + /** + * 获取子游戏ZIP包下载地址 + * 配置属性:game_download + 游戏ID拼接 + */ + public static getGameZipDownloadUrl(config: any, gameData: any, gameId: string): string { + // 基础下载地址 + const baseDownloadUrl = ConfigParameterHelper.getGameDownloadUrl(config, gameData); + + // 拼接游戏ID构成完整下载地址 + const gameZipUrl = `${baseDownloadUrl}/${gameId}.zip`; + + console.log(`子游戏${gameId}的ZIP包下载地址: ${gameZipUrl}`); + return gameZipUrl; + } +} +``` + +### 3.6 解压路径和启动路径详解 + +#### 大厅ZIP解压路径详解 + +```typescript +export class HallPathResolver { + + /** + * 大厅ZIP包解压的完整路径规范 + */ + public static getHallPaths(): HallPathInfo { + const appRootPath = getContext().filesDir; + + return { + // 1. 大厅ZIP包下载临时路径 + downloadTempPath: `${appRootPath}/downloads/hall_temp.zip`, + + // 2. 大厅资源解压目标路径 + extractTargetPath: `${appRootPath}/game_resources/hall`, + + // 3. 大厅启动入口文件路径 + entryFilePath: `${appRootPath}/game_resources/hall/index.html`, + + // 4. 大厅资源验证路径 + versionFilePath: `${appRootPath}/game_resources/hall/version.txt`, + configFilePath: `${appRootPath}/game_resources/hall/config.json`, + + // 5. 大厅WebView加载URL + webViewLoadUrl: `file://${appRootPath}/game_resources/hall/index.html` + }; + } + + /** + * 大厅解压流程详解 + */ + public static async extractHallZip(zipFilePath: string): Promise { + const paths = this.getHallPaths(); + + console.log(`=== 大厅ZIP包解压流程 ===`); + console.log(`源文件: ${zipFilePath}`); + console.log(`目标路径: ${paths.extractTargetPath}`); + + // 1. 清理旧的大厅资源 + if (await fileIo.access(paths.extractTargetPath)) { + await fileIo.rmdir(paths.extractTargetPath, true); + console.log(`已清理旧大厅资源: ${paths.extractTargetPath}`); + } + + // 2. 创建解压目标目录 + await fileIo.mkdir(paths.extractTargetPath, true); + + // 3. 执行ZIP解压 + await ZipExtractor.extractToDirectory(zipFilePath, paths.extractTargetPath); + + // 4. 验证关键文件 + await this.validateHallFiles(paths); + + console.log(`大厅ZIP包解压完成,启动路径: ${paths.webViewLoadUrl}`); + } + + /** + * 验证大厅文件完整性 + */ + private static async validateHallFiles(paths: HallPathInfo): Promise { + const requiredFiles = [ + paths.entryFilePath, // index.html - 必须存在 + `${paths.extractTargetPath}/js/main.js`, // 主逻辑文件 + `${paths.extractTargetPath}/css/main.css` // 主样式文件 + ]; + + for (const filePath of requiredFiles) { + if (!await fileIo.access(filePath)) { + throw new Error(`大厅关键文件缺失: ${filePath}`); + } + } + + console.log(`大厅文件验证通过`); + } +} +``` + +#### 子游戏ZIP解压路径详解 + +```typescript +export class GamePathResolver { + + /** + * 子游戏ZIP包解压的完整路径规范 + */ + public static getGamePaths(gameId: string): GamePathInfo { + const appRootPath = getContext().filesDir; + + return { + // 1. 子游戏ZIP包下载临时路径 + downloadTempPath: `${appRootPath}/downloads/${gameId}_temp.zip`, + + // 2. 子游戏资源解压目标路径 + extractTargetPath: `${appRootPath}/game_resources/games/${gameId}`, + + // 3. 子游戏启动入口文件路径 + entryFilePath: `${appRootPath}/game_resources/games/${gameId}/index.html`, + + // 4. 子游戏资源验证路径 + versionFilePath: `${appRootPath}/game_resources/games/${gameId}/version.txt`, + configFilePath: `${appRootPath}/game_resources/games/${gameId}/game.json`, + + // 5. 子游戏WebView加载URL + webViewLoadUrl: `file://${appRootPath}/game_resources/games/${gameId}/index.html`, + + // 6. 子游戏资源子目录 + jsDir: `${appRootPath}/game_resources/games/${gameId}/js`, + cssDir: `${appRootPath}/game_resources/games/${gameId}/css`, + imagesDir: `${appRootPath}/game_resources/games/${gameId}/images`, + audioDir: `${appRootPath}/game_resources/games/${gameId}/audio` + }; + } + + /** + * 子游戏解压流程详解 + */ + public static async extractGameZip(zipFilePath: string, gameId: string): Promise { + const paths = this.getGamePaths(gameId); + + console.log(`=== 子游戏${gameId}的ZIP包解压流程 ===`); + console.log(`源文件: ${zipFilePath}`); + console.log(`目标路径: ${paths.extractTargetPath}`); + + // 1. 清理旧的游戏资源 + if (await fileIo.access(paths.extractTargetPath)) { + await fileIo.rmdir(paths.extractTargetPath, true); + console.log(`已清理旧游戏${gameId}资源: ${paths.extractTargetPath}`); + } + + // 2. 创建游戏目录结构 + await this.createGameDirectories(paths); + + // 3. 执行ZIP解压 + await ZipExtractor.extractToDirectory(zipFilePath, paths.extractTargetPath); + + // 4. 验证游戏文件 + await this.validateGameFiles(gameId, paths); + + console.log(`子游戏${gameId}解压完成,启动路径: ${paths.webViewLoadUrl}`); + } + + /** + * 创建游戏目录结构 + */ + private static async createGameDirectories(paths: GamePathInfo): Promise { + const directories = [ + paths.extractTargetPath, + paths.jsDir, + paths.cssDir, + paths.imagesDir, + paths.audioDir + ]; + + for (const dir of directories) { + await fileIo.mkdir(dir, true); + } + + console.log(`游戏目录结构创建完成`); + } + + /** + * 验证游戏文件完整性 + */ + private static async validateGameFiles(gameId: string, paths: GamePathInfo): Promise { + const requiredFiles = [ + paths.entryFilePath, // index.html - 游戏入口 + `${paths.jsDir}/game.js`, // 游戏主逻辑 + `${paths.cssDir}/game.css` // 游戏样式 + ]; + + for (const filePath of requiredFiles) { + if (!await fileIo.access(filePath)) { + throw new Error(`游戏${gameId}关键文件缺失: ${filePath}`); + } + } + + console.log(`游戏${gameId}文件验证通过`); + } +} +``` + +### 3.7 大厅跳转子游戏的具体逻辑详解 + +#### 跳转触发和参数传递 + +```typescript +export class HallGameSwitchController { + + /** + * 大厅跳转子游戏的完整流程 + * 这是从大厅点击游戏到子游戏启动的详细逻辑 + */ + public static async switchFromHallToGame(gameId: string, gameData: any): Promise { + try { + console.log(`=== 大厅跳转子游戏流程开始 ===`); + console.log(`目标游戏ID: ${gameId}`); + console.log(`游戏数据:`, gameData); + + // 第一步:在大厅WebView中接收跳转请求 + await this.handleHallGameClick(gameId, gameData); + + // 第二步:检查子游戏资源状态 + const resourceStatus = await this.checkGameResourceStatus(gameId); + + // 第三步:根据资源状态决定后续流程 + if (resourceStatus.needDownload) { + await this.downloadAndPrepareGame(gameId, resourceStatus); + } + + // 第四步:切换WebView并启动子游戏 + await this.switchWebViewToGame(gameId, gameData); + + console.log(`=== 大厅跳转子游戏流程完成 ===`); + + } catch (error) { + console.error(`大厅跳转子游戏失败:`, error); + await this.handleSwitchError(gameId, error); + } + } + + /** + * 第一步:处理大厅中的游戏点击事件 + */ + private static async handleHallGameClick(gameId: string, gameData: any): Promise { + console.log(`=== 第一步:处理大厅游戏点击 ===`); + + // 1. 在大厅WebView中触发JSBridge调用 + // 大厅JS代码会调用: window.WebViewJavascriptBridge.callHandler('SwitchOverGameData', {...}) + + // 2. 验证游戏参数 + this.validateGameSwitchParams(gameId, gameData); + + // 3. 记录跳转日志用于统计 + await Logger.logGameSwitch(gameId, 'hall_click', gameData); + + // 4. 显示切换加载界面 + await UIController.showGameSwitchLoading(gameId); + + console.log(`大厅游戏点击处理完成`); + } + + /** + * 第二步:检查子游戏资源状态 + */ + private static async checkGameResourceStatus(gameId: string): Promise { + console.log(`=== 第二步:检查游戏${gameId}资源状态 ===`); + + const paths = GamePathResolver.getGamePaths(gameId); + const config = await ConfigManager.getRemoteConfig(); + const gameData = await ConfigManager.getCurrentGameData(); + + // 1. 检查游戏目录是否存在 + const gameExists = await fileIo.access(paths.extractTargetPath); + console.log(`游戏目录存在: ${gameExists}`); + + if (!gameExists) { + return { + needDownload: true, + reason: 'game_not_exists', + downloadUrl: DownloadUrlResolver.getGameZipDownloadUrl(config, gameData, gameId) + }; + } + + // 2. 检查游戏版本是否需要更新 + const remoteVersion = ConfigParameterHelper.getGameVersion(config, gameData); + const localVersion = await this.getLocalGameVersion(gameId, paths); + + console.log(`远程游戏版本: ${remoteVersion}`); + console.log(`本地游戏版本: ${localVersion}`); + + const needUpdate = VersionComparator.isVersionNewer(remoteVersion, localVersion); + + if (needUpdate) { + return { + needDownload: true, + reason: 'version_update', + downloadUrl: DownloadUrlResolver.getGameZipDownloadUrl(config, gameData, gameId), + oldVersion: localVersion, + newVersion: remoteVersion + }; + } + + // 3. 验证游戏文件完整性 + const isValid = await this.validateGameIntegrity(gameId, paths); + + if (!isValid) { + return { + needDownload: true, + reason: 'file_corruption', + downloadUrl: DownloadUrlResolver.getGameZipDownloadUrl(config, gameData, gameId) + }; + } + + console.log(`游戏${gameId}资源检查通过,无需下载`); + return { + needDownload: false, + reason: 'ready', + launchUrl: paths.webViewLoadUrl + }; + } + + /** + * 第三步:下载并准备游戏资源(如果需要) + */ + private static async downloadAndPrepareGame(gameId: string, resourceStatus: GameResourceStatus): Promise { + console.log(`=== 第三步:下载并准备游戏${gameId}资源 ===`); + console.log(`下载原因: ${resourceStatus.reason}`); + console.log(`下载地址: ${resourceStatus.downloadUrl}`); + + const paths = GamePathResolver.getGamePaths(gameId); + + // 1. 显示下载进度界面 + await UIController.showGameDownloadProgress(gameId, resourceStatus); + + // 2. 下载游戏ZIP包 + await FileDownloader.downloadWithProgress( + resourceStatus.downloadUrl, + paths.downloadTempPath, + { + onProgress: (progress: number, total: number) => { + const percent = Math.floor((progress / total) * 100); + UIController.updateGameDownloadProgress(gameId, percent); + }, + timeout: 300000 // 5分钟超时 + } + ); + + console.log(`游戏${gameId}ZIP包下载完成: ${paths.downloadTempPath}`); + + // 3. 解压游戏资源 + await GamePathResolver.extractGameZip(paths.downloadTempPath, gameId); + + // 4. 清理临时文件 + await fileIo.unlink(paths.downloadTempPath); + + // 5. 隐藏下载进度界面 + await UIController.hideGameDownloadProgress(gameId); + + console.log(`游戏${gameId}资源准备完成`); + } + + /** + * 第四步:切换WebView并启动子游戏 + */ + private static async switchWebViewToGame(gameId: string, gameData: any): Promise { + console.log(`=== 第四步:切换WebView启动游戏${gameId} ===`); + + const paths = GamePathResolver.getGamePaths(gameId); + + // 1. 隐藏大厅WebView + await WebViewManager.hideHallWebView(); + console.log(`大厅WebView已隐藏`); + + // 2. 初始化子游戏WebView + await WebViewManager.initGameWebView(gameId); + console.log(`子游戏WebView初始化完成`); + + // 3. 配置子游戏WebView参数 + await this.configureGameWebView(gameId, gameData); + + // 4. 加载子游戏页面 + console.log(`开始加载游戏页面: ${paths.webViewLoadUrl}`); + await WebViewManager.loadGamePage(gameId, paths.webViewLoadUrl); + + // 5. 显示子游戏WebView + await WebViewManager.showGameWebView(gameId); + console.log(`子游戏WebView已显示`); + + // 6. 向子游戏传递启动参数 + await this.passGameStartupParams(gameId, gameData); + + // 7. 隐藏加载界面 + await UIController.hideGameSwitchLoading(); + + console.log(`游戏${gameId}启动完成`); + } + + /** + * 配置子游戏WebView的特定参数 + */ + private static async configureGameWebView(gameId: string, gameData: any): Promise { + const webView = WebViewManager.getGameWebView(gameId); + + // 1. 设置用户代理 + webView.setUserAgent(`TSGame-HarmonyOS/${await DeviceInfo.getAppVersion()} Game/${gameId}`); + + // 2. 设置JavaScript Bridge + await JSBridgeManager.setupGameBridge(gameId, webView); + + // 3. 注册游戏专用接口 + await this.registerGameSpecificHandlers(gameId, webView); + + console.log(`游戏${gameId}的WebView配置完成`); + } + + /** + * 向子游戏传递启动参数 + */ + private static async passGameStartupParams(gameId: string, gameData: any): Promise { + const webView = WebViewManager.getGameWebView(gameId); + + // 构造游戏启动参数 + const startupParams = { + gameId: gameId, + userId: gameData.userId, + userToken: gameData.userToken, + serverUrl: ConfigParameterHelper.getServerUrl(await ConfigManager.getRemoteConfig(), gameData), + fromPage: 'hall', + timestamp: Date.now(), + deviceInfo: await DeviceInfo.getBasicInfo() + }; + + // 通过JSBridge传递参数给游戏 + webView.callHandler('onGameInit', startupParams, (response) => { + console.log(`游戏${gameId}初始化回调:`, response); + }); + + console.log(`游戏${gameId}启动参数传递完成:`, startupParams); + } + + /** + * 获取本地游戏版本 + */ + private static async getLocalGameVersion(gameId: string, paths: GamePathInfo): Promise { + try { + if (await fileIo.access(paths.versionFilePath)) { + const versionContent = await fileIo.readText(paths.versionFilePath); + return versionContent.trim(); + } + } catch (error) { + console.warn(`读取游戏${gameId}版本失败:`, error); + } + return ''; + } + + /** + * 验证游戏文件完整性 + */ + private static async validateGameIntegrity(gameId: string, paths: GamePathInfo): Promise { + try { + // 检查关键文件是否存在 + const requiredFiles = [ + paths.entryFilePath, + `${paths.jsDir}/game.js`, + `${paths.cssDir}/game.css` + ]; + + for (const filePath of requiredFiles) { + if (!await fileIo.access(filePath)) { + console.warn(`游戏${gameId}关键文件缺失: ${filePath}`); + return false; + } + } + + return true; + } catch (error) { + console.error(`验证游戏${gameId}完整性失败:`, error); + return false; + } + } + + /** + * 处理切换错误 + */ + private static async handleSwitchError(gameId: string, error: Error): Promise { + console.error(`游戏${gameId}切换失败:`, error); + + // 隐藏加载界面 + await UIController.hideGameSwitchLoading(); + + // 显示错误提示 + await UIController.showErrorDialog(`游戏启动失败`, error.message); + + // 记录错误日志 + await Logger.logError('GAME_SWITCH_ERROR', { + gameId, + error: error.message, + stack: error.stack + }); + } +} + +// 相关数据结构定义 +interface GameResourceStatus { + needDownload: boolean; + reason: 'game_not_exists' | 'version_update' | 'file_corruption' | 'ready'; + downloadUrl?: string; + oldVersion?: string; + newVersion?: string; + launchUrl?: string; +} + +interface HallPathInfo { + downloadTempPath: string; + extractTargetPath: string; + entryFilePath: string; + versionFilePath: string; + configFilePath: string; + webViewLoadUrl: string; +} + +interface GamePathInfo { + downloadTempPath: string; + extractTargetPath: string; + entryFilePath: string; + versionFilePath: string; + configFilePath: string; + webViewLoadUrl: string; + jsDir: string; + cssDir: string; + imagesDir: string; + audioDir: string; +} +``` + +--- + +## 资源目录和解压路径 + +### 4.1 文件系统结构 + +#### HarmonyOS应用文件系统布局 + +``` +/data/app/el2/100/base/com.jx.jyhd.harmonyos/haps/entry/files/ +├── game_resources/ # 游戏资源根目录 +│ ├── hall/ # 大厅资源目录 +│ │ ├── index.html # 大厅入口文件 +│ │ ├── js/ # 大厅JS文件 +│ │ │ ├── main.js # 大厅主要逻辑 +│ │ │ ├── bridge.js # JSBridge桥接文件 +│ │ │ └── utils.js # 工具函数 +│ │ ├── css/ # 大厅样式文件 +│ │ │ ├── main.css # 主样式 +│ │ │ └── responsive.css # 响应式样式 +│ │ ├── images/ # 大厅图片资源 +│ │ │ ├── logo.png # 应用Logo +│ │ │ ├── bg.jpg # 背景图片 +│ │ │ └── icons/ # 图标文件夹 +│ │ └── version.js # 大厅版本信息 +│ ├── games/ # 子游戏资源目录 +│ │ ├── game001/ # 斗地主游戏 +│ │ │ ├── index.html # 游戏入口文件 +│ │ │ ├── js/ # 游戏JS文件 +│ │ │ ├── css/ # 游戏样式文件 +│ │ │ ├── images/ # 游戏图片资源 +│ │ │ ├── audio/ # 游戏音频资源 +│ │ │ └── version.js # 游戏版本信息 +│ │ ├── game002/ # 麻将游戏 +│ │ │ ├── index.html +│ │ │ ├── js/ +│ │ │ ├── css/ +│ │ │ ├── images/ +│ │ │ ├── audio/ +│ │ │ └── version.js +│ │ └── ... # 其他子游戏 +│ ├── downloads/ # 临时下载目录 +│ │ ├── hall_temp.zip # 临时大厅ZIP包 +│ │ ├── game001_temp.zip # 临时游戏ZIP包 +│ │ └── ... +│ └── cache/ # 缓存目录 +│ ├── images/ # 图片缓存 +│ ├── config/ # 配置缓存 +│ └── temp/ # 临时文件 +├── config_cache/ # 配置缓存目录 +│ ├── remote_config.json # 远程配置缓存 +│ └── startup_config.json # 启动配置缓存 +└── logs/ # 日志目录 + ├── app.log # 应用日志 + ├── download.log # 下载日志 + └── error.log # 错误日志 +``` + +### 4.2 ZIP包解压路径规范 + +#### 路径管理类 + +```typescript +export class PathManager { + + /** + * 获取应用根目录路径 + */ + public static getAppRootPath(): string { + return getContext().filesDir; + } + + /** + * 获取游戏资源根目录路径 + */ + public static getGameResourcesPath(): string { + return `${this.getAppRootPath()}/game_resources`; + } + + /** + * 获取大厅资源目录路径 + */ + public static getHallResourcePath(): string { + return `${this.getGameResourcesPath()}/hall`; + } + + /** + * 获取子游戏资源目录路径 + * @param gameId 游戏ID + */ + public static getGameResourcePath(gameId: string): string { + return `${this.getGameResourcesPath()}/games/${gameId}`; + } + + /** + * 获取下载临时目录路径 + */ + public static getDownloadsPath(): string { + return `${this.getGameResourcesPath()}/downloads`; + } + + /** + * 获取大厅ZIP包临时下载路径 + */ + public static getHallZipTempPath(): string { + return `${this.getDownloadsPath()}/hall_temp.zip`; + } + + /** + * 获取子游戏ZIP包临时下载路径 + * @param gameId 游戏ID + */ + public static getGameZipTempPath(gameId: string): string { + return `${this.getDownloadsPath()}/${gameId}_temp.zip`; + } + + /** + * 获取配置缓存目录路径 + */ + public static getConfigCachePath(): string { + return `${this.getAppRootPath()}/config_cache`; + } + + /** + * 获取远程配置缓存文件路径 + */ + public static getRemoteConfigCachePath(): string { + return `${this.getConfigCachePath()}/remote_config.json`; + } +} +``` + +#### ZIP包解压流程 + +```typescript +export class ZipExtractor { + + /** + * 解压大厅ZIP包到指定目录 + * @param zipFilePath ZIP包文件路径 + */ + public static async extractHallZip(zipFilePath: string): Promise { + const targetPath = PathManager.getHallResourcePath(); + + console.log(`开始解压大厅ZIP包:`); + console.log(`源文件: ${zipFilePath}`); + console.log(`目标路径: ${targetPath}`); + + // 1. 清理目标目录 + await this.cleanDirectory(targetPath); + + // 2. 创建目标目录 + await fileIo.mkdir(targetPath, true); + + // 3. 解压ZIP包 + await this.extractZipToDirectory(zipFilePath, targetPath); + + // 4. 验证解压结果 + await this.verifyExtractedFiles(targetPath); + + console.log('大厅ZIP包解压完成'); + } + + /** + * 解压子游戏ZIP包到指定目录 + * @param zipFilePath ZIP包文件路径 + * @param gameId 游戏ID + */ + public static async extractGameZip(zipFilePath: string, gameId: string): Promise { + const targetPath = PathManager.getGameResourcePath(gameId); + + console.log(`开始解压游戏ZIP包:`); + console.log(`游戏ID: ${gameId}`); + console.log(`源文件: ${zipFilePath}`); + console.log(`目标路径: ${targetPath}`); + + // 1. 清理目标目录 + await this.cleanDirectory(targetPath); + + // 2. 创建目标目录 + await fileIo.mkdir(targetPath, true); + + // 3. 解压ZIP包 + await this.extractZipToDirectory(zipFilePath, targetPath); + + // 4. 验证解压结果 + await this.verifyExtractedFiles(targetPath); + + console.log(`游戏${gameId}的ZIP包解压完成`); + } + + /** + * 清理目录 + */ + private static async cleanDirectory(dirPath: string): Promise { + if (await fileIo.access(dirPath)) { + await fileIo.rmdir(dirPath, true); + console.log(`已清理目录: ${dirPath}`); + } + } + + /** + * 执行ZIP包解压 + */ + private static async extractZipToDirectory(zipPath: string, targetPath: string): Promise { + // 使用HarmonyOS的解压API + const zipFile = new zlib.ZipFile(zipPath); + await zipFile.extractAll(targetPath); + + console.log(`ZIP包解压完成: ${zipPath} -> ${targetPath}`); + } + + /** + * 验证解压后的文件 + */ + private static async verifyExtractedFiles(dirPath: string): Promise { + // 检查必要的文件是否存在 + const indexHtmlPath = `${dirPath}/index.html`; + if (!await fileIo.access(indexHtmlPath)) { + throw new Error(`解压验证失败: 缺少index.html文件`); + } + + console.log(`解压文件验证通过: ${dirPath}`); + } +} +``` + +--- + +## 大厅启动逻辑 + +### 5.1 大厅资源初始化 + +#### 大厅管理器 + +```typescript +export class HallManager { + + /** + * 初始化大厅资源 + */ + public static async initializeHall(): Promise { + try { + console.log('开始初始化大厅资源'); + + // 1. 检查大厅资源版本 + const needUpdate = await this.checkHallVersion(); + + if (needUpdate) { + // 2. 下载大厅资源 + await this.downloadHallResources(); + + // 3. 解压大厅资源 + await this.extractHallResources(); + } + + // 4. 验证大厅资源完整性 + await this.verifyHallResources(); + + // 5. 初始化大厅WebView + await this.initializeHallWebView(); + + console.log('大厅资源初始化完成'); + + } catch (error) { + console.error('大厅资源初始化失败:', error); + throw error; + } + } + + /** + * 检查大厅版本 + */ + private static async checkHallVersion(): Promise { + const config = await ConfigManager.getRemoteConfig(); + const gameData = await ConfigManager.getCurrentGameData(); + + // 获取远程大厅版本 + const remoteVersion = ConfigParameterHelper.getGameVersion(config, gameData); + console.log('远程大厅版本:', remoteVersion); + + // 获取本地大厅版本 + const localVersion = await this.getLocalHallVersion(); + console.log('本地大厅版本:', localVersion); + + // 比较版本 + const needUpdate = VersionComparator.isVersionNewer(remoteVersion, localVersion); + console.log('大厅需要更新:', needUpdate); + + return needUpdate; + } + + /** + * 下载大厅资源 + */ + private static async downloadHallResources(): Promise { + const config = await ConfigManager.getRemoteConfig(); + const gameData = await ConfigManager.getCurrentGameData(); + + // 获取大厅下载URL + const downloadUrl = ConfigParameterHelper.getGameDownloadUrl(config, gameData); + console.log('大厅下载URL:', downloadUrl); + + if (!downloadUrl) { + throw new Error('未找到大厅下载URL'); + } + + // 下载大厅ZIP包 + const zipPath = PathManager.getHallZipTempPath(); + await FileDownloader.download(downloadUrl, zipPath, { + onProgress: (progress: number, total: number) => { + const percent = Math.floor((progress / total) * 100); + console.log(`大厅下载进度: ${percent}%`); + } + }); + + console.log('大厅ZIP包下载完成:', zipPath); + } + + /** + * 解压大厅资源 + */ + private static async extractHallResources(): Promise { + const zipPath = PathManager.getHallZipTempPath(); + + // 解压到大厅目录 + await ZipExtractor.extractHallZip(zipPath); + + // 清理临时ZIP文件 + await fileIo.unlink(zipPath); + + console.log('大厅资源解压完成'); + } + + /** + * 获取本地大厅版本 + */ + private static async getLocalHallVersion(): Promise { + const versionPath = `${PathManager.getHallResourcePath()}/version.txt`; + + try { + if (await fileIo.access(versionPath)) { + const versionContent = await fileIo.readText(versionPath); + return versionContent.trim(); + } + } catch (error) { + console.warn('读取本地大厅版本失败:', error); + } + + return ''; + } +} +``` + +### 5.2 大厅WebView启动 + +#### WebView管理器 + +```typescript +export class HallWebViewController { + private webView: WebviewController | null = null; + + /** + * 初始化大厅WebView + */ + public async initializeHallWebView(): Promise { + try { + console.log('开始初始化大厅WebView'); + + // 1. 创建WebView控制器 + this.webView = new webview.WebviewController(); + + // 2. 配置WebView设置 + await this.configureWebViewSettings(); + + // 3. 注册JS Bridge接口 + await this.registerJSBridgeHandlers(); + + // 4. 加载大厅HTML页面 + await this.loadHallPage(); + + console.log('大厅WebView初始化完成'); + + } catch (error) { + console.error('大厅WebView初始化失败:', error); + throw error; + } + } + + /** + * 配置WebView设置 + */ + private async configureWebViewSettings(): Promise { + if (!this.webView) return; + + // 启用JavaScript + this.webView.enableJavaScript = true; + + // 启用DOM存储 + this.webView.domStorageAccess = true; + + // 启用文件访问 + this.webView.fileAccess = true; + + // 设置用户代理 + this.webView.userAgent = 'TSGame_HarmonyOS/3.6.0 (HarmonyOS)'; + + console.log('WebView设置配置完成'); + } + + /** + * 注册JS Bridge接口 + */ + private async registerJSBridgeHandlers(): Promise { + if (!this.webView) return; + + // 注册所有JS Bridge接口 + await JSBridgeManager.registerAllHandlers(this.webView); + + console.log('JS Bridge接口注册完成'); + } + + /** + * 加载大厅HTML页面 + */ + private async loadHallPage(): Promise { + if (!this.webView) return; + + const hallIndexPath = `${PathManager.getHallResourcePath()}/index.html`; + + // 检查大厅HTML文件是否存在 + if (!await fileIo.access(hallIndexPath)) { + throw new Error('大厅HTML文件不存在'); + } + + // 构建文件URL + const fileUrl = `file://${hallIndexPath}`; + console.log('加载大厅页面:', fileUrl); + + // 加载页面 + await this.webView.loadUrl(fileUrl); + + // 设置页面加载监听 + this.webView.onPageBegin = (event) => { + console.log('大厅页面开始加载:', event.url); + }; + + this.webView.onPageEnd = (event) => { + console.log('大厅页面加载完成:', event.url); + this.onHallPageLoadCompleted(); + }; + + this.webView.onErrorReceive = (event) => { + console.error('大厅页面加载错误:', event.error); + }; + } + + /** + * 大厅页面加载完成回调 + */ + private onHallPageLoadCompleted(): void { + console.log('大厅启动完成,可以接受用户操作'); + + // 通知应用大厅已就绪 + EventManager.emit('hall_ready'); + } +} +``` + +--- + +## 子游戏跳转启动逻辑 + +### 6.1 子游戏资源管理 + +#### 子游戏启动的完整时序 + +``` +大厅点击游戏 + ↓ +HallWebView.callHandler('SwitchOverGameData') + ↓ +GameSwitchController.handleGameSwitch() + ↓ +检查子游戏资源状态 ← 读取 game_version 配置属性 + ↓ +[如果需要] 下载子游戏ZIP ← 使用 game_download 配置属性 + ↓ +[如果需要] 解压到游戏目录 ← 解压到 /game_resources/games/{gameId}/ + ↓ +隐藏大厅WebView,初始化游戏WebView + ↓ +加载游戏页面 ← 加载 file:///game_resources/games/{gameId}/index.html + ↓ +显示游戏WebView,传递启动参数 + ↓ +子游戏启动完成 +``` + +#### 子游戏跳转的JSBridge接口调用 + +```typescript +// 在大厅WebView中的JavaScript代码 +function switchToGame(gameInfo) { + // 调用SwitchOverGameData接口跳转到子游戏 + window.WebViewJavascriptBridge.callHandler('SwitchOverGameData', { + gameId: gameInfo.gameId, // 子游戏唯一标识 + gameType: gameInfo.gameType, // 游戏类型 + gameUrl: gameInfo.gameUrl, // 游戏访问地址(用于fallback) + gameName: gameInfo.gameName, // 游戏显示名称 + gameIcon: gameInfo.gameIcon, // 游戏图标URL + gameDesc: gameInfo.gameDesc, // 游戏描述 + extraData: { // 传递给子游戏的额外数据 + userId: currentUser.userId, + userToken: currentUser.token, + fromHall: true, + timestamp: Date.now() + } + }); +} +``` + +### 6.2 子游戏WebView切换的详细实现 + +#### WebView切换管理器的完整实现 + +```typescript +export class GameWebViewController { + private static hallWebView: WebviewController | null = null; + private static gameWebViews: Map = new Map(); + private static currentGameId: string = ''; + + /** + * 处理大厅到子游戏的切换 + * 这是SwitchOverGameData接口的具体实现 + */ + public static async handleSwitchOverGameData(params: SwitchGameParams): Promise { + try { + console.log(`=== 开始处理游戏切换请求 ===`); + console.log(`游戏ID: ${params.gameId}`); + console.log(`游戏参数:`, params); + + // 第一阶段:资源检查和准备 + await this.prepareGameResources(params.gameId, params); + + // 第二阶段:WebView切换 + await this.performWebViewSwitch(params.gameId, params); + + // 第三阶段:游戏启动 + await this.launchGameInWebView(params.gameId, params); + + console.log(`=== 游戏切换完成 ===`); + + } catch (error) { + console.error(`游戏切换失败:`, error); + await this.handleSwitchError(params.gameId, error); + } + } + + /** + * 第一阶段:准备游戏资源 + */ + private static async prepareGameResources(gameId: string, params: SwitchGameParams): Promise { + console.log(`=== 第一阶段:准备游戏${gameId}资源 ===`); + + // 1. 获取远程配置,检查版本信息 + const config = await ConfigManager.getRemoteConfig(); + const gameData = await ConfigManager.getCurrentGameData(); + + // 2. 读取游戏版本配置属性进行版本检查 + const remoteGameVersion = ConfigParameterHelper.getGameVersion(config, gameData); + console.log(`远程游戏版本: ${remoteGameVersion}`); + + // 3. 获取游戏路径信息 + const gamePaths = GamePathResolver.getGamePaths(gameId); + console.log(`游戏资源路径: ${gamePaths.extractTargetPath}`); + console.log(`游戏启动路径: ${gamePaths.webViewLoadUrl}`); + + // 4. 检查本地游戏资源状态 + const resourceStatus = await this.checkGameResourceStatus(gameId, remoteGameVersion, gamePaths); + + // 5. 如果需要下载,执行下载和解压流程 + if (resourceStatus.needDownload) { + await this.downloadAndExtractGame(gameId, config, gameData, gamePaths); + } + + console.log(`游戏${gameId}资源准备完成`); + } + + /** + * 检查游戏资源状态的详细逻辑 + */ + private static async checkGameResourceStatus( + gameId: string, + remoteVersion: string, + gamePaths: GamePathInfo + ): Promise { + + // 1. 检查游戏目录是否存在 + const gameExists = await fileIo.access(gamePaths.extractTargetPath); + if (!gameExists) { + console.log(`游戏${gameId}目录不存在: ${gamePaths.extractTargetPath}`); + return { needDownload: true, reason: 'not_exists' }; + } + + // 2. 检查游戏入口文件 + const entryExists = await fileIo.access(gamePaths.entryFilePath); + if (!entryExists) { + console.log(`游戏${gameId}入口文件不存在: ${gamePaths.entryFilePath}`); + return { needDownload: true, reason: 'entry_missing' }; + } + + // 3. 读取本地版本信息 + const localVersion = await this.getLocalGameVersion(gamePaths.versionFilePath); + console.log(`本地游戏版本: ${localVersion}`); + + // 4. 版本比较 + if (VersionComparator.isVersionNewer(remoteVersion, localVersion)) { + console.log(`游戏${gameId}需要版本更新: ${localVersion} -> ${remoteVersion}`); + return { + needDownload: true, + reason: 'version_update', + oldVersion: localVersion, + newVersion: remoteVersion + }; + } + + // 5. 验证关键文件完整性 + const isValid = await this.validateGameFiles(gameId, gamePaths); + if (!isValid) { + console.log(`游戏${gameId}文件验证失败`); + return { needDownload: true, reason: 'file_corruption' }; + } + + console.log(`游戏${gameId}资源检查通过`); + return { needDownload: false, reason: 'ready' }; + } + + /** + * 下载和解压游戏的详细流程 + */ + private static async downloadAndExtractGame( + gameId: string, + config: any, + gameData: any, + gamePaths: GamePathInfo + ): Promise { + + console.log(`=== 开始下载和解压游戏${gameId} ===`); + + // 1. 读取游戏下载地址配置属性 + const gameDownloadUrl = DownloadUrlResolver.getGameZipDownloadUrl(config, gameData, gameId); + console.log(`游戏下载地址: ${gameDownloadUrl}`); + + if (!gameDownloadUrl) { + throw new Error(`未找到游戏${gameId}的下载地址配置`); + } + + // 2. 显示下载进度界面 + await UIController.showGameDownloadDialog(gameId); + + try { + // 3. 下载游戏ZIP包到临时路径 + console.log(`开始下载到: ${gamePaths.downloadTempPath}`); + await FileDownloader.downloadWithProgress( + gameDownloadUrl, + gamePaths.downloadTempPath, + { + onProgress: (loaded: number, total: number) => { + const percent = Math.floor((loaded / total) * 100); + UIController.updateGameDownloadProgress(gameId, percent); + console.log(`游戏${gameId}下载进度: ${percent}%`); + }, + timeout: 300000 // 5分钟超时 + } + ); + + console.log(`游戏${gameId}下载完成`); + + // 4. 解压游戏ZIP包到目标路径 + console.log(`开始解压到: ${gamePaths.extractTargetPath}`); + await GamePathResolver.extractGameZip(gamePaths.downloadTempPath, gameId); + + console.log(`游戏${gameId}解压完成`); + + // 5. 清理临时下载文件 + await fileIo.unlink(gamePaths.downloadTempPath); + console.log(`临时文件已清理: ${gamePaths.downloadTempPath}`); + + } finally { + // 6. 隐藏下载进度界面 + await UIController.hideGameDownloadDialog(gameId); + } + } + + /** + * 第二阶段:执行WebView切换 + */ + private static async performWebViewSwitch(gameId: string, params: SwitchGameParams): Promise { + console.log(`=== 第二阶段:执行WebView切换到游戏${gameId} ===`); + + // 1. 保存当前大厅状态 + await this.saveHallState(); + + // 2. 隐藏大厅WebView + await this.hideHallWebView(); + console.log(`大厅WebView已隐藏`); + + // 3. 初始化或获取游戏WebView + const gameWebView = await this.getOrCreateGameWebView(gameId); + console.log(`游戏${gameId}的WebView已准备`); + + // 4. 配置游戏WebView + await this.configureGameWebView(gameId, gameWebView, params); + console.log(`游戏${gameId}的WebView配置完成`); + + // 5. 显示游戏WebView + await this.showGameWebView(gameId); + console.log(`游戏${gameId}的WebView已显示`); + + // 6. 更新当前游戏状态 + this.currentGameId = gameId; + } + + /** + * 第三阶段:在WebView中启动游戏 + */ + private static async launchGameInWebView(gameId: string, params: SwitchGameParams): Promise { + console.log(`=== 第三阶段:在WebView中启动游戏${gameId} ===`); + + const gamePaths = GamePathResolver.getGamePaths(gameId); + const gameWebView = this.gameWebViews.get(gameId); + + if (!gameWebView) { + throw new Error(`游戏${gameId}的WebView未找到`); + } + + // 1. 加载游戏页面 + console.log(`加载游戏页面: ${gamePaths.webViewLoadUrl}`); + await gameWebView.loadUrl(gamePaths.webViewLoadUrl); + + // 2. 等待页面加载完成 + await this.waitForGamePageReady(gameId, gameWebView); + + // 3. 设置游戏启动参数 + const startupParams = await this.buildGameStartupParams(gameId, params); + console.log(`游戏启动参数:`, startupParams); + + // 4. 通过JSBridge传递启动参数 + await this.passStartupParamsToGame(gameId, gameWebView, startupParams); + + // 5. 通知游戏初始化完成 + await this.notifyGameInitComplete(gameId, gameWebView); + + console.log(`游戏${gameId}在WebView中启动完成`); + } + + /** + * 获取或创建游戏WebView + */ + private static async getOrCreateGameWebView(gameId: string): Promise { + let gameWebView = this.gameWebViews.get(gameId); + + if (!gameWebView) { + console.log(`创建新的游戏${gameId}WebView`); + + // 创建新的WebView实例 + gameWebView = new webview.WebviewController(); + + // 基础配置 + gameWebView.setJavaScriptEnabled(true); + gameWebView.setDomStorageEnabled(true); + gameWebView.setFileAccessEnabled(true); + gameWebView.setAllowFileAccessFromFileURLs(true); + + // 设置用户代理 + const userAgent = `TSGame-HarmonyOS/${await DeviceInfo.getAppVersion()} Game/${gameId}`; + gameWebView.setUserAgent(userAgent); + + // 缓存WebView实例 + this.gameWebViews.set(gameId, gameWebView); + + console.log(`游戏${gameId}WebView创建完成`); + } + + return gameWebView; + } + + /** + * 配置游戏WebView的专用设置 + */ + private static async configureGameWebView( + gameId: string, + gameWebView: WebviewController, + params: SwitchGameParams + ): Promise { + + // 1. 设置JSBridge + await JSBridgeManager.setupGameJSBridge(gameId, gameWebView); + console.log(`游戏${gameId}的JSBridge设置完成`); + + // 2. 注册游戏专用的Handler + await this.registerGameSpecificHandlers(gameId, gameWebView); + + // 3. 设置WebView事件监听 + this.setupGameWebViewListeners(gameId, gameWebView); + + // 4. 配置游戏特定的WebView选项 + await this.applyGameSpecificWebViewConfig(gameId, gameWebView, params); + } + + /** + * 构建游戏启动参数 + */ + private static async buildGameStartupParams(gameId: string, params: SwitchGameParams): Promise { + const config = await ConfigManager.getRemoteConfig(); + const gameData = await ConfigManager.getCurrentGameData(); + const userInfo = await UserManager.getCurrentUserInfo(); + + return { + // 游戏基础信息 + gameId: gameId, + gameName: params.gameName, + gameType: params.gameType, + + // 用户信息 + userId: userInfo.userId, + userToken: userInfo.token, + nickname: userInfo.nickname, + avatar: userInfo.avatar, + coins: userInfo.coins, + level: userInfo.level, + + // 服务器配置 + serverUrl: ConfigParameterHelper.getServerUrl(config, gameData), + apiVersion: 'v1.0', + + // 启动上下文 + fromPage: 'hall', + timestamp: Date.now(), + sessionId: generateSessionId(), + + // 设备信息 + deviceInfo: await DeviceInfo.getBasicInfo(), + + // 传递的额外数据 + extraData: params.extraData || {} + }; + } + + /** + * 通过JSBridge传递启动参数给游戏 + */ + private static async passStartupParamsToGame( + gameId: string, + gameWebView: WebviewController, + startupParams: any + ): Promise { + + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => { + reject(new Error(`游戏${gameId}启动参数传递超时`)); + }, 10000); + + // 调用游戏的初始化Handler + gameWebView.callHandler('onGameInit', startupParams, (response) => { + clearTimeout(timeout); + + console.log(`游戏${gameId}初始化响应:`, response); + + if (response && response.success) { + resolve(); + } else { + reject(new Error(`游戏${gameId}初始化失败: ${response?.message || '未知错误'}`)); + } + }); + }); + } + + /** + * 等待游戏页面加载完成 + */ + private static async waitForGamePageReady(gameId: string, gameWebView: WebviewController): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => { + reject(new Error(`游戏${gameId}页面加载超时`)); + }, 30000); + + // 监听页面加载完成事件 + gameWebView.setOnPageFinished((url) => { + clearTimeout(timeout); + console.log(`游戏${gameId}页面加载完成: ${url}`); + resolve(); + }); + + // 监听页面加载错误 + gameWebView.setOnPageError((error) => { + clearTimeout(timeout); + reject(new Error(`游戏${gameId}页面加载失败: ${error.description}`)); + }); + }); + } + + /** + * 隐藏大厅WebView + */ + private static async hideHallWebView(): Promise { + if (this.hallWebView) { + // 通知大厅页面即将隐藏 + this.hallWebView.callHandler('onPagePause', { reason: 'game_switch' }); + + // 隐藏大厅WebView UI + await UIController.hideHallWebView(); + } + } + + /** + * 显示游戏WebView + */ + private static async showGameWebView(gameId: string): Promise { + // 显示游戏WebView UI + await UIController.showGameWebView(gameId); + + // 通知游戏页面已显示 + const gameWebView = this.gameWebViews.get(gameId); + if (gameWebView) { + gameWebView.callHandler('onPageResume', { + fromBackground: false, + reason: 'game_start' + }); + } + } + + /** + * 游戏返回大厅的逻辑 + */ + public static async switchBackToHall(gameId: string): Promise { + console.log(`=== 游戏${gameId}返回大厅 ===`); + + // 1. 隐藏游戏WebView + await UIController.hideGameWebView(gameId); + + // 2. 通知游戏页面暂停 + const gameWebView = this.gameWebViews.get(gameId); + if (gameWebView) { + gameWebView.callHandler('onPagePause', { reason: 'back_to_hall' }); + } + + // 3. 显示大厅WebView + await UIController.showHallWebView(); + + // 4. 通知大厅页面恢复 + if (this.hallWebView) { + this.hallWebView.callHandler('onPageResume', { + fromBackground: false, + reason: 'back_from_game', + gameId: gameId + }); + } + + // 5. 更新当前状态 + this.currentGameId = ''; + + console.log(`已返回大厅`); + } + + /** + * 处理切换错误 + */ + private static async handleSwitchError(gameId: string, error: Error): Promise { + console.error(`游戏${gameId}切换失败:`, error); + + // 记录错误日志 + await Logger.logError('GAME_SWITCH_ERROR', { + gameId, + error: error.message, + stack: error.stack, + timestamp: Date.now() + }); + + // 隐藏可能的加载界面 + await UIController.hideGameDownloadDialog(gameId); + + // 显示错误提示 + await UIController.showErrorDialog(`游戏启动失败`, `${error.message}\n\n请稍后重试或联系客服。`); + + // 确保回到大厅状态 + await this.switchBackToHall(gameId); + } +} + +// 辅助数据结构 +interface SwitchGameParams { + gameId: string; + gameType: string; + gameUrl: string; + gameName: string; + gameIcon: string; + gameDesc?: string; + extraData?: any; +} + +interface GameResourceStatus { + needDownload: boolean; + reason: 'not_exists' | 'entry_missing' | 'version_update' | 'file_corruption' | 'ready'; + oldVersion?: string; + newVersion?: string; +} +``` + +### 6.3 子游戏启动流程的配置属性读取详解 + +#### 启动过程中读取的具体配置属性 + +```typescript +export class GameStartupConfigReader { + + /** + * 子游戏启动过程中需要读取的所有配置属性 + */ + public static async readGameStartupConfig(gameId: string): Promise { + const config = await ConfigManager.getRemoteConfig(); + const gameData = await ConfigManager.getCurrentGameData(); + + console.log(`=== 读取游戏${gameId}启动配置 ===`); + + return { + // 版本相关配置(用于资源检查) + gameVersion: ConfigParameterHelper.getGameVersion(config, gameData), + + // 下载相关配置(用于资源下载) + gameDownloadUrl: ConfigParameterHelper.getGameDownloadUrl(config, gameData), + gameSize: ConfigParameterHelper.getGameSize(config, gameData), + + // 服务器相关配置(传递给游戏用于网络请求) + serverUrl: ConfigParameterHelper.getServerUrl(config, gameData), + apiEndpoint: ConfigParameterHelper.getString(config, gameData, 'api_endpoint', '/api'), + + // 功能开关配置 + enableAudio: ConfigParameterHelper.getBoolean(config, gameData, 'enable_audio', true), + enableVibration: ConfigParameterHelper.getBoolean(config, gameData, 'enable_vibration', true), + + // 游戏专用配置 + maxPlayers: ConfigParameterHelper.getNumber(config, gameData, 'max_players', 4), + gameTimeout: ConfigParameterHelper.getNumber(config, gameData, 'game_timeout', 300), + + // 调试配置 + debugMode: ConfigParameterHelper.getBoolean(config, gameData, 'debug_mode', false), + logLevel: ConfigParameterHelper.getString(config, gameData, 'log_level', 'info') + }; + } + + /** + * 打印配置读取详细信息 + */ + public static logConfigDetails(gameId: string, config: any, gameData: any): void { + console.log(`=== 游戏${gameId}配置读取详情 ===`); + + // 显示配置文件层级结构 + console.log(`配置文件层级信息:`); + console.log(`- 代理商ID: ${gameData.agentid}`); + console.log(`- 渠道ID: ${gameData.channelid}`); + console.log(`- 市场ID: ${gameData.marketid}`); + + // 显示版本配置读取路径 + console.log(`版本配置读取路径:`); + this.logConfigPath('game_version', config, gameData); + + // 显示下载配置读取路径 + console.log(`下载配置读取路径:`); + this.logConfigPath('game_download', config, gameData); + + // 显示服务器配置读取路径 + console.log(`服务器配置读取路径:`); + this.logConfigPath('url', config, gameData); + } + + /** + * 记录具体配置属性的读取路径 + */ + private static logConfigPath(propertyName: string, config: any, gameData: any): void { + const paths = [ + `marketlist[${gameData.marketid}].${propertyName}`, + `channellist[${gameData.channelid}].${propertyName}`, + `agentlist[${gameData.agentid}].${propertyName}`, + `data.${propertyName}` + ]; + + for (const path of paths) { + const value = this.getValueByPath(config, path); + if (value !== undefined) { + console.log(` ✓ ${path} = ${value}`); + break; + } else { + console.log(` ✗ ${path} = undefined`); + } + } + } + + /** + * 根据路径获取配置值 + */ + private static getValueByPath(config: any, path: string): any { + const parts = path.split('.'); + let current = config; + + for (const part of parts) { + if (part.includes('[') && part.includes(']')) { + // 处理数组索引,如 marketlist[market001] + const arrayName = part.substring(0, part.indexOf('[')); + const index = part.substring(part.indexOf('[') + 1, part.indexOf(']')); + + if (current[arrayName] && Array.isArray(current[arrayName])) { + current = current[arrayName].find((item: any) => + item.marketid === index || item.channelid === index || item.agentid === index + ); + } else { + return undefined; + } + } else { + current = current[part]; + } + + if (current === undefined) { + return undefined; + } + } + + return current; + } +} + +interface GameStartupConfig { + gameVersion: string; + gameDownloadUrl: string; + gameSize: string; + serverUrl: string; + apiEndpoint: string; + enableAudio: boolean; + enableVibration: boolean; + maxPlayers: number; + gameTimeout: number; + debugMode: boolean; + logLevel: string; +} +``` + +### 6.4 子游戏启动路径的完整解析 + +#### 游戏启动路径的构建和验证 + +```typescript +export class GameLaunchPathResolver { + + /** + * 解析游戏的完整启动路径 + */ + public static resolveGameLaunchPaths(gameId: string): GameLaunchPaths { + const appRoot = getContext().filesDir; + + const paths = { + // 基础路径 + appRootPath: appRoot, + gameRootPath: `${appRoot}/game_resources/games/${gameId}`, + + // 启动相关路径 + entryHtmlPath: `${appRoot}/game_resources/games/${gameId}/index.html`, + webViewLoadUrl: `file://${appRoot}/game_resources/games/${gameId}/index.html`, + + // 资源路径 + jsPath: `${appRoot}/game_resources/games/${gameId}/js`, + cssPath: `${appRoot}/game_resources/games/${gameId}/css`, + imagesPath: `${appRoot}/game_resources/games/${gameId}/images`, + audioPath: `${appRoot}/game_resources/games/${gameId}/audio`, + + // 配置和数据路径 + gameConfigPath: `${appRoot}/game_resources/games/${gameId}/game.json`, + versionFilePath: `${appRoot}/game_resources/games/${gameId}/version.txt`, + saveDataPath: `${appRoot}/game_resources/games/${gameId}/savedata`, + + // 临时和缓存路径 + tempPath: `${appRoot}/game_resources/games/${gameId}/temp`, + cachePath: `${appRoot}/game_resources/games/${gameId}/cache` + }; + + console.log(`=== 游戏${gameId}启动路径解析 ===`); + console.log(`游戏根目录: ${paths.gameRootPath}`); + console.log(`启动入口: ${paths.entryHtmlPath}`); + console.log(`WebView加载URL: ${paths.webViewLoadUrl}`); + + return paths; + } + + /** + * 验证游戏启动路径的有效性 + */ + public static async validateGameLaunchPaths(gameId: string, paths: GameLaunchPaths): Promise { + console.log(`=== 验证游戏${gameId}启动路径 ===`); + + const validationResult: ValidationResult = { + isValid: true, + errors: [], + warnings: [] + }; + + // 1. 验证游戏根目录 + if (!await fileIo.access(paths.gameRootPath)) { + validationResult.isValid = false; + validationResult.errors.push(`游戏根目录不存在: ${paths.gameRootPath}`); + } + + // 2. 验证启动入口文件 + if (!await fileIo.access(paths.entryHtmlPath)) { + validationResult.isValid = false; + validationResult.errors.push(`游戏入口文件不存在: ${paths.entryHtmlPath}`); + } + + // 3. 验证关键资源目录 + const requiredDirs = [paths.jsPath, paths.cssPath]; + for (const dir of requiredDirs) { + if (!await fileIo.access(dir)) { + validationResult.warnings.push(`资源目录不存在: ${dir}`); + } + } + + // 4. 验证版本文件 + if (!await fileIo.access(paths.versionFilePath)) { + validationResult.warnings.push(`版本文件不存在: ${paths.versionFilePath}`); + } + + console.log(`游戏${gameId}路径验证结果:`, validationResult); + return validationResult; + } + + /** + * 创建游戏启动所需的目录结构 + */ + public static async createGameDirectoryStructure(gameId: string, paths: GameLaunchPaths): Promise { + console.log(`=== 创建游戏${gameId}目录结构 ===`); + + const directories = [ + paths.gameRootPath, + paths.jsPath, + paths.cssPath, + paths.imagesPath, + paths.audioPath, + paths.saveDataPath, + paths.tempPath, + paths.cachePath + ]; + + for (const dir of directories) { + try { + await fileIo.mkdir(dir, true); + console.log(`目录创建成功: ${dir}`); + } catch (error) { + console.warn(`目录创建失败: ${dir}`, error); + } + } + } +} + +interface GameLaunchPaths { + appRootPath: string; + gameRootPath: string; + entryHtmlPath: string; + webViewLoadUrl: string; + jsPath: string; + cssPath: string; + imagesPath: string; + audioPath: string; + gameConfigPath: string; + versionFilePath: string; + saveDataPath: string; + tempPath: string; + cachePath: string; +} + +interface ValidationResult { + isValid: boolean; + errors: string[]; + warnings: string[]; +} +``` + +--- + +## 总结 + +TSGame HarmonyOS应用的启动流程采用分阶段、可恢复的设计理念,通过精确的配置属性读取和路径管理实现应用和游戏的动态更新。 + +### 关键配置属性汇总 + +#### 应用升级验证的配置属性 + +| 配置属性 | 读取方法 | 作用说明 | 使用时机 | +|---------|----------|----------|----------| +| `app_version` | `ConfigParameterHelper.getAppVersion()` | **主要验证属性** - 远程应用版本号,与本地版本比较判断是否需要升级 | 应用启动时版本检查 | +| `app_download` | `ConfigParameterHelper.getAppDownloadUrl()` | **下载地址属性** - 应用APK/APP安装包下载URL | 确认需要升级时获取下载地址 | +| `app_size` | `ConfigParameterHelper.getAppSize()` | 应用安装包大小,用于显示下载进度和预估时间 | 下载过程中显示进度 | +| `force_update` | `ConfigParameterHelper.getBooleanValue()` | 强制更新标志,控制是否必须升级 | 版本检查时确定升级策略 | +| `min_version` | `ConfigParameterHelper.getString()` | 最低支持版本,低于此版本强制升级 | 版本检查时确定升级策略 | +| `showmessage` | `ConfigParameterHelper.getShowMessage()` | 版本更新说明,向用户展示升级内容 | 升级提示对话框显示 | + +#### 游戏资源管理的配置属性 + +| 配置属性 | 读取方法 | 作用说明 | 使用时机 | +|---------|----------|----------|----------| +| `game_version` | `ConfigParameterHelper.getGameVersion()` | **主要验证属性** - 远程游戏资源版本号,与本地比较判断是否需要更新 | 游戏启动前资源检查 | +| `game_download` | `ConfigParameterHelper.getGameDownloadUrl()` | **下载地址属性** - 游戏ZIP包基础下载URL,拼接gameId构成完整下载地址 | 需要下载游戏资源时 | +| `game_size` | `ConfigParameterHelper.getGameSize()` | 游戏ZIP包大小,用于下载进度显示 | 游戏资源下载过程中 | + +#### 服务器和功能配置属性 + +| 配置属性 | 读取方法 | 作用说明 | 使用时机 | +|---------|----------|----------|----------| +| `url` | `ConfigParameterHelper.getServerUrl()` | **服务器地址属性** - API服务器基础URL,传递给游戏用于网络请求 | 游戏启动时传递给WebView | +| `api_endpoint` | `ConfigParameterHelper.getString()` | API端点路径,拼接到服务器地址后 | 构建完整API地址 | +| `enable_audio` | `ConfigParameterHelper.getBoolean()` | 音频功能开关,控制游戏是否启用音频 | 游戏初始化时配置 | +| `enable_vibration` | `ConfigParameterHelper.getBoolean()` | 震动功能开关,控制游戏是否启用震动反馈 | 游戏初始化时配置 | + +### 关键路径汇总 + +#### 大厅相关路径 + +| 路径类型 | 具体路径 | 用途说明 | +|---------|----------|----------| +| **大厅ZIP下载临时路径** | `{filesDir}/downloads/hall_temp.zip` | 大厅ZIP包下载的临时存储位置 | +| **大厅资源解压目标路径** | `{filesDir}/game_resources/hall/` | 大厅ZIP包解压后的资源存放目录 | +| **大厅启动入口路径** | `{filesDir}/game_resources/hall/index.html` | 大厅WebView加载的HTML入口文件 | +| **大厅WebView加载URL** | `file://{filesDir}/game_resources/hall/index.html` | 大厅WebView实际加载的file://协议URL | + +#### 子游戏相关路径 + +| 路径类型 | 具体路径模板 | 用途说明 | +|---------|-------------|----------| +| **子游戏ZIP下载临时路径** | `{filesDir}/downloads/{gameId}_temp.zip` | 子游戏ZIP包下载的临时存储位置 | +| **子游戏资源解压目标路径** | `{filesDir}/game_resources/games/{gameId}/` | 子游戏ZIP包解压后的资源存放目录 | +| **子游戏启动入口路径** | `{filesDir}/game_resources/games/{gameId}/index.html` | 子游戏WebView加载的HTML入口文件 | +| **子游戏WebView加载URL** | `file://{filesDir}/game_resources/games/{gameId}/index.html` | 子游戏WebView实际加载的file://协议URL | +| **子游戏JS资源路径** | `{filesDir}/game_resources/games/{gameId}/js/` | 子游戏JavaScript文件存放目录 | +| **子游戏CSS资源路径** | `{filesDir}/game_resources/games/{gameId}/css/` | 子游戏CSS样式文件存放目录 | +| **子游戏图片资源路径** | `{filesDir}/game_resources/games/{gameId}/images/` | 子游戏图片资源存放目录 | +| **子游戏音频资源路径** | `{filesDir}/game_resources/games/{gameId}/audio/` | 子游戏音频文件存放目录 | + +#### 配置和缓存路径 + +| 路径类型 | 具体路径 | 用途说明 | +|---------|----------|----------| +| **远程配置缓存路径** | `{filesDir}/config_cache/remote_config.json` | 远程配置文件的本地缓存 | +| **启动配置缓存路径** | `{filesDir}/config_cache/startup_config.json` | 应用启动配置的本地缓存 | + +### 大厅跳转子游戏的完整流程 + +#### 第一阶段:接收跳转请求 +1. **触发方式**:大厅WebView中JavaScript调用 `window.WebViewJavascriptBridge.callHandler('SwitchOverGameData', {...})` +2. **参数验证**:验证gameId、gameName等必要参数 +3. **显示加载**:显示游戏切换加载界面 + +#### 第二阶段:资源检查和准备 +1. **读取配置**: + - 读取 `game_version` 属性进行版本比较 + - 读取 `game_download` 属性获取下载地址 + - 读取 `game_size` 属性用于进度显示 + +2. **资源检查**: + - 检查游戏目录:`{filesDir}/game_resources/games/{gameId}/` + - 检查入口文件:`{filesDir}/game_resources/games/{gameId}/index.html` + - 读取本地版本:`{filesDir}/game_resources/games/{gameId}/version.txt` + +3. **下载解压**(如需要): + - 下载到临时路径:`{filesDir}/downloads/{gameId}_temp.zip` + - 解压到目标路径:`{filesDir}/game_resources/games/{gameId}/` + - 清理临时文件 + +#### 第三阶段:WebView切换 +1. **隐藏大厅**:调用大厅WebView的 `onPagePause` 事件 +2. **初始化游戏WebView**:创建或获取gameId对应的WebView实例 +3. **配置JSBridge**:设置游戏专用的JavaScript Bridge接口 +4. **显示游戏WebView**:将游戏WebView设置为可见状态 + +#### 第四阶段:游戏启动 +1. **加载游戏页面**:WebView加载 `file://{filesDir}/game_resources/games/{gameId}/index.html` +2. **传递启动参数**: + - 用户信息(userId、token、coins等) + - 服务器配置(从 `url` 属性读取) + - 游戏配置(从其他配置属性读取) +3. **调用游戏初始化**:通过JSBridge调用游戏的 `onGameInit` 接口 +4. **隐藏加载界面**:游戏初始化完成后隐藏加载界面 + +### 配置属性读取的层级优先级 + +TSGame应用的配置读取遵循严格的层级优先级规则: + +``` +市场级别配置 (最高优先级) + ↓ 覆盖 +渠道级别配置 + ↓ 覆盖 +代理商级别配置 + ↓ 覆盖 +全局级别配置 (最低优先级,默认值) +``` + +#### 具体的配置路径读取顺序 + +以 `app_version` 配置属性为例: + +1. **第一优先级**:`marketlist[{marketid}].app_version` +2. **第二优先级**:`channellist[{channelid}].app_version` +3. **第三优先级**:`agentlist[{agentid}].app_version` +4. **第四优先级**:`data.app_version`(全局默认值) + +### 核心特性总结 + +1. **配置驱动启动**:所有启动决策基于远程配置文件的具体属性值 +2. **分层配置管理**:支持全局、代理商、渠道、市场四级配置覆盖机制 +3. **精确路径管理**:每个资源都有明确的下载路径、解压路径和启动路径 +4. **双WebView架构**:大厅和子游戏完全独立的WebView实例和资源管理 +5. **版本检查机制**:基于 `app_version` 和 `game_version` 的自动版本检测 +6. **异常降级处理**:配置获取失败、资源下载失败等多重降级策略 + +### 开发者要点 + +1. **配置属性命名**:所有配置属性名称必须与Android版本保持一致 +2. **路径兼容性**:文件路径需要适配HarmonyOS的沙盒文件系统 +3. **权限申请**:文件读写、网络访问等权限需要动态申请 +4. **性能优化**:WebView初始化、资源解压等耗时操作需要异步处理 +5. **错误处理**:每个环节都需要完善的错误处理和用户提示机制 + +这个启动流程设计确保了TSGame应用在HarmonyOS平台上的高可用性、可维护性和用户体验的一致性。通过精确的配置管理和路径规范,实现了与Android版本完全一致的功能特性。 diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..ec50c74 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,85 @@ +apply plugin: 'com.android.application' + +android { + signingConfigs { release { + storeFile file('./keystore/gamehall.keystore') + storePassword 'tswl2015' + keyPassword 'tswl2015' + keyAlias = 'gamehall' + v1SigningEnabled true + v2SigningEnabled true + } + + debug { + storeFile file('./keystore/gamehall.keystore') + storePassword 'tswl2015' + keyPassword 'tswl2015' + keyAlias = 'gamehall' + v1SigningEnabled true + v2SigningEnabled true + } + + } + compileSdk 33 + buildToolsVersion '33.0.0' + + defaultConfig { + applicationId "com.jx.jyhd" + minSdkVersion 21 + targetSdkVersion 32 + versionCode= 3 + versionName="3.6.3" + multiDexEnabled true + + ndk { + abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'//, 'mips', 'mips64' + } + + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + signingConfig signingConfigs.release + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + lintOptions { + abortOnError false + checkReleaseBuilds false + } +} + +dependencies { + //noinspection GradleCompatible + implementation 'com.android.support:support-v4:28.0.0' + //noinspection GradleCompatible + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.google.code.gson:gson:2.8.9' + implementation 'com.yanzhenjie.nohttp:nohttp:1.1.2' + implementation 'com.orhanobut:logger:2.2.0' + implementation 'com.android.volley:volley:1.2.1' + implementation 'com.tencent.bugly:crashreport:3.4.4' + implementation 'com.android.support:multidex:1.0.3' + implementation 'com.umeng.sdk:common:1.5.0' + implementation 'com.umeng.sdk:analytics:7.5.0' + implementation 'com.squareup.okhttp3:okhttp:4.12.0' + implementation 'com.squareup.okio:okio:3.6.0' + implementation 'org.nanohttpd:nanohttpd:2.3.1' + implementation 'com.qiniu:happy-dns:2.0.0' + implementation ('com.qiniu:qiniu-android-sdk:8.5.0'){ + exclude (group: 'com.squareup.okhttp3', module: 'okhttp') + } + implementation('com.qiniu:qiniu-java-sdk:7.7.0') { + exclude group: 'com.squareup.okhttp3', module: 'okhttp' + } + implementation 'android.arch.lifecycle:extensions:1.1.1' + api 'com.tencent.tbs:tbssdk:44286' + api 'com.tencent.mm.opensdk:wechat-sdk-android:6.8.11' + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation files('libs/AMap2DMap_5.2.0_AMapSearch_6.9.2_AMapLocation_4.7.2_20191009.jar') +} diff --git a/app/libs/AMap2DMap_5.2.0_AMapSearch_6.9.2_AMapLocation_4.7.2_20191009.jar b/app/libs/AMap2DMap_5.2.0_AMapSearch_6.9.2_AMapLocation_4.7.2_20191009.jar new file mode 100644 index 0000000..1a61cc7 Binary files /dev/null and b/app/libs/AMap2DMap_5.2.0_AMapSearch_6.9.2_AMapLocation_4.7.2_20191009.jar differ diff --git a/app/libs/agora-rtc-sdk.jar b/app/libs/agora-rtc-sdk.jar new file mode 100644 index 0000000..062cd0b Binary files /dev/null and b/app/libs/agora-rtc-sdk.jar differ diff --git a/app/libs/android-async-http-1.4.9.jar b/app/libs/android-async-http-1.4.9.jar new file mode 100644 index 0000000..c2d8b86 Binary files /dev/null and b/app/libs/android-async-http-1.4.9.jar differ diff --git a/app/libs/android-support-percent.jar b/app/libs/android-support-percent.jar new file mode 100644 index 0000000..2fa8a9f Binary files /dev/null and b/app/libs/android-support-percent.jar differ diff --git a/app/libs/andserver1.0.1.jar b/app/libs/andserver1.0.1.jar new file mode 100644 index 0000000..3030621 Binary files /dev/null and b/app/libs/andserver1.0.1.jar differ diff --git a/app/libs/ddmlib.jar b/app/libs/ddmlib.jar new file mode 100644 index 0000000..3b4d4df Binary files /dev/null and b/app/libs/ddmlib.jar differ diff --git a/app/libs/org.apache.http.legacy.jar b/app/libs/org.apache.http.legacy.jar new file mode 100644 index 0000000..5b89fbd Binary files /dev/null and b/app/libs/org.apache.http.legacy.jar differ diff --git a/app/libs/xUtils-2.6.14.jar b/app/libs/xUtils-2.6.14.jar new file mode 100644 index 0000000..0e8d26f Binary files /dev/null and b/app/libs/xUtils-2.6.14.jar differ diff --git a/app/libs/zxing.jar b/app/libs/zxing.jar new file mode 100644 index 0000000..e7b7afc Binary files /dev/null and b/app/libs/zxing.jar differ diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json new file mode 100644 index 0000000..cda7cd8 --- /dev/null +++ b/app/release/output-metadata.json @@ -0,0 +1,18 @@ +{ + "version": 2, + "artifactType": { + "type": "APK", + "kind": "Directory" + }, + "applicationId": "com.jx.jyhd", + "variantName": "processReleaseResources", + "elements": [ + { + "type": "SINGLE", + "filters": [], + "versionCode": 3, + "versionName": "3.6.3", + "outputFile": "app-release.apk" + } + ] +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..75a5d47 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,243 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/assets/WebViewJavascriptBridge.js b/app/src/main/assets/WebViewJavascriptBridge.js new file mode 100644 index 0000000..37e9220 --- /dev/null +++ b/app/src/main/assets/WebViewJavascriptBridge.js @@ -0,0 +1,145 @@ +//notation: js file can only use this kind of comments +//since comments will cause error when use in webview.loadurl, +//comments will be remove by java use regexp +(function() { + if (window.WebViewJavascriptBridge) { + return; + } + + var messagingIframe; + var sendMessageQueue = []; + var receiveMessageQueue = []; + var messageHandlers = {}; + + var CUSTOM_PROTOCOL_SCHEME = 'yy'; + var QUEUE_HAS_MESSAGE = '__QUEUE_MESSAGE__/'; + + var responseCallbacks = {}; + var uniqueId = 1; + + // 创建队列iframe + function _createQueueReadyIframe(doc) { + messagingIframe = doc.createElement('iframe'); + messagingIframe.style.display = 'none'; + doc.documentElement.appendChild(messagingIframe); + } + + //set default messageHandler 初始化默认的消息线程 + function init(messageHandler) { + if (WebViewJavascriptBridge._messageHandler) { + throw new Error('WebViewJavascriptBridge.init called twice'); + } + WebViewJavascriptBridge._messageHandler = messageHandler; + var receivedMessages = receiveMessageQueue; + receiveMessageQueue = null; + for (var i = 0; i < receivedMessages.length; i++) { + _dispatchMessageFromNative(receivedMessages[i]); + } + } + + // 发送 + function send(data, responseCallback) { + _doSend({ + data: data + }, responseCallback); + } + + // 注册线程 往数组里面添加值 + function registerHandler(handlerName, handler) { + messageHandlers[handlerName] = handler; + } + // 调用线程 + function callHandler(handlerName, data, responseCallback) { + _doSend({ + handlerName: handlerName, + data: data + }, responseCallback); + } + + //sendMessage add message, 触发native处理 sendMessage + function _doSend(message, responseCallback) { + if (responseCallback) { + var callbackId = 'cb_' + (uniqueId++) + '_' + new Date().getTime(); + responseCallbacks[callbackId] = responseCallback; + message.callbackId = callbackId; + } + + sendMessageQueue.push(message); + messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE; + } + + // 提供给native调用,该函数作用:获取sendMessageQueue返回给native,由于android不能直接获取返回的内容,所以使用url shouldOverrideUrlLoading 的方式返回内容 + function _fetchQueue() { + var messageQueueString = JSON.stringify(sendMessageQueue); + sendMessageQueue = []; + //android can't read directly the return data, so we can reload iframe src to communicate with java + messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://return/_fetchQueue/' + encodeURIComponent(messageQueueString); + } + + //提供给native使用, + function _dispatchMessageFromNative(messageJSON) { + setTimeout(function() { + var message = JSON.parse(messageJSON); + var responseCallback; + //java call finished, now need to call js callback function + if (message.responseId) { + responseCallback = responseCallbacks[message.responseId]; + if (!responseCallback) { + return; + } + responseCallback(message.responseData); + delete responseCallbacks[message.responseId]; + } else { + //直接发送 + if (message.callbackId) { + var callbackResponseId = message.callbackId; + responseCallback = function(responseData) { + _doSend({ + responseId: callbackResponseId, + responseData: responseData + }); + }; + } + + var handler = WebViewJavascriptBridge._messageHandler; + if (message.handlerName) { + handler = messageHandlers[message.handlerName]; + } + //查找指定handler + try { + handler(message.data, responseCallback); + } catch (exception) { + if (typeof console != 'undefined') { + console.log("WebViewJavascriptBridge: WARNING: javascript handler threw.", message, exception); + } + } + } + }); + } + + //提供给native调用,receiveMessageQueue 在会在页面加载完后赋值为null,所以 + function _handleMessageFromNative(messageJSON) { + console.log(messageJSON); + if (receiveMessageQueue) { + receiveMessageQueue.push(messageJSON); + } + _dispatchMessageFromNative(messageJSON); + + } + + var WebViewJavascriptBridge = window.WebViewJavascriptBridge = { + init: init, + send: send, + registerHandler: registerHandler, + callHandler: callHandler, + _fetchQueue: _fetchQueue, + _handleMessageFromNative: _handleMessageFromNative + }; + + var doc = document; + _createQueueReadyIframe(doc); + var readyEvent = doc.createEvent('Events'); + readyEvent.initEvent('WebViewJavascriptBridgeReady'); + readyEvent.bridge = WebViewJavascriptBridge; + doc.dispatchEvent(readyEvent); +})(); diff --git a/app/src/main/assets/agent/BoolTest.java b/app/src/main/assets/agent/BoolTest.java new file mode 100644 index 0000000..f895cd6 --- /dev/null +++ b/app/src/main/assets/agent/BoolTest.java @@ -0,0 +1,24 @@ +import java.util.Scanner; +public class BoolTest { + public static void main (String[]args){ + Scanner input= new Scanner(System.in); + System.out.println("عϵͳͻϵͳӿͻϢ\n"); + System.out.print("Ա4λ:"); + int huiyuan=input.nextInt(); + System.out.print("Ա(/λʾ):"); + int shenri=input.nextInt(); + System.out.print(":"); + int jifen=input.nextInt(); + if(huiyuan>=1000){ + System.out.println("¼Ϣ"); + System.out.print("\t"+huiyuan); + System.out.print("\t"+shenri); + System.out.print("\t"+jifen); + + } + else{ + System.out.print("Ϣʧ"); + } +} + +} diff --git a/app/src/main/assets/agent/veRa0qrBf0df2K1G4de2tgfmVxB2jxpv/BoolTest.java b/app/src/main/assets/agent/veRa0qrBf0df2K1G4de2tgfmVxB2jxpv/BoolTest.java new file mode 100644 index 0000000..f895cd6 --- /dev/null +++ b/app/src/main/assets/agent/veRa0qrBf0df2K1G4de2tgfmVxB2jxpv/BoolTest.java @@ -0,0 +1,24 @@ +import java.util.Scanner; +public class BoolTest { + public static void main (String[]args){ + Scanner input= new Scanner(System.in); + System.out.println("عϵͳͻϵͳӿͻϢ\n"); + System.out.print("Ա4λ:"); + int huiyuan=input.nextInt(); + System.out.print("Ա(/λʾ):"); + int shenri=input.nextInt(); + System.out.print(":"); + int jifen=input.nextInt(); + if(huiyuan>=1000){ + System.out.println("¼Ϣ"); + System.out.print("\t"+huiyuan); + System.out.print("\t"+shenri); + System.out.print("\t"+jifen); + + } + else{ + System.out.print("Ϣʧ"); + } +} + +} diff --git a/app/src/main/assets/appversion/1/BoolTest.java b/app/src/main/assets/appversion/1/BoolTest.java new file mode 100644 index 0000000..f895cd6 --- /dev/null +++ b/app/src/main/assets/appversion/1/BoolTest.java @@ -0,0 +1,24 @@ +import java.util.Scanner; +public class BoolTest { + public static void main (String[]args){ + Scanner input= new Scanner(System.in); + System.out.println("عϵͳͻϵͳӿͻϢ\n"); + System.out.print("Ա4λ:"); + int huiyuan=input.nextInt(); + System.out.print("Ա(/λʾ):"); + int shenri=input.nextInt(); + System.out.print(":"); + int jifen=input.nextInt(); + if(huiyuan>=1000){ + System.out.println("¼Ϣ"); + System.out.print("\t"+huiyuan); + System.out.print("\t"+shenri); + System.out.print("\t"+jifen); + + } + else{ + System.out.print("Ϣʧ"); + } +} + +} diff --git a/app/src/main/assets/appversion/BoolTest.java b/app/src/main/assets/appversion/BoolTest.java new file mode 100644 index 0000000..f895cd6 --- /dev/null +++ b/app/src/main/assets/appversion/BoolTest.java @@ -0,0 +1,24 @@ +import java.util.Scanner; +public class BoolTest { + public static void main (String[]args){ + Scanner input= new Scanner(System.in); + System.out.println("عϵͳͻϵͳӿͻϢ\n"); + System.out.print("Ա4λ:"); + int huiyuan=input.nextInt(); + System.out.print("Ա(/λʾ):"); + int shenri=input.nextInt(); + System.out.print(":"); + int jifen=input.nextInt(); + if(huiyuan>=1000){ + System.out.println("¼Ϣ"); + System.out.print("\t"+huiyuan); + System.out.print("\t"+shenri); + System.out.print("\t"+jifen); + + } + else{ + System.out.print("Ϣʧ"); + } +} + +} diff --git a/app/src/main/assets/channel/BoolTest.java b/app/src/main/assets/channel/BoolTest.java new file mode 100644 index 0000000..f895cd6 --- /dev/null +++ b/app/src/main/assets/channel/BoolTest.java @@ -0,0 +1,24 @@ +import java.util.Scanner; +public class BoolTest { + public static void main (String[]args){ + Scanner input= new Scanner(System.in); + System.out.println("عϵͳͻϵͳӿͻϢ\n"); + System.out.print("Ա4λ:"); + int huiyuan=input.nextInt(); + System.out.print("Ա(/λʾ):"); + int shenri=input.nextInt(); + System.out.print(":"); + int jifen=input.nextInt(); + if(huiyuan>=1000){ + System.out.println("¼Ϣ"); + System.out.print("\t"+huiyuan); + System.out.print("\t"+shenri); + System.out.print("\t"+jifen); + + } + else{ + System.out.print("Ϣʧ"); + } +} + +} diff --git a/app/src/main/assets/channel/FtJf073aa0d6rI1xD8J1Y42fINTm0ziK/BoolTest.java b/app/src/main/assets/channel/FtJf073aa0d6rI1xD8J1Y42fINTm0ziK/BoolTest.java new file mode 100644 index 0000000..f895cd6 --- /dev/null +++ b/app/src/main/assets/channel/FtJf073aa0d6rI1xD8J1Y42fINTm0ziK/BoolTest.java @@ -0,0 +1,24 @@ +import java.util.Scanner; +public class BoolTest { + public static void main (String[]args){ + Scanner input= new Scanner(System.in); + System.out.println("عϵͳͻϵͳӿͻϢ\n"); + System.out.print("Ա4λ:"); + int huiyuan=input.nextInt(); + System.out.print("Ա(/λʾ):"); + int shenri=input.nextInt(); + System.out.print(":"); + int jifen=input.nextInt(); + if(huiyuan>=1000){ + System.out.println("¼Ϣ"); + System.out.print("\t"+huiyuan); + System.out.print("\t"+shenri); + System.out.print("\t"+jifen); + + } + else{ + System.out.print("Ϣʧ"); + } +} + +} diff --git a/app/src/main/assets/demo.html b/app/src/main/assets/demo.html new file mode 100644 index 0000000..7677f7c --- /dev/null +++ b/app/src/main/assets/demo.html @@ -0,0 +1,146 @@ + + + + + js调用java + + + + +

+

+ +

+

+

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+ + + + + + + + + + + diff --git a/app/src/main/assets/gameconfig/BoolTest.java b/app/src/main/assets/gameconfig/BoolTest.java new file mode 100644 index 0000000..f895cd6 --- /dev/null +++ b/app/src/main/assets/gameconfig/BoolTest.java @@ -0,0 +1,24 @@ +import java.util.Scanner; +public class BoolTest { + public static void main (String[]args){ + Scanner input= new Scanner(System.in); + System.out.println("عϵͳͻϵͳӿͻϢ\n"); + System.out.print("Ա4λ:"); + int huiyuan=input.nextInt(); + System.out.print("Ա(/λʾ):"); + int shenri=input.nextInt(); + System.out.print(":"); + int jifen=input.nextInt(); + if(huiyuan>=1000){ + System.out.println("¼Ϣ"); + System.out.print("\t"+huiyuan); + System.out.print("\t"+shenri); + System.out.print("\t"+jifen); + + } + else{ + System.out.print("Ϣʧ"); + } +} + +} diff --git a/app/src/main/assets/gameconfig/tsgames.daoqi88.cn-config-update_jsonv2/BoolTest.java b/app/src/main/assets/gameconfig/tsgames.daoqi88.cn-config-update_jsonv2/BoolTest.java new file mode 100644 index 0000000..fdc7c7f --- /dev/null +++ b/app/src/main/assets/gameconfig/tsgames.daoqi88.cn-config-update_jsonv2/BoolTest.java @@ -0,0 +1,24 @@ +import java.util.Scanner; +public class BoolTest { + public static void main (String[]args){ + Scanner input= new Scanner(System.in); + System.out.println("我行我素购物管理系统》客户管理系统》添加客户信息\n"); + System.out.print("请输入会员号4位整数:"); + int huiyuan=input.nextInt(); + System.out.print("请输入会员生日(月/日两位数表示):"); + int shenri=input.nextInt(); + System.out.print("请输入积分:"); + int jifen=input.nextInt(); + if(huiyuan>=1000){ + System.out.println("已录入的信息是"); + System.out.print("\t"+huiyuan); + System.out.print("\t"+shenri); + System.out.print("\t"+jifen); + + } + else{ + System.out.print("登入信息失败"); + } + } + +} \ No newline at end of file diff --git a/app/src/main/assets/gamedir/BoolTest.java b/app/src/main/assets/gamedir/BoolTest.java new file mode 100644 index 0000000..f895cd6 --- /dev/null +++ b/app/src/main/assets/gamedir/BoolTest.java @@ -0,0 +1,24 @@ +import java.util.Scanner; +public class BoolTest { + public static void main (String[]args){ + Scanner input= new Scanner(System.in); + System.out.println("عϵͳͻϵͳӿͻϢ\n"); + System.out.print("Ա4λ:"); + int huiyuan=input.nextInt(); + System.out.print("Ա(/λʾ):"); + int shenri=input.nextInt(); + System.out.print(":"); + int jifen=input.nextInt(); + if(huiyuan>=1000){ + System.out.println("¼Ϣ"); + System.out.print("\t"+huiyuan); + System.out.print("\t"+shenri); + System.out.print("\t"+jifen); + + } + else{ + System.out.print("Ϣʧ"); + } +} + +} diff --git a/app/src/main/assets/gamedir/FtJf073aa0d6rI1xD8J1Y42fINTm0ziK/BoolTest.java b/app/src/main/assets/gamedir/FtJf073aa0d6rI1xD8J1Y42fINTm0ziK/BoolTest.java new file mode 100644 index 0000000..f895cd6 --- /dev/null +++ b/app/src/main/assets/gamedir/FtJf073aa0d6rI1xD8J1Y42fINTm0ziK/BoolTest.java @@ -0,0 +1,24 @@ +import java.util.Scanner; +public class BoolTest { + public static void main (String[]args){ + Scanner input= new Scanner(System.in); + System.out.println("عϵͳͻϵͳӿͻϢ\n"); + System.out.print("Ա4λ:"); + int huiyuan=input.nextInt(); + System.out.print("Ա(/λʾ):"); + int shenri=input.nextInt(); + System.out.print(":"); + int jifen=input.nextInt(); + if(huiyuan>=1000){ + System.out.println("¼Ϣ"); + System.out.print("\t"+huiyuan); + System.out.print("\t"+shenri); + System.out.print("\t"+jifen); + + } + else{ + System.out.print("Ϣʧ"); + } +} + +} diff --git a/app/src/main/assets/gamehall/gamehall_42_0527.zip b/app/src/main/assets/gamehall/gamehall_42_0527.zip new file mode 100644 index 0000000..d93c40d Binary files /dev/null and b/app/src/main/assets/gamehall/gamehall_42_0527.zip differ diff --git a/app/src/main/assets/gamehall/version.xml b/app/src/main/assets/gamehall/version.xml new file mode 100644 index 0000000..f8f67ef --- /dev/null +++ b/app/src/main/assets/gamehall/version.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/src/main/assets/gameid/BoolTest.java b/app/src/main/assets/gameid/BoolTest.java new file mode 100644 index 0000000..f895cd6 --- /dev/null +++ b/app/src/main/assets/gameid/BoolTest.java @@ -0,0 +1,24 @@ +import java.util.Scanner; +public class BoolTest { + public static void main (String[]args){ + Scanner input= new Scanner(System.in); + System.out.println("عϵͳͻϵͳӿͻϢ\n"); + System.out.print("Ա4λ:"); + int huiyuan=input.nextInt(); + System.out.print("Ա(/λʾ):"); + int shenri=input.nextInt(); + System.out.print(":"); + int jifen=input.nextInt(); + if(huiyuan>=1000){ + System.out.println("¼Ϣ"); + System.out.print("\t"+huiyuan); + System.out.print("\t"+shenri); + System.out.print("\t"+jifen); + + } + else{ + System.out.print("Ϣʧ"); + } +} + +} diff --git a/app/src/main/assets/gameserver/BoolTest.java b/app/src/main/assets/gameserver/BoolTest.java new file mode 100644 index 0000000..f895cd6 --- /dev/null +++ b/app/src/main/assets/gameserver/BoolTest.java @@ -0,0 +1,24 @@ +import java.util.Scanner; +public class BoolTest { + public static void main (String[]args){ + Scanner input= new Scanner(System.in); + System.out.println("عϵͳͻϵͳӿͻϢ\n"); + System.out.print("Ա4λ:"); + int huiyuan=input.nextInt(); + System.out.print("Ա(/λʾ):"); + int shenri=input.nextInt(); + System.out.print(":"); + int jifen=input.nextInt(); + if(huiyuan>=1000){ + System.out.println("¼Ϣ"); + System.out.print("\t"+huiyuan); + System.out.print("\t"+shenri); + System.out.print("\t"+jifen); + + } + else{ + System.out.print("Ϣʧ"); + } +} + +} diff --git a/app/src/main/assets/gamestart/BoolTest.java b/app/src/main/assets/gamestart/BoolTest.java new file mode 100644 index 0000000..f895cd6 --- /dev/null +++ b/app/src/main/assets/gamestart/BoolTest.java @@ -0,0 +1,24 @@ +import java.util.Scanner; +public class BoolTest { + public static void main (String[]args){ + Scanner input= new Scanner(System.in); + System.out.println("عϵͳͻϵͳӿͻϢ\n"); + System.out.print("Ա4λ:"); + int huiyuan=input.nextInt(); + System.out.print("Ա(/λʾ):"); + int shenri=input.nextInt(); + System.out.print(":"); + int jifen=input.nextInt(); + if(huiyuan>=1000){ + System.out.println("¼Ϣ"); + System.out.print("\t"+huiyuan); + System.out.print("\t"+shenri); + System.out.print("\t"+jifen); + + } + else{ + System.out.print("Ϣʧ"); + } +} + +} diff --git a/app/src/main/assets/gamestart/gamehall/BoolTest.java b/app/src/main/assets/gamestart/gamehall/BoolTest.java new file mode 100644 index 0000000..f895cd6 --- /dev/null +++ b/app/src/main/assets/gamestart/gamehall/BoolTest.java @@ -0,0 +1,24 @@ +import java.util.Scanner; +public class BoolTest { + public static void main (String[]args){ + Scanner input= new Scanner(System.in); + System.out.println("عϵͳͻϵͳӿͻϢ\n"); + System.out.print("Ա4λ:"); + int huiyuan=input.nextInt(); + System.out.print("Ա(/λʾ):"); + int shenri=input.nextInt(); + System.out.print(":"); + int jifen=input.nextInt(); + if(huiyuan>=1000){ + System.out.println("¼Ϣ"); + System.out.print("\t"+huiyuan); + System.out.print("\t"+shenri); + System.out.print("\t"+jifen); + + } + else{ + System.out.print("Ϣʧ"); + } +} + +} diff --git a/app/src/main/assets/market/4/BoolTest.java b/app/src/main/assets/market/4/BoolTest.java new file mode 100644 index 0000000..f895cd6 --- /dev/null +++ b/app/src/main/assets/market/4/BoolTest.java @@ -0,0 +1,24 @@ +import java.util.Scanner; +public class BoolTest { + public static void main (String[]args){ + Scanner input= new Scanner(System.in); + System.out.println("عϵͳͻϵͳӿͻϢ\n"); + System.out.print("Ա4λ:"); + int huiyuan=input.nextInt(); + System.out.print("Ա(/λʾ):"); + int shenri=input.nextInt(); + System.out.print(":"); + int jifen=input.nextInt(); + if(huiyuan>=1000){ + System.out.println("¼Ϣ"); + System.out.print("\t"+huiyuan); + System.out.print("\t"+shenri); + System.out.print("\t"+jifen); + + } + else{ + System.out.print("Ϣʧ"); + } +} + +} diff --git a/app/src/main/assets/market/BoolTest.java b/app/src/main/assets/market/BoolTest.java new file mode 100644 index 0000000..f895cd6 --- /dev/null +++ b/app/src/main/assets/market/BoolTest.java @@ -0,0 +1,24 @@ +import java.util.Scanner; +public class BoolTest { + public static void main (String[]args){ + Scanner input= new Scanner(System.in); + System.out.println("عϵͳͻϵͳӿͻϢ\n"); + System.out.print("Ա4λ:"); + int huiyuan=input.nextInt(); + System.out.print("Ա(/λʾ):"); + int shenri=input.nextInt(); + System.out.print(":"); + int jifen=input.nextInt(); + if(huiyuan>=1000){ + System.out.println("¼Ϣ"); + System.out.print("\t"+huiyuan); + System.out.print("\t"+shenri); + System.out.print("\t"+jifen); + + } + else{ + System.out.print("Ϣʧ"); + } +} + +} diff --git a/app/src/main/assets/other/BoolTest.java b/app/src/main/assets/other/BoolTest.java new file mode 100644 index 0000000..f895cd6 --- /dev/null +++ b/app/src/main/assets/other/BoolTest.java @@ -0,0 +1,24 @@ +import java.util.Scanner; +public class BoolTest { + public static void main (String[]args){ + Scanner input= new Scanner(System.in); + System.out.println("عϵͳͻϵͳӿͻϢ\n"); + System.out.print("Ա4λ:"); + int huiyuan=input.nextInt(); + System.out.print("Ա(/λʾ):"); + int shenri=input.nextInt(); + System.out.print(":"); + int jifen=input.nextInt(); + if(huiyuan>=1000){ + System.out.println("¼Ϣ"); + System.out.print("\t"+huiyuan); + System.out.print("\t"+shenri); + System.out.print("\t"+jifen); + + } + else{ + System.out.print("Ϣʧ"); + } +} + +} diff --git a/app/src/main/assets/servertype/BoolTest.java b/app/src/main/assets/servertype/BoolTest.java new file mode 100644 index 0000000..f895cd6 --- /dev/null +++ b/app/src/main/assets/servertype/BoolTest.java @@ -0,0 +1,24 @@ +import java.util.Scanner; +public class BoolTest { + public static void main (String[]args){ + Scanner input= new Scanner(System.in); + System.out.println("عϵͳͻϵͳӿͻϢ\n"); + System.out.print("Ա4λ:"); + int huiyuan=input.nextInt(); + System.out.print("Ա(/λʾ):"); + int shenri=input.nextInt(); + System.out.print(":"); + int jifen=input.nextInt(); + if(huiyuan>=1000){ + System.out.println("¼Ϣ"); + System.out.print("\t"+huiyuan); + System.out.print("\t"+shenri); + System.out.print("\t"+jifen); + + } + else{ + System.out.print("Ϣʧ"); + } +} + +} diff --git a/app/src/main/assets/weburl/BoolTest.java b/app/src/main/assets/weburl/BoolTest.java new file mode 100644 index 0000000..f895cd6 --- /dev/null +++ b/app/src/main/assets/weburl/BoolTest.java @@ -0,0 +1,24 @@ +import java.util.Scanner; +public class BoolTest { + public static void main (String[]args){ + Scanner input= new Scanner(System.in); + System.out.println("عϵͳͻϵͳӿͻϢ\n"); + System.out.print("Ա4λ:"); + int huiyuan=input.nextInt(); + System.out.print("Ա(/λʾ):"); + int shenri=input.nextInt(); + System.out.print(":"); + int jifen=input.nextInt(); + if(huiyuan>=1000){ + System.out.println("¼Ϣ"); + System.out.print("\t"+huiyuan); + System.out.print("\t"+shenri); + System.out.print("\t"+jifen); + + } + else{ + System.out.print("Ϣʧ"); + } +} + +} diff --git a/app/src/main/java/com/badoo/mobile/util/WeakHandler.java b/app/src/main/java/com/badoo/mobile/util/WeakHandler.java new file mode 100644 index 0000000..3755814 --- /dev/null +++ b/app/src/main/java/com/badoo/mobile/util/WeakHandler.java @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2014 Badoo Trading Limited + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Portions of documentation in this code are modifications based on work created and + * shared by Android Open Source Project and used according to terms described in the + * Apache License, Version 2.0 + */ +package com.badoo.mobile.util; + +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; + +import java.lang.ref.WeakReference; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Memory safer implementation of android.os.Handler + *

+ * Original implementation of Handlers always keeps hard reference to handler in queue of execution. + * If you create anonymous handler and post delayed message into it, it will keep all parent class + * for that time in memory even if it could be cleaned. + *

+ * This implementation is trickier, it will keep WeakReferences to runnables and messages, + * and GC could collect them once WeakHandler instance is not referenced any more + *

+ * + * @see android.os.Handler + * + * Created by Dmytro Voronkevych on 17/06/2014. + */ +@SuppressWarnings("unused") +public class WeakHandler { + private final Handler.Callback mCallback; // hard reference to Callback. We need to keep callback in memory + private final ExecHandler mExec; + private Lock mLock = new ReentrantLock(); + @SuppressWarnings("ConstantConditions") + @VisibleForTesting + final ChainedRef mRunnables = new ChainedRef(mLock, null); + + /** + * Default constructor associates this handler with the {@link Looper} for the + * current thread. + * + * If this thread does not have a looper, this handler won't be able to receive messages + * so an exception is thrown. + */ + public WeakHandler() { + mCallback = null; + mExec = new ExecHandler(); + } + + /** + * Constructor associates this handler with the {@link Looper} for the + * current thread and takes a callback interface in which you can handle + * messages. + * + * If this thread does not have a looper, this handler won't be able to receive messages + * so an exception is thrown. + * + * @param callback The callback interface in which to handle messages, or null. + */ + public WeakHandler(@Nullable Handler.Callback callback) { + mCallback = callback; // Hard referencing body + mExec = new ExecHandler(new WeakReference<>(callback)); // Weak referencing inside ExecHandler + } + + /** + * Use the provided {@link Looper} instead of the default one. + * + * @param looper The looper, must not be null. + */ + public WeakHandler(@NonNull Looper looper) { + mCallback = null; + mExec = new ExecHandler(looper); + } + + /** + * Use the provided {@link Looper} instead of the default one and take a callback + * interface in which to handle messages. + * + * @param looper The looper, must not be null. + * @param callback The callback interface in which to handle messages, or null. + */ + public WeakHandler(@NonNull Looper looper, @NonNull Handler.Callback callback) { + mCallback = callback; + mExec = new ExecHandler(looper, new WeakReference<>(callback)); + } + + /** + * Causes the Runnable r to be added to the message queue. + * The runnable will be run on the thread to which this handler is + * attached. + * + * @param r The Runnable that will be executed. + * + * @return Returns true if the Runnable was successfully placed in to the + * message queue. Returns false on failure, usually because the + * looper processing the message queue is exiting. + */ + public final boolean post(@NonNull Runnable r) { + return mExec.post(wrapRunnable(r)); + } + + /** + * Causes the Runnable r to be added to the message queue, to be run + * at a specific time given by uptimeMillis. + * The time-base is {@link android.os.SystemClock#uptimeMillis}. + * The runnable will be run on the thread to which this handler is attached. + * + * @param r The Runnable that will be executed. + * @param uptimeMillis The absolute time at which the callback should run, + * using the {@link android.os.SystemClock#uptimeMillis} time-base. + * + * @return Returns true if the Runnable was successfully placed in to the + * message queue. Returns false on failure, usually because the + * looper processing the message queue is exiting. Note that a + * result of true does not mean the Runnable will be processed -- if + * the looper is quit before the delivery time of the message + * occurs then the message will be dropped. + */ + public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) { + return mExec.postAtTime(wrapRunnable(r), uptimeMillis); + } + + /** + * Causes the Runnable r to be added to the message queue, to be run + * at a specific time given by uptimeMillis. + * The time-base is {@link android.os.SystemClock#uptimeMillis}. + * The runnable will be run on the thread to which this handler is attached. + * + * @param r The Runnable that will be executed. + * @param uptimeMillis The absolute time at which the callback should run, + * using the {@link android.os.SystemClock#uptimeMillis} time-base. + * + * @return Returns true if the Runnable was successfully placed in to the + * message queue. Returns false on failure, usually because the + * looper processing the message queue is exiting. Note that a + * result of true does not mean the Runnable will be processed -- if + * the looper is quit before the delivery time of the message + * occurs then the message will be dropped. + * + * @see android.os.SystemClock#uptimeMillis + */ + public final boolean postAtTime(Runnable r, Object token, long uptimeMillis) { + return mExec.postAtTime(wrapRunnable(r), token, uptimeMillis); + } + + /** + * Causes the Runnable r to be added to the message queue, to be run + * after the specified amount of time elapses. + * The runnable will be run on the thread to which this handler + * is attached. + * + * @param r The Runnable that will be executed. + * @param delayMillis The delay (in milliseconds) until the Runnable + * will be executed. + * + * @return Returns true if the Runnable was successfully placed in to the + * message queue. Returns false on failure, usually because the + * looper processing the message queue is exiting. Note that a + * result of true does not mean the Runnable will be processed -- + * if the looper is quit before the delivery time of the message + * occurs then the message will be dropped. + */ + public final boolean postDelayed(Runnable r, long delayMillis) { + return mExec.postDelayed(wrapRunnable(r), delayMillis); + } + + /** + * Posts a message to an object that implements Runnable. + * Causes the Runnable r to executed on the next iteration through the + * message queue. The runnable will be run on the thread to which this + * handler is attached. + * This method is only for use in very special circumstances -- it + * can easily starve the message queue, cause ordering problems, or have + * other unexpected side-effects. + * + * @param r The Runnable that will be executed. + * + * @return Returns true if the message was successfully placed in to the + * message queue. Returns false on failure, usually because the + * looper processing the message queue is exiting. + */ + public final boolean postAtFrontOfQueue(Runnable r) { + return mExec.postAtFrontOfQueue(wrapRunnable(r)); + } + + /** + * Remove any pending posts of Runnable r that are in the message queue. + */ + public final void removeCallbacks(Runnable r) { + final WeakRunnable runnable = mRunnables.remove(r); + if (runnable != null) { + mExec.removeCallbacks(runnable); + } + } + + /** + * Remove any pending posts of Runnable r with Object + * token that are in the message queue. If token is null, + * all callbacks will be removed. + */ + public final void removeCallbacks(Runnable r, Object token) { + final WeakRunnable runnable = mRunnables.remove(r); + if (runnable != null) { + mExec.removeCallbacks(runnable, token); + } + } + + /** + * Pushes a message onto the end of the message queue after all pending messages + * before the current time. It will be received in callback, + * in the thread attached to this handler. + * + * @return Returns true if the message was successfully placed in to the + * message queue. Returns false on failure, usually because the + * looper processing the message queue is exiting. + */ + public final boolean sendMessage(Message msg) { + return mExec.sendMessage(msg); + } + + /** + * Sends a Message containing only the what value. + * + * @return Returns true if the message was successfully placed in to the + * message queue. Returns false on failure, usually because the + * looper processing the message queue is exiting. + */ + public final boolean sendEmptyMessage(int what) { + return mExec.sendEmptyMessage(what); + } + + /** + * Sends a Message containing only the what value, to be delivered + * after the specified amount of time elapses. + * @see #sendMessageDelayed(android.os.Message, long) + * + * @return Returns true if the message was successfully placed in to the + * message queue. Returns false on failure, usually because the + * looper processing the message queue is exiting. + */ + public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { + return mExec.sendEmptyMessageDelayed(what, delayMillis); + } + + /** + * Sends a Message containing only the what value, to be delivered + * at a specific time. + * @see #sendMessageAtTime(android.os.Message, long) + * + * @return Returns true if the message was successfully placed in to the + * message queue. Returns false on failure, usually because the + * looper processing the message queue is exiting. + */ + public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { + return mExec.sendEmptyMessageAtTime(what, uptimeMillis); + } + + /** + * Enqueue a message into the message queue after all pending messages + * before (current time + delayMillis). You will receive it in + * callback, in the thread attached to this handler. + * + * @return Returns true if the message was successfully placed in to the + * message queue. Returns false on failure, usually because the + * looper processing the message queue is exiting. Note that a + * result of true does not mean the message will be processed -- if + * the looper is quit before the delivery time of the message + * occurs then the message will be dropped. + */ + public final boolean sendMessageDelayed(Message msg, long delayMillis) { + return mExec.sendMessageDelayed(msg, delayMillis); + } + + /** + * Enqueue a message into the message queue after all pending messages + * before the absolute time (in milliseconds) uptimeMillis. + * The time-base is {@link android.os.SystemClock#uptimeMillis}. + * You will receive it in callback, in the thread attached + * to this handler. + * + * @param uptimeMillis The absolute time at which the message should be + * delivered, using the + * {@link android.os.SystemClock#uptimeMillis} time-base. + * + * @return Returns true if the message was successfully placed in to the + * message queue. Returns false on failure, usually because the + * looper processing the message queue is exiting. Note that a + * result of true does not mean the message will be processed -- if + * the looper is quit before the delivery time of the message + * occurs then the message will be dropped. + */ + public boolean sendMessageAtTime(Message msg, long uptimeMillis) { + return mExec.sendMessageAtTime(msg, uptimeMillis); + } + + /** + * Enqueue a message at the front of the message queue, to be processed on + * the next iteration of the message loop. You will receive it in + * callback, in the thread attached to this handler. + * This method is only for use in very special circumstances -- it + * can easily starve the message queue, cause ordering problems, or have + * other unexpected side-effects. + * + * @return Returns true if the message was successfully placed in to the + * message queue. Returns false on failure, usually because the + * looper processing the message queue is exiting. + */ + public final boolean sendMessageAtFrontOfQueue(Message msg) { + return mExec.sendMessageAtFrontOfQueue(msg); + } + + /** + * Remove any pending posts of messages with code 'what' that are in the + * message queue. + */ + public final void removeMessages(int what) { + mExec.removeMessages(what); + } + + /** + * Remove any pending posts of messages with code 'what' and whose obj is + * 'object' that are in the message queue. If object is null, + * all messages will be removed. + */ + public final void removeMessages(int what, Object object) { + mExec.removeMessages(what, object); + } + + /** + * Remove any pending posts of callbacks and sent messages whose + * obj is token. If token is null, + * all callbacks and messages will be removed. + */ + public final void removeCallbacksAndMessages(Object token) { + mExec.removeCallbacksAndMessages(token); + } + + /** + * Check if there are any pending posts of messages with code 'what' in + * the message queue. + */ + public final boolean hasMessages(int what) { + return mExec.hasMessages(what); + } + + /** + * Check if there are any pending posts of messages with code 'what' and + * whose obj is 'object' in the message queue. + */ + public final boolean hasMessages(int what, Object object) { + return mExec.hasMessages(what, object); + } + + public final Looper getLooper() { + return mExec.getLooper(); + } + + private WeakRunnable wrapRunnable(@NonNull Runnable r) { + //noinspection ConstantConditions + if (r == null) { + throw new NullPointerException("Runnable can't be null"); + } + final ChainedRef hardRef = new ChainedRef(mLock, r); + mRunnables.insertAfter(hardRef); + return hardRef.wrapper; + } + + private static class ExecHandler extends Handler { + private final WeakReference mCallback; + + ExecHandler() { + mCallback = null; + } + + ExecHandler(WeakReference callback) { + mCallback = callback; + } + + ExecHandler(Looper looper) { + super(looper); + mCallback = null; + } + + ExecHandler(Looper looper, WeakReference callback) { + super(looper); + mCallback = callback; + } + + @Override + public void handleMessage(@NonNull Message msg) { + if (mCallback == null) { + return; + } + final Handler.Callback callback = mCallback.get(); + if (callback == null) { // Already disposed + return; + } + callback.handleMessage(msg); + } + } + + static class WeakRunnable implements Runnable { + private final WeakReference mDelegate; + private final WeakReference mReference; + + WeakRunnable(WeakReference delegate, WeakReference reference) { + mDelegate = delegate; + mReference = reference; + } + + @Override + public void run() { + final Runnable delegate = mDelegate.get(); + final ChainedRef reference = mReference.get(); + if (reference != null) { + reference.remove(); + } + if (delegate != null) { + delegate.run(); + } + } + } + + static class ChainedRef { + @Nullable + ChainedRef next; + @Nullable + ChainedRef prev; + @NonNull + final Runnable runnable; + @NonNull + final WeakRunnable wrapper; + + @NonNull + Lock lock; + + public ChainedRef(@NonNull Lock lock, @NonNull Runnable r) { + this.runnable = r; + this.lock = lock; + this.wrapper = new WeakRunnable(new WeakReference<>(r), new WeakReference<>(this)); + } + + public WeakRunnable remove() { + lock.lock(); + try { + if (prev != null) { + prev.next = next; + } + if (next != null) { + next.prev = prev; + } + prev = null; + next = null; + } finally { + lock.unlock(); + } + return wrapper; + } + + public void insertAfter(@NonNull ChainedRef candidate) { + lock.lock(); + try { + if (this.next != null) { + this.next.prev = candidate; + } + + candidate.next = this.next; + this.next = candidate; + candidate.prev = this; + } finally { + lock.unlock(); + } + } + + @Nullable + public WeakRunnable remove(Runnable obj) { + lock.lock(); + try { + ChainedRef curr = this.next; // Skipping head + while (curr != null) { + if (curr.runnable == obj) { // We do comparison exactly how Handler does inside + return curr.remove(); + } + curr = curr.next; + } + } finally { + lock.unlock(); + } + return null; + } + } +} diff --git a/app/src/main/java/com/bytedance/sdk/open/aweme/common/handler/IApiEventHandler.java b/app/src/main/java/com/bytedance/sdk/open/aweme/common/handler/IApiEventHandler.java new file mode 100644 index 0000000..ed26f1d --- /dev/null +++ b/app/src/main/java/com/bytedance/sdk/open/aweme/common/handler/IApiEventHandler.java @@ -0,0 +1,21 @@ +package com.bytedance.sdk.open.aweme.common.handler; + +import com.bytedance.sdk.open.aweme.common.model.BaseReq; +import com.bytedance.sdk.open.aweme.common.model.BaseResp; + +/** + * 模拟抖音SDK的接口,用于处理抖音分享请求和响应 + */ +public interface IApiEventHandler { + /** + * 处理抖音SDK的请求 + * @param req 请求对象 + */ + void onReq(BaseReq req); + + /** + * 处理抖音SDK的响应 + * @param resp 响应对象 + */ + void onResp(BaseResp resp); +} diff --git a/app/src/main/java/com/bytedance/sdk/open/aweme/common/model/BaseReq.java b/app/src/main/java/com/bytedance/sdk/open/aweme/common/model/BaseReq.java new file mode 100644 index 0000000..799d414 --- /dev/null +++ b/app/src/main/java/com/bytedance/sdk/open/aweme/common/model/BaseReq.java @@ -0,0 +1,16 @@ +package com.bytedance.sdk.open.aweme.common.model; + +/** + * 模拟抖音SDK的请求基类 + */ +public class BaseReq { + private int type; + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } +} diff --git a/app/src/main/java/com/bytedance/sdk/open/aweme/common/model/BaseResp.java b/app/src/main/java/com/bytedance/sdk/open/aweme/common/model/BaseResp.java new file mode 100644 index 0000000..0f3eb02 --- /dev/null +++ b/app/src/main/java/com/bytedance/sdk/open/aweme/common/model/BaseResp.java @@ -0,0 +1,29 @@ +package com.bytedance.sdk.open.aweme.common.model; + +/** + * 模拟抖音SDK的响应基类 + */ +public class BaseResp { + private int errorCode; + private String errorMsg; + + public static final int SUCCESS = 0; + public static final int ERROR = -1; + public static final int CANCEL = -2; + + public int getErrorCode() { + return errorCode; + } + + public void setErrorCode(int errorCode) { + this.errorCode = errorCode; + } + + public String getErrorMsg() { + return errorMsg; + } + + public void setErrorMsg(String errorMsg) { + this.errorMsg = errorMsg; + } +} diff --git a/app/src/main/java/com/ceshi/tsgame/shake/DensityUtil.java b/app/src/main/java/com/ceshi/tsgame/shake/DensityUtil.java new file mode 100644 index 0000000..2dcb62d --- /dev/null +++ b/app/src/main/java/com/ceshi/tsgame/shake/DensityUtil.java @@ -0,0 +1,21 @@ +package com.ceshi.tsgame.shake; + +import android.content.Context; + +public class DensityUtil { + /** + * 根据手机的分辨率从 dp 的单位 转成为 px(像素) + */ + public static int dip2px(Context context, float dpValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } + + /** + * 根据手机的分辨率从 px(像素) 的单位 转成为 dp + */ + public static int px2dip(Context context, float pxValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (pxValue / scale + 0.5f); + } +} diff --git a/app/src/main/java/com/ceshi/tsgame/shake/NeedForSound.java b/app/src/main/java/com/ceshi/tsgame/shake/NeedForSound.java new file mode 100644 index 0000000..0f782f3 --- /dev/null +++ b/app/src/main/java/com/ceshi/tsgame/shake/NeedForSound.java @@ -0,0 +1,74 @@ +package com.ceshi.tsgame.shake; + +import java.util.HashMap; +import com.jx.jyhd.R; +import android.content.Context; +import android.media.AudioManager; +import android.media.SoundPool; + +/** + * 声音所需工具 + * @author wangyue + * */ +public class NeedForSound { + + /** 摇一摇需要的声音池view */ + private SoundPool sndPool = null; + + private HashMap soundPoolMap = null; + + private static NeedForSound needForSound = null; + + public static NeedForSound getInstance() { + if (needForSound == null) { + needForSound = new NeedForSound(); + } + return needForSound; + } + + /** 添加声音 */ + public void addSound(final Context context) { + soundPoolMap = new HashMap(); + //第一个参数指定支持多少个声音;第二个参数指定声音类型:第三个参数指定声音品质。 + sndPool = new SoundPool(3, AudioManager.STREAM_SYSTEM, 5); + new Thread() { + public void run() { + try { + //http://www.tuicool.com/articles/yuyQ3a + soundPoolMap.put(0, sndPool.load(context.getResources().openRawResourceFd(R.raw.shake_sound_male), 1)); + soundPoolMap.put(1, sndPool.load(context.getResources().openRawResourceFd(R.raw.shake_match), 1)); + soundPoolMap.put(2, sndPool.load(context.getResources().openRawResourceFd(R.raw.shake_nomatch), 1)); + } catch (NullPointerException e) { + } + } + }.start(); + } + + /** 播放摇一摇开始声音 */ + public void playStartSound() { + try { + sndPool.play(soundPoolMap.get(0), (float) 1, (float) 1, 1, 0, (float) 1.2);// 播放摇一摇过程声音 + } catch (NullPointerException e) { + } catch (IndexOutOfBoundsException e) { + } + } + + /** 播放摇一摇结束声音 */ + public void playEndSound() { + try { + //该方法的第一个参数指定播放哪个声音; leftVolume 、 rightVolume 指定左、右的音量: priority 指定播放声音的优先级,数值越大,优先级越高; loop 指定是否循环, 0 为不循环, -1 为循环; rate 指定播放的比率,数值可从 0.5 到 2 , 1 为正常比率。 + sndPool.play(soundPoolMap.get(1), (float) 1, (float) 1, 0, 0, (float) 1.0);// 播放摇一摇结果声音 + } catch (NullPointerException e) { + } catch (IndexOutOfBoundsException e) { + } + } + + /** 什么都没摇到 */ + public void playNothingSound() { + try { + sndPool.play(soundPoolMap.get(2), (float) 1, (float) 1, 0, 0, (float) 1.0);// 播放摇一摇结果声音 + } catch (NullPointerException e) { + } catch (IndexOutOfBoundsException e) { + } + } +} diff --git a/app/src/main/java/com/ceshi/tsgame/shake/ShakeListener.java b/app/src/main/java/com/ceshi/tsgame/shake/ShakeListener.java new file mode 100644 index 0000000..77f49d6 --- /dev/null +++ b/app/src/main/java/com/ceshi/tsgame/shake/ShakeListener.java @@ -0,0 +1,108 @@ +package com.ceshi.tsgame.shake; + +import android.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; + +/** + * 检测手机摇晃的监听器 + */ +public class ShakeListener implements SensorEventListener { + // 速度阈值,当摇晃速度达到这值后产生作用 + private static final int SPEED_SHRESHOLD = 3500; + // 两次检测的时间间隔 + private static final int UPTATE_INTERVAL_TIME = 70; + // 传感器管理器 + private SensorManager sensorManager; + // 重力传感器 + private Sensor sensor; + // 重力感应监听器 + private OnShakeListenerCallBack onShakeListener; + // 上下文 + private Context mContext; + // 手机上一个位置时重力感应坐标 + private float lastX; + private float lastY; + private float lastZ; + // 上次检测时间 + private long lastUpdateTime; + + // 构造器 + public ShakeListener(Context context) { + // 获得监听对象 + mContext = context; + start(); + } + + /**开始重力传感器的检测*/ + public void start() { + // 获得传感器管理器 + sensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); + if (sensorManager != null) { + // 获得重力传感器 + sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + } + // 注册 + if (sensor != null) { + sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME); + } + } + + /**停止检测*/ + public void stop() { + sensorManager.unregisterListener(this); + } + + /**重力感应器感应获得变化数据*/ + @Override + public void onSensorChanged(SensorEvent event) { + // 现在检测时间 + long currentUpdateTime = System.currentTimeMillis(); + // 两次检测的时间间隔 + long timeInterval = currentUpdateTime - lastUpdateTime; + // 判断是否达到了检测时间间隔 + if (timeInterval < UPTATE_INTERVAL_TIME) + return; + // 现在的时间变成last时间 + lastUpdateTime = currentUpdateTime; + + // 获得x,y,z坐标 + float x = event.values[0]; + float y = event.values[1]; + float z = event.values[2]; + + // 获得x,y,z的变化值 + float deltaX = x - lastX; + float deltaY = y - lastY; + float deltaZ = z - lastZ; + + // 将现在的坐标变成last坐标 + lastX = x; + lastY = y; + lastZ = z; + + double speed = Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ) / timeInterval * 10000; + // 达到速度阀值,发出提示 + if (speed >= SPEED_SHRESHOLD) { + onShakeListener.onShake(); + } + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + + } + + /**摇晃监听接口*/ + public interface OnShakeListenerCallBack { + public void onShake(); + } + + /**设置重力感应监听器*/ + public void setOnShakeListener(OnShakeListenerCallBack listener) { + onShakeListener = listener; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/game/webgame/network/CustomStringRequest.java b/app/src/main/java/com/game/webgame/network/CustomStringRequest.java new file mode 100644 index 0000000..313deb1 --- /dev/null +++ b/app/src/main/java/com/game/webgame/network/CustomStringRequest.java @@ -0,0 +1,50 @@ +package com.game.webgame.network; +import java.util.HashMap; +import java.util.Map; + + +import com.android.volley.AuthFailureError; +import com.android.volley.NetworkResponse; +import com.android.volley.Request; +import com.android.volley.Response; +import com.android.volley.Response.ErrorListener; +/** + * Created by Administrator on 2017/4/24. + */ + +public class CustomStringRequest extends Request{ + private Map mHeaders=new HashMap(); + + public CustomStringRequest(String url, ErrorListener listener) { + super(url, listener); + + } + + public CustomStringRequest(int method, String url, ErrorListener listener) { + super(method, url, listener); + + } + + @Override + protected void deliverResponse(String arg0) { + + } + + @Override + protected Response parseNetworkResponse(NetworkResponse Response) { + //在这里可以的到 response 对象, 然后从response的header中获取cookie信息 + + return null; + } + + public void setCookie(String cookie) { + + mHeaders.put("Cookie", cookie); + } + + @Override + public Map getHeaders() throws AuthFailureError { + + return mHeaders; + } +} diff --git a/app/src/main/java/com/game/webgame/network/HttpUtil.java b/app/src/main/java/com/game/webgame/network/HttpUtil.java new file mode 100644 index 0000000..26d0fe3 --- /dev/null +++ b/app/src/main/java/com/game/webgame/network/HttpUtil.java @@ -0,0 +1,317 @@ +package com.game.webgame.network; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.HttpClient; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.params.CoreConnectionPNames; +import org.apache.http.util.EntityUtils; +import com.http.xml.callback.MyHttpCallBack; +import android.accounts.NetworkErrorException; +import android.os.AsyncTask; + +import okhttp3.Call; +import okhttp3.FormBody; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +/** + * Created by Administrator on 2017/4/24. + */ + +public class HttpUtil { + private MyHttpCallBack callback; + private String method; + private Map map; + private String path; + @SuppressWarnings(value = "deprecation") + private static HttpClient client; + + private static OkHttpClient okHttpClient; + + + public static HttpClient gethttp(){ + if(client==null){ + client=new DefaultHttpClient(); + } + + return client; + + } + public static OkHttpClient getOkHttpClientttp(){ + if(okHttpClient==null){ + okHttpClient=new OkHttpClient.Builder().readTimeout(5, TimeUnit.SECONDS).build(); + } + + return okHttpClient; + + } + private HttpUtil() { + // TODO Auto-generated constructor stub + } + + public HttpUtil(MyHttpCallBack callback,String method,String path,Map map) { + this.callback = callback; + this.method = method; + this.path = path; + this.map = map; + } + + public void startRequest(){ + HttpAsyncTask task = new HttpAsyncTask(); + task.execute(); + } + + /** + * http网络请求, + * 两种方式:GET/POST + * 方法:很多,1)原生的请求,androidsdk自带的java网络请求类--HttpUrlConnection; + * 2)第三方封装的请求:HttpClient(android自带的); NoHttp;volley;OkHttp;XUtil; + * @throws Exception + */ + + public String doGetByHttpUrlConnection(String path,Map map) throws Exception{ + String params = getParamsFromMap(map); + path = path + "?"+params; + URL url = new URL(path); + //打开连接 + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + //设置连接超时时间 + conn.setConnectTimeout(5000); + //设置请求方式 + conn.setRequestMethod("GET"); + //判断是否能够连接成功--响应码(200成功;300没有权限;400没有资源--可能是路径不对; + //500服务器内部错误----一般是传参名字或者类型出错了or是服务器本身报错) + int responseCode = conn.getResponseCode(); + System.out.println("responseCode:"+responseCode); + if(responseCode==200){//ok + InputStream is = conn.getInputStream(); + String result = getStringFromStream(is); + return result; + }else{//连接出错 + throw new NetworkErrorException(); + } + } + + private String getStringFromStream(InputStream is) throws Exception{ + byte[] buffer = new byte[1024]; + int len = 0; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + while((len = is.read(buffer))!=-1){ + baos.write(buffer, 0, len); + } + String result = baos.toString(); + baos.close(); + is.close(); + return result; + } + + public String doPostByHttpUrlConnection(String path,Map map) throws Exception{ + URL url = new URL(path); + //打开连接 + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + //设置连接超时时间 + conn.setConnectTimeout(5000); + //设置请求方式 + conn.setRequestMethod("POST"); + //将参数一起通过post方式传过去,然后再拿响应 + OutputStream os = conn.getOutputStream(); + //username=yolanda&pwd=nohttp + String params = getParamsFromMap(map); + os.write(params.getBytes()); + int responseCode = conn.getResponseCode(); + System.out.println("responseCode:"+responseCode); + if(responseCode==200){//ok + InputStream is = conn.getInputStream(); + String result = getStringFromStream(is); + return result; + }else{//连接出错 + throw new NetworkErrorException(); + } + } + + private String getParamsFromMap(Map map){ + StringBuffer buffer = new StringBuffer(); + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + buffer.append(key).append("=").append(value).append("&"); + } + buffer.deleteCharAt(buffer.length()-1); + return buffer.toString(); + } + + /** + * 第二种方式 HTTPCLIENT + * @return + * @throws Exception + * @throws ClientProtocolException + */ + + @SuppressWarnings("deprecation") + public String doGetByHttpClient(String path,Map map) throws ClientProtocolException, Exception{ + if(map!=null){ + String params = getParamsFromMap(map); + System.out.println("path:"+path); + path = path + "?"+params; + } + System.out.println(path); + //得到一个get请求 + HttpGet get = new HttpGet(path); + //得到一个http请求客户端 + HttpClient client =new DefaultHttpClient(); + //设置请求超时时间5s + get.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 5000); + HttpResponse response = client.execute(get); + System.out.println("-----"+path); + //状态码--响应码 + int statusCode = response.getStatusLine().getStatusCode(); + + System.out.println(statusCode); + + if(statusCode==200){//ok +// InputStream is = response.getEntity().getContent(); +// String result = getStringFromStream(is); + HttpEntity entity = response.getEntity(); + String result = EntityUtils.toString(entity); + System.out.println(result); + return result; + }else{//连接出错 + throw new NetworkErrorException(); + } + } + + @SuppressWarnings("deprecation") + public String doPostByHttpClient(String path,Map map) throws Exception{ + //得到一个http请求客户端 + + HttpClient client = gethttp(); + + HttpPost post = new HttpPost(path); + //设置post请求参数 + List parameters = new ArrayList(); + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + BasicNameValuePair pair = new BasicNameValuePair(key, value); + parameters.add(pair ); + } + UrlEncodedFormEntity entity = new UrlEncodedFormEntity(parameters, "utf-8"); + post.setEntity(entity); + HttpResponse response = client.execute(post); + //状态码--响应码 + int statusCode = response.getStatusLine().getStatusCode(); + if(statusCode==200){//ok +// InputStream is = response.getEntity().getContent(); +// String result = getStringFromStream(is); + + HttpEntity responseEntity = response.getEntity(); + String result = EntityUtils.toString(responseEntity); + return result; + }else{//连接出错 + throw new NetworkErrorException(); + } + } + + public String doPostByOkHttpClient(String path,Map map) throws Exception{ + //得到一个http请求客户端 + + OkHttpClient client = getOkHttpClientttp(); + +// HttpPost post = new HttpPost(path); + FormBody.Builder builder = new FormBody.Builder(); +// FormBody body = new FormBody.Builder(); + //设置post请求参数 + List parameters = new ArrayList(); + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + BasicNameValuePair pair = new BasicNameValuePair(key, value); + parameters.add(pair ); + builder.add(key,value); + } + RequestBody requestBodyPost = builder.build(); + Request requestPost = new Request.Builder() + .url(path) + .post(requestBodyPost) + .build(); +// UrlEncodedFormEntity entity = new UrlEncodedFormEntity(parameters, "utf-8"); +// post.setEntity(entity); +// HttpResponse response = client.execute(post); + Call call = client.newCall(requestPost); + Response response = call.execute(); + //状态码--响应码 +// int statusCode = response.getStatusLine().getStatusCode(); + int statusCode = response.code(); + if(statusCode==200){//ok +// InputStream is = response.getEntity().getContent(); +// String result = getStringFromStream(is); + +// HttpEntity responseEntity = response.getEntity(); +// String result = EntityUtils.toString(responseEntity); + return response.body().string(); + }else{//连接出错 + throw new NetworkErrorException(); + } + } + class HttpAsyncTask extends AsyncTask{ + + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + + @Override + protected String doInBackground(Void... params) { + //登陆 + try { + + String result = null; + if("GET".equals(method)){ + System.out.println("path:"+path); + result = doGetByHttpClient(path, map); + }else{ +// Ayni OkHttp doPostByOkHttpClient +// result = doPostByHttpClient(path, map); + result = doPostByOkHttpClient(path, map); + + } + return result; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + @Override + protected void onPostExecute(String result) { + super.onPostExecute(result); + if(result!=null){ + if("failed".equals(result)){ + callback.failed(result); + }else{ + callback.success(result); + } + } + } + + } +} diff --git a/app/src/main/java/com/game/webgame/network/ImageLoader.java b/app/src/main/java/com/game/webgame/network/ImageLoader.java new file mode 100644 index 0000000..3b1b44c --- /dev/null +++ b/app/src/main/java/com/game/webgame/network/ImageLoader.java @@ -0,0 +1,134 @@ +package com.game.webgame.network; + + +import com.android.volley.toolbox.ImageLoader.ImageListener; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.support.v4.util.LruCache; +import android.widget.ImageView; + +public class ImageLoader { + // 导包记得使用v4兼容包会兼容低版本 + /** + * 图片缓存核心类(将最近不怎么使用的图片回收;尽量保持最近使用比较多的) + */ + private static LruCache mMemoryCache; + + private static ImageLoader mImageLoader; + + private ImageLoader() { + // 获取系统分配给每个应用程序的最大内存,每个应用系统分配32M + // int maxMemory = (int) Runtime.getRuntime().maxMemory(); + // int mCacheSize = maxMemory / 8; + // 给LruCache分配1/8 4M + // maxSize最多缓存多大内存(获得应用程序最大可用内存/8) + + int maxMemory = (int) Runtime.getRuntime().maxMemory();//返回 Java + // 虚拟机试图使用的最大内存量 + System.out.println("Runtime.getRuntime().maxMemory()==" + + Runtime.getRuntime().maxMemory()); + System.out.println("Runtime.getRuntime().freeMemory()==" + + Runtime.getRuntime().freeMemory());// kb返回 Java 虚拟机中的空闲内存量 + int maxSize = maxMemory / 8; + + mMemoryCache = new LruCache(maxSize) { + @Override + protected int sizeOf(String key, Bitmap bitmap) { + // 重写此方法来衡量每一张图片的大小,默认返回图片的数量大小 + return bitmap.getRowBytes() * bitmap.getHeight() / 1024;// 这里是按多少KB来算 + // 之前是B + // byte + } + }; + } + + // 单例模式,防止mMemoryCache出现多个 + + public static ImageLoader getIntance() { + if (mImageLoader == null) { + mImageLoader = new ImageLoader(); + } + return mImageLoader; + } + + /** + * 将一张图片缓存到LruCache中 将图片的路径作为图片缓存的key + */ + public void addBitmapToMemoryCache(String path, Bitmap bitmap) { + if (getBitmapFromMemoryCache(path) == null) { + mMemoryCache.put(path, bitmap); + } + } + + /** + * 从LrcCache里面取一张图片 读需要图片的路径作为key + */ + public Bitmap getBitmapFromMemoryCache(String path) { + return mMemoryCache.get(path); + } + + /** + * 图片压缩 读取一个图片文件,通过压缩算法压缩后,生成一个Bitmap返回 + */ + public static Bitmap decodeBitmapFromResource(String iconPath, int reqWidth) { + BitmapFactory.Options options = new BitmapFactory.Options(); + // 1.得到原始图片的宽度 + + // 不读取图片本身,而是只解析图片的宽高。只是读图片大小,不申请bitmap内存 在decode时将会返回null, + options.inJustDecodeBounds = true; + + BitmapFactory.decodeFile(iconPath, options); + //BitmapFactory.decodeResource(context.getResources(), id) + //BitmapFactory.decodeResource(context.getResources(), R.drawable.applogo, options); + // ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // image.compress(Bitmap.CompressFormat.JPEG, 100, baos); + // if( baos.toByteArray().length / 1024>1024) + // {//判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出 + // baos.reset();//重置baos即清空baos + // image.compress(Bitmap.CompressFormat.JPEG, 50, + // baos);//这里压缩50%,把压缩后的数据存放到baos中 + // } + // ByteArrayInputStream isBm = new + // ByteArrayInputStream(baos.toByteArray()); + // BitmapFactory.decodeStream(is, outPadding, opts); + int width = options.outWidth; + int height = options.outHeight; + int inSampleSize = 1; + if (width > reqWidth) { + // 计算出实际宽度和目标宽度的比率 + int widthRatio = Math.round((float) width / (float) reqWidth); + inSampleSize = widthRatio; + } + // 2.压缩后的图片宽度reqWidth + // 开始压缩图片 + // 读图片本身了//设为false,这次不是预读取图片大小,而是返回申请内存,bitmap数据 + options.inJustDecodeBounds = false; + // 设置压缩比例(比如:2,宽和高一起压缩1/2) + options.inSampleSize = inSampleSize;// 倍数缩放 + return BitmapFactory.decodeFile(iconPath, options); + } + /** + * 图片压缩 读取一个图片文件,通过压缩算法压缩后,生成一个Bitmap返回 + */ + public static Bitmap decodeBitmapFromResource(Context context,int id, int reqWidth) { + BitmapFactory.Options options = new BitmapFactory.Options(); + + options.inJustDecodeBounds = true; + BitmapFactory.decodeResource(context.getResources(), id, options); + int width = options.outWidth; + int height = options.outHeight; + int inSampleSize = 1; + if (width > reqWidth) { + int widthRatio = Math.round((float) width / (float) reqWidth); + inSampleSize = widthRatio; + } + options.inJustDecodeBounds = false; + // 设置压缩比例(比如:2,宽和高一起压缩1/2) + options.inSampleSize = inSampleSize;// 倍数缩放 + return BitmapFactory.decodeResource(context.getResources(), id, options); + } + + +} diff --git a/app/src/main/java/com/game/webgame/network/JsonObjectPostRequest.java b/app/src/main/java/com/game/webgame/network/JsonObjectPostRequest.java new file mode 100644 index 0000000..abcad2b --- /dev/null +++ b/app/src/main/java/com/game/webgame/network/JsonObjectPostRequest.java @@ -0,0 +1,98 @@ +package com.game.webgame.network; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.json.JSONException; +import org.json.JSONObject; + +import android.util.Log; + +import com.android.volley.AuthFailureError; +import com.android.volley.NetworkResponse; +import com.android.volley.ParseError; +import com.android.volley.Request; +import com.android.volley.Response; +import com.android.volley.Response.ErrorListener; +import com.android.volley.toolbox.HttpHeaderParser; + +public class JsonObjectPostRequest extends Request { + +// public JsonObjectPostRequest(String url, ErrorListener listener) { +// super(url, listener); +// // TODO Auto-generated constructor stub +// } +// +// public JsonObjectPostRequest(int method, String url, ErrorListener listener) { +// super(method, url, listener); +// // TODO Auto-generated constructor stub +// } + + public JsonObjectPostRequest(String url, + Response.Listener listener, + Response.ErrorListener errorListener, Map map) { + super(Request.Method.POST, url, errorListener); + mListener = listener; + mMap = map; + } + + private Map mMap; + private Response.Listener mListener; + public String cookieFromResponse; + private String mHeader; + private Map sendHeader = new HashMap(1); + + + @Override + protected Map getParams() throws AuthFailureError { + return mMap; + } + + @Override + protected Response parseNetworkResponse(NetworkResponse response) { + try { + String jsonString = new String(response.data, + HttpHeaderParser.parseCharset(response.headers)); + mHeader = response.headers.toString(); + Log.w("LOG", "get headers in parseNetworkResponse " + + response.headers.toString()); + + Pattern pattern = Pattern.compile("Set-Cookie.*?;"); + Matcher m = pattern.matcher(mHeader); + if (m.find()) { + cookieFromResponse = m.group(); + Log.w("LOG", "cookie from server " + cookieFromResponse); + } + cookieFromResponse = cookieFromResponse.substring(11, + cookieFromResponse.length() - 1); + Log.w("LOG", "cookie substring " + cookieFromResponse); + JSONObject jsonObject = new JSONObject(jsonString); + jsonObject.put("Cookie", cookieFromResponse); + Log.w("LOG", "jsonObject " + jsonObject.toString()); + return Response.success(jsonObject, + HttpHeaderParser.parseCacheHeaders(response)); + } catch (UnsupportedEncodingException e) { + return Response.error(new ParseError(e)); + } catch (JSONException je) { + return Response.error(new ParseError(je)); + } + } + + @Override + protected void deliverResponse(JSONObject response) { + mListener.onResponse(response); + } + + @Override + public Map getHeaders() throws AuthFailureError { + return sendHeader; + } + + public void setSendCookie(String cookie) { + sendHeader.put("Cookie", cookie); + } + +} diff --git a/app/src/main/java/com/game/webgame/network/PreferencesCookieStore.java b/app/src/main/java/com/game/webgame/network/PreferencesCookieStore.java new file mode 100644 index 0000000..e6cc095 --- /dev/null +++ b/app/src/main/java/com/game/webgame/network/PreferencesCookieStore.java @@ -0,0 +1,218 @@ +package com.game.webgame.network; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.http.client.CookieStore; +import org.apache.http.cookie.Cookie; +import org.apache.http.impl.cookie.BasicClientCookie; + + +import android.content.Context; +import android.content.SharedPreferences; +import android.text.TextUtils; +/** + * Created by Administrator on 2017/4/24. + */ + +public class PreferencesCookieStore implements CookieStore{ + private static final String COOKIE_PREFS = "CookiePrefsFile"; + private static final String COOKIE_NAME_STORE = "names"; + private static final String COOKIE_NAME_PREFIX = "cookie_"; + + private final ConcurrentHashMap cookies; + private final SharedPreferences cookiePrefs; + + /** + * Construct a persistent cookie store. + */ + public PreferencesCookieStore(Context context) { + cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, 0); + cookies = new ConcurrentHashMap(); + + // Load any previously stored cookies into the store + String storedCookieNames = cookiePrefs.getString(COOKIE_NAME_STORE, null); + if(storedCookieNames != null) { + String[] cookieNames = TextUtils.split(storedCookieNames, ","); + for(String name : cookieNames) { + String encodedCookie = cookiePrefs.getString(COOKIE_NAME_PREFIX + name, null); + if(encodedCookie != null) { + Cookie decodedCookie = decodeCookie(encodedCookie); + if(decodedCookie != null) { + cookies.put(name, decodedCookie); + } + } + } + + // Clear out expired cookies + clearExpired(new Date()); + } + } + + @Override + public void addCookie(Cookie cookie) { + String name = cookie.getName(); + + // Save cookie into local store, or remove if expired + if(!cookie.isExpired(new Date())) { + cookies.put(name, cookie); + } else { + cookies.remove(name); + } + + // Save cookie into persistent store + SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); + prefsWriter.putString(COOKIE_NAME_STORE, TextUtils.join(",", cookies.keySet())); + prefsWriter.putString(COOKIE_NAME_PREFIX + name, encodeCookie(new SerializableCookie(cookie))); + prefsWriter.commit(); + } + + @Override + public void clear() { + // Clear cookies from local store + cookies.clear(); + + // Clear cookies from persistent store + SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); + for(String name : cookies.keySet()) { + prefsWriter.remove(COOKIE_NAME_PREFIX + name); + } + prefsWriter.remove(COOKIE_NAME_STORE); + prefsWriter.commit(); + } + + @Override + public boolean clearExpired(Date date) { + boolean clearedAny = false; + SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); + + for(ConcurrentHashMap.Entry entry : cookies.entrySet()) { + String name = entry.getKey(); + Cookie cookie = entry.getValue(); + if(cookie.isExpired(date)) { + // ���cookies + cookies.remove(name); + + // Clear cookies from persistent store + prefsWriter.remove(COOKIE_NAME_PREFIX + name); + + // We've cleared at least one + clearedAny = true; + } + } + + // Update names in persistent store + if(clearedAny) { + prefsWriter.putString(COOKIE_NAME_STORE, TextUtils.join(",", cookies.keySet())); + } + prefsWriter.commit(); + + return clearedAny; + } + + @Override + public List getCookies() { + return new ArrayList(cookies.values()); + } + + + + protected String encodeCookie(SerializableCookie cookie) { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + try { + ObjectOutputStream outputStream = new ObjectOutputStream(os); + outputStream.writeObject(cookie); + } catch (Exception e) { + return null; + } + + return byteArrayToHexString(os.toByteArray()); + } + + protected Cookie decodeCookie(String cookieStr) { + byte[] bytes = hexStringToByteArray(cookieStr); + ByteArrayInputStream is = new ByteArrayInputStream(bytes); + Cookie cookie = null; + try { + ObjectInputStream ois = new ObjectInputStream(is); + cookie = ((SerializableCookie)ois.readObject()).getCookie(); + } catch (Exception e) { + e.printStackTrace(); + } + + return cookie; + } + + // Using some super basic byte array <-> hex conversions so we don't have + // to rely on any large Base64 libraries. Can be overridden if you like! + protected String byteArrayToHexString(byte[] b) { + StringBuffer sb = new StringBuffer(b.length * 2); + for (byte element : b) { + int v = element & 0xff; + if(v < 16) { + sb.append('0'); + } + sb.append(Integer.toHexString(v)); + } + return sb.toString().toUpperCase(); + } + + protected byte[] hexStringToByteArray(String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + for(int i=0; i mlistener; + public static ErrorListener mErrorLisener; + + public Volleyinterface(Context context, Listener mlistener, + ErrorListener errorlisener) { + + this.mcontext = context; + this.mErrorLisener = errorlisener; + this.mlistener = mlistener; + + } + + public abstract void onsuccess(String result); + + public abstract void onerror(VolleyError arg0); + + public Listener loadinglisener() { + mlistener = new Listener() { + + @Override + public void onResponse(JSONObject arg0) { + //System.out.println(arg0); + onsuccess(arg0.toString()); + } + }; + return mlistener; + } + + public ErrorListener errorListener() { + mErrorLisener = new ErrorListener() { + + @Override + public void onErrorResponse(VolleyError arg0) { + // System.out.println(arg0.toString()); + onerror(arg0); + + } + + }; + return mErrorLisener; + } +} diff --git a/app/src/main/java/com/game/webgame/network/Volleyinterface1.java b/app/src/main/java/com/game/webgame/network/Volleyinterface1.java new file mode 100644 index 0000000..3c0266a --- /dev/null +++ b/app/src/main/java/com/game/webgame/network/Volleyinterface1.java @@ -0,0 +1,44 @@ +package com.game.webgame.network; +import android.content.Context; +import com.android.volley.VolleyError; +import com.android.volley.Response.ErrorListener; +import com.android.volley.Response.Listener; + +public abstract class Volleyinterface1 { + public Context mcontext; + public static Listener mlistener; + public static ErrorListener mErrorLisener; + + public Volleyinterface1(Context context, Listener mlistener, + ErrorListener errorlisener) { + this.mcontext = context; + this.mErrorLisener = errorlisener; + this.mlistener = mlistener; + + } + + public abstract void onsuccess(String result); + + public abstract void onerror(VolleyError arg0); + + public Listener loadinglisener() { + mlistener = new Listener() { + + @Override + public void onResponse(String arg0) { + onsuccess(arg0.toString()); + } + }; + return mlistener; + } + public ErrorListener errorListener() { + mErrorLisener = new ErrorListener() { + @Override + public void onErrorResponse(VolleyError arg0) { + onerror(arg0); + } + + }; + return mErrorLisener; + } +} diff --git a/app/src/main/java/com/game/webgame/network/httpxutils.java b/app/src/main/java/com/game/webgame/network/httpxutils.java new file mode 100644 index 0000000..6d745b7 --- /dev/null +++ b/app/src/main/java/com/game/webgame/network/httpxutils.java @@ -0,0 +1,39 @@ +package com.game.webgame.network; + +import com.lidroid.xutils.HttpUtils; +import com.lidroid.xutils.exception.HttpException; +import com.lidroid.xutils.http.ResponseInfo; +import com.lidroid.xutils.http.callback.RequestCallBack; +import com.lidroid.xutils.http.client.HttpRequest; +import com.tsgame.tsgame_niuniu.system.Myapplication; + + +public class httpxutils { +public void xutils(){ + HttpUtils http = new HttpUtils(); + http.configCookieStore(new PreferencesCookieStore(Myapplication.application)); + + http.send(HttpRequest.HttpMethod.POST, "", new RequestCallBack() { + @Override + public void onLoading(long total, long current, boolean isUploading) { + super.onLoading(total, current, isUploading); + } + @Override + public void onStart() { + + super.onStart(); + } + @Override + public void onFailure(HttpException arg0, String arg1) { + + } + + @Override + public void onSuccess(ResponseInfo arg0) { + + + } + }); + +} +} diff --git a/app/src/main/java/com/game/webgame/network/register.java b/app/src/main/java/com/game/webgame/network/register.java new file mode 100644 index 0000000..8352b0d --- /dev/null +++ b/app/src/main/java/com/game/webgame/network/register.java @@ -0,0 +1,150 @@ +package com.game.webgame.network; +import java.util.Map; + +import org.json.JSONException; +import org.json.JSONObject; +import com.android.volley.Request.Method; +import com.android.volley.AuthFailureError; +import com.android.volley.DefaultRetryPolicy; +import com.android.volley.Response; +import com.android.volley.Response.Listener; +import com.android.volley.VolleyError; +import com.android.volley.toolbox.JsonObjectRequest; +import com.android.volley.toolbox.StringRequest; + +public class register { + + public static void PostJsonrequest(Map map, String url, + Volleyinterface inface) { + JSONObject jsonObject = new JSONObject(map); + System.out.println(jsonObject.toString()); + + JsonObjectRequest JsonObject1 = new JsonObjectRequest(Method.POST, url, + jsonObject, inface.loadinglisener(), inface.errorListener()); + JsonObject1.setShouldCache(false); + volleymanager.getInstance().getmRequestQueue().getCache().remove(url); + volleymanager.getInstance().getmRequestQueue().add(JsonObject1); + } + + public static void PostJsonrequest1(String json, String url, + Volleyinterface inface) { + JSONObject jsonObject=null; + try { + if(json!=null){ + jsonObject = new JSONObject(json); + } + + JsonObjectRequest JsonObject1 = new JsonObjectRequest(Method.POST, url, + jsonObject, inface.loadinglisener(), inface.errorListener()); + JsonObject1.setShouldCache(false); + volleymanager.getInstance().getmRequestQueue().getCache().remove(url); + + JsonObject1.setRetryPolicy(new DefaultRetryPolicy( + 12000, + DefaultRetryPolicy.DEFAULT_MAX_RETRIES, + DefaultRetryPolicy.DEFAULT_BACKOFF_MULT)); + + volleymanager.getInstance().getmRequestQueue().add(JsonObject1); + + } catch (JSONException e) { + + e.printStackTrace(); + } + //JSONObject jsonObject = new JSONObject(map); + + } + + public static void webservers(Map map, String url, + Volleyinterface inface) { + JsonObjectRequest JsonObject; + if (map != null) { + JSONObject jsonObject = new JSONObject(map); + JsonObject = new JsonObjectRequest(Method.POST, url, jsonObject, + inface.loadinglisener(), inface.errorListener()); + } else { + JsonObject = new JsonObjectRequest(Method.POST, url, null, + inface.loadinglisener(), inface.errorListener()); + } + JsonObject.setShouldCache(false); + volleymanager.getInstance().getmRequestQueue().getCache().remove(url); + volleymanager.getInstance().getmRequestQueue().add(JsonObject); + + } + + public static void Stringpostrequest(final Map map, + String url) { + + StringRequest string = new StringRequest(Method.POST, url, + new Listener() { + + @Override + public void onResponse(String arg0) { + System.out.println(arg0); + } + }, new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError arg0) { + + } + }) { + @Override + protected Map getParams() throws AuthFailureError { + return map; + } + }; + string.setShouldCache(false); + volleymanager.getInstance().getmRequestQueue().add(string); + } + + public static void StringGETrequest(final Map map, + String url,Volleyinterface1 inface) { + + if(map!=null){ + url = url + "?" + getParamsFromMap(map); + } + + StringRequest string = new StringRequest(Method.GET, url,inface.loadinglisener(), inface.errorListener()); + string.setShouldCache(false); + + volleymanager.getInstance().getmRequestQueue().add(string); + } + + public static void Getjsonrequest(Map map, String url) { + + + url = url + "?" + getParamsFromMap(map); + System.out.println(url); + + JsonObjectRequest JsonObject = new JsonObjectRequest(Method.GET, url, + null, new Response.Listener() { + @Override + public void onResponse(JSONObject jsonObject1) { + + if (jsonObject1 == null) { + System.out.println("返回值为空"); + } + + System.out.println(jsonObject1.toString()); + } + }, new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError arg0) { + + } + }); + JsonObject.setShouldCache(false); + // Myapplication.getqueue().getCache().remove(url); + volleymanager.getInstance().getmRequestQueue().add(JsonObject); + } + + private static String getParamsFromMap(Map map) { + StringBuffer buffer = new StringBuffer(); + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + buffer.append(key).append("=").append(value).append("&"); + } + buffer.deleteCharAt(buffer.length() - 1); + return buffer.toString(); + } +} diff --git a/app/src/main/java/com/game/webgame/network/volleymanager.java b/app/src/main/java/com/game/webgame/network/volleymanager.java new file mode 100644 index 0000000..7ae831e --- /dev/null +++ b/app/src/main/java/com/game/webgame/network/volleymanager.java @@ -0,0 +1,83 @@ +package com.game.webgame.network; + + + +import java.net.CookieHandler; +import java.net.CookieManager; +import java.net.CookiePolicy; +import java.util.prefs.Preferences; + +import org.apache.http.client.CookieStore; +import org.apache.http.client.HttpClient; +import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.impl.client.BasicCookieStore; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; +import org.apache.http.params.HttpParams; + + +import android.annotation.SuppressLint; +import android.content.Context; +import com.android.volley.RequestQueue; +import com.android.volley.toolbox.HttpClientStack; +import com.android.volley.toolbox.HttpStack; +import com.android.volley.toolbox.Volley; +import com.tsgame.tsgame_niuniu.system.Myapplication; + +import okhttp3.OkHttpClient; + +public class volleymanager { + private static volleymanager mInstance = null; + + private static RequestQueue mRequestQueue; + + @SuppressLint("NewApi") @SuppressWarnings("deprecation") + private volleymanager(Context context) { + + + +// DefaultHttpClient httpclient = new DefaultHttpClient(); + OkHttpClient okHttpClient = new OkHttpClient.Builder().build(); + //�dz־û��洢(�ڴ�洢) BasicCookieStore | �־û��洢 PreferencesCookieStore +// CookieStore cookieStore = new BasicCookieStore(); +// httpclient.setCookieStore(cookieStore); +// HttpStack httpStack = new HttpClientStack(httpclient); +// mRequestQueue = Volley.newRequestQueue(context.getApplicationContext(),httpStack); + + + CookieManager manager= new CookieManager(new volleypreferencesCookie(context), CookiePolicy.ACCEPT_ALL); + CookieHandler.setDefault(manager); + + + +// DefaultHttpClient defaultHttpClient = new DefaultHttpClient(); +// ClientConnectionManager mClientConnectionManager = defaultHttpClient.getConnectionManager(); +// HttpParams mHttpParams = defaultHttpClient.getParams(); +// ThreadSafeClientConnManager mThreadSafeClientConnManager = new ThreadSafeClientConnManager( mHttpParams, +// mClientConnectionManager.getSchemeRegistry() ); +// defaultHttpClient = new DefaultHttpClient( mThreadSafeClientConnManager, mHttpParams ); +// CookieStore cookieStore = new PreferencesCookieStore( context ); +// defaultHttpClient.setCookieStore( cookieStore ); +// HttpStack httpStack = new HttpClientStack( defaultHttpClient ); + + mRequestQueue = + Volley.newRequestQueue(context.getApplicationContext()); + } + + public static synchronized volleymanager getInstance() { + if (mInstance == null) { + mInstance = new volleymanager(Myapplication.application); + } + return mInstance; + } + + public RequestQueue getmRequestQueue() { + if (mRequestQueue == null) { + mRequestQueue = Volley.newRequestQueue(Myapplication.application + .getApplicationContext()); + } + + return mRequestQueue; + } + +} diff --git a/app/src/main/java/com/game/webgame/network/volleypreferencesCookie.java b/app/src/main/java/com/game/webgame/network/volleypreferencesCookie.java new file mode 100644 index 0000000..3f069cc --- /dev/null +++ b/app/src/main/java/com/game/webgame/network/volleypreferencesCookie.java @@ -0,0 +1,227 @@ +package com.game.webgame.network; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.SharedPreferences; +import android.text.TextUtils; +import android.util.Log; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.CookieStore; +import java.net.HttpCookie; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + + +@SuppressLint("NewApi") public class volleypreferencesCookie implements CookieStore{ + + private static final String LOG_TAG = "PersistentCookieStore"; + private static final String COOKIE_PREFS = "CookiePrefsFile"; + private static final String COOKIE_NAME_PREFIX = "cookie_"; + + private final HashMap> cookies; + private final SharedPreferences cookiePrefs; + + /** + * Construct a persistent cookie store. + * + * @param context Context to attach cookie store to + */ + public volleypreferencesCookie(Context context) { + cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, 0); + cookies = new HashMap>(); + + // Load any previously stored cookies into the store + Map prefsMap = cookiePrefs.getAll(); + for(Map.Entry entry : prefsMap.entrySet()) { + if (((String)entry.getValue()) != null && !((String)entry.getValue()).startsWith(COOKIE_NAME_PREFIX)) { + String[] cookieNames = TextUtils.split((String)entry.getValue(), ","); + for (String name : cookieNames) { + String encodedCookie = cookiePrefs.getString(COOKIE_NAME_PREFIX + name, null); + if (encodedCookie != null) { + HttpCookie decodedCookie = decodeCookie(encodedCookie); + if (decodedCookie != null) { + if(!cookies.containsKey(entry.getKey())) + cookies.put(entry.getKey(), new ConcurrentHashMap()); + cookies.get(entry.getKey()).put(name, decodedCookie); + } + } + } + + } + } + } + + @Override + public void add(URI uri, HttpCookie cookie) { + String name = getCookieToken(uri, cookie); + + + if (!cookie.hasExpired()) { + if(!cookies.containsKey(uri.getHost())) + cookies.put(uri.getHost(), new ConcurrentHashMap()); + cookies.get(uri.getHost()).put(name, cookie); + } else { + if(cookies.containsKey(uri.toString())) + cookies.get(uri.getHost()).remove(name); + } + + // Save cookie into persistent store + SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); + prefsWriter.putString(uri.getHost(), TextUtils.join(",", cookies.get(uri.getHost()).keySet())); + prefsWriter.putString(COOKIE_NAME_PREFIX + name, encodeCookie(new SerializableHttpCookie(cookie))); + prefsWriter.apply(); + } + + protected String getCookieToken(URI uri, HttpCookie cookie) { + return cookie.getName() + cookie.getDomain(); + } + + @Override + public List get(URI uri) { + ArrayList ret = new ArrayList(); + if(cookies.containsKey(uri.getHost())) + ret.addAll(cookies.get(uri.getHost()).values()); + return ret; + } + + @Override + public boolean removeAll() { + SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); + prefsWriter.clear(); + prefsWriter.apply(); + cookies.clear(); + return true; + } + + + @Override + public boolean remove(URI uri, HttpCookie cookie) { + String name = getCookieToken(uri, cookie); + + if(cookies.containsKey(uri.getHost()) && cookies.get(uri.getHost()).containsKey(name)) { + cookies.get(uri.getHost()).remove(name); + + SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); + if(cookiePrefs.contains(COOKIE_NAME_PREFIX + name)) { + prefsWriter.remove(COOKIE_NAME_PREFIX + name); + } + prefsWriter.putString(uri.getHost(), TextUtils.join(",", cookies.get(uri.getHost()).keySet())); + prefsWriter.apply(); + + return true; + } else { + return false; + } + } + + @Override + public List getCookies() { + ArrayList ret = new ArrayList(); + for (String key : cookies.keySet()) + ret.addAll(cookies.get(key).values()); + + return ret; + } + + @Override + public List getURIs() { + ArrayList ret = new ArrayList(); + for (String key : cookies.keySet()) + try { + ret.add(new URI(key)); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + + return ret; + } + + /** + * Serializes Cookie object into String + * + * @param cookie cookie to be encoded, can be null + * @return cookie encoded as String + */ + protected String encodeCookie(SerializableHttpCookie cookie) { + if (cookie == null) + return null; + ByteArrayOutputStream os = new ByteArrayOutputStream(); + try { + ObjectOutputStream outputStream = new ObjectOutputStream(os); + outputStream.writeObject(cookie); + } catch (IOException e) { + Log.d(LOG_TAG, "IOException in encodeCookie " + e.toString()); + return null; + } + + return byteArrayToHexString(os.toByteArray()); + } + + /** + * Returns cookie decoded from cookie string + * + * @param cookieString string of cookie as returned from http request + * @return decoded cookie or null if exception occured + */ + protected HttpCookie decodeCookie(String cookieString) { + byte[] bytes = hexStringToByteArray(cookieString); + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); + HttpCookie cookie = null; + try { + ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); + cookie = ((SerializableHttpCookie) objectInputStream.readObject()).getCookie(); + } catch (IOException e) { + Log.d(LOG_TAG, "IOException in decodeCookie " + e.toString()); + } catch (ClassNotFoundException e) { + Log.d(LOG_TAG, "ClassNotFoundException in decodeCookie " + e.toString()); + } + + return cookie; + } + + /** + * Using some super basic byte array <-> hex conversions so we don't have to rely on any + * large Base64 libraries. Can be overridden if you like! + * + * @param bytes byte array to be converted + * @return string containing hex values + */ + protected String byteArrayToHexString(byte[] bytes) { + StringBuilder sb = new StringBuilder(bytes.length * 2); + for (byte element : bytes) { + int v = element & 0xff; + if (v < 16) { + sb.append('0'); + } + sb.append(Integer.toHexString(v)); + } + return sb.toString().toUpperCase(Locale.US); + } + + /** + * Converts hex values from strings to byte arra + * + * @param hexString string of hex-encoded values + * @return decoded byte array + */ + protected byte[] hexStringToByteArray(String hexString) { + int len = hexString.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i + 1), 16)); + } + return data; + } + + +} diff --git a/app/src/main/java/com/game/webgame/view/ListViewUtils.java b/app/src/main/java/com/game/webgame/view/ListViewUtils.java new file mode 100644 index 0000000..af5f985 --- /dev/null +++ b/app/src/main/java/com/game/webgame/view/ListViewUtils.java @@ -0,0 +1,39 @@ +package com.game.webgame.view; + +import android.view.View; +import android.widget.Adapter; +import android.widget.ListView; + +/** + * Created by Administrator on 2017/4/24. + */ + +public class ListViewUtils { + //TODO 解决ScollView、GridView及Expandlistview嵌套ListView显示不全问题 + /*******************************************************************/ + private int totalHeight = 0; + + public int setListViewHeight(ListView listView){ + /*得到适配器*/ + Adapter adapter = listView.getAdapter(); + + /*遍历控件*/ + for (int i = 0; i < adapter .getCount(); i++) { + View view = adapter.getView(i, null, listView); + /*测量一下子控件的高度*/ + view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); + totalHeight+=view.getMeasuredHeight(); + } + + /*控件之间的间隙*/ + totalHeight+=listView.getDividerHeight()*(listView.getCount()-1); + +// /*2、赋值给ListView的LayoutParams对象*/ +// ViewGroup.LayoutParams params = listView.getLayoutParams(); +// params.height = totalHeight; +// +// listView.setLayoutParams(params); + return totalHeight; + + } +} diff --git a/app/src/main/java/com/game/webgame/view/SpUtil.java b/app/src/main/java/com/game/webgame/view/SpUtil.java new file mode 100644 index 0000000..b2281c8 --- /dev/null +++ b/app/src/main/java/com/game/webgame/view/SpUtil.java @@ -0,0 +1,72 @@ +package com.game.webgame.view; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; + +public class SpUtil { + + private static final String NAME = "erqiwang"; + private static SpUtil instance; + static { + instance = new SpUtil(); + } + + public static SpUtil getInstance() { + if (instance == null) { + instance = new SpUtil(); + } + return instance; + } + + public static SharedPreferences getSharePerference(Context context) { + return context.getSharedPreferences(NAME, Context.MODE_PRIVATE); + } + + public static boolean isFirst(SharedPreferences sp) { + return sp.getBoolean("isFirst", false); + } + + public static void setStringSharedPerference(SharedPreferences sp, + String key, String value) { + Editor editor = sp.edit(); + editor.putString(key, value); + + editor.commit(); + } + public static void setLongSharedPerference(SharedPreferences sp, + String key, Long value) { + Editor editor = sp.edit(); + editor.putLong(key, value); + + editor.commit(); + } + public static void setIntSharedPerference(SharedPreferences sp, + String key, int value) { + Editor editor = sp.edit(); + editor.putInt(key, value); + editor.commit(); + } + + public static int getIntSharedPerference(SharedPreferences sp, + String key) { + + return sp.getInt(key, 0); + } + public static String getStringSharedPerference(SharedPreferences sp, + String key) { + return sp.getString(key, null); + } + public static Long getLongSharedPerference(SharedPreferences sp, + String key) { + return sp.getLong(key, 0); + } + public static void setBooleanSharedPerference(SharedPreferences sp, + String key, boolean value) { + Editor editor = sp.edit(); + editor.putBoolean(key, value); + editor.commit(); + + } + +} diff --git a/app/src/main/java/com/game/webgame/view/dialogexit.java b/app/src/main/java/com/game/webgame/view/dialogexit.java new file mode 100644 index 0000000..8aa5ddb --- /dev/null +++ b/app/src/main/java/com/game/webgame/view/dialogexit.java @@ -0,0 +1,58 @@ +package com.game.webgame.view; + +import com.jx.jyhd.R; + +import android.content.Context; +import android.support.v7.app.AlertDialog; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.LinearLayout.LayoutParams; +import android.widget.TextView; + +public class dialogexit { + public interface onexitlistener { + public void paylistener(); + + public void cancellistener(); + + }; + + public static void show(Context con, String content, + final onexitlistener listener) { + View v = View.inflate(con,R.layout.titledialog, null); + TextView content1 = (TextView) v.findViewById(R.id.text); + if (!pmutil.isnullorEmpty(content)) { + content1.setText(content); + } + + TextView confim = (TextView) v.findViewById(R.id.confim); + TextView cancel = (TextView) v.findViewById(R.id.cancel); + final AlertDialog dialog = new AlertDialog.Builder(con).create(); + dialog.setCancelable(false); + dialog.show(); + dialog.setContentView(v); + confim.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + + dialog.dismiss(); + listener.paylistener(); + + } + }); + cancel.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + + dialog.dismiss(); + listener.cancellistener(); + + } + }); + dialog.getWindow().setLayout(pmutil.pmw() / 3 * 2, + LayoutParams.WRAP_CONTENT); + dialog.getWindow().setBackgroundDrawableResource(R.drawable.dialogexit); + } + +} diff --git a/app/src/main/java/com/game/webgame/view/exitTitle.java b/app/src/main/java/com/game/webgame/view/exitTitle.java new file mode 100644 index 0000000..b7f06e9 --- /dev/null +++ b/app/src/main/java/com/game/webgame/view/exitTitle.java @@ -0,0 +1,38 @@ +package com.game.webgame.view; + + + + + +import com.jx.jyhd.R; + +import android.content.Context; +import android.support.v7.app.AlertDialog; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.TextView; +import android.widget.LinearLayout.LayoutParams; + +public class exitTitle { + public static void show(Context con, String content) { + View v = View.inflate(con, R.layout.hintdialog, null); + TextView content1 = (TextView) v.findViewById(R.id.confim); + if (!pmutil.isnullorEmpty(content)) { + content1.setText(content); + } + TextView cancel = (TextView) v.findViewById(R.id.exit); + final AlertDialog dialog = new AlertDialog.Builder(con).create(); + dialog.setCancelable(false); + dialog.show(); + dialog.setContentView(v); + cancel.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + dialog.dismiss(); + } + }); + dialog.getWindow().setLayout(pmutil.pmw() / 3 * 2, + LayoutParams.WRAP_CONTENT); + dialog.getWindow().setBackgroundDrawableResource(R.drawable.dialogexit); + } +} diff --git a/app/src/main/java/com/game/webgame/view/gameutil.java b/app/src/main/java/com/game/webgame/view/gameutil.java new file mode 100644 index 0000000..144c95d --- /dev/null +++ b/app/src/main/java/com/game/webgame/view/gameutil.java @@ -0,0 +1,12 @@ +package com.game.webgame.view; + +import com.android.volley.RequestQueue; + +public class gameutil { + + public static Boolean isAuto=true; + public static Boolean islogin=true; + + + +} diff --git a/app/src/main/java/com/game/webgame/view/getAppinfo.java b/app/src/main/java/com/game/webgame/view/getAppinfo.java new file mode 100644 index 0000000..6897167 --- /dev/null +++ b/app/src/main/java/com/game/webgame/view/getAppinfo.java @@ -0,0 +1,60 @@ +package com.game.webgame.view; + + +import com.tsgame.tsgame_niuniu.system.Myapplication; + +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager.NameNotFoundException; + +public class getAppinfo { + public static String getAppVersionName() { + PackageInfo packageInfo; + try { + packageInfo = Myapplication.application.getPackageManager() + .getPackageInfo(Myapplication.application.getPackageName(), + 0); + return packageInfo.versionName; + } catch (NameNotFoundException e) { + e.printStackTrace(); + } + return "1.0"; + } + public static String getAppName() { + PackageInfo packageInfo; + try { + packageInfo = Myapplication.application.getPackageManager() + .getPackageInfo(Myapplication.application.getPackageName(), + 0); + + return packageInfo.applicationInfo.loadLabel(Myapplication.application.getPackageManager()).toString(); + } catch (NameNotFoundException e) { + e.printStackTrace(); + } + return "1.0"; + } + public static int getAppVersioncode() { + PackageInfo packageInfo; + try { + packageInfo = Myapplication.application.getPackageManager().getPackageInfo(Myapplication.application.getPackageName(),0); + return packageInfo.versionCode; + } catch (NameNotFoundException e) { + e.printStackTrace(); + } + return 1; + } + public static String getAppos() { + + return "ANDROID"; + } + + public static Long getTimeStamp() { + + return System.currentTimeMillis(); + } + + public static String getSign() { + + return ""; + } + +} diff --git a/app/src/main/java/com/game/webgame/view/pmutil.java b/app/src/main/java/com/game/webgame/view/pmutil.java new file mode 100644 index 0000000..00872cd --- /dev/null +++ b/app/src/main/java/com/game/webgame/view/pmutil.java @@ -0,0 +1,63 @@ +package com.game.webgame.view; + + +import com.tsgame.tsgame_niuniu.system.Myapplication; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.WindowManager; + +public class pmutil { + static String userid; + static SharedPreferences sp; + + public static int pmw() { + + WindowManager manager = (WindowManager) Myapplication.application + .getSystemService(Context.WINDOW_SERVICE); + DisplayMetrics dm = new DisplayMetrics(); + manager.getDefaultDisplay().getMetrics(dm); + int width2 = dm.widthPixels; + return width2; + } + + public static int pmh() { + WindowManager manager = (WindowManager) Myapplication.application + .getSystemService(Context.WINDOW_SERVICE); + DisplayMetrics dm = new DisplayMetrics(); + manager.getDefaultDisplay().getMetrics(dm); + + int height2 = dm.heightPixels; + return height2; + } + + public static String Appname(){ + + return getAppinfo.getAppName(); + + + } + + public static boolean isnullorEmpty(String name){ + boolean isflag=false; + if(name==null||name.trim().length()==0){ + isflag=true; + } + return isflag; + + } + + public static int dp2px(int dpval,Context context) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, + dpval, context.getResources().getDisplayMetrics()); + } + + public static int sp2px(int spval,Context context) { + + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, + spval, context.getResources().getDisplayMetrics()); + + } +} diff --git a/app/src/main/java/com/http/xml/callback/MyHttpCallBack.java b/app/src/main/java/com/http/xml/callback/MyHttpCallBack.java new file mode 100644 index 0000000..399185d --- /dev/null +++ b/app/src/main/java/com/http/xml/callback/MyHttpCallBack.java @@ -0,0 +1,8 @@ +package com.http.xml.callback; + +public interface MyHttpCallBack { + + void success(String result); + void failed(String result); + +} diff --git a/app/src/main/java/com/jx/jyhd/MainActivity.java b/app/src/main/java/com/jx/jyhd/MainActivity.java new file mode 100644 index 0000000..b17e52d --- /dev/null +++ b/app/src/main/java/com/jx/jyhd/MainActivity.java @@ -0,0 +1,40 @@ +package com.jx.jyhd; + + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.Menu; +import android.view.MenuItem; + +import com.jx.jyhd.simcpux.Util; + + +public class MainActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + Util.verifyStoragePermissions(this); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + if (id == R.id.action_settings) { + return true; + } + return super.onOptionsItemSelected(item); + } + +} diff --git a/app/src/main/java/com/jx/jyhd/sgapi/SGEntryActivity.java b/app/src/main/java/com/jx/jyhd/sgapi/SGEntryActivity.java new file mode 100644 index 0000000..b6ccb32 --- /dev/null +++ b/app/src/main/java/com/jx/jyhd/sgapi/SGEntryActivity.java @@ -0,0 +1,119 @@ +//package com.jx.jyhd.sgapi; +// +//import android.app.Activity; +//import android.content.Intent; +//import android.os.Bundle; +//import android.os.Handler; +//import android.widget.Toast; +// +////import org.xianliao.im.sdk.api.ISGAPI; +////import org.xianliao.im.sdk.api.ISGAPIEventHandler; +////import org.xianliao.im.sdk.api.SGAPIFactory; +////import org.xianliao.im.sdk.constants.SGConstants; +////import org.xianliao.im.sdk.modelbase.BaseReq; +////import org.xianliao.im.sdk.modelbase.BaseResp; +////import org.xianliao.im.sdk.modelmsg.SendAuth; +// +// +// +///** +// * Created by nickyang on 2017/1/18. +// * +// * 此类用于接收从闲聊返回到应用的返回值 +// * +// * 注意: "sgapi" 目录名和 "SGEntryActivity" 类名都不能改动 +// * +// */ +//public class SGEntryActivity extends Activity implements ISGAPIEventHandler { +// +// ISGAPI api; +// public static Handler sharehandler; +// // 分享成功 +// public static final int sharesucces = 2; +// // 分享失败 +// public static final int sharecancel = 3; +// +// @Override +// protected void onCreate(Bundle savedInstanceState) { +// super.onCreate(savedInstanceState); +// +// //Constants.SG_APPID 修改成自己申请的appId +// api = SGAPIFactory.createSGAPI(this, XLConstants.SG_APPID); +// +// api.handleIntent(getIntent(),this); +// } +// +// @Override +// protected void onNewIntent(Intent intent) { +// super.onNewIntent(intent); +// setIntent(intent); +// api.handleIntent(intent, this); +// } +// public static void setshareHandler(Handler handler) { +// sharehandler = handler; +// } +// @Override +// public void onReq(BaseReq req) { +// +// } +// +// @Override +// public void onResp(BaseResp resp) { +// switch (resp.getType()){ +// case SGConstants.COMMAND_AUTH: { //授权登陆 +// SendAuth.Resp respAuth = (SendAuth.Resp) resp; +// if (resp.errCode == SGConstants.ERR_OK) { +// Toast.makeText(this, "授权登录成功!" + resp.errCode + "\ncode: " + respAuth.code, Toast.LENGTH_SHORT).show(); +// } else if (resp.errCode == SGConstants.ERR_CANCEL) { +// Toast.makeText(this, "授权登录取消!" + resp.errCode, Toast.LENGTH_SHORT).show(); +// } else if (resp.errCode == SGConstants.ERR_FAIL) { +// Toast.makeText(this, "授权登录失败!" + resp.errCode, Toast.LENGTH_SHORT).show(); +// } +// +// //传递code到其他页面 (可选) +//// Intent intent = new Intent(this, MainActivity.class); +//// intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); +//// intent.putExtra("code", respAuth.code); +//// startActivity(intent); +// +// break; +// } +// case SGConstants.COMMAND_SHARE: { //分享文本,图片,邀请 +// if (resp.errCode == SGConstants.ERR_OK) { +// sharehandler.sendEmptyMessage(sharesucces); +// +// Toast.makeText(this, "分享成功!", Toast.LENGTH_SHORT).show(); +// } else if (resp.errCode == SGConstants.ERR_CANCEL) { +// sharehandler.sendEmptyMessage(sharecancel); +// Toast.makeText(this, "分享取消!" , Toast.LENGTH_SHORT).show(); +// } else if (resp.errCode == SGConstants.ERR_FAIL) { +// sharehandler.sendEmptyMessage(sharecancel); +// Toast.makeText(this, "分享失败!" , Toast.LENGTH_SHORT).show(); +// } +// break; +// } +// case SGConstants.COMMAND_INVITE: { //从闲聊点击邀请进入应用, +// /** +// * 需要Manifest里面配置特殊 intent-filter 才有用,详情参见AndroidManifest +// */ +//// InvitationResp invitationResp = (InvitationResp) resp; +//// Toast.makeText(this, "邀请进入: roomId: " + invitationResp.roomId + " roomToken: " + invitationResp.roomToken, Toast.LENGTH_LONG).show(); +//// +//// //传递roomId roomToken到其他页面 +//// Intent intent = new Intent(this, SDKDemoActivity.class); +//// intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); +//// intent.putExtra("roomId", invitationResp.roomId); +//// intent.putExtra("roomToken", invitationResp.roomToken); +//// intent.putExtra("openId", invitationResp.openId); +//// startActivity(intent); +// break; +// } +// } +// finish(); +// } +// +// @Override +// protected void onResume() { +// super.onResume(); +// } +//} diff --git a/app/src/main/java/com/jx/jyhd/sgapi/XLConstants.java b/app/src/main/java/com/jx/jyhd/sgapi/XLConstants.java new file mode 100644 index 0000000..1311ff6 --- /dev/null +++ b/app/src/main/java/com/jx/jyhd/sgapi/XLConstants.java @@ -0,0 +1,9 @@ +package com.jx.jyhd.sgapi; + +/** + * Created by nickyang on 2017/3/17. + */ + +public class XLConstants { + public static final String SG_APPID = "DaxGcxAYUJbcDmiK"; +} diff --git a/app/src/main/java/com/jx/jyhd/simcpux/AppRegister.java b/app/src/main/java/com/jx/jyhd/simcpux/AppRegister.java new file mode 100644 index 0000000..d96b002 --- /dev/null +++ b/app/src/main/java/com/jx/jyhd/simcpux/AppRegister.java @@ -0,0 +1,19 @@ +package com.jx.jyhd.simcpux; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + + +import com.tencent.mm.opensdk.openapi.IWXAPI; +import com.tencent.mm.opensdk.openapi.WXAPIFactory; + +public class AppRegister extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + final IWXAPI api = WXAPIFactory.createWXAPI(context, null); + // 注册 + api.registerApp(Constants.APP_ID); + } +} diff --git a/app/src/main/java/com/jx/jyhd/simcpux/Constants.java b/app/src/main/java/com/jx/jyhd/simcpux/Constants.java new file mode 100644 index 0000000..83de045 --- /dev/null +++ b/app/src/main/java/com/jx/jyhd/simcpux/Constants.java @@ -0,0 +1,27 @@ +package com.jx.jyhd.simcpux; + + +public class Constants { + + public static class ShowMsgActivity { + public static final String STitle = "showmsg_title"; + public static final String SMessage = "showmsg_message"; + public static final String BAThumbData = "showmsg_thumb_data"; + } + + //appid + public static final String APP_ID = "wxd2bd650e06bdfe58"; + + public static final int PERMISSIONS_REQUEST_STORAGE = 1; + + //商户号 + public static final String MCH_ID = "1448669802"; + + //API密钥,在商户平台设置 + public static final String API_KEY="ClMrQsAcidRa7uJT4TgHgVAOHbzQjdPa"; + + //app 微信AppSecret 秘钥 b2792724b9565be23e8f5ba548f117cf + public static final String AppSecret="1934a281c82ad1a059130fe51341b74b"; + + +} diff --git a/app/src/main/java/com/jx/jyhd/simcpux/MD5.java b/app/src/main/java/com/jx/jyhd/simcpux/MD5.java new file mode 100644 index 0000000..a30260f --- /dev/null +++ b/app/src/main/java/com/jx/jyhd/simcpux/MD5.java @@ -0,0 +1,28 @@ +package com.jx.jyhd.simcpux; + +import java.security.MessageDigest; + +public class MD5 { + + private MD5() {} + + public final static String getMessageDigest(byte[] buffer) { + char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + try { + MessageDigest mdTemp = MessageDigest.getInstance("MD5"); + mdTemp.update(buffer); + byte[] md = mdTemp.digest(); + int j = md.length; + char str[] = new char[j * 2]; + int k = 0; + for (int i = 0; i < j; i++) { + byte byte0 = md[i]; + str[k++] = hexDigits[byte0 >>> 4 & 0xf]; + str[k++] = hexDigits[byte0 & 0xf]; + } + return new String(str); + } catch (Exception e) { + return null; + } + } +} diff --git a/app/src/main/java/com/jx/jyhd/simcpux/MD5Util.java b/app/src/main/java/com/jx/jyhd/simcpux/MD5Util.java new file mode 100644 index 0000000..e55cd9a --- /dev/null +++ b/app/src/main/java/com/jx/jyhd/simcpux/MD5Util.java @@ -0,0 +1,43 @@ +package com.jx.jyhd.simcpux; + +import java.security.MessageDigest; + +public class MD5Util { + + private static String byteArrayToHexString(byte b[]) { + StringBuffer resultSb = new StringBuffer(); + for (int i = 0; i < b.length; i++) + resultSb.append(byteToHexString(b[i])); + + return resultSb.toString(); + } + + private static String byteToHexString(byte b) { + int n = b; + if (n < 0) + n += 256; + int d1 = n / 16; + int d2 = n % 16; + return hexDigits[d1] + hexDigits[d2]; + } + + public static String MD5Encode(String origin, String charsetname) { + String resultString = null; + try { + resultString = new String(origin); + MessageDigest md = MessageDigest.getInstance("MD5"); + if (charsetname == null || "".equals(charsetname)) + resultString = byteArrayToHexString(md.digest(resultString + .getBytes())); + else + resultString = byteArrayToHexString(md.digest(resultString + .getBytes(charsetname))); + } catch (Exception exception) { + } + return resultString; + } + + private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5", + "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" }; + +} diff --git a/app/src/main/java/com/jx/jyhd/simcpux/Util.java b/app/src/main/java/com/jx/jyhd/simcpux/Util.java new file mode 100644 index 0000000..7070a1b --- /dev/null +++ b/app/src/main/java/com/jx/jyhd/simcpux/Util.java @@ -0,0 +1,393 @@ +package com.jx.jyhd.simcpux; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Build; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.util.Log; + +import com.tsgame.tsgame_niuniu.system.Myapplication; + +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.HttpVersion; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.conn.scheme.PlainSocketFactory; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.HttpParams; +import org.apache.http.params.HttpProtocolParams; +import org.apache.http.protocol.HTTP; +import org.apache.http.util.EntityUtils; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.net.Socket; +import java.net.UnknownHostException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +public class Util { + + public static final String TAG = "Util"; + private static final String[] PERMISSIONS_STORAGE = { + "android.permission.READ_EXTERNAL_STORAGE", + "android.permission.WRITE_EXTERNAL_STORAGE" }; + + public static void verifyStoragePermissions(Activity activity) { + + try { + //检测是否有写的权限 + int permission = ContextCompat.checkSelfPermission(activity, + Manifest.permission.WRITE_EXTERNAL_STORAGE); + if (permission != PackageManager.PERMISSION_GRANTED) { + // 没有写的权限,去申请写的权限,会弹出对话框 + ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE, + Constants.PERMISSIONS_REQUEST_STORAGE); + } + + if (Build.VERSION.SDK_INT >= 23) { + String[] permissions = PERMISSIONS_STORAGE; + //验证是否许可权限 + for (String str : permissions) { + if (activity.checkSelfPermission(str) != PackageManager.PERMISSION_GRANTED) { + //申请权限 + activity.requestPermissions(permissions, Constants.PERMISSIONS_REQUEST_STORAGE); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static String GetFileAbsolutePath(){ + return Objects.requireNonNull(Myapplication.application.getExternalFilesDir(null)).getAbsolutePath(); + } + public static File GetDirectory(){ + return Myapplication.application.getExternalFilesDir(null); + } + + public static byte[] bmpToByteArray(final Bitmap bmp, final boolean needRecycle) { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + bmp.compress(Bitmap.CompressFormat.PNG, 100, output); + if (needRecycle) { + bmp.recycle(); + } + + byte[] result = output.toByteArray(); + try { + output.close(); + } catch (Exception e) { + e.printStackTrace(); + } + + return result; + } + + public static byte[] httpGet(final String url) { + if (url == null || url.length() == 0) { + Log.e(TAG, "httpGet, url is null"); + return null; + } + + HttpClient httpClient = getNewHttpClient(); + HttpGet httpGet = new HttpGet(url); + + try { + HttpResponse resp = httpClient.execute(httpGet); + if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { + Log.e(TAG, "httpGet fail, status code = " + resp.getStatusLine().getStatusCode()); + return null; + } + + return EntityUtils.toByteArray(resp.getEntity()); + + } catch (Exception e) { + Log.e(TAG, "httpGet exception, e = " + e.getMessage()); + e.printStackTrace(); + return null; + } + } + + public static byte[] httpPost(String url, String entity) { + if (url == null || url.length() == 0) { + Log.e(TAG, "httpPost, url is null"); + return null; + } + + HttpClient httpClient = getNewHttpClient(); + + HttpPost httpPost = new HttpPost(url); + + try { + httpPost.setEntity(new StringEntity(entity)); + httpPost.setHeader("Accept", "application/json"); + httpPost.setHeader("Content-type", "application/json"); + + HttpResponse resp = httpClient.execute(httpPost); + if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { + Log.e(TAG, "httpGet fail, status code = " + resp.getStatusLine().getStatusCode()); + return null; + } + + return EntityUtils.toByteArray(resp.getEntity()); + } catch (Exception e) { + Log.e(TAG, "httpPost exception, e = " + e.getMessage()); + e.printStackTrace(); + return null; + } + } + + private static class SSLSocketFactoryEx extends SSLSocketFactory { + + SSLContext sslContext = SSLContext.getInstance("TLS"); + + public SSLSocketFactoryEx(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { + super(truststore); + + TrustManager tm = new X509TrustManager() { + + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + @SuppressLint("TrustAllX509TrustManager") + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) { + } + + @SuppressLint("TrustAllX509TrustManager") + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) { + } + }; + + sslContext.init(null, new TrustManager[] { tm }, null); + } + + @Override + public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { + return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); + } + + @Override + public Socket createSocket() throws IOException { + return sslContext.getSocketFactory().createSocket(); + } + } + + private static HttpClient getNewHttpClient() { + try { + KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + trustStore.load(null, null); + + SSLSocketFactory sf = new SSLSocketFactoryEx(trustStore); + sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + + HttpParams params = new BasicHttpParams(); + HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); + HttpProtocolParams.setContentCharset(params, HTTP.UTF_8); + + SchemeRegistry registry = new SchemeRegistry(); + registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); + registry.register(new Scheme("https", sf, 443)); + + ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry); + + return new DefaultHttpClient(ccm, params); + } catch (Exception e) { + return new DefaultHttpClient(); + } + } + + public static byte[] readFromFile(String fileName, int offset, int len) { + if (fileName == null) { + return null; + } + + File file = new File(fileName); + if (!file.exists()) { + Log.i(TAG, "readFromFile: file not found"); + return null; + } + + if (len == -1) { + len = (int) file.length(); + } + + Log.d(TAG, "readFromFile : offset = " + offset + " len = " + len + " offset + len = " + (offset + len)); + + if(offset <0){ + Log.e(TAG, "readFromFile invalid offset:" + offset); + return null; + } + if(len <=0 ){ + Log.e(TAG, "readFromFile invalid len:" + len); + return null; + } + if(offset + len > (int) file.length()){ + Log.e(TAG, "readFromFile invalid file len:" + file.length()); + return null; + } + + byte[] b = null; + try { + RandomAccessFile in = new RandomAccessFile(fileName, "r"); + b = new byte[len]; // ´´½¨ºÏÊÊÎļþ´óСµÄÊý×é + in.seek(offset); + in.readFully(b); + in.close(); + + } catch (Exception e) { + Log.e(TAG, "readFromFile : errMsg = " + e.getMessage()); + e.printStackTrace(); + } + return b; + } + + private static final int MAX_DECODE_PICTURE_SIZE = 1920 * 1440; + + public static Bitmap extractThumbNail(final String path, final int height, final int width, final boolean crop) { +// Assert.assertTrue(path != null && !path.equals("") && height > 0 && width > 0); + + BitmapFactory.Options options = new BitmapFactory.Options(); + + try { + options.inJustDecodeBounds = true; + Bitmap tmp = BitmapFactory.decodeFile(path, options); + if (tmp != null) { + tmp.recycle(); + tmp = null; + } + + Log.d(TAG, "extractThumbNail: round=" + width + "x" + height + ", crop=" + crop); + final double beY = options.outHeight * 1.0 / height; + final double beX = options.outWidth * 1.0 / width; + Log.d(TAG, "extractThumbNail: extract beX = " + beX + ", beY = " + beY); + options.inSampleSize = (int) (crop ? (beY > beX ? beX : beY) : (beY < beX ? beX : beY)); + if (options.inSampleSize <= 1) { + options.inSampleSize = 1; + } + + // NOTE: out of memory error + while (options.outHeight * options.outWidth / options.inSampleSize > MAX_DECODE_PICTURE_SIZE) { + options.inSampleSize++; + } + + int newHeight = height; + int newWidth = width; + if (crop) { + if (beY > beX) { + newHeight = (int) (newWidth * 1.0 * options.outHeight / options.outWidth); + } else { + newWidth = (int) (newHeight * 1.0 * options.outWidth / options.outHeight); + } + } else { + if (beY < beX) { + newHeight = (int) (newWidth * 1.0 * options.outHeight / options.outWidth); + } else { + newWidth = (int) (newHeight * 1.0 * options.outWidth / options.outHeight); + } + } + + options.inJustDecodeBounds = false; + + Log.i(TAG, "bitmap required size=" + newWidth + "x" + newHeight + ", orig=" + options.outWidth + "x" + options.outHeight + ", sample=" + options.inSampleSize); + Bitmap bm = BitmapFactory.decodeFile(path, options); + if (bm == null) { + Log.e(TAG, "bitmap decode failed"); + return null; + } + + Log.i(TAG, "bitmap decoded size=" + bm.getWidth() + "x" + bm.getHeight()); + final Bitmap scale = Bitmap.createScaledBitmap(bm, newWidth, newHeight, true); + if (scale != null) { + bm.recycle(); + bm = scale; + } + + if (crop) { + final Bitmap cropped = Bitmap.createBitmap(bm, (bm.getWidth() - width) >> 1, (bm.getHeight() - height) >> 1, width, height); + if (cropped == null) { + return bm; + } + + bm.recycle(); + bm = cropped; + Log.i(TAG, "bitmap croped size=" + bm.getWidth() + "x" + bm.getHeight()); + } + return bm; + + } catch (final OutOfMemoryError e) { + Log.e(TAG, "decode bitmap failed: " + e.getMessage()); + options = null; + } + + return null; + } + + public static String sha1(String str) { + if (str == null || str.length() == 0) { + return null; + } + + char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + + try { + MessageDigest mdTemp = MessageDigest.getInstance("SHA1"); + mdTemp.update(str.getBytes()); + + byte[] md = mdTemp.digest(); + int j = md.length; + char buf[] = new char[j * 2]; + int k = 0; + for (int i = 0; i < j; i++) { + byte byte0 = md[i]; + buf[k++] = hexDigits[byte0 >>> 4 & 0xf]; + buf[k++] = hexDigits[byte0 & 0xf]; + } + return new String(buf); + } catch (Exception e) { + return null; + } + } + + public static List stringsToList(final String[] src) { + if (src == null || src.length == 0) { + return null; + } + final List result = new ArrayList(); + for (int i = 0; i < src.length; i++) { + result.add(src[i]); + } + return result; + } +} diff --git a/app/src/main/java/com/jx/jyhd/simcpux/Wxistrue.java b/app/src/main/java/com/jx/jyhd/simcpux/Wxistrue.java new file mode 100644 index 0000000..c28c134 --- /dev/null +++ b/app/src/main/java/com/jx/jyhd/simcpux/Wxistrue.java @@ -0,0 +1,12 @@ +package com.jx.jyhd.simcpux; + +public class Wxistrue { + public static boolean islogin=true; + + public static boolean isshare=true; + + public static boolean isphotoshare=true; + + public static int sharetype=1;//分享类型1 好友 2 朋友圈 + +} diff --git a/app/src/main/java/com/jx/jyhd/simcpux/util/WeChatShareUtil.java b/app/src/main/java/com/jx/jyhd/simcpux/util/WeChatShareUtil.java new file mode 100644 index 0000000..712135e --- /dev/null +++ b/app/src/main/java/com/jx/jyhd/simcpux/util/WeChatShareUtil.java @@ -0,0 +1,358 @@ +package com.jx.jyhd.simcpux.util; + +import android.app.Activity; +import android.content.Context; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.widget.Toast; + +import com.jx.jyhd.simcpux.Constants; +import com.jx.jyhd.simcpux.Util; +import com.jx.jyhd.wxapi.WXEntryActivity; +import com.tagmae.tsgame_erwang.utils.Base64ImageUtil; +import com.tencent.mm.opensdk.modelmsg.SendMessageToWX; +import com.tencent.mm.opensdk.modelmsg.WXImageObject; +import com.tencent.mm.opensdk.modelmsg.WXMediaMessage; +import com.tencent.mm.opensdk.modelmsg.WXWebpageObject; +import com.tencent.mm.opensdk.openapi.IWXAPI; +import com.tencent.mm.opensdk.openapi.WXAPIFactory; + +import java.io.File; + +/** + * 微信分享工具类 + */ +public class WeChatShareUtil { + + private static final int THUMB_SIZE = 150; + private static WeChatShareUtil instance; + private final Context mContext; + private final IWXAPI mWxApi; + private WeChatShareCallback mCallback; + + private WeChatShareUtil(Context context) { + this.mContext = context.getApplicationContext(); + // 初始化微信API + mWxApi = WXAPIFactory.createWXAPI(mContext, Constants.APP_ID, true); + mWxApi.registerApp(Constants.APP_ID); + } + + /** + * 获取实例 + * @param context 上下文 + * @return WeChatShareUtil实例 + */ + public static WeChatShareUtil getInstance(Context context) { + if (instance == null && context != null) { + instance = new WeChatShareUtil(context); + } + return instance; + } + + /** + * 检查微信是否已安装 + * @return 是否安装 + */ + public boolean isWeChatInstalled() { + try { + return mWxApi.isWXAppInstalled(); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 设置分享回调 + * @param callback 分享回调 + */ + public void setShareCallback(WeChatShareCallback callback) { + this.mCallback = callback; + } + + /** + * 获取分享回调 + * @return 分享回调 + */ + public WeChatShareCallback getShareCallback() { + return mCallback; + } + + /** + * 分享网页到微信 + * @param activity 活动 + * @param webpageUrl 网页链接 + * @param title 标题 + * @param description 描述 + * @param scene 分享场景(0:好友, 1:朋友圈) + */ + public void shareWebPage(Activity activity, String webpageUrl, String title, String description, int scene) { + if (!isWeChatInstalled()) { + Toast.makeText(activity, "请先安装微信客户端", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-1, "未安装微信客户端"); + } + return; + } + + try { + // 设置分享回调处理 + // 创建Handler来接收微信分享结果 + final Handler shareHandler = new Handler(Looper.getMainLooper()) { + @Override + public void handleMessage(Message msg) { + // 处理微信分享回调 + if (mCallback != null) { + if (msg.what == 0) { // 成功 + mCallback.onSuccess(); + } else if (msg.what == -2) { // 取消 + mCallback.onCancel(); + } else { // 错误 + mCallback.onError(msg.what, "微信分享失败,错误码:" + msg.what); + } + } + } + }; + + // 设置分享回调 + WXEntryActivity.setshareHandler(shareHandler); + + // 创建网页消息对象 + WXWebpageObject webpage = new WXWebpageObject(); + webpage.webpageUrl = webpageUrl; + + // 创建多媒体消息 + WXMediaMessage msg = new WXMediaMessage(webpage); + msg.title = title; + msg.description = description; + + // 设置缩略图 - 使用应用的启动图标 logo6 而不是 ic_launcher + Bitmap thumbBmp = BitmapFactory.decodeResource(mContext.getResources(), + mContext.getResources().getIdentifier("logo6", "drawable", mContext.getPackageName())); + + // 如果找不到logo6,则退回到使用ic_launcher + if (thumbBmp == null) { + thumbBmp = BitmapFactory.decodeResource(mContext.getResources(), + com.jx.jyhd.R.mipmap.ic_launcher); + } + + if (thumbBmp != null) { + Bitmap thumbBitmap = Bitmap.createScaledBitmap(thumbBmp, THUMB_SIZE, THUMB_SIZE, true); + thumbBmp.recycle(); + msg.thumbData = Util.bmpToByteArray(thumbBitmap, true); + } + + // 构建发送请求 + SendMessageToWX.Req req = new SendMessageToWX.Req(); + req.transaction = buildTransaction("webpage"); + req.message = msg; + req.scene = scene == 0 ? SendMessageToWX.Req.WXSceneSession : SendMessageToWX.Req.WXSceneTimeline; + + // 发送请求 + boolean result = mWxApi.sendReq(req); + + if (!result) { + Toast.makeText(activity, "微信分享请求发送失败", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-2, "微信分享请求发送失败"); + } + } + + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(activity, "微信分享失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-3, "微信分享失败: " + e.getMessage()); + } + } + } + + /** + * 分享图片到微信 + * @param activity 活动 + * @param imagePath 图片路径 + * @param scene 分享场景(0:好友, 1:朋友圈) + */ + public void shareImage(Activity activity, String imagePath, int scene) { + if (!isWeChatInstalled()) { + Toast.makeText(activity, "请先安装微信客户端", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-1, "未安装微信客户端"); + } + return; + } + + // 使用新的图片处理工具类检查图片是否存在,不存在时可以尝试使用其他备用方案 + Uri imageFile = Base64ImageUtil.base64ToImageFile(activity,imagePath,null); + //Uri imageFile = Uri.parse(imagePath); + + if (imageFile == null) { + //Toast.makeText(activity, "分享图片不存在,尝试创建临时图片", Toast.LENGTH_SHORT).show(); + + // 如果是Bitmap对象,可以使用ImageProcessUtils保存 + if (imagePath.startsWith("data:image/") || imagePath.startsWith("base64,")) { + // 对于Base64编码的图片,使用ImageProcessUtils保存 + com.tagmae.tsgame_erwang.utils.ImageProcessUtils.saveBase64ImageToCache( + activity, + imagePath, + new com.tagmae.tsgame_erwang.utils.ImageProcessUtils.ImageSaveCallback() { + @Override + public void onSuccess(String savedImagePath) { + // 保存成功,使用新路径进行分享 + shareImageInternal(activity, savedImagePath, scene); + } + + @Override + public void onError(String errorMsg) { + Toast.makeText(activity, errorMsg, Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-2, errorMsg); + } + } + } + ); + return; + } else { + // 图片不存在且不能处理 + if (mCallback != null) { + mCallback.onError(-2, "图片文件不存在"); + } + return; + } + } + + // 直接使用现有图片路径分享 + shareImageInternal(activity, imageFile.getPath(), scene); + } + + /** + * 内部图片分享实现 + */ + private void shareImageInternal(Activity activity, String imagePath, int scene) { + try { + // 设置分享回调处理 + // 创建Handler来接收微信分享结果 + final Handler shareHandler = new Handler(Looper.getMainLooper()) { + @Override + public void handleMessage(Message msg) { + // 处理微信分享回调 + if (mCallback != null) { + if (msg.what == 0) { // 成功 + mCallback.onSuccess(); + } else if (msg.what == -2) { // 取消 + mCallback.onCancel(); + } else { // 错误 + mCallback.onError(msg.what, "微信分享失败,错误码:" + msg.what); + } + } + } + }; + + // 设置分享回调 + WXEntryActivity.setshareHandler(shareHandler); + + // 加载要分享的图片 + Bitmap bmp = BitmapFactory.decodeFile(imagePath); + if (bmp == null) { + Toast.makeText(activity, "图片加载失败", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-3, "图片加载失败"); + } + return; + } + + // 创建图片对象 + WXImageObject imgObj = new WXImageObject(bmp); + + // 创建多媒体消息 + WXMediaMessage msg = new WXMediaMessage(); + msg.mediaObject = imgObj; + + // 设置缩略图 + Bitmap thumbBmp = Bitmap.createScaledBitmap(bmp, THUMB_SIZE, THUMB_SIZE, true); + bmp.recycle(); + msg.thumbData = Util.bmpToByteArray(thumbBmp, true); + + // 构建发送请求 + SendMessageToWX.Req req = new SendMessageToWX.Req(); + req.transaction = buildTransaction("img"); + req.message = msg; + req.scene = scene == 0 ? SendMessageToWX.Req.WXSceneSession : SendMessageToWX.Req.WXSceneTimeline; + + // 发送请求 + boolean result = mWxApi.sendReq(req); + + if (!result) { + Toast.makeText(activity, "微信分享请求发送失败", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-4, "微信分享请求发送失败"); + } + } + + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(activity, "微信分享失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-5, "微信分享失败: " + e.getMessage()); + } + } + } + + /** + * 分享Bitmap到微信 + * @param activity 活动 + * @param bitmap 位图对象 + * @param scene 分享场景(0:好友, 1:朋友圈) + */ + public void shareBitmap(Activity activity, Bitmap bitmap, int scene) { + if (bitmap == null) { + Toast.makeText(activity, "分享图片为空", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-1, "分享图片为空"); + } + return; + } + + // 使用ImageProcessUtils保存Bitmap + com.tagmae.tsgame_erwang.utils.ImageProcessUtils.saveBitmapToCache( + activity, + bitmap, + new com.tagmae.tsgame_erwang.utils.ImageProcessUtils.ImageSaveCallback() { + @Override + public void onSuccess(String imagePath) { + // 保存成功,使用生成的图片路径分享 + shareImageInternal(activity, imagePath, scene); + } + + @Override + public void onError(String errorMsg) { + Toast.makeText(activity, errorMsg, Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-2, errorMsg); + } + } + } + ); + } + + /** + * 构建交易ID + */ + private String buildTransaction(String type) { + return type + System.currentTimeMillis(); + } + + /** + * 微信分享回调接口 + */ + public interface WeChatShareCallback { + void onSuccess(); + void onError(int code, String message); + void onCancel(); + } +} diff --git a/app/src/main/java/com/jx/jyhd/wxapi/WXEntryActivity.java b/app/src/main/java/com/jx/jyhd/wxapi/WXEntryActivity.java new file mode 100644 index 0000000..75735c8 --- /dev/null +++ b/app/src/main/java/com/jx/jyhd/wxapi/WXEntryActivity.java @@ -0,0 +1,421 @@ +package com.jx.jyhd.wxapi; + + +import android.app.Activity; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.util.Log; +import android.widget.ImageView; +import android.widget.TextView; + +import com.android.volley.VolleyError; +import com.game.webgame.network.Volleyinterface1; +import com.game.webgame.network.register; +import com.game.webgame.view.SpUtil; +import com.jx.jyhd.R; +import com.jx.jyhd.simcpux.Constants; +import com.tencent.mm.opensdk.constants.ConstantsAPI; +import com.tencent.mm.opensdk.modelbase.BaseReq; +import com.tencent.mm.opensdk.modelbase.BaseResp; +import com.tencent.mm.opensdk.modelmsg.SendAuth; +import com.tencent.mm.opensdk.modelmsg.ShowMessageFromWX; +import com.tencent.mm.opensdk.openapi.IWXAPI; +import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler; +import com.tencent.mm.opensdk.openapi.WXAPIFactory; +import com.jx.jyhd.R; +import com.jx.jyhd.simcpux.Constants; +import com.tsgame.tsgame_niuniu.system.WX_Myurl; +import com.tsgame.tsgame_niuniu.util.apputil; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.HttpClient; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.protocol.HTTP; +import org.apache.http.util.EntityUtils; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class WXEntryActivity extends Activity implements IWXAPIEventHandler { + + public static final String TAG = "WXEntryActivity"; + private IWXAPI api; + TextView text; + ImageView image; + public static Handler sharehandler; + + SharedPreferences sp; + + // 分享成功 + public static final int sharesucces = 2; + // 分享失败 + public static final int sharecancel = 3; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.wxuserinfo); + + api = WXAPIFactory.createWXAPI(this, Constants.APP_ID, false); + try { + Intent intent = getIntent(); + api.handleIntent(intent, this); + } catch (Exception e) { + e.printStackTrace(); + } + + sp = SpUtil.getSharePerference(WXEntryActivity.this); + initview(); + } + + private void initview() { + text = (TextView) findViewById(R.id.user); + image = (ImageView) findViewById(R.id.image); + + } + + public static void setshareHandler(Handler handler) { + sharehandler = handler; + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + setIntent(intent); + api.handleIntent(intent, this); + } + + // 微信发送请求到第三方应用时,会回调到该方法 + @Override + public void onReq(BaseReq req) { + switch (req.getType()) { + case ConstantsAPI.COMMAND_GETMESSAGE_FROM_WX: + // goToGetMsg(); + break; + case ConstantsAPI.COMMAND_SHOWMESSAGE_FROM_WX: + // goToShowMsg((ShowMessageFromWX.Req) req); + break; + default: + break; + } + } + + // 第三方应用发送到微信的请求处理后的响应结果,会回调到该方法 + @Override + public void onResp(BaseResp resp) { + int result = 0; + switch (resp.errCode){ + case BaseResp.ErrCode.ERR_OK: + if (apputil.wxtype == 1) {// 分享 + sharehandler.sendEmptyMessage(sharesucces); + } + result = R.string.errcode_success; + break; + case BaseResp.ErrCode.ERR_USER_CANCEL: + result = R.string.errcode_cancel; + break; + case BaseResp.ErrCode.ERR_AUTH_DENIED: + result = R.string.errcode_deny; + break; + case BaseResp.ErrCode.ERR_UNSUPPORT: + result = R.string.errcode_unsupport; + break; + default: + result = R.string.errcode_unknown; + break; + } + Log.e(TAG, getString(result) + ", type=" + resp.getType()); + if (resp.getType() == ConstantsAPI.COMMAND_SENDAUTH) { + SendAuth.Resp authResp = (SendAuth.Resp)resp; + final String code = authResp.code; + getaccess_token(code); + } + finish(); + } + + private void getaccess_token(String code) { + Map map = new HashMap(); + map.put("appid", Constants.APP_ID); + map.put("secret", Constants.AppSecret); + map.put("code", code); + map.put("grant_type", "authorization_code"); + + register.StringGETrequest(map, WX_Myurl.getwxaccess_token, + new Volleyinterface1(this, Volleyinterface1.mlistener, + Volleyinterface1.mErrorLisener) { + + @Override + public void onsuccess(String result) { + try { + + JSONObject object = new JSONObject(result); + String access_token = object + .optString("access_token"); + + SpUtil.setStringSharedPerference(sp, + "access_token", access_token); + + int expires_in = object.optInt("expires_in"); + + String refresh_token = object + .optString("refresh_token"); + + SpUtil.setStringSharedPerference(sp, + "refresh_token", refresh_token); + + String openid = object.optString("openid"); + // getuserinfo(access_token,openid); + + SpUtil.setStringSharedPerference(sp, "openid", + openid); + + getUserInfo(access_token, openid); + + // Toast.makeText( + // WXEntryActivity.this, + // "access_token+=" + expires_in + // + "refresh_token" + refresh_token, + // Toast.LENGTH_LONG).show(); + + } catch (JSONException e) { + + e.printStackTrace(); + } + + } + + @Override + public void onerror(VolleyError arg0) { + Log.i("WxError","Start"); + arg0.printStackTrace(); + Log.i("WxError",arg0.toString()); + Log.i("WxError",arg0.getMessage()); + Log.i("WxError","End"); + } + }); + + } + + protected void getuserinfo(String access_token, String openid) { + Map map = new HashMap(); + map.put("access_token", access_token); + map.put("openid", openid); + + register.StringGETrequest(map, WX_Myurl.getwxuserinfo, + new Volleyinterface1(this, Volleyinterface1.mlistener, + Volleyinterface1.mErrorLisener) { + @Override + public void onsuccess(String result) { + String str = null; + try { + try { + // URLEncoder、URLDecoder进行URL参数的转码与解码 + URLEncoder.encode(result, "utf-8"); + } catch (UnsupportedEncodingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // EntityUtils.toString(response.getEntity(),HTTP.UTF_8);//在这里转换 + JSONObject object = new JSONObject(result); + // Toast.makeText(WXEntryActivity.this, + // "result=" + str, Toast.LENGTH_LONG).show(); + } catch (JSONException e) { + + e.printStackTrace(); + } + + } + + @Override + public void onerror(VolleyError arg0) { + + } + }); + + } + + @SuppressWarnings("deprecation") + public static String getWeixinUserinfo(String access_token, String openid) { + String URLs = WX_Myurl.getwxuserinfo;// 微信登录地址 + String result = ""; + List list = new ArrayList(); + + NameValuePair pairappid = new BasicNameValuePair("access_token", + access_token); + NameValuePair pairsecret = new BasicNameValuePair("openid", openid); + list.add(pairappid); + list.add(pairsecret); + + try { + HttpEntity requestHttpEntity = new UrlEncodedFormEntity(list, + HTTP.UTF_8); + URL url = new URL(URLs); + URI uri = new URI(url.getProtocol(), url.getHost(), url.getPath(), + url.getQuery(), null); + HttpPost httpPost = new HttpPost(uri); + httpPost.setEntity(requestHttpEntity); + HttpClient httpClient = new DefaultHttpClient(); + HttpResponse response = httpClient.execute(httpPost); + if (response.getStatusLine().getStatusCode() == 200) { + result = EntityUtils.toString(response.getEntity(), HTTP.UTF_8);// 在这里转换 + } + return result; + + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } + + public interface OnGetUserInfoListener { + void onGetUserInfo(String userInfo); // json字符串 + + void onNetError(); + } + + static class GetUserInfoTask extends AsyncTask { + + private OnGetUserInfoListener mListener; + private String mUrl; + + public GetUserInfoTask(OnGetUserInfoListener listener, + String getUserInfoUrl) { + mListener = listener; + mUrl = getUserInfoUrl; + } + + @Override + protected void onPreExecute() { + + super.onPreExecute(); + } + + @Override + protected String doInBackground(Object... params) { + HttpURLConnection conn = null; + BufferedReader in = null; + StringBuilder result = new StringBuilder(); + + try { + conn = (HttpURLConnection) new URL(mUrl).openConnection(); + in = new BufferedReader(new InputStreamReader( + conn.getInputStream(), "UTF-8")); + String buf; + while ((buf = in.readLine()) != null) + result.append(buf); + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (conn != null) + conn.disconnect(); + + // FileUtils.close(in); + } + return result.toString(); + } + + @Override + protected void onPostExecute(String s) { + Log.d("", "onPostExecute " + s); + mListener.onGetUserInfo(s); + } + } + + private void getUserInfo(String accessToken, String openId) { + String url = "https://api.weixin.qq.com/sns/userinfo?" + + "access_token=" + accessToken + "&openid=" + openId; + GetUserInfoTask mGetUserInfoTask = new GetUserInfoTask( + new OnGetUserInfoListener() { + + @Override + public void onNetError() { + + } + + @Override + public void onGetUserInfo(String userInfo) { + // text.setText(userInfo); + JSONObject object; + try { + object = new JSONObject(userInfo); + System.out.println(userInfo); + + String url = object.optString("headimgurl"); + + String unionid = object.optString("unionid"); + String openid = object.optString("openid"); + String nickname = object.optString("nickname"); + String sex = object.optString("sex"); + + String country = object.optString("country"); + SpUtil.setStringSharedPerference(sp, "country", + country); + String city = object.optString("city"); + SpUtil.setStringSharedPerference(sp, "city", city); + String province = object.optString("province"); + SpUtil.setStringSharedPerference(sp, "province", + province); + + SpUtil.setStringSharedPerference(sp, "unionid", + unionid); + SpUtil.setStringSharedPerference(sp, "headimgurl", + url); + + SpUtil.setStringSharedPerference(sp, "openid", + openid); + SpUtil.setStringSharedPerference(sp, "nickname", + nickname); + SpUtil.setStringSharedPerference(sp, "sex", sex); + + // ImageListener in1 = ImageLoader.getImageListener( + // image, R.drawable.ic_launcher, + // R.drawable.ic_launcher); + // ImageCacheManager.loadImage(url, in1); + + sharehandler.sendEmptyMessage(1); + + finish(); + + } catch (JSONException e) { + e.printStackTrace(); + } +// Toast.makeText(WXEntryActivity.this, +// "result=" + userInfo, Toast.LENGTH_LONG).show(); + } + }, url); // this代表WXEntryActivity.this + + mGetUserInfoTask.execute(); + } + + private void goToGetMsg() { + + } + + private void goToShowMsg(ShowMessageFromWX.Req showReq) { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/jx/jyhd/wxapi/WXPayEntryActivity.java b/app/src/main/java/com/jx/jyhd/wxapi/WXPayEntryActivity.java new file mode 100644 index 0000000..d4441b6 --- /dev/null +++ b/app/src/main/java/com/jx/jyhd/wxapi/WXPayEntryActivity.java @@ -0,0 +1,94 @@ +package com.jx.jyhd.wxapi; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.support.annotation.Nullable; +import android.util.Log; +import android.widget.Toast; + +import com.tencent.mm.opensdk.constants.ConstantsAPI; +import com.tencent.mm.opensdk.modelbase.BaseReq; +import com.tencent.mm.opensdk.modelbase.BaseResp; +import com.tencent.mm.opensdk.openapi.IWXAPI; +import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler; +import com.tencent.mm.opensdk.openapi.WXAPIFactory; +import com.jx.jyhd.R; +import com.jx.jyhd.simcpux.Constants; +import com.jx.jyhd.simcpux.Util; +import com.tsgame.tsgame_niuniu.util.Settingutil; + +public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler { + + private static final String TAG = "MicroMsg.SDKSample.WXPayEntryActivity"; + + private IWXAPI api; + + public static Handler handler; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.pay_result); + api = WXAPIFactory.createWXAPI(this, Constants.APP_ID); + api.handleIntent(getIntent(), this); + Util.verifyStoragePermissions(this); + } + + public void setHandler(Handler handler) { + this.handler = handler; + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + setIntent(intent); + api.handleIntent(intent, this); + } + + @Override + public void onReq(BaseReq baseReq) { + + } + + @Override + public void onResp(BaseResp baseResp) { + int what = 0; + + Log.d(TAG, "onPayFinish, errCode = " + baseResp.errCode); + if (baseResp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) { + // Toast.makeText(this, "进入", 1).show(); + switch (baseResp.errCode) { + + case BaseResp.ErrCode.ERR_OK: + Toast.makeText(this, "您支付成功", Toast.LENGTH_SHORT).show(); + what = 1; + System.out.println("-----------------------"); + break; + case BaseResp.ErrCode.ERR_USER_CANCEL: + Toast.makeText(this, "您取消支付", Toast.LENGTH_SHORT).show(); + + break; + case BaseResp.ErrCode.ERR_AUTH_DENIED: + Toast.makeText(this, "支付失败", Toast.LENGTH_SHORT).show(); + + break; + default: + + break; + } + + if (Settingutil.iswxpay) { + Settingutil.iswxpay = false; + handler.sendEmptyMessage(what); + } + finish(); + } + } + + @Override + public void onPointerCaptureChanged(boolean hasCapture) { + + } +} diff --git a/app/src/main/java/com/lsjwzh/widget/materialloadingprogressbar/CircleProgressBar.java b/app/src/main/java/com/lsjwzh/widget/materialloadingprogressbar/CircleProgressBar.java new file mode 100644 index 0000000..f78e397 --- /dev/null +++ b/app/src/main/java/com/lsjwzh/widget/materialloadingprogressbar/CircleProgressBar.java @@ -0,0 +1,428 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.lsjwzh.widget.materialloadingprogressbar; + + +import com.jx.jyhd.R; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RadialGradient; +import android.graphics.Shader; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.ShapeDrawable; +import android.graphics.drawable.shapes.OvalShape; +import android.net.Uri; +import android.support.v4.content.ContextCompat; +import android.support.v4.view.ViewCompat; +import android.util.AttributeSet; +import android.view.animation.Animation; +import android.widget.ImageView; + +/** + * Private class created to work around issues with AnimationListeners being + * called before the animation is actually complete and support shadows on older + * platforms. + * + */ + @SuppressLint("AppCompatCustomView") + public class CircleProgressBar extends ImageView { + + private static final int KEY_SHADOW_COLOR = 0x1E000000; + private static final int FILL_SHADOW_COLOR = 0x3D000000; + // PX + private static final float X_OFFSET = 0f; + private static final float Y_OFFSET = 1.75f; + private static final float SHADOW_RADIUS = 3.5f; + private static final int SHADOW_ELEVATION = 4; + + + private static final int DEFAULT_CIRCLE_BG_LIGHT = 0xFFFAFAFA; + private static final int DEFAULT_CIRCLE_DIAMETER = 56; + private static final int STROKE_WIDTH_LARGE = 3; + public static final int DEFAULT_TEXT_SIZE = 9; + + private Animation.AnimationListener mListener; + private int mShadowRadius; + private int mBackGroundColor; + private int mProgressColor; + private int mProgressStokeWidth; + private int mArrowWidth; + private int mArrowHeight; + private int mProgress; + private int mMax; + private int mDiameter; + private int mInnerRadius; + private Paint mTextPaint; + private int mTextColor; + private int mTextSize; + private boolean mIfDrawText; + private boolean mShowArrow; + private MaterialProgressDrawable mProgressDrawable; + private ShapeDrawable mBgCircle; + private boolean mCircleBackgroundEnabled; + private int[] mColors = new int[]{Color.BLACK}; +Context context; + + public CircleProgressBar(Context context) { + super(context); + init(context, null, 0); + + } + + public CircleProgressBar(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs, 0); + + } + + public CircleProgressBar(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context, attrs, defStyleAttr); + } + private void init(Context context, AttributeSet attrs, int defStyleAttr) { + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.CircleProgressBar, defStyleAttr,0); + this.context=context; +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// + final float density = getContext().getResources().getDisplayMetrics().density; + + mBackGroundColor = a.getColor( + R.styleable.CircleProgressBar_mlpb_background_color, DEFAULT_CIRCLE_BG_LIGHT); + + mProgressColor = a.getColor( + R.styleable.CircleProgressBar_mlpb_progress_color, DEFAULT_CIRCLE_BG_LIGHT);//ToDO 默认颜色 + + mInnerRadius = a.getDimensionPixelOffset( + R.styleable.CircleProgressBar_mlpb_inner_radius, -1); + + mProgressStokeWidth = a.getDimensionPixelOffset( + R.styleable.CircleProgressBar_mlpb_progress_stoke_width, (int) (STROKE_WIDTH_LARGE*density)); + mArrowWidth = a.getDimensionPixelOffset( + R.styleable.CircleProgressBar_mlpb_arrow_width, -1); + mArrowHeight = a.getDimensionPixelOffset( + R.styleable.CircleProgressBar_mlpb_arrow_height, -1); + mTextSize = a.getDimensionPixelOffset( + R.styleable.CircleProgressBar_mlpb_progress_text_size, (int)(DEFAULT_TEXT_SIZE *density)); + mTextColor = a.getColor( + R.styleable.CircleProgressBar_mlpb_progress_text_color, Color.BLACK); + + mShowArrow = a.getBoolean(R.styleable.CircleProgressBar_mlpb_show_arrow,false); + mCircleBackgroundEnabled = a.getBoolean(R.styleable.CircleProgressBar_mlpb_enable_circle_background,true); + + + + mProgress = a.getInt(R.styleable.CircleProgressBar_mlpb_progress, 0); + mMax = a.getInt(R.styleable.CircleProgressBar_mlpb_max, 100); + int textVisible = a.getInt(R.styleable.CircleProgressBar_mlpb_progress_text_visibility,1); + if(textVisible != 1){ + mIfDrawText = true; + } + + mTextPaint = new Paint(); + mTextPaint.setStyle(Paint.Style.FILL); + mTextPaint.setColor(mTextColor); + mTextPaint.setTextSize(mTextSize); + mTextPaint.setAntiAlias(true); + a.recycle(); + mProgressDrawable = new MaterialProgressDrawable(getContext(), this); + super.setImageDrawable(mProgressDrawable); + } + + + + private boolean elevationSupported() { + return android.os.Build.VERSION.SDK_INT >= 21; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (!elevationSupported()) { + setMeasuredDimension(getMeasuredWidth() + mShadowRadius * 2, getMeasuredHeight() + + mShadowRadius * 2); + } + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + final float density = getContext().getResources().getDisplayMetrics().density; + mDiameter = Math.min(getMeasuredWidth(),getMeasuredHeight()); + if(mDiameter <=0){ + mDiameter = (int)density*DEFAULT_CIRCLE_DIAMETER; + } + if(getBackground()==null&& mCircleBackgroundEnabled){ + final int shadowYOffset = (int) (density * Y_OFFSET); + final int shadowXOffset = (int) (density * X_OFFSET); + mShadowRadius = (int) (density * SHADOW_RADIUS); + + + if (elevationSupported()) { + mBgCircle = new ShapeDrawable(new OvalShape()); + ViewCompat.setElevation(this, SHADOW_ELEVATION * density); + } else { + OvalShape oval = new OvalShadow(mShadowRadius, mDiameter); + mBgCircle = new ShapeDrawable(oval); + ViewCompat.setLayerType(this, ViewCompat.LAYER_TYPE_SOFTWARE, mBgCircle.getPaint()); + mBgCircle.getPaint().setShadowLayer(mShadowRadius, shadowXOffset, shadowYOffset, + KEY_SHADOW_COLOR); + final int padding = (int) mShadowRadius; + // set padding so the inner image sits correctly within the shadow. + setPadding(padding, padding, padding, padding); + } + mBgCircle.getPaint().setColor(mBackGroundColor); + setBackgroundDrawable(mBgCircle); + } + mProgressDrawable.setBackgroundColor(mBackGroundColor); + mProgressDrawable.setColorSchemeColors(mColors); + mProgressDrawable.setSizeParameters(mDiameter, mDiameter, + mInnerRadius <= 0 ? (mDiameter - mProgressStokeWidth * 2) / 4 : mInnerRadius, + mProgressStokeWidth, + mArrowWidth < 0 ? mProgressStokeWidth * 4 : mArrowWidth, + mArrowHeight < 0 ? mProgressStokeWidth * 2 : mArrowHeight); + if(isShowArrow()){ + mProgressDrawable.setArrowScale(1f); + mProgressDrawable.showArrow(true); + } + super.setImageDrawable(null); + super.setImageDrawable(mProgressDrawable); + mProgressDrawable.setAlpha(255); + mProgressDrawable.start(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if(mIfDrawText) { + String text = String.format("%s%%", mProgress); + int x = getWidth() / 2 - text.length() * mTextSize / 4; + int y = getHeight() / 2 + mTextSize / 4; + canvas.drawText(text, x, y, mTextPaint); + } + } + + @Override + final public void setImageResource(int resId) { + + } + + + + public boolean isShowArrow() { + return mShowArrow; + } + + public void setShowArrow(boolean showArrow) { + this.mShowArrow = showArrow; + } + + + @Override + final public void setImageURI(Uri uri) { + super.setImageURI(uri); + } + + @Override + final public void setImageDrawable(Drawable drawable) { + } + + public void setAnimationListener(Animation.AnimationListener listener) { + mListener = listener; + } + + @Override + public void onAnimationStart() { + super.onAnimationStart(); + if (mListener != null) { + mListener.onAnimationStart(getAnimation()); + } + } + + @Override + public void onAnimationEnd() { + super.onAnimationEnd(); + if (mListener != null) { + mListener.onAnimationEnd(getAnimation()); + } + } + + + /** + * Set the color resources used in the progress animation from color resources. + * The first color will also be the color of the bar that grows in response + * to a user swipe gesture. + * + * @param colorResIds + */ + @SuppressWarnings("deprecation") + public void setColorSchemeResources(int... colorResIds) { + final Resources res = getResources(); + int[] colorRes = new int[colorResIds.length]; + for (int i = 0; i < colorResIds.length; i++) { + colorRes[i] = (ContextCompat.getColor(context, colorResIds[i])); + } + setColorSchemeColors(colorRes); + } + + /** + * Set the colors used in the progress animation. The first + * color will also be the color of the bar that grows in response to a user + * swipe gesture. + * + * @param colors + */ + public void setColorSchemeColors(int... colors) { + mColors = colors; + if(mProgressDrawable!=null) { + mProgressDrawable.setColorSchemeColors(colors); + } + } + /** + * Update the background color of the mBgCircle image view. + */ + public void setBackgroundColor(int colorRes) { + if (getBackground() instanceof ShapeDrawable) { + final Resources res = getResources(); + + ((ShapeDrawable) getBackground()).getPaint().setColor(ContextCompat.getColor(context, colorRes)); + } + } + + public boolean isShowProgressText() { + return mIfDrawText; + } + + public void setShowProgressText(boolean mIfDrawText) { + this.mIfDrawText = mIfDrawText; + } + + public int getMax() { + return mMax; + } + + public void setMax(int max) { + mMax = max; + } + + public int getProgress() { + return mProgress; + } + + public void setProgress(int progress) { + if (getMax() > 0) { + mProgress = progress; + } + } + + + public boolean circleBackgroundEnabled() { + return mCircleBackgroundEnabled; + } + + public void setCircleBackgroundEnabled(boolean enableCircleBackground) { + this.mCircleBackgroundEnabled = enableCircleBackground; + } + + + @Override + public int getVisibility() { + return super.getVisibility(); + } + + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + if (mProgressDrawable != null) { + if(visibility!=VISIBLE) { + mProgressDrawable.stop(); + } + mProgressDrawable.setVisible(visibility == VISIBLE, false); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (mProgressDrawable != null) { + mProgressDrawable.stop(); + mProgressDrawable.setVisible(getVisibility() == VISIBLE, false); + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (mProgressDrawable != null) { + mProgressDrawable.stop(); + mProgressDrawable.setVisible(false, false); + } + } + + + private class OvalShadow extends OvalShape { + private RadialGradient mRadialGradient; + private int mShadowRadius; + private Paint mShadowPaint; + private int mCircleDiameter; + + public OvalShadow(int shadowRadius, int circleDiameter) { + super(); + mShadowPaint = new Paint(); + mShadowRadius = shadowRadius; + mCircleDiameter = circleDiameter; + mRadialGradient = new RadialGradient(mCircleDiameter / 2, mCircleDiameter / 2, + mShadowRadius, new int[] { + FILL_SHADOW_COLOR, Color.TRANSPARENT + }, null, Shader.TileMode.CLAMP); + mShadowPaint.setShader(mRadialGradient); + } + + @Override + public void draw(Canvas canvas, Paint paint) { + final int viewWidth = CircleProgressBar.this.getWidth(); + final int viewHeight = CircleProgressBar.this.getHeight(); + canvas.drawCircle(viewWidth / 2, viewHeight / 2, (mCircleDiameter / 2 + mShadowRadius), + mShadowPaint); + canvas.drawCircle(viewWidth / 2, viewHeight / 2, (mCircleDiameter / 2), paint); + } + } +} diff --git a/app/src/main/java/com/lsjwzh/widget/materialloadingprogressbar/MaterialProgressDrawable.java b/app/src/main/java/com/lsjwzh/widget/materialloadingprogressbar/MaterialProgressDrawable.java new file mode 100644 index 0000000..829e711 --- /dev/null +++ b/app/src/main/java/com/lsjwzh/widget/materialloadingprogressbar/MaterialProgressDrawable.java @@ -0,0 +1,723 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.lsjwzh.widget.materialloadingprogressbar; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.Paint.Style; +import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.Animatable; +import android.graphics.drawable.Drawable; +import android.support.annotation.IntDef; +import android.support.annotation.NonNull; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.View; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.Animation; +import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; +import android.view.animation.Transformation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; + +/** + * Fancy progress indicator for Material theme. + * + * @hide + */ +public class MaterialProgressDrawable extends Drawable implements Animatable { + // Maps to ProgressBar.Large style + public static final int LARGE = 0; + // Maps to ProgressBar default style + public static final int DEFAULT = 1; + private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); + private static final Interpolator END_CURVE_INTERPOLATOR = new EndCurveInterpolator(); + private static final Interpolator START_CURVE_INTERPOLATOR = new StartCurveInterpolator(); + private static final Interpolator EASE_INTERPOLATOR = new AccelerateDecelerateInterpolator(); + // Maps to ProgressBar default style + private static final int CIRCLE_DIAMETER = 40; + private static final float CENTER_RADIUS = 8.75f; //should add up to 10 when + stroke_width + private static final float STROKE_WIDTH = 2.5f; + // Maps to ProgressBar.Large style + private static final int CIRCLE_DIAMETER_LARGE = 56; + private static final float CENTER_RADIUS_LARGE = 12.5f; + static final float STROKE_WIDTH_LARGE = 3f; + /** + * The duration of a single progress spin in milliseconds. + */ + private static final int ANIMATION_DURATION = 1000 * 80 / 60; + /** + * The number of points in the progress "star". + */ + private static final float NUM_POINTS = 5f; + /** + * Layout info for the arrowhead in dp + */ + private static final int ARROW_WIDTH = 10; + private static final int ARROW_HEIGHT = 5; + private static final float ARROW_OFFSET_ANGLE = 0; + /** + * Layout info for the arrowhead for the large spinner in dp + */ + static final int ARROW_WIDTH_LARGE = 12; + static final int ARROW_HEIGHT_LARGE = 6; + private static final float MAX_PROGRESS_ARC = .8f; + private final int[] COLORS = new int[]{ + Color.BLACK + }; + /** + * The list of animators operating on this drawable. + */ + private final ArrayList mAnimators = new ArrayList(); + /** + * The indicator ring, used to manage animation state. + */ + private final Ring mRing; + private final Callback mCallback = new Callback() { + @Override + public void invalidateDrawable(Drawable d) { + invalidateSelf(); + } + + @Override + public void scheduleDrawable(Drawable d, Runnable what, long when) { + scheduleSelf(what, when); + } + + @Override + public void unscheduleDrawable(Drawable d, Runnable what) { + unscheduleSelf(what); + } + }; + boolean mFinishing; + /** + * Canvas rotation in degrees. + */ + private float mRotation; + private Resources mResources; + private View mAnimExcutor; + private Animation mAnimation; + private float mRotationCount; + private double mWidth; + private double mHeight; + + public MaterialProgressDrawable(Context context, View animExcutor) { + mAnimExcutor = animExcutor; + mResources = context.getResources(); + + mRing = new Ring(mCallback); + mRing.setColors(COLORS); + + updateSizes(DEFAULT); + setupAnimators(); + } + + public void setSizeParameters(double progressCircleWidth, double progressCircleHeight, + double centerRadius, double strokeWidth, float arrowWidth, float arrowHeight) { + final Ring ring = mRing; + mWidth = progressCircleWidth; + mHeight = progressCircleHeight ; + ring.setStrokeWidth((float) strokeWidth ); + ring.setCenterRadius(centerRadius); + ring.setColorIndex(0); + ring.setArrowDimensions(arrowWidth , arrowHeight ); + ring.setInsets((int) mWidth, (int) mHeight); + } + + /** + * Set the overall size for the progress spinner. This updates the radius + * and stroke width of the ring. + * + * @param size One of {@link MaterialProgressDrawable.LARGE} or + * {@link MaterialProgressDrawable.DEFAULT} + */ + public void updateSizes(@ProgressDrawableSize int size) { + final DisplayMetrics metrics = mResources.getDisplayMetrics(); + final float screenDensity = metrics.density; + + if (size == LARGE) { + setSizeParameters(CIRCLE_DIAMETER_LARGE*screenDensity, CIRCLE_DIAMETER_LARGE*screenDensity, CENTER_RADIUS_LARGE*screenDensity, + STROKE_WIDTH_LARGE*screenDensity, ARROW_WIDTH_LARGE*screenDensity, ARROW_HEIGHT_LARGE*screenDensity); + } else { + setSizeParameters(CIRCLE_DIAMETER*screenDensity, CIRCLE_DIAMETER*screenDensity, CENTER_RADIUS*screenDensity, STROKE_WIDTH*screenDensity, + ARROW_WIDTH*screenDensity, ARROW_HEIGHT*screenDensity); + } + } + + /** + * @param show Set to true to display the arrowhead on the progress spinner. + */ + public void showArrow(boolean show) { + mRing.setShowArrow(show); + } + + /** + * @param scale Set the scale of the arrowhead for the spinner. + */ + public void setArrowScale(float scale) { + mRing.setArrowScale(scale); + } + + /** + * Set the start and end trim for the progress spinner arc. + * + * @param startAngle start angle + * @param endAngle end angle + */ + public void setStartEndTrim(float startAngle, float endAngle) { + mRing.setStartTrim(startAngle); + mRing.setEndTrim(endAngle); + } + + /** + * Set the amount of rotation to apply to the progress spinner. + * + * @param rotation Rotation is from [0..1] + */ + public void setProgressRotation(float rotation) { + mRing.setRotation(rotation); + } + + /** + * Update the background color of the circle image view. + */ + public void setBackgroundColor(int color) { + mRing.setBackgroundColor(color); + } + + /** + * Set the colors used in the progress animation from color resources. + * The first color will also be the color of the bar that grows in response + * to a user swipe gesture. + * + * @param colors + */ + public void setColorSchemeColors(int... colors) { + mRing.setColors(colors); + mRing.setColorIndex(0); + } + + @Override + public int getIntrinsicHeight() { + return (int) mHeight; + } + + @Override + public int getIntrinsicWidth() { + return (int) mWidth; + } + + @Override + public void draw(Canvas c) { + final Rect bounds = getBounds(); + final int saveCount = c.save(); + c.rotate(mRotation, bounds.exactCenterX(), bounds.exactCenterY()); + mRing.draw(c, bounds); + c.restoreToCount(saveCount); + } + + public int getAlpha() { + return mRing.getAlpha(); + } + + @Override + public void setAlpha(int alpha) { + mRing.setAlpha(alpha); + } + + @Override + public void setColorFilter(ColorFilter colorFilter) { + mRing.setColorFilter(colorFilter); + } + + @SuppressWarnings("unused") + private float getRotation() { + return mRotation; + } + + @SuppressWarnings("unused") + void setRotation(float rotation) { + mRotation = rotation; + invalidateSelf(); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + @Override + public boolean isRunning() { + final ArrayList animators = mAnimators; + final int N = animators.size(); + for (int i = 0; i < N; i++) { + final Animation animator = animators.get(i); + if (animator.hasStarted() && !animator.hasEnded()) { + return true; + } + } + return false; + } + + @Override + public void start() { + mAnimation.reset(); + mRing.storeOriginals(); + // Already showing some part of the ring + if (mRing.getEndTrim() != mRing.getStartTrim()) { + mFinishing = true; + mAnimation.setDuration(ANIMATION_DURATION / 2); + mAnimExcutor.startAnimation(mAnimation); + } else { + mRing.setColorIndex(0); + mRing.resetOriginals(); + mAnimation.setDuration(ANIMATION_DURATION); + mAnimExcutor.startAnimation(mAnimation); + } + } + + @Override + public void stop() { + mAnimExcutor.clearAnimation(); + setRotation(0); + mRing.setShowArrow(false); + mRing.setColorIndex(0); + mRing.resetOriginals(); + } + + private void applyFinishTranslation(float interpolatedTime, Ring ring) { + // shrink back down and complete a full rotation before + // starting other circles + // Rotation goes between [0..1]. + float targetRotation = (float) (Math.floor(ring.getStartingRotation() / MAX_PROGRESS_ARC) + + 1f); + final float startTrim = ring.getStartingStartTrim() + + (ring.getStartingEndTrim() - ring.getStartingStartTrim()) * interpolatedTime; + ring.setStartTrim(startTrim); + final float rotation = ring.getStartingRotation() + + ((targetRotation - ring.getStartingRotation()) * interpolatedTime); + ring.setRotation(rotation); + } + + private void setupAnimators() { + final Ring ring = mRing; + final Animation animation = new Animation() { + @Override + public void applyTransformation(float interpolatedTime, Transformation t) { + if (mFinishing) { + applyFinishTranslation(interpolatedTime, ring); + } else { + // The minProgressArc is calculated from 0 to create an + // angle that + // matches the stroke width. + final float minProgressArc = (float) Math.toRadians( + ring.getStrokeWidth() / (2 * Math.PI * ring.getCenterRadius())); + final float startingEndTrim = ring.getStartingEndTrim(); + final float startingTrim = ring.getStartingStartTrim(); + final float startingRotation = ring.getStartingRotation(); + + // Offset the minProgressArc to where the endTrim is + // located. + final float minArc = MAX_PROGRESS_ARC - minProgressArc; + float endTrim = startingEndTrim + (minArc + * START_CURVE_INTERPOLATOR.getInterpolation(interpolatedTime)); + float startTrim = startingTrim + (MAX_PROGRESS_ARC + * END_CURVE_INTERPOLATOR.getInterpolation(interpolatedTime)); + + final float sweepTrim = endTrim-startTrim; + //Avoid the ring to be a full circle + if(Math.abs(sweepTrim)>=1){ + endTrim = startTrim+0.5f; + } + + ring.setEndTrim(endTrim); + + ring.setStartTrim(startTrim); + + final float rotation = startingRotation + (0.25f * interpolatedTime); + ring.setRotation(rotation); + + float groupRotation = ((720.0f / NUM_POINTS) * interpolatedTime) + + (720.0f * (mRotationCount / NUM_POINTS)); + setRotation(groupRotation); + } + } + }; + animation.setRepeatCount(Animation.INFINITE); + animation.setRepeatMode(Animation.RESTART); + animation.setInterpolator(LINEAR_INTERPOLATOR); + animation.setAnimationListener(new Animation.AnimationListener() { + + @Override + public void onAnimationStart(Animation animation) { + mRotationCount = 0; + } + + @Override + public void onAnimationEnd(Animation animation) { + // do nothing + } + + @Override + public void onAnimationRepeat(Animation animation) { + ring.storeOriginals(); + ring.goToNextColor(); + ring.setStartTrim(ring.getEndTrim()); + if (mFinishing) { + // finished closing the last ring from the swipe gesture; go + // into progress mode + mFinishing = false; + animation.setDuration(ANIMATION_DURATION); + ring.setShowArrow(false); + } else { + mRotationCount = (mRotationCount + 1) % (NUM_POINTS); + } + } + }); + mAnimation = animation; + } + + @Retention(RetentionPolicy.CLASS) + @IntDef({LARGE, DEFAULT}) + public @interface ProgressDrawableSize { + } + + private static class Ring { + private final RectF mTempBounds = new RectF(); + private final Paint mPaint = new Paint(); + private final Paint mArrowPaint = new Paint(); + + private final Callback mCallback; + private final Paint mCirclePaint = new Paint(); + private float mStartTrim = 0.0f; + private float mEndTrim = 0.0f; + private float mRotation = 0.0f; + private float mStrokeWidth = 5.0f; + private float mStrokeInset = 2.5f; + private int[] mColors; + // mColorIndex represents the offset into the available mColors that the + // progress circle should currently display. As the progress circle is + // animating, the mColorIndex moves by one to the next available color. + private int mColorIndex; + private float mStartingStartTrim; + private float mStartingEndTrim; + private float mStartingRotation; + private boolean mShowArrow; + private Path mArrow; + private float mArrowScale; + private double mRingCenterRadius; + private int mArrowWidth; + private int mArrowHeight; + private int mAlpha; + private int mBackgroundColor; + + public Ring(Callback callback) { + mCallback = callback; + + mPaint.setStrokeCap(Paint.Cap.SQUARE); + mPaint.setAntiAlias(true); + mPaint.setStyle(Style.STROKE); + + mArrowPaint.setStyle(Paint.Style.FILL); + mArrowPaint.setAntiAlias(true); + } + + public void setBackgroundColor(int color) { + mBackgroundColor = color; + } + + /** + * Set the dimensions of the arrowhead. + * + * @param width Width of the hypotenuse of the arrow head + * @param height Height of the arrow point + */ + public void setArrowDimensions(float width, float height) { + mArrowWidth = (int) width; + mArrowHeight = (int) height; + } + + /** + * Draw the progress spinner + */ + public void draw(Canvas c, Rect bounds) { + final RectF arcBounds = mTempBounds; + arcBounds.set(bounds); + arcBounds.inset(mStrokeInset, mStrokeInset); + + final float startAngle = (mStartTrim + mRotation) * 360; + final float endAngle = (mEndTrim + mRotation) * 360; + float sweepAngle = endAngle - startAngle; + mPaint.setColor(mColors[mColorIndex]); + c.drawArc(arcBounds, startAngle, sweepAngle, false, mPaint); + + drawTriangle(c, startAngle, sweepAngle, bounds); + + if (mAlpha < 255) { + mCirclePaint.setColor(mBackgroundColor); + mCirclePaint.setAlpha(255 - mAlpha); + c.drawCircle(bounds.exactCenterX(), bounds.exactCenterY(), bounds.width() / 2, + mCirclePaint); + } + } + + private void drawTriangle(Canvas c, float startAngle, float sweepAngle, Rect bounds) { + if (mShowArrow) { + if (mArrow == null) { + mArrow = new android.graphics.Path(); + mArrow.setFillType(android.graphics.Path.FillType.EVEN_ODD); + } else { + mArrow.reset(); + } + + // Adjust the position of the triangle so that it is inset as + // much as the arc, but also centered on the arc. + float x = (float) (mRingCenterRadius * Math.cos(0) + bounds.exactCenterX()); + float y = (float) (mRingCenterRadius * Math.sin(0) + bounds.exactCenterY()); + + // Update the path each time. This works around an issue in SKIA + // where concatenating a rotation matrix to a scale matrix + // ignored a starting negative rotation. This appears to have + // been fixed as of API 21. + mArrow.moveTo(0, 0); + mArrow.lineTo((mArrowWidth) * mArrowScale, 0); + mArrow.lineTo(((mArrowWidth) * mArrowScale / 2), (mArrowHeight + * mArrowScale)); + mArrow.offset(x-((mArrowWidth) * mArrowScale / 2), y); + mArrow.close(); + // draw a triangle + mArrowPaint.setColor(mColors[mColorIndex]); + //when sweepAngle < 0 adjust the position of the arrow + c.rotate(startAngle + (sweepAngle<0?0:sweepAngle) - ARROW_OFFSET_ANGLE, bounds.exactCenterX(), + bounds.exactCenterY()); + c.drawPath(mArrow, mArrowPaint); + } + } + + /** + * Set the colors the progress spinner alternates between. + * + * @param colors Array of integers describing the colors. Must be non-null. + */ + public void setColors(@NonNull int[] colors) { + mColors = colors; + // if colors are reset, make sure to reset the color index as well + setColorIndex(0); + } + + /** + * @param index Index into the color array of the color to display in + * the progress spinner. + */ + public void setColorIndex(int index) { + mColorIndex = index; + } + + /** + * Proceed to the next available ring color. This will automatically + * wrap back to the beginning of colors. + */ + public void goToNextColor() { + mColorIndex = (mColorIndex + 1) % (mColors.length); + } + + public void setColorFilter(ColorFilter filter) { + mPaint.setColorFilter(filter); + invalidateSelf(); + } + + /** + * @return Current alpha of the progress spinner and arrowhead. + */ + public int getAlpha() { + return mAlpha; + } + + /** + * @param alpha Set the alpha of the progress spinner and associated arrowhead. + */ + public void setAlpha(int alpha) { + mAlpha = alpha; + } + + @SuppressWarnings("unused") + public float getStrokeWidth() { + return mStrokeWidth; + } + + /** + * @param strokeWidth Set the stroke width of the progress spinner in pixels. + */ + public void setStrokeWidth(float strokeWidth) { + mStrokeWidth = strokeWidth; + mPaint.setStrokeWidth(strokeWidth); + invalidateSelf(); + } + + @SuppressWarnings("unused") + public float getStartTrim() { + return mStartTrim; + } + + @SuppressWarnings("unused") + public void setStartTrim(float startTrim) { + mStartTrim = startTrim; + invalidateSelf(); + } + + public float getStartingStartTrim() { + return mStartingStartTrim; + } + + public float getStartingEndTrim() { + return mStartingEndTrim; + } + + @SuppressWarnings("unused") + public float getEndTrim() { + return mEndTrim; + } + + @SuppressWarnings("unused") + public void setEndTrim(float endTrim) { + mEndTrim = endTrim; + invalidateSelf(); + } + + @SuppressWarnings("unused") + public float getRotation() { + return mRotation; + } + + @SuppressWarnings("unused") + public void setRotation(float rotation) { + mRotation = rotation; + invalidateSelf(); + } + + public void setInsets(int width, int height) { + final float minEdge = (float) Math.min(width, height); + float insets; + if (mRingCenterRadius <= 0 || minEdge < 0) { + insets = (float) Math.ceil(mStrokeWidth / 2.0f); + } else { + insets = (float) (minEdge / 2.0f - mRingCenterRadius); + } + mStrokeInset = insets; + } + + @SuppressWarnings("unused") + public float getInsets() { + return mStrokeInset; + } + + public double getCenterRadius() { + return mRingCenterRadius; + } + + /** + * @param centerRadius Inner radius in px of the circle the progress + * spinner arc traces. + */ + public void setCenterRadius(double centerRadius) { + mRingCenterRadius = centerRadius; + } + + /** + * @param show Set to true to show the arrow head on the progress spinner. + */ + public void setShowArrow(boolean show) { + if (mShowArrow != show) { + mShowArrow = show; + invalidateSelf(); + } + } + + /** + * @param scale Set the scale of the arrowhead for the spinner. + */ + public void setArrowScale(float scale) { + if (scale != mArrowScale) { + mArrowScale = scale; + invalidateSelf(); + } + } + + /** + * @return The amount the progress spinner is currently rotated, between [0..1]. + */ + public float getStartingRotation() { + return mStartingRotation; + } + + /** + * If the start / end trim are offset to begin with, store them so that + * animation starts from that offset. + */ + public void storeOriginals() { + mStartingStartTrim = mStartTrim; + mStartingEndTrim = mEndTrim; + mStartingRotation = mRotation; + } + + /** + * Reset the progress spinner to default rotation, start and end angles. + */ + public void resetOriginals() { + mStartingStartTrim = 0; + mStartingEndTrim = 0; + mStartingRotation = 0; + setStartTrim(0); + setEndTrim(0); + setRotation(0); + } + + private void invalidateSelf() { + mCallback.invalidateDrawable(null); + } + } + + /** + * Squishes the interpolation curve into the second half of the animation. + */ + private static class EndCurveInterpolator extends AccelerateDecelerateInterpolator { + @Override + public float getInterpolation(float input) { + return super.getInterpolation(Math.max(0, (input - 0.5f) * 2.0f)); + } + } + + /** + * Squishes the interpolation curve into the first half of the animation. + */ + private static class StartCurveInterpolator extends AccelerateDecelerateInterpolator { + @Override + public float getInterpolation(float input) { + return super.getInterpolation(Math.min(1, input * 2.0f)); + } + } +} diff --git a/app/src/main/java/com/lsjwzh/widget/materialloadingprogressbar/WebviewProgressDialog.java b/app/src/main/java/com/lsjwzh/widget/materialloadingprogressbar/WebviewProgressDialog.java new file mode 100644 index 0000000..3e87a46 --- /dev/null +++ b/app/src/main/java/com/lsjwzh/widget/materialloadingprogressbar/WebviewProgressDialog.java @@ -0,0 +1,52 @@ +package com.lsjwzh.widget.materialloadingprogressbar; + + +import com.lsjwzh.widget.materialloadingprogressbar.CircleProgressBar; +import com.jx.jyhd.R; + +import android.annotation.SuppressLint; +import android.app.Dialog; +import android.content.Context; +import android.view.Gravity; + +public class WebviewProgressDialog extends Dialog { + static CircleProgressBar progress1; + private static WebviewProgressDialog customProgressDialog = null; + + public WebviewProgressDialog(Context context, int themeResId) { + super(context, themeResId); + // TODO Auto-generated constructor stub + } + + public WebviewProgressDialog(Context context) { + super(context); + + } + + @SuppressLint("InlinedApi") + public static WebviewProgressDialog createDialog(Context context) { + + customProgressDialog = new WebviewProgressDialog(context, + R.style.CustomProgressDialog); + + + + customProgressDialog.setContentView(R.layout.webviewdialog); + + progress1 = (CircleProgressBar) customProgressDialog + .findViewById(R.id.progress1); + + progress1.setColorSchemeResources(android.R.color.holo_green_light, + android.R.color.holo_orange_light, + android.R.color.holo_red_light); + + customProgressDialog.getWindow().getAttributes().gravity = Gravity.CENTER; + + return customProgressDialog; + } + + public void setProgress(int Progress) { + + progress1.setProgress(Progress); + } +} diff --git a/app/src/main/java/com/nickming/view/AudioManager.java b/app/src/main/java/com/nickming/view/AudioManager.java new file mode 100644 index 0000000..42de263 --- /dev/null +++ b/app/src/main/java/com/nickming/view/AudioManager.java @@ -0,0 +1,190 @@ +package com.nickming.view; + +import java.io.File; +import java.io.IOException; +import java.util.UUID; + +import android.media.MediaRecorder; + +public class AudioManager { + + private MediaRecorder mRecorder; + private String mDirString;// + private String mCurrentFilePathString; + + public boolean isPrepared = false;// 是否准备好了 + + /** + * 单例化的方法 1 先声明一个static 类型的变量a 2 在声明默认的构造函数 3 再用public synchronized static + * 类名 getInstance() { if(a==null) { a=new 类();} return a; } 或者用以下的方法 + */ + + /** + * 单例化这个类 + */ + private static AudioManager mInstance; + + private AudioManager(String dir) { + mDirString = dir; + } + + public static AudioManager getInstance(String dir) { + if (mInstance == null) { + // 同步 + synchronized (AudioManager.class) { + if (mInstance == null) { + mInstance = new AudioManager(dir); + + } + } + } + return mInstance; + + } + + /** + * 回调函数,准备完毕,准备好后,button才会开始显示录音框 + * + * @author nickming + * + */ + public interface AudioStageListener { + void wellPrepared(); + + void resetPrepared(); + + } + + public AudioStageListener mListener; + + public void setOnAudioStageListener(AudioStageListener listener) { + mListener = listener; + } + + // 准备方法 + public void prepareAudio() { + try { + // 一开始应该是false的 + isPrepared = false; + + File dir = new File(mDirString); + if (!dir.exists()) { + dir.mkdirs(); + } + + String fileNameString = generalFileName(); + File file = new File(dir, fileNameString); + + mCurrentFilePathString = file.getAbsolutePath(); + + mRecorder = new MediaRecorder(); + // 设置输出文件 + mRecorder.setOutputFile(file.getAbsolutePath()); + // 设置meidaRecorder的音频源是麦克风 + mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); + // 设置文件音频的输出格式为amr + mRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR); + // 设置音频的编码格式为amr + mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); + + // 严格遵守google官方api给出的mediaRecorder的状态流程图 + mRecorder.prepare(); + System.out.println("prepare()"); + mRecorder.start(); + System.out.println("start()"); + // 准备结束 + isPrepared = true; + // 已经准备好了,可以录制了 + if (mListener != null) { + mListener.wellPrepared(); + } + + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + System.out.println("音频==" + e.toString()); + // 已经准备好了,可以录制了 + if (mListener != null) { + mListener.resetPrepared(); + } + } + + } + + /** + * 随机生成文件的名称 + * + * @return + */ + private String generalFileName() { + // TODO Auto-generated method stub + + return UUID.randomUUID().toString() + ".amr";// javaJDK提供的一个自动生成主键的方法。UUID(Universally + // Unique + // Identifier)全局唯一标识符,是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的,是由一个十六位的数字组成,表现出来的 + // 形式 + } + + // 获得声音的level + public int getVoiceLevel(int maxLevel) { + // mRecorder.getMaxAmplitude()这个是音频的振幅范围,值域是1-32767 + if (isPrepared) { + try { + // 取证+1,否则去不到7 + return maxLevel * mRecorder.getMaxAmplitude() / 32768 + 1; + } catch (Exception e) { + // TODO Auto-generated catch block + + } + } + + return 1; + } + + // 释放资源 + public void release() { + // 严格按照api流程进行 + try { + + mRecorder.setOnErrorListener(null); + mRecorder.setOnInfoListener(null); + mRecorder.setPreviewDisplay(null); + + // 防止某些手机崩溃,例如联想 + mRecorder.stop(); + mRecorder.release(); + mRecorder = null; + + } catch (IllegalStateException e) { + e.printStackTrace(); + } catch (RuntimeException e) { + // TODO: handle exception + + } catch (Exception e) { + // TODO: handle exception + + } + + } + + // 取消,因为prepare时产生了一个文件,所以cancel方法应该要删除这个文件, + // 这是与release的方法的区别 + public void cancel() { + if(mRecorder!=null){ + release(); + } + + if (mCurrentFilePathString != null) { + File file = new File(mCurrentFilePathString); + file.delete(); + mCurrentFilePathString = null; + } + + } + + public String getCurrentFilePath() { + // TODO Auto-generated method stub + return mCurrentFilePathString; + } + +} diff --git a/app/src/main/java/com/nickming/view/DialogManager.java b/app/src/main/java/com/nickming/view/DialogManager.java new file mode 100644 index 0000000..66327ad --- /dev/null +++ b/app/src/main/java/com/nickming/view/DialogManager.java @@ -0,0 +1,127 @@ +package com.nickming.view; + + + + +import com.jx.jyhd.R; + +import android.app.Dialog; +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +public class DialogManager { + + + + private Dialog mDialog; + + private ImageView mIcon; + private ImageView mVoice; + + private TextView mLable; + + private Context mContext; + + public DialogManager(Context context) { + // TODO Auto-generated constructor stub + mContext = context; + } + + public void showRecordingDialog() { + // TODO Auto-generated method stub + if(mContext==null){ + System.out.println("上下文mContext为空"); + } + + mDialog = new Dialog(mContext,R.style.Theme_audioDialog); + + LayoutInflater inflater = LayoutInflater.from(mContext); + View view = inflater.inflate(R.layout.dialog_manager, null); + mDialog.setContentView(view); + + + mIcon = (ImageView) mDialog.findViewById(R.id.dialog_icon); + mVoice = (ImageView) mDialog.findViewById(R.id.dialog_voice); + mLable = (TextView) mDialog.findViewById(R.id.recorder_dialogtext); + try { + mDialog.show(); + } catch (Exception e) { + System.out.println("mDialog没有显示"); + } + + + } + public void recording() { + if (mDialog != null && mDialog.isShowing()) { + mIcon.setVisibility(View.VISIBLE); + mVoice.setVisibility(View.VISIBLE); + mLable.setVisibility(View.VISIBLE); + + mIcon.setImageResource(R.drawable.recorder); + mLable.setText(R.string.shouzhishanghua); + } + } + + + public void wantToCancel() { + // TODO Auto-generated method stub + if (mDialog != null && mDialog.isShowing()) { + mIcon.setVisibility(View.VISIBLE); + mVoice.setVisibility(View.GONE); + mLable.setVisibility(View.VISIBLE); + + mIcon.setImageResource(R.drawable.cancel); + mLable.setText(R.string.want_to_cancle); + } + + } + + // ʱ����� + public void tooShort() { + // TODO Auto-generated method stub + if (mDialog != null && mDialog.isShowing()) { + + mIcon.setVisibility(View.VISIBLE); + mVoice.setVisibility(View.GONE); + mLable.setVisibility(View.VISIBLE); + + mIcon.setImageResource(R.drawable.voice_to_short); + mLable.setText(R.string.tooshort); + } + + } + + + public void dimissDialog() { + // TODO Auto-generated method stub + + if (mDialog != null && mDialog.isShowing()) { + mDialog.dismiss(); + mDialog = null; + } + + } + + public void updateVoiceLevel(int level) { + // TODO Auto-generated method stub + + if (mDialog != null && mDialog.isShowing()) { + + //�Ȳ��ı�����Ĭ��״̬ +// mIcon.setVisibility(View.VISIBLE); +// mVoice.setVisibility(View.VISIBLE); +// mLable.setVisibility(View.VISIBLE); + + //ͨ��level���ҵ�ͼƬ��id��Ҳ������switch��Ѱַ�����Ǵ�����ܻ�Ƚϳ� + int resId = mContext.getResources().getIdentifier("v" + level, + "drawable", mContext.getPackageName()); + + mVoice.setImageResource(resId); + } + + } + +} diff --git a/app/src/main/java/com/nickming/view/Falcon.java b/app/src/main/java/com/nickming/view/Falcon.java new file mode 100644 index 0000000..0883772 --- /dev/null +++ b/app/src/main/java/com/nickming/view/Falcon.java @@ -0,0 +1,410 @@ +package com.nickming.view; + + +import android.app.Activity; +import android.app.Application; +import android.content.Context; +import android.content.ContextWrapper; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.os.Build; +import android.os.Looper; +import android.util.Log; +import android.view.View; +import android.view.WindowManager.LayoutParams; + +import java.io.*; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CountDownLatch; + +import static android.graphics.Bitmap.Config.ARGB_8888; +import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; + +/** + * Utility class to take screenshots of activity screen + */ +public final class Falcon { + //region Constants + + private static final String TAG = "Falcon"; + + //endregion + + //region Public API + + /** + * Takes screenshot of provided activity and saves it to provided file. + * File content will be overwritten if there is already some content. + * + * @param activity Activity of which the screenshot will be taken. + * @param toFile File where the screenshot will be saved. + * If there is some content it will be overwritten + * @throws UnableToTakeScreenshotException When there is unexpected error during taking screenshot + */ + public static void takeScreenshot(Activity activity, final File toFile) { + if (activity == null) { + throw new IllegalArgumentException("Parameter activity cannot be null."); + } + + if (toFile == null) { + throw new IllegalArgumentException("Parameter toFile cannot be null."); + } + + Bitmap bitmap = null; + try { + bitmap = takeBitmapUnchecked(activity); + writeBitmap(bitmap, toFile); + } catch (Exception e) { + String message = "Unable to take screenshot to file " + toFile.getAbsolutePath() + + " of activity " + activity.getClass().getName(); + + Log.e(TAG, message, e); + throw new UnableToTakeScreenshotException(message, e); + } finally { + if (bitmap != null) { + bitmap.recycle(); + } + } + + Log.d(TAG, "Screenshot captured to " + toFile.getAbsolutePath()); + } + + /** + * Takes screenshot of provided activity and puts it into bitmap. + * + * @param activity Activity of which the screenshot will be taken. + * @return Bitmap of what is displayed in activity. + * @throws UnableToTakeScreenshotException When there is unexpected error during taking screenshot + */ + public static Bitmap takeScreenshotBitmap(Activity activity) { + if (activity == null) { + throw new IllegalArgumentException("Parameter activity cannot be null."); + } + + try { + return takeBitmapUnchecked(activity); + } catch (Exception e) { + String message = "Unable to take screenshot to bitmap of activity " + + activity.getClass().getName(); + + Log.e(TAG, message, e); + throw new UnableToTakeScreenshotException(message, e); + } + } + + //endregion + + //region Methods + + private static Bitmap takeBitmapUnchecked(Activity activity) throws InterruptedException { + final List viewRoots = getRootViews(activity); + if (viewRoots.isEmpty()) { + throw new UnableToTakeScreenshotException("Unable to capture any view data in " + activity); + } + + int maxWidth = Integer.MIN_VALUE; + int maxHeight = Integer.MIN_VALUE; + + for (ViewRootData viewRoot : viewRoots) { + if (viewRoot._winFrame.right > maxWidth) { + maxWidth = viewRoot._winFrame.right; + } + + if (viewRoot._winFrame.bottom > maxHeight) { + maxHeight = viewRoot._winFrame.bottom; + } + } + + final Bitmap bitmap = Bitmap.createBitmap(maxWidth, maxHeight, Bitmap.Config.ARGB_8888); + + // We need to do it in main thread + if (Looper.myLooper() == Looper.getMainLooper()) { + drawRootsToBitmap(viewRoots, bitmap); + } else { + final CountDownLatch latch = new CountDownLatch(1); + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + try { + drawRootsToBitmap(viewRoots, bitmap); + } finally { + latch.countDown(); + } + } + }); + + latch.await(); + } + + return bitmap; + } + + private static void drawRootsToBitmap(List viewRoots, Bitmap bitmap) { + for (ViewRootData rootData : viewRoots) { + drawRootToBitmap(rootData, bitmap); + } + } + + private static void drawRootToBitmap(ViewRootData config, Bitmap bitmap) { + // now only dim supported + if ((config._layoutParams.flags & FLAG_DIM_BEHIND) == FLAG_DIM_BEHIND) { + Canvas dimCanvas = new Canvas(bitmap); + + int alpha = (int) (255 * config._layoutParams.dimAmount); + dimCanvas.drawARGB(alpha, 0, 0, 0); + } + + Canvas canvas = new Canvas(bitmap); + canvas.translate(config._winFrame.left, config._winFrame.top); + config._view.draw(canvas); + } + + private static void writeBitmap(Bitmap bitmap, File toFile) throws IOException { + OutputStream outputStream = null; + try { + outputStream = new BufferedOutputStream(new FileOutputStream(toFile)); + bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream); + } finally { + closeQuietly(outputStream); + } + } + + private static void closeQuietly(Closeable closable) { + if (closable != null) { + try { + closable.close(); + } catch (IOException e) { + // Do nothing + } + } + } + + @SuppressWarnings("unchecked") // no way to check + private static List getRootViews(Activity activity) { + List rootViews = new ArrayList(); + + Object globalWindowManager; + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) { + globalWindowManager = getFieldValue("mWindowManager", activity.getWindowManager()); + } else { + globalWindowManager = getFieldValue("mGlobal", activity.getWindowManager()); + } + Object rootObjects = getFieldValue("mRoots", globalWindowManager); + Object paramsObject = getFieldValue("mParams", globalWindowManager); + + Object[] roots; + LayoutParams[] params; + + // There was a change to ArrayList implementation in 4.4 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + roots = ((List) rootObjects).toArray(); + + List paramsList = (List) paramsObject; + params = paramsList.toArray(new LayoutParams[paramsList.size()]); + } else { + roots = (Object[]) rootObjects; + params = (LayoutParams[]) paramsObject; + } + + for (int i = 0; i < roots.length; i++) { + Object root = roots[i]; + + View view = (View) getFieldValue("mView", root); + + // fixes https://github.com/jraska/Falcon/issues/10 + if (view == null) { + Log.e(TAG, "null View stored as root in Global window manager, skipping"); + continue; + } + + Object attachInfo = getFieldValue("mAttachInfo", root); + int top =(Integer) getFieldValue("mWindowTop", attachInfo); + int left = (Integer) getFieldValue("mWindowLeft", attachInfo); + + Rect winFrame = (Rect) getFieldValue("mWinFrame", root); + Rect area = new Rect(left, top, left + winFrame.width(), top + winFrame.height()); + + rootViews.add(new ViewRootData(view, area, params[i])); + } + + if (rootViews.isEmpty()) { + return Collections.emptyList(); + } + + offsetRootsTopLeft(rootViews); + ensureDialogsAreAfterItsParentActivities(rootViews); + + return rootViews; + } + + private static void offsetRootsTopLeft(List rootViews) { + int minTop = Integer.MAX_VALUE; + int minLeft = Integer.MAX_VALUE; + for (ViewRootData rootView : rootViews) { + if (rootView._winFrame.top < minTop) { + minTop = rootView._winFrame.top; + } + + if (rootView._winFrame.left < minLeft) { + minLeft = rootView._winFrame.left; + } + } + + for (ViewRootData rootView : rootViews) { + rootView._winFrame.offset(-minLeft, -minTop); + } + } + + // This fixes issue #11. It is not perfect solution and maybe there is another case + // of different type of view, but it works for most common case of dialogs. + private static void ensureDialogsAreAfterItsParentActivities(List viewRoots) { + if (viewRoots.size() <= 1) { + return; + } + + for (int dialogIndex = 0; dialogIndex < viewRoots.size() - 1; dialogIndex++) { + ViewRootData viewRoot = viewRoots.get(dialogIndex); + if (!viewRoot.isDialogType()) { + continue; + } + + Activity dialogOwnerActivity = ownerActivity(viewRoot.context()); + if (dialogOwnerActivity == null) { + // make sure we will never compare null == null + return; + } + + for (int parentIndex = dialogIndex + 1; parentIndex < viewRoots.size(); parentIndex++) { + ViewRootData possibleParent = viewRoots.get(parentIndex); + if (possibleParent.isActivityType() + && ownerActivity(possibleParent.context()) == dialogOwnerActivity) { + viewRoots.remove(possibleParent); + viewRoots.add(dialogIndex, possibleParent); + + break; + } + } + } + } + + private static Activity ownerActivity(Context context) { + Context currentContext = context; + + while (currentContext != null) { + if (currentContext instanceof Activity) { + return (Activity) currentContext; + } + + if (currentContext instanceof ContextWrapper && !(currentContext instanceof Application)) { + currentContext = ((ContextWrapper) currentContext).getBaseContext(); + } else { + break; + } + } + + return null; + } + + private static Object getFieldValue(String fieldName, Object target) { + try { + return getFieldValueUnchecked(fieldName, target); + } catch (Exception e) { + throw new UnableToTakeScreenshotException(e); + } + } + + private static Object getFieldValueUnchecked(String fieldName, Object target) + throws NoSuchFieldException, IllegalAccessException { + Field field = findField(fieldName, target.getClass()); + + field.setAccessible(true); + return field.get(target); + } + + private static Field findField(String name, Class clazz) throws NoSuchFieldException { + Class currentClass = clazz; + while (currentClass != Object.class) { + for (Field field : currentClass.getDeclaredFields()) { + if (name.equals(field.getName())) { + return field; + } + } + + currentClass = currentClass.getSuperclass(); + } + + throw new NoSuchFieldException("Field " + name + " not found for class " + clazz); + } + + //endregion + + //region Constructors + + // No instances + private Falcon() { + } + + //endregion + + //region Nested classes + + /** + * Custom exception thrown if there is some exception thrown during + * screenshot capturing to enable better client code exception handling. + */ + public static class UnableToTakeScreenshotException extends RuntimeException { + private UnableToTakeScreenshotException(String detailMessage) { + super(detailMessage); + } + + private UnableToTakeScreenshotException(String detailMessage, Exception exception) { + super(detailMessage, extractException(exception)); + } + + private UnableToTakeScreenshotException(Exception ex) { + super(extractException(ex)); + } + + /** + * Method to avoid multiple wrapping. If there is already our exception, + * just wrap the cause again + */ + private static Throwable extractException(Exception ex) { + if (ex instanceof UnableToTakeScreenshotException) { + return ex.getCause(); + } + + return ex; + } + } + + private static class ViewRootData { + private final View _view; + private final Rect _winFrame; + private final LayoutParams _layoutParams; + + ViewRootData(View view, Rect winFrame, LayoutParams layoutParams) { + _view = view; + _winFrame = winFrame; + _layoutParams = layoutParams; + } + + boolean isDialogType() { + return _layoutParams.type == LayoutParams.TYPE_APPLICATION; + } + + boolean isActivityType() { + return _layoutParams.type == LayoutParams.TYPE_BASE_APPLICATION; + } + + Context context() { + return _view.getContext(); + } + } + + //endregion +} diff --git a/app/src/main/java/com/nickming/view/ScreenShoddmlib.java b/app/src/main/java/com/nickming/view/ScreenShoddmlib.java new file mode 100644 index 0000000..d0ea351 --- /dev/null +++ b/app/src/main/java/com/nickming/view/ScreenShoddmlib.java @@ -0,0 +1,77 @@ +package com.nickming.view; + +import com.android.ddmlib.AndroidDebugBridge; +import com.android.ddmlib.IDevice; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Created by Administrator on 2017/4/24. + */ + +public class ScreenShoddmlib { + //private BufferedImage image = null; + + /** + * @param args + */ + public static void main(String[] args) { + // TODO Auto-generated method stub + AndroidDebugBridge.init(false); // + ScreenShoddmlib screenshot = new ScreenShoddmlib(); + IDevice device = screenshot.getDevice(); + + for (int i = 0; i < 10; i++) { + + Date date = new Date(); + SimpleDateFormat df = new SimpleDateFormat("MM-dd-HH-mm-ss"); + String nowTime = df.format(date); + // screenshot.getScreenShot(device, "Robotium" + nowTime); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + + + + /** + * 获取得到device对象 + * + * @return + */ + private IDevice getDevice() { + IDevice device; + AndroidDebugBridge bridge = AndroidDebugBridge + .createBridge("adb", true);// 如果代码有问题请查看API,修改此处的参数值试一下 + waitDevicesList(bridge); + IDevice devices[] = bridge.getDevices(); + device = devices[0]; + return device; + } + + /** + * 等待查找device + * + * @param bridge + */ + private void waitDevicesList(AndroidDebugBridge bridge) { + int count = 0; + while (bridge.hasInitialDeviceList() == false) { + try { + Thread.sleep(500); + count++; + } catch (InterruptedException e) { + } + if (count > 240) { + System.err.print("等待获取设备超时"); + break; + } + } + } +} diff --git a/app/src/main/java/com/nickming/view/Screenshot.java b/app/src/main/java/com/nickming/view/Screenshot.java new file mode 100644 index 0000000..9e691b0 --- /dev/null +++ b/app/src/main/java/com/nickming/view/Screenshot.java @@ -0,0 +1,153 @@ +package com.nickming.view; + +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.graphics.Bitmap; +import android.graphics.PixelFormat; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.Display; + +import com.jx.jyhd.simcpux.Util; + +/** + * 通过读取文件 /dev/graphics/fb0获取屏幕截图 + * 截图获取bitmap只需�?100ms左右 + * + * @author gudh + * @data 2014-1-17 + */ +public class Screenshot { + + final static String FB0FILE1 = "/dev/graphics/fb0"; + final static String FB0FILE2 = "/dev/fb0"; + + static File fbFile; + static FileInputStream graphics = null; + static int screenWidth = 480; // 屏幕宽(像素,如�?480px�? + static int screenHeight = 800; // 屏幕高(像素,如�?800p�? + static byte[] piex; + + /** + * 初始化基本信�? + * + * @param context + */ + public static void init(Activity context) { + fbFile = new File(FB0FILE1); + if (!fbFile.exists()) { + File nFile = new File(FB0FILE2); + if (nFile.exists()) { + fbFile = nFile; + } + } + // 初始化事件文件的权限 + try { + Process sh = Runtime.getRuntime().exec("su", null, null); + OutputStream os = sh.getOutputStream(); + os.write(("chmod 777 " + fbFile.getAbsolutePath()).getBytes()); + os.flush(); + os.close(); + sh.waitFor(); + } catch (Exception e) { + e.printStackTrace(); + } + + DisplayMetrics dm = new DisplayMetrics(); + Display display = context.getWindowManager().getDefaultDisplay(); + display.getMetrics(dm); + screenWidth = dm.widthPixels; // 屏幕宽(像素,如�?480px�? + screenHeight = dm.heightPixels; // 屏幕高(像素,如�?800p�? + + PixelFormat pixelFormat = new PixelFormat(); + PixelFormat.getPixelFormatInfo(PixelFormat.RGBA_8888, pixelFormat); + int deepth = pixelFormat.bytesPerPixel; // 位深 + piex = new byte[screenHeight * screenWidth * deepth]; // 像素 + } + + /** + * 测试截图 + */ + @SuppressLint("SdCardPath") + public static void testShot() { + long start = System.currentTimeMillis(); + try { + Bitmap bm = getScreenBitmap(); + File file; + +// if (Environment.getExternalStorageState().equals( +// Environment.MEDIA_MOUNTED)) { +// // sd卡存储(/mnt/sdcard/cache) +// file = Environment.getExternalStorageDirectory();// 获取跟目录 +// } else { +// // 没有SD卡,缓存到系统存储 +// file = Environment.getDataDirectory(); +// } + file = Util.GetDirectory(); + saveMyBitmap(bm, file.getAbsolutePath() + File.separator + "ws.png"); + + } catch (IOException e) { + e.printStackTrace(); + } + long end = System.currentTimeMillis(); + Log.i("Screenshot", "time cost:" + (end - start)); + } + + /** + * 保存bitmap到文�? + * + * @param bitmap + * @param bitName + * @throws IOException + */ + public static void saveMyBitmap(Bitmap bitmap, String bitName) + throws IOException { + File f = new File(bitName); + f.createNewFile(); + FileOutputStream fOut = new FileOutputStream(f); + + bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut); + fOut.flush(); + fOut.close(); + } + + /** + * 获取当前屏幕截图,一定要先init + * + * @return + * @throws IOException + */ + public synchronized static Bitmap getScreenBitmap() throws IOException { + try { + graphics = new FileInputStream(fbFile); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return null; + } + + DataInputStream dStream = new DataInputStream(graphics); + dStream.readFully(piex); + dStream.close(); + + int[] colors = new int[screenHeight * screenWidth]; + // 将rgb转为色�?? + for (int m = 0; m < colors.length; m++) { + int r = (piex[m * 4] & 0xFF); + int g = (piex[m * 4 + 1] & 0xFF); + int b = (piex[m * 4 + 2] & 0xFF); + int a = (piex[m * 4 + 3] & 0xFF); + colors[m] = (a << 24) + (r << 16) + (g << 8) + b; + } + + return Bitmap.createBitmap(colors, screenWidth, screenHeight, + Bitmap.Config.ARGB_8888); + } +} diff --git a/app/src/main/java/com/nickming/view/listener/savelistener.java b/app/src/main/java/com/nickming/view/listener/savelistener.java new file mode 100644 index 0000000..0062d65 --- /dev/null +++ b/app/src/main/java/com/nickming/view/listener/savelistener.java @@ -0,0 +1,6 @@ +package com.nickming.view.listener; + +public interface savelistener { + public void save(String bitmappath); + +} diff --git a/app/src/main/java/com/tagmae/jsbridge/BridgeHandler.java b/app/src/main/java/com/tagmae/jsbridge/BridgeHandler.java new file mode 100644 index 0000000..b85b029 --- /dev/null +++ b/app/src/main/java/com/tagmae/jsbridge/BridgeHandler.java @@ -0,0 +1,7 @@ +package com.tagmae.jsbridge; + +public interface BridgeHandler { + + void handler(String data, CallBackFunction function); + +} diff --git a/app/src/main/java/com/tagmae/jsbridge/BridgeUtil.java b/app/src/main/java/com/tagmae/jsbridge/BridgeUtil.java new file mode 100644 index 0000000..d175d21 --- /dev/null +++ b/app/src/main/java/com/tagmae/jsbridge/BridgeUtil.java @@ -0,0 +1,126 @@ +package com.tagmae.jsbridge; + +import android.content.Context; + +import com.tencent.smtt.sdk.WebView; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +public class BridgeUtil { + final static String YY_OVERRIDE_SCHEMA = "yy://"; + final static String YY_RETURN_DATA = YY_OVERRIDE_SCHEMA + "return/";//格式为 yy://return/{function}/returncontent + final static String YY_FETCH_QUEUE = YY_RETURN_DATA + "_fetchQueue/"; + final static String EMPTY_STR = ""; + final static String UNDERLINE_STR = "_"; + final static String SPLIT_MARK = "/"; + + final static String CALLBACK_ID_FORMAT = "JAVA_CB_%s"; + final static String JS_HANDLE_MESSAGE_FROM_JAVA = "javascript:WebViewJavascriptBridge._handleMessageFromNative('%s');"; + final static String JS_FETCH_QUEUE_FROM_JAVA = "javascript:WebViewJavascriptBridge._fetchQueue();"; + public final static String JAVASCRIPT_STR = "javascript:"; + + // 例子 javascript:WebViewJavascriptBridge._fetchQueue(); --> _fetchQueue + public static String parseFunctionName(String jsUrl){ + return jsUrl.replace("javascript:WebViewJavascriptBridge.", "").replaceAll("\\(.*\\);", ""); + } + + // 获取到传递信息的body值 + // url = yy://return/_fetchQueue/[{"responseId":"JAVA_CB_2_3957","responseData":"Javascript Says Right back aka!"}] + public static String getDataFromReturnUrl(String url) { + if(url.startsWith(YY_FETCH_QUEUE)) { + // return = [{"responseId":"JAVA_CB_2_3957","responseData":"Javascript Says Right back aka!"}] + return url.replace(YY_FETCH_QUEUE, EMPTY_STR); + } + + // temp = _fetchQueue/[{"responseId":"JAVA_CB_2_3957","responseData":"Javascript Says Right back aka!"}] + String temp = url.replace(YY_RETURN_DATA, EMPTY_STR); + String[] functionAndData = temp.split(SPLIT_MARK); + + if(functionAndData.length >= 2) { + StringBuilder sb = new StringBuilder(); + for (int i = 1; i < functionAndData.length; i++) { + sb.append(functionAndData[i]); + } + // return = [{"responseId":"JAVA_CB_2_3957","responseData":"Javascript Says Right back aka!"}] + return sb.toString(); + } + return null; + } + + // 获取到传递信息的方法 + // url = yy://return/_fetchQueue/[{"responseId":"JAVA_CB_1_360","responseData":"Javascript Says Right back aka!"}] + public static String getFunctionFromReturnUrl(String url) { + // temp = _fetchQueue/[{"responseId":"JAVA_CB_1_360","responseData":"Javascript Says Right back aka!"}] + String temp = url.replace(YY_RETURN_DATA, EMPTY_STR); + String[] functionAndData = temp.split(SPLIT_MARK); + if(functionAndData.length >= 1){ + // functionAndData[0] = _fetchQueue + return functionAndData[0]; + } + return null; + } + + + + /** + * js 文件将注入为第一个script引用 + * @param view WebView + * @param url url + */ + public static void webViewLoadJs(WebView view, String url){ + String js = "var newscript = document.createElement(\"script\");"; + js += "newscript.src=\"" + url + "\";"; + js += "document.scripts[0].parentNode.insertBefore(newscript,document.scripts[0]);"; + view.loadUrl("javascript:" + js); + } + + /** + * 这里只是加载lib包中assets中的 WebViewJavascriptBridge.js + * @param view webview + * @param path 路径 + */ + public static void webViewLoadLocalJs(WebView view, String path){ + String jsContent = assetFile2Str(view.getContext(), path); + view.loadUrl("javascript:" + jsContent); + } + + /** + * 解析assets文件夹里面的代码,去除注释,取可执行的代码 + * @param c context + * @param urlStr 路径 + * @return 可执行代码 + */ + public static String assetFile2Str(Context c, String urlStr){ + InputStream in = null; + try{ + in = c.getAssets().open(urlStr); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in)); + String line = null; + StringBuilder sb = new StringBuilder(); + do { + line = bufferedReader.readLine(); + if (line != null && !line.matches("^\\s*\\/\\/.*")) { // 去除注释 + sb.append(line); + } + } while (line != null); + + bufferedReader.close(); + in.close(); + + return sb.toString(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if(in != null) { + try { + in.close(); + } catch (IOException e) { + } + } + } + return null; + } +} diff --git a/app/src/main/java/com/tagmae/jsbridge/BridgeWebView.java b/app/src/main/java/com/tagmae/jsbridge/BridgeWebView.java new file mode 100644 index 0000000..4967e0a --- /dev/null +++ b/app/src/main/java/com/tagmae/jsbridge/BridgeWebView.java @@ -0,0 +1,267 @@ +package com.tagmae.jsbridge; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.os.Build; +import android.os.Looper; +import android.os.SystemClock; +import android.text.TextUtils; +import android.util.AttributeSet; + +import com.tencent.smtt.sdk.WebView; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +@SuppressLint("SetJavaScriptEnabled") +public class BridgeWebView extends WebView implements WebViewJavascriptBridge { + + private final String TAG = "BridgeWebView"; + + public static final String toLoadJs = "WebViewJavascriptBridge.js"; + Map responseCallbacks = new HashMap(); + Map messageHandlers = new HashMap(); + BridgeHandler defaultHandler = new DefaultHandler(); + + private List startupMessage = new ArrayList(); + + public List getStartupMessage() { + return startupMessage; + } + + public void setStartupMessage(List startupMessage) { + this.startupMessage = startupMessage; + } + + private long uniqueId = 0; + + public BridgeWebView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public BridgeWebView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + public BridgeWebView(Context context) { + super(context); + init(); + } + + /** + * + * @param handler + * default handler,handle messages send by js without assigned handler name, + * if js message has handler name, it will be handled by named handlers registered by native + */ + public void setDefaultHandler(BridgeHandler handler) { + this.defaultHandler = handler; + } + + private void init() { + this.setVerticalScrollBarEnabled(false); + this.setHorizontalScrollBarEnabled(false); + this.getSettings().setJavaScriptEnabled(true); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + WebView.setWebContentsDebuggingEnabled(true); + } + this.setWebViewClient(generateBridgeWebViewClient()); + } + + protected BridgeWebViewClient generateBridgeWebViewClient() { + return new BridgeWebViewClient(this); + } + + /** + * 获取到CallBackFunction data执行调用并且从数据集移除 + * @param url + */ + void handlerReturnData(String url) { + String functionName = BridgeUtil.getFunctionFromReturnUrl(url); + CallBackFunction f = responseCallbacks.get(functionName); + String data = BridgeUtil.getDataFromReturnUrl(url); + if (f != null) { + f.onCallBack(data); + responseCallbacks.remove(functionName); + return; + } + } + + @Override + public void send(String data) { + send(data, null); + } + + @Override + public void send(String data, CallBackFunction responseCallback) { + doSend(null, data, responseCallback); + } + + /** + * 保存message到消息队列 + * @param handlerName handlerName + * @param data data + * @param responseCallback CallBackFunction + */ + private void doSend(String handlerName, String data, CallBackFunction responseCallback) { + Message m = new Message(); + if (!TextUtils.isEmpty(data)) { + m.setData(data); + } + if (responseCallback != null) { + String callbackStr = String.format(BridgeUtil.CALLBACK_ID_FORMAT, ++uniqueId + (BridgeUtil.UNDERLINE_STR + SystemClock.currentThreadTimeMillis())); + responseCallbacks.put(callbackStr, responseCallback); + m.setCallbackId(callbackStr); + } + if (!TextUtils.isEmpty(handlerName)) { + m.setHandlerName(handlerName); + } + queueMessage(m); + } + + /** + * list != null 添加到消息集合否则分发消息 + * @param m Message + */ + private void queueMessage(Message m) { + if (startupMessage != null) { + startupMessage.add(m); + } else { + dispatchMessage(m); + } + } + + /** + * 分发message 必须在主线程才分发成功 + * @param m Message + */ + void dispatchMessage(Message m) { + String messageJson = m.toJson(); + if(messageJson!=null){ + //escape special characters for json string 为json字符串转义特殊字符 + messageJson = messageJson.replaceAll("(\\\\)([^utrn])", "\\\\\\\\$1$2"); + messageJson = messageJson.replaceAll("(?<=[^\\\\])(\")", "\\\\\""); + String javascriptCommand = String.format(BridgeUtil.JS_HANDLE_MESSAGE_FROM_JAVA, messageJson); + // 必须要找主线程才会将数据传递出去 --- 划重点 + if (Thread.currentThread() == Looper.getMainLooper().getThread()) { + this.loadUrl(javascriptCommand); + } + } + + } + + /** + * 刷新消息队列 + */ + void flushMessageQueue() { + if (Thread.currentThread() == Looper.getMainLooper().getThread()) { + loadUrl(BridgeUtil.JS_FETCH_QUEUE_FROM_JAVA, new CallBackFunction() { + + @Override + public void onCallBack(String data) { + // deserializeMessage 反序列化消息 + List list = null; + try { + list = Message.toArrayList(data); + } catch (Exception e) { + e.printStackTrace(); + return; + } + if (list == null || list.size() == 0) { + return; + } + for (int i = 0; i < list.size(); i++) { + Message m = list.get(i); + String responseId = m.getResponseId(); + // 是否是response CallBackFunction + if (!TextUtils.isEmpty(responseId)) { + CallBackFunction function = responseCallbacks.get(responseId); + String responseData = m.getResponseData(); + Objects.requireNonNull(function).onCallBack(responseData); + responseCallbacks.remove(responseId); + } else { + CallBackFunction responseFunction = null; + // if had callbackId 如果有回调Id + final String callbackId = m.getCallbackId(); + if (!TextUtils.isEmpty(callbackId)) { + responseFunction = new CallBackFunction() { + @Override + public void onCallBack(String data) { + Message responseMsg = new Message(); + responseMsg.setResponseId(callbackId); + responseMsg.setResponseData(data); + queueMessage(responseMsg); + } + }; + } else { + responseFunction = new CallBackFunction() { + @Override + public void onCallBack(String data) { + // do nothing + } + }; + } + // BridgeHandler执行 + BridgeHandler handler; + if (!TextUtils.isEmpty(m.getHandlerName())) { + handler = messageHandlers.get(m.getHandlerName()); + } else { + handler = defaultHandler; + } + if (handler != null){ + handler.handler(m.getData(), responseFunction); + } + } + } + } + }); + } + } + + + public void loadUrl(String jsUrl, CallBackFunction returnCallback) { + this.loadUrl(jsUrl); + // 添加至 Map + responseCallbacks.put(BridgeUtil.parseFunctionName(jsUrl), returnCallback); + } + + /** + * register handler,so that javascript can call it + * 注册处理程序,以便javascript调用它 + * @param handlerName handlerName + * @param handler BridgeHandler + */ + public void registerHandler(String handlerName, BridgeHandler handler) { + if (handler != null) { + // 添加至 Map + messageHandlers.put(handlerName, handler); + } + } + + /** + * unregister handler + * + * @param handlerName + */ + public void unregisterHandler(String handlerName) { + if (handlerName != null) { + messageHandlers.remove(handlerName); + } + } + + /** + * call javascript registered handler + * 调用javascript处理程序注册 + * @param handlerName handlerName + * @param data data + * @param callBack CallBackFunction + */ + public void callHandler(String handlerName, String data, CallBackFunction callBack) { + doSend(handlerName, data, callBack); + } +} diff --git a/app/src/main/java/com/tagmae/jsbridge/BridgeWebViewClient.java b/app/src/main/java/com/tagmae/jsbridge/BridgeWebViewClient.java new file mode 100644 index 0000000..57804ed --- /dev/null +++ b/app/src/main/java/com/tagmae/jsbridge/BridgeWebViewClient.java @@ -0,0 +1,87 @@ +package com.tagmae.jsbridge; + +import android.graphics.Bitmap; + +import com.tencent.smtt.sdk.WebView; +import com.tencent.smtt.sdk.WebViewClient; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; + +/** + * 如果要自定义WebViewClient必须要集成此类 + * Created by bruce on 10/28/15. + */ +public class BridgeWebViewClient extends WebViewClient { + private BridgeWebView webView; + + public BridgeWebViewClient(BridgeWebView webView) { + this.webView = webView; + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + try { + url = URLDecoder.decode(url, "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + if (url.startsWith(BridgeUtil.YY_RETURN_DATA)) { // 如果是返回数据 + webView.handlerReturnData(url); + return true; + } else if (url.startsWith(BridgeUtil.YY_OVERRIDE_SCHEMA)) { // + webView.flushMessageQueue(); + return true; + } else { + return super.shouldOverrideUrlLoading(view, url); + } + } + +// // 增加shouldOverrideUrlLoading在api》=24时 +// @Override +// public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { +// +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { +// String url = request.getUrl().toString(); +// try { +// url = URLDecoder.decode(url, "UTF-8"); +// } catch (UnsupportedEncodingException ex) { +// ex.printStackTrace(); +// } +// if (url.startsWith(BridgeUtil.YY_RETURN_DATA)) { // 如果是返回数据 +// webView.handlerReturnData(url); +// return true; +// } else if (url.startsWith(BridgeUtil.YY_OVERRIDE_SCHEMA)) { // +// webView.flushMessageQueue(); +// return true; +// } else { +// return super.shouldOverrideUrlLoading(view, request); +// } +// }else { +// return super.shouldOverrideUrlLoading(view, request); +// } +// } + + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + super.onPageStarted(view, url, favicon); + } + + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + + if (BridgeWebView.toLoadJs != null) { + BridgeUtil.webViewLoadLocalJs(view, BridgeWebView.toLoadJs); + } + + // + if (webView.getStartupMessage() != null) { + for (Message m : webView.getStartupMessage()) { + webView.dispatchMessage(m); + } + webView.setStartupMessage(null); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tagmae/jsbridge/CallBackFunction.java b/app/src/main/java/com/tagmae/jsbridge/CallBackFunction.java new file mode 100644 index 0000000..d5ca3bc --- /dev/null +++ b/app/src/main/java/com/tagmae/jsbridge/CallBackFunction.java @@ -0,0 +1,7 @@ +package com.tagmae.jsbridge; + +public interface CallBackFunction { + + public void onCallBack(String data); + +} diff --git a/app/src/main/java/com/tagmae/jsbridge/DefaultHandler.java b/app/src/main/java/com/tagmae/jsbridge/DefaultHandler.java new file mode 100644 index 0000000..b1cf1c4 --- /dev/null +++ b/app/src/main/java/com/tagmae/jsbridge/DefaultHandler.java @@ -0,0 +1,14 @@ +package com.tagmae.jsbridge; + +public class DefaultHandler implements BridgeHandler{ + + String TAG = "DefaultHandler"; + + @Override + public void handler(String data, CallBackFunction function) { + if(function != null){ + function.onCallBack("DefaultHandler response data"); + } + } + +} diff --git a/app/src/main/java/com/tagmae/jsbridge/Message.java b/app/src/main/java/com/tagmae/jsbridge/Message.java new file mode 100644 index 0000000..ca623cd --- /dev/null +++ b/app/src/main/java/com/tagmae/jsbridge/Message.java @@ -0,0 +1,119 @@ +package com.tagmae.jsbridge; + +import android.text.TextUtils; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; + +import java.util.ArrayList; +import java.util.List; + +/** + * data of bridge + * @author haoqing + * + */ +public class Message { + + private String callbackId; //callbackId + private String responseId; //responseId + private String responseData; //responseData + private String data; //data of message + private String handlerName; //name of handler + + private final static String CALLBACK_ID_STR = "callbackId"; + private final static String RESPONSE_ID_STR = "responseId"; + private final static String RESPONSE_DATA_STR = "responseData"; + private final static String DATA_STR = "data"; + private final static String HANDLER_NAME_STR = "handlerName"; + + public String getResponseId() { + return responseId; + } + public void setResponseId(String responseId) { + this.responseId = responseId; + } + public String getResponseData() { + return responseData; + } + public void setResponseData(String responseData) { + this.responseData = responseData; + } + public String getCallbackId() { + return callbackId; + } + public void setCallbackId(String callbackId) { + this.callbackId = callbackId; + } + public String getData() { + return data; + } + public void setData(String data) { + this.data = data; + } + public String getHandlerName() { + return handlerName; + } + public void setHandlerName(String handlerName) { + this.handlerName = handlerName; + } + + public String toJson() { + JSONObject jsonObject= new JSONObject(); + try { + jsonObject.put(CALLBACK_ID_STR, getCallbackId()); + jsonObject.put(DATA_STR, getData()); + jsonObject.put(HANDLER_NAME_STR, getHandlerName()); + String data = getResponseData(); + if (TextUtils.isEmpty(data)) { + jsonObject.put(RESPONSE_DATA_STR, data); + } else { + jsonObject.put(RESPONSE_DATA_STR, new JSONTokener(data).nextValue()); + } + jsonObject.put(RESPONSE_DATA_STR, getResponseData()); + jsonObject.put(RESPONSE_ID_STR, getResponseId()); + return jsonObject.toString(); + } catch (JSONException e) { + e.printStackTrace(); + } + return null; + } + + public static Message toObject(String jsonStr) { + Message m = new Message(); + try { + JSONObject jsonObject = new JSONObject(jsonStr); + m.setHandlerName(jsonObject.has(HANDLER_NAME_STR) ? jsonObject.getString(HANDLER_NAME_STR):null); + m.setCallbackId(jsonObject.has(CALLBACK_ID_STR) ? jsonObject.getString(CALLBACK_ID_STR):null); + m.setResponseData(jsonObject.has(RESPONSE_DATA_STR) ? jsonObject.getString(RESPONSE_DATA_STR):null); + m.setResponseId(jsonObject.has(RESPONSE_ID_STR) ? jsonObject.getString(RESPONSE_ID_STR):null); + m.setData(jsonObject.has(DATA_STR) ? jsonObject.getString(DATA_STR):null); + return m; + } catch (JSONException e) { + e.printStackTrace(); + } + return m; + } + + public static List toArrayList(String jsonStr){ + List list = new ArrayList(); + try { + JSONArray jsonArray = new JSONArray(jsonStr); + for(int i = 0; i < jsonArray.length(); i++){ + Message m = new Message(); + JSONObject jsonObject = jsonArray.getJSONObject(i); + m.setHandlerName(jsonObject.has(HANDLER_NAME_STR) ? jsonObject.getString(HANDLER_NAME_STR):null); + m.setCallbackId(jsonObject.has(CALLBACK_ID_STR) ? jsonObject.getString(CALLBACK_ID_STR):null); + m.setResponseData(jsonObject.has(RESPONSE_DATA_STR) ? jsonObject.getString(RESPONSE_DATA_STR):null); + m.setResponseId(jsonObject.has(RESPONSE_ID_STR) ? jsonObject.getString(RESPONSE_ID_STR):null); + m.setData(jsonObject.has(DATA_STR) ? jsonObject.getString(DATA_STR):null); + list.add(m); + } + } catch (JSONException e) { + e.printStackTrace(); + } + return list; + } +} diff --git a/app/src/main/java/com/tagmae/jsbridge/WebViewJavascriptBridge.java b/app/src/main/java/com/tagmae/jsbridge/WebViewJavascriptBridge.java new file mode 100644 index 0000000..86fa575 --- /dev/null +++ b/app/src/main/java/com/tagmae/jsbridge/WebViewJavascriptBridge.java @@ -0,0 +1,11 @@ +package com.tagmae.jsbridge; + + +public interface WebViewJavascriptBridge { + + public void send(String data); + public void send(String data, CallBackFunction responseCallback); + + + +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/AndServerTestHandle.java b/app/src/main/java/com/tagmae/tsgame_erwang/AndServerTestHandle.java new file mode 100644 index 0000000..45a96c9 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/AndServerTestHandle.java @@ -0,0 +1,216 @@ +package com.tagmae.tsgame_erwang; + +import android.graphics.Bitmap; +import android.graphics.Bitmap.CompressFormat; +import android.graphics.BitmapFactory; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.Message; +import android.util.Base64; + +import com.nickming.view.listener.savelistener; +import com.jx.jyhd.simcpux.Util; +import com.jx.jyhd.simcpux.Wxistrue; +import com.yanzhenjie.andserver.AndServerRequestHandler; +import com.yanzhenjie.andserver.util.HttpRequestParser; + +import org.apache.http.HttpException; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.entity.StringEntity; +import org.apache.http.protocol.HttpContext; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.security.InvalidParameterException; +import java.util.Map; + +public class AndServerTestHandle implements AndServerRequestHandler { + + + private static savelistener listener1; + + public static Handler hanler; + + private static String bitmappath; + public static void setPhotoListerer(savelistener listener){ + listener1=listener; + } + + + public static void setPhotohandler(Handler hanler1){ + hanler=hanler1; + } + + @SuppressWarnings("deprecation") + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext arg2) + throws HttpException, IOException { + + if(Wxistrue.isphotoshare){//避免重复点击 + System.out.println("8888888888"); + if(HttpRequestParser.isPosterMethod(request)){ + if(hanler!=null){ + hanler.postDelayed(new Runnable() { + @Override + public void run() { + Wxistrue.isphotoshare=true; + Wxistrue.isphotoshare=true; + } + },3000); + } + + Wxistrue.isphotoshare=false; + + String name=HttpRequestParser.getContentForPost(request); + + System.out.println(name); + String photo=""; + + String type=name.substring(name.indexOf("data")-1, name.indexOf("data")); + + + //type="3"; + + System.out.println(type); + + try { + JSONObject object=new JSONObject(name); + photo=object.optString("name"); + + + photo=deleteheard(photo); + System.out.println("json格式"); + } catch (JSONException e) { + photo=deleteheard(name); + System.out.println("不是json格式"); + e.printStackTrace(); + } + saveBase64(photo); + Message msg=new Message(); + + + + //listener1.save(bitmappath); + + Bundle data=new Bundle(); + data.putString("bitpath", bitmappath); + data.putString("type", type); + System.out.println(type); + msg.setData(data); + hanler.sendMessage(msg); + + + + }else{ + // 拿到客户端参数key-value。 + Map params = HttpRequestParser.parse(request); + StringBuilder stringBuilder = new StringBuilder(); + for (Map.Entry entry : params.entrySet()) { + System.out.println(entry.getKey() + ": " + entry.getValue()); + stringBuilder.append(entry.getKey() + ": " + entry.getValue() + "\r\n"); + } + + System.out.println("客户端提交的参数:" + stringBuilder.toString()); + } + + response.setEntity(new StringEntity("请求成功。", "utf-8")); + } + + + } + private String deleteheard(String photo) { + int start=photo.indexOf(","); + photo=photo.substring(start+1, photo.length()); + System.out.println(photo); + return photo; + } + + public void saveBase64(String iconBase64){ + File file; + + if (Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED)) { + // sd卡存储(/mnt/sdcard/cache) + file = Environment.getExternalStorageDirectory();// 获取跟目录 + } else { + // 没有SD卡,缓存到系统存储 + file = Environment.getDataDirectory(); + } + file = Util.GetDirectory(); + bitmappath = file.getAbsolutePath() + File.separator + "photo.png"; + Bitmap bit1=stringtoBitmap(iconBase64); + if(bit1==null){ + System.out.println("图片为空"); + } + getScreenHot(bit1,bitmappath); + + + + } + +private void getScreenHot(Bitmap b1,String filePath) { + System.out.println(filePath); + if(b1==null){ + System.out.println("-----"); + } + File file1 = new File(filePath); + try { + file1.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + + try { + try { + + FileOutputStream fos = new FileOutputStream(file1); + b1.compress(CompressFormat.PNG, 100, fos); + fos.flush(); + fos.close(); + } catch (FileNotFoundException e) { + throw new InvalidParameterException(); + } + } catch (Exception e) { + e.printStackTrace(); + } +} + + + public Bitmap stringtoBitmap(String string) { + // 将字符串转换成Bitmap类型 + Bitmap bitmap = null; + try { + byte[] bitmapArray; + System.out.println(string); + bitmapArray = Base64.decode(string, Base64.DEFAULT); + bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0, + bitmapArray.length); + + } catch (Exception e) { + e.printStackTrace(); + } + return bitmap; + + } + public String bitmaptoString(Bitmap bitmap) { + // 将Bitmap转换成字符串 + String string = null; + ByteArrayOutputStream bStream = new ByteArrayOutputStream(); + bitmap.compress(CompressFormat.PNG, 100, bStream); + byte[] bytes = bStream.toByteArray(); + string = Base64.encodeToString(bytes, Base64.DEFAULT); + return string; + } + + + interface savePhotoListener{ + void success(); + } +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/AndroidBug5497Workaround.java b/app/src/main/java/com/tagmae/tsgame_erwang/AndroidBug5497Workaround.java new file mode 100644 index 0000000..5d97824 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/AndroidBug5497Workaround.java @@ -0,0 +1,56 @@ +package com.tagmae.tsgame_erwang; + +import android.app.Activity; +import android.graphics.Rect; +import android.view.View; +import android.view.ViewTreeObserver; +import android.widget.FrameLayout; + +/** + * 作者:YMI on 2017/12/4 10:18 + * 邮箱:18702631465@163.com + * QQ:1078561230 + */ + +public class AndroidBug5497Workaround { + // For more information, see https://code.google.com/p/android/issues/detail?id=5497 +// To use this class, simply invoke assistActivity() on an Activity that already has its content view set. + public static void assistActivity (Activity activity) { + new AndroidBug5497Workaround(activity); + } + private View mChildOfContent; + private int usableHeightPrevious; + private FrameLayout.LayoutParams frameLayoutParams; + private AndroidBug5497Workaround(Activity activity) { + FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content); + mChildOfContent = content.getChildAt(0); + mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + public void onGlobalLayout() { + possiblyResizeChildOfContent(); + } + }); + frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams(); + } + private void possiblyResizeChildOfContent() { + int usableHeightNow = computeUsableHeight(); + if (usableHeightNow != usableHeightPrevious) { + int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight(); + int heightDifference = usableHeightSansKeyboard - usableHeightNow; + if (heightDifference > (usableHeightSansKeyboard/4)) { +// keyboard probably just became visible + frameLayoutParams.height = usableHeightSansKeyboard - heightDifference; + } else { +// keyboard probably just became hidden + frameLayoutParams.height = usableHeightSansKeyboard; + } + mChildOfContent.requestLayout(); + usableHeightPrevious = usableHeightNow; + } + } + private int computeUsableHeight() { + Rect r = new Rect(); + mChildOfContent.getWindowVisibleDisplayFrame(r); + return (r.bottom - r.top);// 全屏模式下: return r.bottom + } + +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/BrowserUtil.java b/app/src/main/java/com/tagmae/tsgame_erwang/BrowserUtil.java new file mode 100644 index 0000000..dedbf80 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/BrowserUtil.java @@ -0,0 +1,26 @@ +package com.tagmae.tsgame_erwang; + +import java.io.File; + +/** + * 作者:YMI on 2018/4/16 12:31 + * 邮箱:18702631465@163.com + * QQ:1078561230 + */ +public class BrowserUtil { + /** + * 浏览器应用是否安装 + * @return + */ + public static boolean isQQBrowserInstalled(){ + return isInstallPackage("com.tencent.mtt"); + } + + public static boolean isUCBrowserInstalled(){ + return isInstallPackage("com.UCMobile"); + } + + private static boolean isInstallPackage(String packageName) { + return new File("/data/data/" + packageName).exists(); + } +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/CanvasBase64Example.java b/app/src/main/java/com/tagmae/tsgame_erwang/CanvasBase64Example.java new file mode 100644 index 0000000..53fe017 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/CanvasBase64Example.java @@ -0,0 +1,190 @@ +package com.tagmae.tsgame_erwang; + +import android.util.Log; +import com.tagmae.jsbridge.BridgeWebView; +import com.tencent.smtt.sdk.WebView; +import com.tencent.smtt.sdk.WebViewClient; + +/** + * Canvas转Base64使用示例 + * 展示如何使用WebViewScreenshotUtil中的Canvas相关功能 + */ +public class CanvasBase64Example { + private static final String TAG = "CanvasBase64Example"; + + /** + * 示例1:获取指定ID的Canvas内容 + */ + public static void captureCanvasById(BridgeWebView webView, String canvasId) { + WebViewScreenshotUtil.getCanvasBase64FromWebView(webView, canvasId, + new WebViewScreenshotUtil.CanvasToBase64Callback() { + @Override + public void onSuccess(String base64Data) { + Log.d(TAG, "Canvas captured successfully! Base64 length: " + base64Data.length()); + // 在这里处理获取到的base64数据 + // 例如:保存到文件、上传到服务器、显示在ImageView中等 + handleBase64Data(base64Data); + } + + @Override + public void onError(String error) { + Log.e(TAG, "Failed to capture canvas: " + error); + } + }); + } + + /** + * 示例2:获取页面中第一个Canvas内容 + */ + public static void captureFirstCanvas(BridgeWebView webView) { + WebViewScreenshotUtil.getCanvasBase64FromWebView(webView, null, + new WebViewScreenshotUtil.CanvasToBase64Callback() { + @Override + public void onSuccess(String base64Data) { + Log.d(TAG, "First canvas captured! Base64 length: " + base64Data.length()); + handleBase64Data(base64Data); + } + + @Override + public void onError(String error) { + Log.e(TAG, "Failed to capture first canvas: " + error); + } + }); + } + + /** + * 示例3:获取页面中所有Canvas内容 + */ + public static void captureAllCanvas(BridgeWebView webView) { + WebViewScreenshotUtil.getAllCanvasBase64FromWebView(webView, + new WebViewScreenshotUtil.CanvasToBase64Callback() { + @Override + public void onSuccess(String jsonResult) { + Log.d(TAG, "All canvas captured! JSON result: " + jsonResult); + // jsonResult是一个JSON字符串,包含所有Canvas的信息 + handleAllCanvasData(jsonResult); + } + + @Override + public void onError(String error) { + Log.e(TAG, "Failed to capture all canvas: " + error); + } + }); + } + + /** + * 示例4:高级Canvas截图 - 自动回退机制 + */ + public static void captureCanvasAdvanced(BridgeWebView webView, String canvasId) { + WebViewScreenshotUtil.captureCanvasAdvanced(webView, canvasId, + new WebViewScreenshotUtil.CanvasToBase64Callback() { + @Override + public void onSuccess(String base64Data) { + Log.d(TAG, "Advanced canvas capture succeeded! Base64 length: " + base64Data.length()); + handleBase64Data(base64Data); + } + + @Override + public void onError(String error) { + Log.e(TAG, "Advanced canvas capture failed: " + error); + } + }); + } + + /** + * 示例5:传统WebView截图转base64 + */ + public static void captureWebViewToBase64(BridgeWebView webView) { + // 同步方法,直接返回base64字符串 + String base64 = WebViewScreenshotUtil.captureWebViewToBase64(webView); + if (base64 != null) { + Log.d(TAG, "WebView captured to base64! Length: " + base64.length()); + handleBase64Data(base64); + } else { + Log.e(TAG, "Failed to capture WebView to base64"); + } + } + + /** + * 示例6:自定义质量的WebView截图转base64 + */ + public static void captureWebViewToBase64WithQuality(BridgeWebView webView, int quality) { + String base64 = WebViewScreenshotUtil.captureWebViewToBase64(webView, quality); + if (base64 != null) { + Log.d(TAG, "WebView captured with quality " + quality + "! Base64 length: " + base64.length()); + handleBase64Data(base64); + } else { + Log.e(TAG, "Failed to capture WebView with quality " + quality); + } + } + + /** + * 处理单个Canvas的base64数据 + */ + private static void handleBase64Data(String base64Data) { + // 在这里实现你的业务逻辑 + // 例如: + // 1. 保存到本地文件 + // 2. 上传到服务器 + // 3. 转换为Bitmap显示 + // 4. 分享给其他应用等 + + Log.d(TAG, "Processing base64 data of length: " + base64Data.length()); + + // 示例:如果需要转换回Bitmap + // Bitmap bitmap = base64ToBitmap(base64Data); + } + + /** + * 处理所有Canvas的JSON数据 + */ + private static void handleAllCanvasData(String jsonResult) { + // jsonResult格式示例: + // [{"index":0,"id":"gameCanvas","width":800,"height":600,"dataUrl":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."}] + + Log.d(TAG, "Processing all canvas data: " + jsonResult); + + // 可以使用JSON解析库(如Gson)来解析结果 + // 然后分别处理每个Canvas的数据 + } + + /** + * 工具方法:将base64转换回Bitmap(如果需要的话) + */ + public static android.graphics.Bitmap base64ToBitmap(String base64) { + try { + byte[] decodedBytes = android.util.Base64.decode(base64, android.util.Base64.DEFAULT); + return android.graphics.BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length); + } catch (Exception e) { + Log.e(TAG, "Error converting base64 to bitmap: " + e.getMessage()); + return null; + } + } + + /** + * 在Activity中的完整使用示例 + */ + public static class ActivityExample { + public void onWebViewReady(BridgeWebView webView) { + // 等待WebView加载完成后再进行截图 + webView.setWebViewClient(new WebViewClient() { + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + + // 页面加载完成后,稍微延迟一下确保Canvas渲染完成 + view.postDelayed(new Runnable() { + @Override + public void run() { + // 尝试获取特定Canvas + captureCanvasById(webView, "gameCanvas"); + + // 或者使用高级方法(推荐) + captureCanvasAdvanced(webView, "gameCanvas"); + } + }, 1000); // 延迟1秒 + } + }); + } + } +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/DouYinIntentShareHelper.java b/app/src/main/java/com/tagmae/tsgame_erwang/DouYinIntentShareHelper.java new file mode 100644 index 0000000..4a35af1 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/DouYinIntentShareHelper.java @@ -0,0 +1,1100 @@ +package com.tagmae.tsgame_erwang; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.net.Uri; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; +import android.widget.Toast; + +import com.google.gson.Gson; +import com.tagmae.tsgame_erwang.utils.Base64ImageUtil; +import com.tsgame.tsgame_niuniu.simcpux.bean.sharetypeBean; +import com.tsgame.tsgame_niuniu.util.DouYinIntentShareUtil; +import com.tsgame.tsgame_niuniu.util.FileProviderUtil; + +import java.io.File; +import java.io.FileOutputStream; + +/** + * 抖音分享测试辅助类 + */ +public class DouYinIntentShareHelper { + + /** + * 测试抖音分享 + * + * @param context 上下文 + * @param jsonData 分享数据JSON字符串 + */ + public static void doDouYinShare(Context context, String jsonData) { + try { + // 解析JSON数据 + Gson gson = new Gson(); + sharetypeBean bean = gson.fromJson(jsonData, sharetypeBean.class); + + // 初始化抖音分享工具 + DouYinIntentShareUtil douYinIntentShareUtil = DouYinIntentShareUtil.getInstance(context); + + // 检查抖音是否已安装 - HarmonyOS兼容性修改:移除强制检查 + // if (!douYinIntentShareUtil.isDouyinInstalled()) { + // Toast.makeText(context, "抖音未安装,无法进行抖音分享测试", Toast.LENGTH_SHORT).show(); + // return; + // } + + // 设置分享回调 + douYinIntentShareUtil.setShareCallback(new DouYinIntentShareUtil.DouYinShareCallback() { + @Override + public void onSuccess() { + ((Activity) context).runOnUiThread(() -> + Toast.makeText(context, "抖音分享成功", Toast.LENGTH_SHORT).show() + ); + } + + @Override + public void onError(int errorCode, String errorMsg) { + ((Activity) context).runOnUiThread(() -> + Toast.makeText(context, "抖音分享失败: " + errorMsg, Toast.LENGTH_SHORT).show() + ); + } + + @Override + public void onCancel() { + ((Activity) context).runOnUiThread(() -> + Toast.makeText(context, "抖音分享被取消", Toast.LENGTH_SHORT).show() + ); + } + }); + + // 获取分享类型和图片路径 + String type = bean.getType(); + String imagePath = bean.getDescription(); // 使用WebpageUrl作为图片/视频路径 + String hashTag = "#抖音分享"; // 默认话题标签 + + // 为标题添加至话题标签中 + if (bean.getTitle() != null && !bean.getTitle().isEmpty()) { + hashTag = "#" + bean.getTitle(); + } + + // 显示测试开始提示 + Toast.makeText(context, "正在分享到抖音", Toast.LENGTH_SHORT).show(); + + // 获取分享目标类型:主页(默认)、私信或群聊 + String shareTarget = "private_message"; +// if (shareTarget == null || shareTarget.isEmpty()) { +// shareTarget = "feed"; // 默认分享到主页 +// } + + // 根据分享目标类型执行不同的分享操作 + if ("private_message".equals(shareTarget)) { + // 分享到私信 + shareToPrivateMessage(context, douYinIntentShareUtil, type, bean, imagePath); + } else if ("group_chat".equals(shareTarget)) { + // 分享到群聊 + shareToGroupChat(context, douYinIntentShareUtil, type, bean, imagePath); + } else { + // 默认分享到主页 +// shareToFeed(context, douYinIntentShareUtil, type, bean, imagePath); + } + + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(context, "抖音分享出错: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + + + /** + * 分享到抖音私信 + */ + private static void shareToPrivateMessage(Context context, DouYinIntentShareUtil douYinIntentShareUtil, String type, sharetypeBean bean, String imagePath) { + StringBuilder content = new StringBuilder(); + + // 构建要分享的文本内容 + if (bean.getTitle() != null && !bean.getTitle().isEmpty()) { + content.append(bean.getTitle()).append("\n\n"); + } + + if (bean.getDescription() != null && !bean.getDescription().isEmpty()) { + content.append(bean.getDescription()); + } + + + String textContent = content.toString(); + + // 根据类型执行不同的分享操作 + if (type != null && type.equals("3") && imagePath != null) { + // 准备图片 + try { + + } catch (Exception e) { + e.printStackTrace(); + // 如果图片准备失败,至少分享文本 + //douYinIntentShareUtil.shareToPrivateMessage((Activity) context, textContent, null, null); + } + } else if (type != null && type.equals("4") && imagePath != null) { + // 准备视频URI + try { + File videoFile = new File(imagePath); + if (videoFile.exists()) { + Uri videoUri = FileProviderUtil.getUriForFile(context, videoFile); + if (videoUri != null) { + // 分享视频到私信 + douYinIntentShareUtil.shareToPrivateMessage((Activity) context, textContent, videoUri, "video"); + } else { + // URI为空,退回到纯文本分享 + douYinIntentShareUtil.shareToPrivateMessage((Activity) context, textContent, null, null); + } + } else { + // 文件不存在,退回到纯文本分享 + douYinIntentShareUtil.shareToPrivateMessage((Activity) context, textContent, null, null); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果视频准备失败,至少分享文本 + douYinIntentShareUtil.shareToPrivateMessage((Activity) context, textContent, null, null); + } + } else if (type != null && type.equals("2")) { + // 处理Base64图片分享 +// String description = bean.getDescription(); +// +// if (!TextUtils.isEmpty(description)) { +// Bitmap bitmap = Base64ImageUtil.base64ToBitmap(description); +// if (bitmap != null) { +// try { +// douYinIntentShareUtil.shareBitmapToDouyin((Activity) context,bitmap); +// bitmap.recycle(); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// } +// } // 图片分享 - 使用Canvas截图,直接分享到私信 + GlobalWebViewHelper.getCanvasBase64(new WebViewScreenshotUtil.CanvasToBase64Callback() { + @Override + public void onSuccess(String canvasBase64) { + // 使用Canvas截图的base64数据,直接分享到私信 + Bitmap bitmap = Base64ImageUtil.base64ToBitmap(canvasBase64); + if (bitmap != null) { + try { + // 直接分享到私信,不弹出选择器 + shareImageDirectToPrivateMessage((Activity) context, bitmap); + bitmap.recycle(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + @Override + public void onError(String error) { + // Canvas截图失败,提示用户 + ((Activity) context).runOnUiThread(() -> + Toast.makeText(context, "截图失败: " + error, Toast.LENGTH_SHORT).show() + ); + } }); + + // 如果处理失败,退回到纯文本分享 + //douYinIntentShareUtil.shareToPrivateMessage((Activity) context, textContent, null, null); + } else { + // 只分享文本 - 直接使用Intent分享而不是复制粘贴方式 + shareWebPageDirectToDouYin((Activity) context, bean.getTitle(), bean.getDescription(), ""); + } + } + + /** + * 分享到抖音群聊 + */ + private static void shareToGroupChat(Context context, DouYinIntentShareUtil douYinIntentShareUtil, String type, sharetypeBean bean, String imagePath) { + StringBuilder content = new StringBuilder(); + + // 构建要分享的文本内容 + if (bean.getTitle() != null && !bean.getTitle().isEmpty()) { + content.append(bean.getTitle()).append("\n\n"); + } + + if (bean.getDescription() != null && !bean.getDescription().isEmpty()) { + content.append(bean.getDescription()); + } + + + String textContent = content.toString(); + + // 根据类型执行不同的分享操作 + if (type != null && type.equals("3") && imagePath != null) { + // 准备图片URI + try { + File imageFile = new File(imagePath); + if (imageFile.exists()) { + Uri imageUri = FileProviderUtil.getUriForFile(context, imageFile); + if (imageUri != null) { + // 分享图片到群聊 + douYinIntentShareUtil.shareToGroupChat((Activity) context, textContent, imageUri, "image"); + } else { + // URI为空,退回到纯文本分享 + douYinIntentShareUtil.shareToGroupChat((Activity) context, textContent, null, null); + } + } else { + // 文件不存在,退回到纯文本分享 + douYinIntentShareUtil.shareToGroupChat((Activity) context, textContent, null, null); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果图片准备失败,至少分享文本 + douYinIntentShareUtil.shareToGroupChat((Activity) context, textContent, null, null); + } + } else if (type != null && type.equals("4") && imagePath != null) { + // 准备视频URI + try { + File videoFile = new File(imagePath); + if (videoFile.exists()) { + Uri videoUri = FileProviderUtil.getUriForFile(context, videoFile); + if (videoUri != null) { + // 分享视频到群聊 + douYinIntentShareUtil.shareToGroupChat((Activity) context, textContent, videoUri, "video"); + } else { + // URI为空,退回到纯文本分享 + douYinIntentShareUtil.shareToGroupChat((Activity) context, textContent, null, null); + } + } else { + // 文件不存在,退回到纯文本分享 + douYinIntentShareUtil.shareToGroupChat((Activity) context, textContent, null, null); + } + } catch (Exception e) { + e.printStackTrace(); + // 如果视频准备失败,至少分享文本 + douYinIntentShareUtil.shareToGroupChat((Activity) context, textContent, null, null); + } + } else if (type != null && type.equals("2")) { + // 处理Base64图片分享 + String description = bean.getDescription(); + if (!TextUtils.isEmpty(description)) { + Bitmap bitmap = Base64ImageUtil.base64ToBitmap(description); + if (bitmap != null) { + try { + // 创建文件保存路径 + File imageFolder = new File(((Activity) context).getExternalCacheDir(), "douyin_share"); + if (!imageFolder.exists()) { + imageFolder.mkdirs(); + } + + // 生成唯一的文件名 + String fileName = "douyin_base64_" + System.currentTimeMillis() + ".jpg"; + File imageFile = new File(imageFolder, fileName); + + // 保存图片到文件 + FileOutputStream fos = new FileOutputStream(imageFile); + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos); + fos.flush(); + fos.close(); + + // 回收Bitmap释放内存 + bitmap.recycle(); + + Uri imageUri = FileProviderUtil.getUriForFile(context, imageFile); + if (imageUri != null) { + // 分享图片到群聊 + douYinIntentShareUtil.shareToGroupChat((Activity) context, textContent, imageUri, "image"); + return; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + // 如果处理失败,退回到纯文本分享 + douYinIntentShareUtil.shareToGroupChat((Activity) context, textContent, null, null); + } else { + // 只分享文本 + douYinIntentShareUtil.shareToGroupChat((Activity) context, textContent, null, null); + } + } + + /** + * 分享纯文本到抖音 + * + * @param context 上下文 + * @param text 要分享的文本内容 + */ + public static void shareTextToDouYin(Context context, String text) { + try { + // 初始化抖音分享工具 + DouYinIntentShareUtil douYinIntentShareUtil = DouYinIntentShareUtil.getInstance(context); + + // 检查抖音是否已安装 - HarmonyOS兼容性修改:移除强制检查 + // if (!douYinIntentShareUtil.isDouyinInstalled()) { + // Toast.makeText(context, "抖音未安装,无法分享", Toast.LENGTH_SHORT).show(); + // return; + // } + + // 设置分享回调 + douYinIntentShareUtil.setShareCallback(new DouYinIntentShareUtil.DouYinShareCallback() { + @Override + public void onSuccess() { + ((Activity) context).runOnUiThread(() -> + Toast.makeText(context, "抖音分享成功", Toast.LENGTH_SHORT).show() + ); + } + + @Override + public void onError(int errorCode, String errorMsg) { + ((Activity) context).runOnUiThread(() -> + Toast.makeText(context, "抖音分享失败: " + errorMsg, Toast.LENGTH_SHORT).show() + ); + } + + @Override + public void onCancel() { + ((Activity) context).runOnUiThread(() -> + Toast.makeText(context, "抖音分享被取消", Toast.LENGTH_SHORT).show() + ); + } + }); + + // 显示分享提示 + Toast.makeText(context, "正在分享到抖音", Toast.LENGTH_SHORT).show(); // 修改:直接调用Intent分享方法,而不是复制粘贴方式 + shareTextDirectToDouYin((Activity) context, text); + + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(context, "分享到抖音出错: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + + /** + * 分享网页到抖音私信 + * + * @param activity 当前活动 + * @param title 网页标题 + * @param description 网页描述 + * @param webUrl 网页URL + * @param previewImageBase64 网页预览图(Base64编码,可为null) + */ + public static void shareWebPageToDouYinPrivate(Activity activity, String title, String description, + String webUrl, String previewImageBase64) { + try { + // 初始化抖音分享工具 + DouYinIntentShareUtil douYinIntentShareUtil = DouYinIntentShareUtil.getInstance(activity); + + // 检查抖音是否已安装 - HarmonyOS兼容性修改:移除强制检查 + // if (!douYinIntentShareUtil.isDouyinInstalled()) { + // Toast.makeText(activity, "抖音未安装,无法分享", Toast.LENGTH_SHORT).show(); + // return; + // } + + // 设置分享回调 + douYinIntentShareUtil.setShareCallback(new DouYinIntentShareUtil.DouYinShareCallback() { + @Override + public void onSuccess() { + activity.runOnUiThread(() -> + Toast.makeText(activity, "网页分享成功", Toast.LENGTH_SHORT).show() + ); + } + + @Override + public void onError(int errorCode, String errorMsg) { + activity.runOnUiThread(() -> + Toast.makeText(activity, "网页分享失败: " + errorMsg, Toast.LENGTH_SHORT).show() + ); + } + + @Override + public void onCancel() { + activity.runOnUiThread(() -> + Toast.makeText(activity, "网页分享被取消", Toast.LENGTH_SHORT).show() + ); + } + }); + + // 构建要分享的文本内容 + StringBuilder content = new StringBuilder(); + if (!TextUtils.isEmpty(title)) { + content.append(title).append("\n\n"); + } + if (!TextUtils.isEmpty(description)) { + content.append(description).append("\n\n"); + } + if (!TextUtils.isEmpty(webUrl)) { + content.append(webUrl); + } String textContent = content.toString(); + try { + Context mContext = activity.getApplicationContext(); + // 设置缩略图 - 使用应用的启动图标 logo6 而不是 ic_launcher + Bitmap thumbBmp = BitmapFactory.decodeResource(mContext.getResources(), + mContext.getResources().getIdentifier("logo6", "drawable", mContext.getPackageName())); + Uri imagePath = Base64ImageUtil.saveBitmapToFile(activity, thumbBmp, null); + + // 方式1:尝试分享图文到私信(图片+文本) + if (imagePath != null) { + shareImageWithTextDirectToDouYin(activity, textContent, imagePath); + return; + } + } catch (Exception e) { + e.printStackTrace(); + } + + // 方式2:如果图片处理失败,使用纯文本直接分享 + shareTextDirectToDouYin(activity, textContent); + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(activity, "网页分享出错: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + + /** + * 分享网页到抖音群聊 + * + * @param activity 当前活动 + * @param title 网页标题 + * @param description 网页描述 + * @param webUrl 网页URL + * @param previewImageBase64 网页预览图(Base64编码,可为null) + */ + public static void shareWebPageToDouYinGroup(Activity activity, String title, String description, + String webUrl, String previewImageBase64) { + try { + // 初始化抖音分享工具 + DouYinIntentShareUtil douYinIntentShareUtil = DouYinIntentShareUtil.getInstance(activity); + + // 检查抖音是否已安装 - HarmonyOS兼容性修改:移除强制检查 + // if (!douYinIntentShareUtil.isDouyinInstalled()) { + // Toast.makeText(activity, "抖音未安装,无法分享", Toast.LENGTH_SHORT).show(); + // return; + // } + + // 设置分享回调 + douYinIntentShareUtil.setShareCallback(new DouYinIntentShareUtil.DouYinShareCallback() { + @Override + public void onSuccess() { + activity.runOnUiThread(() -> + Toast.makeText(activity, "网页分享成功", Toast.LENGTH_SHORT).show() + ); + } + + @Override + public void onError(int errorCode, String errorMsg) { + activity.runOnUiThread(() -> + Toast.makeText(activity, "网页分享失败: " + errorMsg, Toast.LENGTH_SHORT).show() + ); + } + + @Override + public void onCancel() { + activity.runOnUiThread(() -> + Toast.makeText(activity, "网页分享被取消", Toast.LENGTH_SHORT).show() + ); + } + }); + + // 构建要分享的文本内容 + StringBuilder content = new StringBuilder(); + if (!TextUtils.isEmpty(title)) { + content.append(title).append("\n\n"); + } + if (!TextUtils.isEmpty(description)) { + content.append(description).append("\n\n"); + } + if (!TextUtils.isEmpty(webUrl)) { + content.append(webUrl); + } + + String textContent = content.toString(); + + // 如果提供了预览图,先处理图片再分享 + if (!TextUtils.isEmpty(previewImageBase64)) { + Bitmap bitmap = Base64ImageUtil.base64ToBitmap(previewImageBase64); + if (bitmap != null) { + try { + // 创建文件保存路径 + File imageFolder = new File(activity.getExternalCacheDir(), "douyin_web_share"); + if (!imageFolder.exists()) { + imageFolder.mkdirs(); + } + + // 生成唯一的文件名 + String fileName = "douyin_webpage_" + System.currentTimeMillis() + ".jpg"; + File imageFile = new File(imageFolder, fileName); + + // 保存图片到文件 + FileOutputStream fos = new FileOutputStream(imageFile); + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos); + fos.flush(); + fos.close(); + + // 回收Bitmap释放内存 + bitmap.recycle(); + + // 获取图片URI + Uri imageUri = FileProviderUtil.getUriForFile(activity, imageFile); + if (imageUri != null) { + // 分享图文到群聊 + douYinIntentShareUtil.shareToGroupChat(activity, textContent, imageUri, "image"); + return; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + // 如果没有预览图或处理失败,退回到纯文本分享 + douYinIntentShareUtil.shareToGroupChat(activity, textContent, null, null); + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(activity, "网页分享出错: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + + /** + * 从JSON数据分享网页到抖音(自动选择私信或群聊) + * + * @param context 上下文 + * @param jsonData 分享数据JSON字符串 + */ + public static void shareWebPageToDouYin(Context context, String jsonData) { + try { + // 解析JSON数据 + Gson gson = new Gson(); + sharetypeBean bean = gson.fromJson(jsonData, sharetypeBean.class); + + // 获取分享参数 + String title = bean.getTitle(); + String description = bean.getDescription(); + String webUrl = bean.getWebpageUrl(); + String imageBase64 = null; + + // 如果描述字段包含Base64图片,则提取出来作为预览图 + if (!TextUtils.isEmpty(description) && + (description.startsWith("data:image") || + description.startsWith("/9j/") || + description.startsWith("iVBOR"))) { + imageBase64 = description; + // 清空描述以避免重复使用 + description = null; + } + + // 获取分享目标类型:私信(默认)或群聊 + String shareTarget = "private_message"; // 默认私信 + + // 根据分享目标执行不同的分享操作 + if ("group_chat".equals(shareTarget)) { + // 分享到群聊 + shareWebPageToDouYinGroup((Activity) context, title, description, webUrl, imageBase64); + } else { + // 分享到私信(默认) + shareWebPageToDouYinPrivate((Activity) context, title, description, webUrl, imageBase64); + } + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(context, "抖音网页分享出错: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + + /** + * 截取当前屏幕并分享到抖音私信 + * + * @param activity 当前活动 + */ /** + * 分享截图到抖音私信(不弹出选择器) + * @param activity 活动上下文 + */ + public static void shareScreenshotToDouYin(Activity activity) { + try { + // 获取当前窗口的根视图 + View rootView = activity.getWindow().getDecorView().getRootView(); + // 创建一个与窗口大小相同的位图 + Bitmap bitmap = Bitmap.createBitmap(rootView.getWidth(), rootView.getHeight(), Bitmap.Config.ARGB_8888); + // 创建画布并将位图绑定到画布上 + Canvas canvas = new Canvas(bitmap); + // 将根视图绘制到画布上 + rootView.draw(canvas); + + // 显示分享提示 + Toast.makeText(activity, "正在分享截图到抖音私信", Toast.LENGTH_SHORT).show(); + + // 直接分享到私信,不弹出选择器 + shareImageDirectToPrivateMessage(activity, bitmap); + + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(activity, "分享截屏到抖音出错: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + + /** + * 直接分享图片到抖音私信,不弹出选择器 + * @param activity 活动上下文 + * @param bitmap 要分享的图片 + */ + public static void shareImageDirectToPrivateMessage(Activity activity, Bitmap bitmap) { + try { + // 检查抖音是否已安装 - HarmonyOS兼容性修改:移除强制检查 + // if (!isAppInstalled(activity, "com.ss.android.ugc.aweme")) { + // Toast.makeText(activity, "抖音未安装,无法分享", Toast.LENGTH_SHORT).show(); + // return; + // } + + // 保存bitmap到文件 + File cacheDir = activity.getExternalCacheDir(); + if (cacheDir == null) { + cacheDir = activity.getCacheDir(); + } + + File imageFile = new File(cacheDir, "douyin_private_share_" + System.currentTimeMillis() + ".jpg"); + FileOutputStream fos = new FileOutputStream(imageFile); + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos); + fos.flush(); + fos.close(); + + // 获取图片URI + Uri imageUri = FileProviderUtil.getUriForFile(activity, imageFile); + if (imageUri != null) { + // 创建专门用于私信分享的Intent + shareImageToPrivateMessageIntent(activity, imageUri); + } else { + Toast.makeText(activity, "获取图片文件失败", Toast.LENGTH_SHORT).show(); + } + + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(activity, "分享出错: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + + /** + * 使用Intent直接分享图片到抖音私信 + * @param activity 活动上下文 + * @param imageUri 图片Uri + */ + /** + * 使用剪贴板 + 弹窗引导的方式进行图片分享 + * 不再使用系统分享Intent,因为在鸿蒙/卓易通上兼容性问题较多 + */ + private static void shareImageToPrivateMessageIntent(Activity activity, Uri imageUri) { + try { + // 1. 复制图片到剪贴板 + boolean success = copyImageToClipboard(activity, imageUri); + + if (success) { + // 2. 显示引导弹窗 + showDouYinGuideDialog(activity); + } else { + Toast.makeText(activity, "复制图片失败,请检查文件权限", Toast.LENGTH_SHORT).show(); + } + + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(activity, "启动分享失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + + /** + * 复制图片Uri到剪贴板 + * 为了确保抖音能读取(粘贴)图片,尝试将图片保存到系统公共图库 + */ + private static boolean copyImageToClipboard(Context context, Uri uri) { + Uri contentUri = uri; // 默认为传入的URI + + // 尝试1:将图片插入系统相册获取公共Content URI (解决FileProvider权限无法跨应用粘贴的问题) + try { + android.content.ContentValues values = new android.content.ContentValues(); + values.put(android.provider.MediaStore.Images.Media.DISPLAY_NAME, "share_douyin_" + System.currentTimeMillis()); + values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg"); + + // 插入Media + Uri publicUri = context.getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); + + if (publicUri != null) { + // 复制文件内容到新URI + try (java.io.OutputStream os = context.getContentResolver().openOutputStream(publicUri); + java.io.InputStream is = context.getContentResolver().openInputStream(uri)) { + if (os != null && is != null) { + byte[] buffer = new byte[4096]; + int bytesRead; + while ((bytesRead = is.read(buffer)) != -1) { + os.write(buffer, 0, bytesRead); + } + // 成功复制内容,使用新的公共URI + contentUri = publicUri; + } + } + } + } catch (Exception e) { + Log.e("DouYinShare", "保存图片到相册失败: " + e.getMessage()); + // 失败时不阻断,继续尝试直接使用原始URI + } + + // 尝试2:设置剪贴板 + try { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newUri(context.getContentResolver(), "Image", contentUri); + clipboard.setPrimaryClip(clip); + return true; + } catch (Exception e) { + Log.e("DouYinShare", "复制图片到剪贴板失败: " + e.getMessage()); + return false; + } + } + + /** + * 显示抖音分享引导弹窗 + */ + private static void showDouYinGuideDialog(final Activity activity) { + android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(activity); + builder.setTitle("抖音分享准备完成"); + + // 构建自定义视图 + android.widget.LinearLayout layout = new android.widget.LinearLayout(activity); + layout.setOrientation(android.widget.LinearLayout.VERTICAL); + int padding = dp2px(activity, 20); + layout.setPadding(padding, padding, padding, padding); + layout.setGravity(android.view.Gravity.CENTER_HORIZONTAL); + + // 状态提示 + android.widget.TextView statusTv = new android.widget.TextView(activity); + statusTv.setText("✅ 图片已复制到剪贴板,并保存到相册"); + statusTv.setTextColor(android.graphics.Color.parseColor("#4CAF50")); + statusTv.setTextSize(16); + statusTv.setTypeface(null, android.graphics.Typeface.BOLD); + statusTv.setGravity(android.view.Gravity.CENTER); + layout.addView(statusTv); + + // 间隔 + android.view.View space = new android.view.View(activity); + layout.addView(space, new android.widget.LinearLayout.LayoutParams(android.view.ViewGroup.LayoutParams.MATCH_PARENT, dp2px(activity, 15))); + + // 步骤文本 + android.widget.TextView stepTv = new android.widget.TextView(activity); + stepTv.setText("分享到好友或群聊步骤:\n\n" + + "1. 点击下方按钮打开抖音\n" + + "2. 找到好友或群聊进入聊天界面\n" + + "3. 点击输入框旁的「+」号 ->「相册」\n" + + "4. 选择第一张图片发送即可\n" + + "(也可以尝试在输入框长按粘贴)"); + stepTv.setTextColor(android.graphics.Color.DKGRAY); + stepTv.setTextSize(14); + // 行间距 + stepTv.setLineSpacing(dp2px(activity, 4), 1.0f); + layout.addView(stepTv); + + builder.setView(layout); + + // 按钮 + builder.setPositiveButton("立即打开抖音", new android.content.DialogInterface.OnClickListener() { + @Override + public void onClick(android.content.DialogInterface dialog, int which) { + tryLaunchDouyinMain(activity); + } + }); + + builder.setNegativeButton("稍后分享", null); + + builder.show(); + } + + /** + * 启动抖音主界面 + */ + private static void tryLaunchDouyinMain(Activity activity) { + try { + Intent launchIntent = null; + + // 方法1: 尝试获取官方启动Intent + try { + launchIntent = activity.getPackageManager().getLaunchIntentForPackage("com.ss.android.ugc.aweme"); + } catch (Exception e) { + // 忽略包可见性异常 + } + + // 方法2: 如果获取不到(HarmonyOS/Android 11+ 可见性限制),尝试构造Intent盲拉 + if (launchIntent == null) { + launchIntent = new Intent(Intent.ACTION_MAIN); + launchIntent.addCategory(Intent.CATEGORY_LAUNCHER); + launchIntent.setPackage("com.ss.android.ugc.aweme"); + } + + launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + activity.startActivity(launchIntent); + + } catch (Exception e) { + // 方法3: 最后的救命稻草 - URL Scheme + try { + Uri uri = Uri.parse("snssdk1128://"); + Intent schemeIntent = new Intent(Intent.ACTION_VIEW, uri); + schemeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + activity.startActivity(schemeIntent); + } catch (Exception ex) { + Toast.makeText(activity, "启动抖音失败,请手动打开", Toast.LENGTH_SHORT).show(); + } + } + } + + private static int dp2px(Context context, float dp) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dp * scale + 0.5f); + } + + /** + * 检查应用是否已安装 + * @param context 上下文 + * @param packageName 包名 + * @return 是否已安装 + */ + private static boolean isAppInstalled(Context context, String packageName) { + try { + context.getPackageManager().getPackageInfo(packageName, 0); + return true; + } catch (Exception e) { + return false; + } + } + + /** + * 直接分享网页到抖音(使用Intent方式,不是复制粘贴) + * + * @param activity 当前活动 + * @param title 网页标题 + * @param description 网页描述 + * @param webUrl 网页URL + */ + public static void shareWebPageDirectToDouYin(Activity activity, String title, String description, String webUrl) { + try { + // 检查抖音是否已安装 - HarmonyOS兼容性修改:移除强制检查 + // if (!isAppInstalled(activity, "com.ss.android.ugc.aweme")) { + // Toast.makeText(activity, "抖音未安装,无法分享", Toast.LENGTH_SHORT).show(); + // return; + // } + + // 构建要分享的文本内容 + StringBuilder content = new StringBuilder(); + if (!TextUtils.isEmpty(title)) { + content.append(title).append("\n\n"); + } + if (!TextUtils.isEmpty(description)) { + content.append(description).append("\n\n"); + } if (!TextUtils.isEmpty(webUrl)) { + content.append(webUrl); + } + + String textContent = content.toString(); + + // 方法1:先尝试直接启动抖音App + if (tryLaunchDouyinDirectly(activity, textContent)) { + return; + } + + // 方法2:尝试使用多种MIME类型的分享Intent + if (tryMultipleShareIntents(activity, textContent)) { + return; + } + + // 方法3:最后的备选方案 - 复制到剪贴板并引导用户 + fallbackCopyAndLaunch(activity, textContent); + + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(activity, "网页分享出错: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } /** + * 直接分享图片和文本到抖音(使用Intent方式) + */ + private static void shareImageWithTextDirectToDouYin(Activity activity, String text, Uri imageUri) { + try { + // 图片分享通常有更好的支持,先尝试图片分享 + Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setType("image/*"); + shareIntent.putExtra(Intent.EXTRA_STREAM, imageUri); + shareIntent.putExtra(Intent.EXTRA_TEXT, text); + shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + + // 检查抖音是否可以处理图片分享 + if (isIntentSafe(activity, shareIntent, "com.ss.android.ugc.aweme")) { + shareIntent.setPackage("com.ss.android.ugc.aweme"); + // 添加额外参数尝试指定分享类型为私信 + shareIntent.putExtra("share_type", "private_message"); + shareIntent.putExtra("type", "private"); + + activity.startActivity(shareIntent); + Toast.makeText(activity, "正在打开抖音图文分享...", Toast.LENGTH_SHORT).show(); + return; + } + + // 如果直接分享失败,使用系统选择器 + Intent chooser = Intent.createChooser(shareIntent.setPackage(null), "分享图文"); + activity.startActivity(chooser); + + new android.os.Handler(android.os.Looper.getMainLooper()).postDelayed(() -> { + Toast.makeText(activity, "请选择抖音进行分享", Toast.LENGTH_LONG).show(); + }, 1000); + + } catch (Exception e) { + e.printStackTrace(); + // 如果图片分享失败,降级为纯文本分享 + Toast.makeText(activity, "图片分享失败,尝试文本分享", Toast.LENGTH_SHORT).show(); + shareTextDirectToDouYin(activity, text); + } + }/** + * 直接分享纯文本到抖音(使用Intent方式) + */ + private static void shareTextDirectToDouYin(Activity activity, String text) { + try { + // 方法1:先尝试直接启动抖音App + if (tryLaunchDouyinDirectly(activity, text)) { + return; + } + + // 方法2:尝试使用多种MIME类型的分享Intent + if (tryMultipleShareIntents(activity, text)) { + return; + } + + // 方法3:最后的备选方案 - 复制到剪贴板并引导用户 + fallbackCopyAndLaunch(activity, text); + + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(activity, "文本分享失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + + /** + * 方法1:尝试直接启动抖音App并复制内容到剪贴板 + */ + private static boolean tryLaunchDouyinDirectly(Activity activity, String content) { + try { + // 复制内容到剪贴板 + copyTextToClipboard(activity, content); + + // 尝试直接启动抖音主页 + Intent launchIntent = activity.getPackageManager().getLaunchIntentForPackage("com.ss.android.ugc.aweme"); + if (launchIntent != null) { + launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + activity.startActivity(launchIntent); + + // 提示用户操作 + Toast.makeText(activity, "内容已复制到剪贴板,请在抖音中点击\"消息\"→选择联系人→粘贴发送", Toast.LENGTH_LONG).show(); + return true; + } + } catch (Exception e) { + Log.e("DouYinShare", "直接启动抖音失败: " + e.getMessage()); + } + return false; + } + + /** + * 方法2:尝试使用多种MIME类型创建分享Intent + */ + private static boolean tryMultipleShareIntents(Activity activity, String content) { + // 尝试的MIME类型列表 + String[] mimeTypes = { + "text/plain", + "*/*", + "application/octet-stream" + }; + + for (String mimeType : mimeTypes) { + try { + Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setType(mimeType); + shareIntent.putExtra(Intent.EXTRA_TEXT, content); + shareIntent.putExtra(Intent.EXTRA_SUBJECT, "网页分享"); + + // 检查是否有抖音可以处理这种Intent + if (isIntentSafe(activity, shareIntent, "com.ss.android.ugc.aweme")) { + shareIntent.setPackage("com.ss.android.ugc.aweme"); + activity.startActivity(shareIntent); + Toast.makeText(activity, "正在打开抖音分享...", Toast.LENGTH_SHORT).show(); + return true; + } + } catch (Exception e) { + Log.e("DouYinShare", "MIME类型 " + mimeType + " 分享失败: " + e.getMessage()); + } + } + + // 如果直接分享失败,尝试使用系统分享选择器 + try { + Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setType("text/plain"); + shareIntent.putExtra(Intent.EXTRA_TEXT, content); + shareIntent.putExtra(Intent.EXTRA_SUBJECT, "网页分享"); + + Intent chooser = Intent.createChooser(shareIntent, "选择分享方式"); + activity.startActivity(chooser); + + // 提示用户如果看不到抖音选项的解决方案 + new android.os.Handler(android.os.Looper.getMainLooper()).postDelayed(() -> { + Toast.makeText(activity, "如果没有抖音选项,请选择\"复制\"然后手动打开抖音粘贴", Toast.LENGTH_LONG).show(); + }, 1000); + return true; + + } catch (Exception e) { + Log.e("DouYinShare", "系统分享选择器失败: " + e.getMessage()); + } + + return false; + } + + /** + * 方法3:备选方案 - 复制到剪贴板并引导用户手动操作 + */ + private static void fallbackCopyAndLaunch(Activity activity, String content) { + try { + // 复制到剪贴板 + copyTextToClipboard(activity, content); + + // 尝试启动抖音 + try { + Intent launchIntent = activity.getPackageManager().getLaunchIntentForPackage("com.ss.android.ugc.aweme"); + if (launchIntent != null) { + launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + activity.startActivity(launchIntent); + } + } catch (Exception e) { + Log.e("DouYinShare", "启动抖音失败: " + e.getMessage()); + } + + // 详细的操作指导 + Toast.makeText(activity, "内容已复制!请在抖音中:消息→选择好友→长按输入框→粘贴→发送", Toast.LENGTH_LONG).show(); + + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(activity, "分享失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + + /** + * 检查指定应用是否可以处理某个Intent + */ + private static boolean isIntentSafe(Activity activity, Intent intent, String packageName) { + try { + intent.setPackage(packageName); + return activity.getPackageManager().resolveActivity(intent, 0) != null; + } catch (Exception e) { + return false; + } + } + + /** + * 复制文本到剪贴板(兼容不同Android版本) + */ + private static void copyTextToClipboard(Activity activity, String text) { + try { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("网页分享", text); + clipboard.setPrimaryClip(clip); + } else { + @SuppressWarnings("deprecation") + android.text.ClipboardManager clipboard = (android.text.ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE); + clipboard.setText(text); + } + } catch (Exception e) { + Log.e("DouYinShare", "复制到剪贴板失败: " + e.getMessage()); + } + } +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/Fileutils.java b/app/src/main/java/com/tagmae/tsgame_erwang/Fileutils.java new file mode 100644 index 0000000..4adac90 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/Fileutils.java @@ -0,0 +1,111 @@ +package com.tagmae.tsgame_erwang; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.RandomAccessFile; + +public class Fileutils { + public static void deleteDir(final String pPath) { + File dir = new File(pPath); + deleteDirWihtFile(dir); + } + + public static void deleteDirWihtFile(File dir) { + if (dir == null || !dir.exists() || !dir.isDirectory()) + return; + for (File file : dir.listFiles()) { + if (file.isFile()) + file.delete(); // 删除所有文件 + else if (file.isDirectory()) + deleteDirWihtFile(file); // 递规的方式删除文件夹 + } + dir.delete();// 删除目录本身 + } + /** *向文件中添加内容 * + * * @param strcontent 内容 + * * @param filePath 地址 + * * @param fileName 文件名 */ + public static void writeToFile(String strcontent, String filePath) { + //生成文件夹之后,再生成文件,不然会出错 + String strFilePath = filePath; + + + + // 每次写入时,都换行写 + String strContent = strcontent + "\t\n"; + File subfile = new File(strFilePath); + RandomAccessFile raf = null; + try { + /** 构造函数 第二个是读写方式 */ + raf = new RandomAccessFile(subfile, "rw"); + /** 将记录指针移动到该文件的最后 */ + raf.seek(subfile.length()); + /** 向文件末尾追加内容 */ + raf.write(strContent.getBytes()); + raf.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + + /** * 修改文件内容(覆盖或者添加) * + * * @param path 文件地址 + * * @param content 覆盖内容 + * * @param append 指定了写入的方式,是覆盖写还是追加写(true=追加)(false=覆盖) */ + public static void modifyFile(String path, String content, boolean append) { + try { + FileWriter fileWriter = new FileWriter(path, append); + BufferedWriter writer = new BufferedWriter(fileWriter); + writer.append(content); + writer.flush(); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 读文件 + * @param fileName + * @return + */ + public static String readFile(String fileName){ + StringBuffer sb = new StringBuffer(""); + FileReader input = null; + BufferedReader reader = null; + try{ + input = new FileReader(fileName); + reader = new BufferedReader(input); + String line = null; + while((line = reader.readLine()) != null){ + sb.append(line); + } + }catch(Exception e){ + e.printStackTrace(); + }finally{ + if(null != reader){ + try { + reader.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + if(null != input){ + try { + input.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + return sb.toString(); + } + +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/GameupdateUtil.java b/app/src/main/java/com/tagmae/tsgame_erwang/GameupdateUtil.java new file mode 100644 index 0000000..f659315 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/GameupdateUtil.java @@ -0,0 +1,218 @@ +package com.tagmae.tsgame_erwang; + +import com.game.webgame.view.pmutil; +import com.orhanobut.logger.Logger; +import com.tsgame.tsgame_niuniu.Bean1.Agentlist; +import com.tsgame.tsgame_niuniu.Bean1.Channellist; +import com.tsgame.tsgame_niuniu.Bean1.ConfigData; +import com.tsgame.tsgame_niuniu.Bean1.Gamelist; +import com.tsgame.tsgame_niuniu.Bean1.Marketlist; +import com.tsgame.tsgame_niuniu.Bean1.gameversionUtil; +import com.tsgame.tsgame_niuniu.util.apputil; + +public class GameupdateUtil { + + + public gameversionUtil agentUtil(ConfigData mconfigData, Agentlist magentlist, Gamelist Ygamelist){ + + gameversionUtil mgameversionutil=new gameversionUtil(); + + if(magentlist!=null){ + if(!pmutil.isnullorEmpty(magentlist.getAgentid())){ + if(magentlist.getAgentid().equals(mconfigData.getAgentid())){ + setshowmessage(magentlist.getShowmessage()); + if(magentlist.getChannellist()!=null){ + for(int i=0;i resultunifiedorder; + private static final String TAG = "MicroMsg.SDKSample.PayActivity"; + static SharedPreferences Shared; + private static String bitmappath; + // ImageView image; + private static final int STATE_NORMAL = 1; + private static final int STATE_RECORDING = 2; + private static final int STATE_WANT_TO_CANCEL = 3; + Handler handler1 = new Handler(); + // Bitmap bitmap; + static int x1; // 按下时的坐标 + static int y1;// 按下时的坐标 + private boolean mReady = false; + private int mCurrentState = STATE_NORMAL; + private boolean isautio = false; + private UploadManager uploadManager; + + private String destFileDir = null; + private String dirs = null; + + private SharedPreferences sp; + + File photofile1; + + /** + * 权限 + */ + public String[] carpermission = new String[] { + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.RECORD_AUDIO }; + + String[] camerapermission1 = new String[] { + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.CAMERA }; + public String[] camerapermission = new String[] { Manifest.permission.CAMERA }; + + private static final String PACKAGE_URL_SCHEME = "package:"; // 方案 + private boolean isDown = false; + + private boolean isPlayaudio = false; + + private boolean isStopPlay = false; + + // 准备三个常量 + private static final int MSG_AUDIO_PREPARED = 0X1110; + private static final int MSG_VOICE_CHANGE = 0X111; + private static final int MSG_DIALOG_DIMISS = 0X112; + private static final int MSG_DIALOG_Audio_DIMISS = 0X113; + // 升级 + + // String m_newVerName; // 最新版的版本名 版本名 + String m_appNameStr = "tsgame_niuniu.apk"; // 下载到本地要给这个APP命的名字 + ProgressDialog m_progressDlg1; + // Handler m_mainHandler; + + List testphoto;// 图片下载目录 + + List testphoto1 = new ArrayList();// 图片下载目录 + + private int photosize = 0; + + private Boolean getphotoistrue = true; + + BatteryReceiver batteryReceiver; + + WifiChangeBroadcastReceiver WifiChangeReceiver; + MyNetReceiver myNetReceiver; + + ScreenListener screen; + private int downloadnum = 0; // 下载失败次数 + + private int downloadsum = 3; // 最多下载次数 + + private OkHttpClient okclient = new OkHttpClient(); + + List photolist = new ArrayList(); + + Wifinetworkbean wifibean = new Wifinetworkbean(); + + /** 上次点击返回键的时间 */ + private long lastBackPressed; + /** 上次点击返回键的时间 */ + private static final int QUIT_INTERVAL = 1000; + + private static String uservoice = "";// 用户座位动画id + + // 初始化AMapLocationClientOption对象 + AMapLocationClientOption mLocationOption = new AMapLocationClientOption(); + // 声明AMapLocationClient类对象 + public AMapLocationClient mLocationClient = null; + OnLocationChangedListener mListener; + + String data; + + /** + * 权限 + */ + public String[] locationpermission = new String[] { + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.READ_PHONE_STATE }; + + @SuppressLint("HandlerLeak") + Handler photohandler = new Handler() { + public void handleMessage(Message msg) { + int what = msg.what; + try{ + if (what == 0) { + getphotoistrue = true; + + Gson gson = new Gson(); +// for (int i = 0; i < testphoto1.size(); i++) { +// savephotoURLBean bean = testphoto1.get(i); +// +// } + + String json = gson.toJson(testphoto1); + + System.out.println("头像回调" + json); + + String getphoto = "javascript:getphoto(" + "'" + json + "'" + + ");"; +// webviewjh(getphoto); + x5webview.callHandler("getphoto", json, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + + } else if (what == 1) { + Bundle bundle = msg.getData(); + String photo = bundle.getString("photo"); + // savephoto(photo); + if (getphotoistrue) { + + savephoto(photo); + } else { + + // System.out.println(photo); + + Message msg1 = new Message(); + msg1.what = 1; + + Bundle bundel = new Bundle(); + bundel.putString("photo", photo); + + msg1.setData(bundel); + photohandler.sendMessageDelayed(msg1, 200); + } + + } + }catch(Exception e){ + getphotoistrue = true; + } + } + }; + + Handler playhandler = new Handler() { + public void handleMessage(Message msg) { + Bundle bundle = msg.getData(); + String audiourl = bundle.getString("audiourl"); + String user = bundle.getString("user"); + if (!isPlayaudio) { + isPlayaudio = true; + play(audiourl, user); + } else { + Message msg1 = new Message(); + msg1.what = 1; + Bundle bundel = new Bundle(); + bundel.putString("audiourl", audiourl); + bundel.putString("user", user); + msg1.setData(bundel); + playhandler.sendMessageDelayed(msg1, 200); + } + + }; + }; + + Handler permissionHandler = new Handler() { + public void handleMessage(Message msg) { + switch (msg.what) { + case 1: + if (!hasPermission(camerapermission)) { + + PermissionGen.needPermission(NewwebviewActivity.this, 18, + camerapermission); + } else { + + open(); + + } + break; + case 2: + + if (!hasPermission(camerapermission1)) { + + PermissionGen.needPermission(NewwebviewActivity.this, 22, + camerapermission1); + } else { + + doTakePhoto();// 用户点击了从照相机获取 + + } + + break; + default: + break; + } + }; + }; + + Handler savehandler = new Handler() { + public void handleMessage(Message msg) { + +// savehandler.postDelayed(new Runnable() { +// @Override +// public void run() { +// Wxistrue.isshare=true; +// Wxistrue.isphotoshare=true; +// } +// },3000); + + System.out.print("Wxistrue.isshare"+ Wxistrue.isshare); +// if (Wxistrue.isshare) { +// Wxistrue.isshare = false; + + Bundle data = msg.getData(); + String bitpath = data.getString("bitpath"); + String bitmapdata = data.getString("bitmap"); + String type = data.getString("type"); + System.out.print("bitpath"+bitpath+"type"+type); + bean = new sharetypeBean(); + bean.setType(type);// 图片分享,分享到朋友圈 + bitmappath = bitmapdata; + + + WXEntryActivity.setshareHandler(handler); +// SGEntryActivity.setshareHandler(handler); + + if (type.equals("1")) { + try { + photosharefriend(); + + } catch (Exception e) { + + Wxistrue.isshare = true; + } + + } else if(type.equals("3")){ +// if(!xlapi.isSGAppInstalled()){ +// Wxistrue.isphotoshare=true; +// Toast.makeText(NewwebviewActivity.this,"闲聊应用未安装,请先安装闲聊应用",Toast.LENGTH_SHORT).show(); +// Wxistrue.isshare = true; +// +// }else{ +// +// xlphotosharefriend(); +// +// } + + + } else { + try{ + + photosharefriends(); + + }catch(Exception e){ + Wxistrue.isshare = true; + } + + } +// }else{ +// h5handler.postDelayed(new Runnable() { +// @Override +// public void run() { +// Wxistrue.isshare = true; +// } +// },1000); +// } + }; + }; + + @SuppressLint("HandlerLeak") + Handler handler = new Handler() { + @SuppressLint({ "ShowToast" }) + @Override + public void handleMessage(Message msg) { + int success = msg.what; + + // Shared = SpUtil.getSharePerference(webviewActivity.this); + + if (success != 1) { + + Wxistrue.isshare = true; + + Wxistrue.isphotoshare = true; + JSONObject json = new JSONObject(); + try { + json.put("success", success); + + json.put("type", Wxistrue.sharetype); + + System.out.println("---" + json.toString()); + x5webview.callHandler("sharesuccess", json.toString(), new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + + } catch (JSONException e) { + e.printStackTrace(); + } +// String sharesuccess = "javascript:sharesuccess(" + "'" +// + success + "'" + ",'" + Wxistrue.sharetype + "'" +// + ");"; +// webviewjh(sharesuccess); + } + + switch (msg.what) { + case 1: + + if (Shared == null) { + // Toast.makeText(webviewActivity.this, "Shared 为空", + // 1).show(); + } + + String openid = SpUtil.getStringSharedPerference(Shared, + "openid"); + openid = openid.replaceAll("'", ""); + + String headimgurl = SpUtil.getStringSharedPerference(Shared, + "headimgurl"); + + headimgurl = headimgurl.replaceAll("'", ""); + + String nickname = SpUtil.getStringSharedPerference(Shared, + "nickname"); + nickname = nickname.replaceAll("'", ""); + + String sex = SpUtil.getStringSharedPerference(Shared, "sex"); + sex = sex.replaceAll("'", ""); + + String city = SpUtil.getStringSharedPerference(Shared, "city"); + city = city.replaceAll("'", ""); + + String province = SpUtil.getStringSharedPerference(Shared, + "province"); + province = province.replaceAll("'", ""); + + String unionid = SpUtil.getStringSharedPerference(Shared, + "unionid"); + unionid = unionid.replaceAll("'", ""); + + Wxistrue.islogin = true; + JSONObject json = new JSONObject(); + try { + json.put("openid", openid); + json.put("headimgurl", headimgurl); + json.put("nickname", nickname); + json.put("sex", sex); + json.put("city", city); + json.put("province", province); + json.put("unionid", unionid); + System.out.println("---" + json.toString()); + x5webview.callHandler("sharelogin", json.toString(), new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + + } catch (JSONException e) { + e.printStackTrace(); + } +// String sharelogin = "javascript:sharelogin(" + "'" + openid +// + "'" + ",'" + headimgurl + "'" + ",'" + nickname + "'" +// + ",'" + sex + "'" + ",'" + city + "'" + ",'" +// + province + "'" + ",'" + unionid + "'" + ");"; +// webviewjh(sharelogin); + + break; + default: + break; + } + super.handleMessage(msg); + } + }; + + Handler paprehandler = new Handler() { + public void handleMessage(Message msg) { + switch (msg.what) { + case 1: + if (!hasPermission(carpermission)) { + + PermissionGen.needPermission(NewwebviewActivity.this, 101, + carpermission); + } else { + prepareAudio(); + } + break; + + default: + break; + } + }; + + }; + + Handler shakehadler = new Handler() { + public void handleMessage(android.os.Message msg) { + switch (msg.what) { + case 1: + mShakeListener.start(); + /** + * 摇一摇结束 + */ +// String shakeEnd = "javascript:shakeEnd();"; +// webviewjh(shakeEnd); + x5webview.callHandler("shakeEnd", "", new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + + break; + + default: + break; + } + }; + }; + // Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_PHONE_STATE + String[] permissons = new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }; + private static WakeLock m_wklk; + + private Vibrator vibrator; + public boolean isShake = false; + private ShakeListener mShakeListener = null; + private Bundle savedInstanceState; + + /* 用来标识请求照相功能的activity */ + private static final int CAMERA_WITH_DATA = 3023; + private String picName = "";// 用户拍照后保存的图片名称 + + /* 拍照的照片存储位置 */ + private static File PHOTO_DIR = null; + + protected void doTakePhoto() { + /** + * 判断sd K 是否重载 + */ + if (Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED)) { + + PHOTO_DIR = new File(Environment.getExternalStorageDirectory() + + "/TestPhotoPic"); + } else { + PHOTO_DIR = new File(Environment.getDataDirectory() + + "/TestPhotoPic"); + } + + Intent imageCaptureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + // 重新分解图片名称将-:的符号去掉 + picName = getPhotoFileName(); + picName = picName.replace("-", ""); + picName = picName.replace(":", ""); + File out = new File(PHOTO_DIR, picName); + Uri uri = Uri.fromFile(out); + imageCaptureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri); + imageCaptureIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); + startActivityForResult(imageCaptureIntent, CAMERA_WITH_DATA); + } + + /** + * 用当前时间给取得的图片命名 + * + */ + @SuppressLint("SimpleDateFormat") + private String getPhotoFileName() { + Date date = new Date(System.currentTimeMillis()); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss"); + return dateFormat.format(date) + ".jpg"; + } + + String titlemsg; + + @SuppressLint("InvalidWakeLockTag") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + + /** + * 方法一 保持屏幕唤醒 + */ + + // getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, + // WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + hideNavigationBar(); + // 初始化分享面板 + SharePanelHelper.initSharePanel(this); + setContentView(R.layout.newwebview); + + msgApi = WXAPIFactory.createWXAPI(NewwebviewActivity.this, Constants.APP_ID, true); + x5webview = (BridgeWebView) findViewById(R.id.x5webview); + + titlemsg="1"; + + OkHttpClient.Builder okclientbuild = new OkHttpClient.Builder() + .connectTimeout(20, TimeUnit.SECONDS) + .hostnameVerifier(new UnSafeHostnameVerifier())// 添加验证 + .readTimeout(20, TimeUnit.SECONDS); + PermitHttpsUtils.setPermitHttps(okclientbuild, false);// 允许https + okclient = okclientbuild.build(); + + // okclient = new OkHttpClient.Builder() + // .connectTimeout(20, TimeUnit.SECONDS) + // .readTimeout(20, TimeUnit.SECONDS).build(); + +// findViewById(R.id.buttn1).setOnClickListener(new OnClickListener() { +// +// @Override +// public void onClick(View v) { +// List testphoto = new ArrayList(); +// +// // String json="[{"+"photourl"+":"+"/0"+","pid":"117"}]"; +// savephotoURLBean url = new savephotoURLBean(); +// url.setPhotourl("/0"); +// url.setPid("117"); +// testphoto.add(url); +// Gson gdon = new Gson(); +// String json = gdon.toJson(testphoto); +// System.out.println(json); +// savephoto(json); +// } +// }); + + sp = SpUtil.getSharePerference(this); + + Myapplication.getInstance().addActivity(NewwebviewActivity.this); + + this.savedInstanceState = savedInstanceState; + getclassname(); + /* + * * + * 方法二 + */ + PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE); + // m_wklk = pm.newWakeLock + // (PowerManager.ACQUIRE_CAUSES_WAKEUP | + // PowerManager.SCREEN_DIM_WAKE_LOCK, "Tag"); + // + + m_wklk = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "cn"); + m_wklk.setReferenceCounted(false); + + m_wklk.acquire();// 设置保持唤醒 + + start(); + getWindow().setFormat(PixelFormat.TRANSLUCENT); + + initShake(); + + initvideo(); + + getAndroiodScreenProperty();//获取当前屏幕宽高含虚拟状态栏宽高 + + // initdate(save); + if (!hasPermission(permissons)) { + + PermissionGen.needPermission(NewwebviewActivity.this, 16, + permissons); + + } else { + + initdate(savedInstanceState); + } + + screen = new ScreenListener(this); + screen.begin(new ScreenListener.ScreenStateListener() { + + @Override + public void onUserPresent() { + + if (isForeground) { + service = 1; + + + if (isfinsh) { +// String appservice = "javascript:appservice(" + "'" +// + service + "'" + ");"; +// webviewjh(appservice); + x5webview.callHandler("appservice", ""+service, new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + } + } + } + + @Override + public void onScreenOn() { + if (isForeground) { + service = 1; + if (isfinsh) { +// String appservice = "javascript:appservice(" + "'" +// + service + "'" + ");"; +// webviewjh(appservice); + x5webview.callHandler("appservice", ""+service, new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + } + } + + // Toast.makeText(webviewActivity.this, "开屏", 1).show(); + + } + + @Override + public void onScreenOff() { + // Toast.makeText(webviewActivity.this, "锁屏", 1).show(); + service = 2; + if (isfinsh) { +// String appservice = "javascript:appservice(" + "'" +// + service + "'" + ");"; +// webviewjh(appservice); + x5webview.callHandler("appservice", ""+service, new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + } + } + }); + + } + + + // 隐藏虚拟按键 + public void hideNavigationBar() + { + int uiFlags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar + | View.SYSTEM_UI_FLAG_FULLSCREEN; // hide status bar + + if( android.os.Build.VERSION.SDK_INT >= 19 ){ + uiFlags |= 0x00001000; //SYSTEM_UI_FLAG_IMMERSIVE_STICKY: hide navigation bars - compatibility: building API level is lower thatn 19, use magic number directly for higher API target level + } else { + uiFlags |= View.SYSTEM_UI_FLAG_LOW_PROFILE; + } + getWindow().getDecorView().setSystemUiVisibility(uiFlags); + } + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + if( hasFocus ) { + hideNavigationBar(); + } + } + + private void getclassname() { + ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); + List runningTasks = manager.getRunningTasks(1); + RunningTaskInfo cinfo = runningTasks.get(0); + ComponentName component = cinfo.topActivity; + System.out.println("current activity is " + component.getClassName()); + apputil.activityname = component.getClassName(); + + } + + private void initShake() { + vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE); + NeedForSound.getInstance().addSound(this); + mShakeListener = new ShakeListener(this); + mShakeListener.setOnShakeListener(shakeListener); + mShakeListener.stop(); + } + + OnShakeListenerCallBack shakeListener = new OnShakeListenerCallBack() { + public void onShake() { + // startShakeAnim(); // 开始 摇一摇手掌动画 + mShakeListener.stop(); + + if (apputil.Voicetype == 1) { + NeedForSound.getInstance().playStartSound(); + } + + // NeedForSound.getInstance().playEndSound(); + // 获取手机震动服务 + // if(apputil.shaketype==0){ + // vibrator.vibrate(new long[] { 100, 300, 100, 300 }, -1); + // } + + shakehadler.sendEmptyMessageDelayed(1, 1000); + + } + }; + private void inithandler() { + + OkHttpPhotoServer.setPhotoHandler(savehandler); + // 注册广播接受者java代码 + IntentFilter intentFilter = new IntentFilter( + Intent.ACTION_BATTERY_CHANGED); + + // 创建广播接受者对象 + batteryReceiver = new BatteryReceiver(); + // 注册receiver + registerReceiver(batteryReceiver, intentFilter); + /** + * wifi 信号改变 + * + */ + WifiChangeReceiver = new WifiChangeBroadcastReceiver(); + registerReceiver(WifiChangeReceiver, new IntentFilter( + WifiManager.RSSI_CHANGED_ACTION)); + myNetReceiver = new MyNetReceiver(); + // 网络状态改变 + + IntentFilter mFilter = new IntentFilter(); + mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + registerReceiver(myNetReceiver, mFilter); + registerMessageReceiver();// 注册广播回调通话状态 + } + + protected void savephoto(String string) { + try { + getphotoistrue = false; + testphoto1.clear(); + + Gson gson = new Gson(); + Type type = new TypeToken>() { + }.getType(); + + testphoto = gson.fromJson(string.toString(), type); + photosize = 0; + + System.out.println("-----" + string); + + if (testphoto.size() > 0) { + for (int i = 0; i < testphoto.size(); i++) { + String url = testphoto.get(i).getPhotourl(); + String pid = testphoto.get(i).getPid(); + System.out.println(i); + + // 后面加 + System.out.println(url); + System.out.println(pid); + + System.out.println("isdownloadphoto=" + isdownloadphoto); + if (isdownloadphoto) { + + downloadsd(url, pid); + } else { + Message msg = new Message(); + msg.what = 1; + Bundle bun = new Bundle(); + bun.putString("url", url); + bun.putString("pid", pid); + msg.setData(bun); + savehanler1.sendMessageDelayed(msg, 300); + } + + } + } else { + String msg = "获取头像失败"; + String procket = "牛牛"; + // commitLog.commitLog(NewwebviewActivity.this, msg, procket); + + // testphoto1 = new ArrayList(testphoto); + savephotoURLBean bean = new savephotoURLBean(); + bean.setPhotourl(""); + bean.setPid(""); + testphoto1.add(bean); + photohandler.sendEmptyMessageDelayed(0, 100); + + } + + } catch (Exception e) { + e.printStackTrace(); + isdownloadphoto = true; + String msg = "初始化头像失败==" + string; + String procket = "NewwebviewActivity catch"; + // commitLog.commitLog(NewwebviewActivity.this, msg, procket); + CrashReport.putUserData(NewwebviewActivity.this, "Errorphoto", + e.toString()); + CrashReport.putUserData(NewwebviewActivity.this, "Errorphotojson", + string); + // testphoto1=new ArrayList(testphoto); + savephotoURLBean bean = new savephotoURLBean(); + bean.setPhotourl(""); + bean.setPid(""); + testphoto1.add(bean); + photohandler.sendEmptyMessageDelayed(0, 100); + } + } + + private void downloadsd(final String url, final String pid) { + isdownloadphoto = false; + + if (pmutil.isnullorEmpty(url)) { + + photosize++; + savephotoURLBean bean = new savephotoURLBean(); + bean.setPhotourl(url); + bean.setPid(pid); + testphoto1.add(bean); + isdownloadphoto = true; + + if (photosize == testphoto.size()) { + System.out.println(testphoto1.toString()); + photohandler.sendEmptyMessageDelayed(0, 100); + } + + } else { + + downloadnum = 0; + // Object obkect = new Object(); + // synchronized (obkect) { + // download(url, pid); + // } + + runOnUiThread(new Runnable() { + @Override + public void run() { + + try { + + download(url, pid); + } catch (Exception e) { + + photosize++; + + savephotoURLBean bean = new savephotoURLBean(); + bean.setPhotourl(url); + bean.setPid(pid); + testphoto1.add(bean); + isdownloadphoto = true; + + if (photosize == testphoto.size()) { + System.out.println("---" + testphoto1.toString()); + photohandler.sendEmptyMessageDelayed(0, 100); + } + } + + } + }); + } + } + + private boolean isdownloadphoto = true;// 是否下载完成 + + Handler savehanler1 = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case 1: + Bundle bundle = msg.getData(); + String url = bundle.getString("url"); + String pid = bundle.getString("pid"); + + if (isdownloadphoto) { + + downloadsd(url, pid); + } else { + Message msg1 = new Message(); + msg1.what = 1; + Bundle bun = new Bundle(); + bun.putString("url", url); + bun.putString("pid", pid); + msg1.setData(bun); + savehanler1.sendMessageDelayed(msg1, 300); + } + break; + + default: + break; + } + super.handleMessage(msg); + } + + }; + + private void download(String url, String id) { + downloadnum++; + + final String pid = id; + final String photourl = url; + + sp = SpUtil.getSharePerference(this); + + final String urlpath = SpUtil.getStringSharedPerference(sp, "urlpath") + + File.separator + gamedirectory1; + + System.out.println("进入下载photosize=" + photosize); + System.out.println("photosize=" + photosize); + + photosize++; + System.out.println("photosize=" + photosize); + + ImageCacheManager.loadImage(photourl, new ImageListener() { + + @Override + public void onErrorResponse(VolleyError volleyError) { + // iv.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher)); + + savephotoURLBean bean = new savephotoURLBean(); + bean.setPhotourl(""); + bean.setPid(pid); + + testphoto1.add(bean); + isdownloadphoto = true; + + if (photosize == testphoto.size()) { + System.out.println(testphoto1.toString()); + + photohandler.sendEmptyMessage(0); + + } + + } + + @Override + public void onResponse(ImageContainer container, boolean b) { + System.out.println("%%%photosize=" + photosize); + + System.out.println("%%%container.hashCode()=" + + container.hashCode()); + + if (container.getBitmap() != null) { + System.out.println("&&&&&&&&&&"); + System.out.println("***photosize=" + photosize); + + photofile1 = new File(urlpath + File.separator + "bmp"); + + if (!photofile1.exists()) { + photofile1.mkdirs(); + } + + System.out.println("---" + photofile1.getAbsolutePath()); + long time = System.currentTimeMillis(); + + int random = (int) (Math.random() * 9000 + 1000); + // 829972 + + String photname = File.separator + "bmp" + File.separator + + time + "" + random + ".png"; + + String photname1 = "bmp" + File.separator + time + "" + + random + ".png"; + + getScreenHot(container.getBitmap(), urlpath + photname); + + savephotoURLBean bean = new savephotoURLBean(); + bean.setPhotourl(photname1); + bean.setPid(pid); + testphoto1.add(bean); + + isdownloadphoto = true; + + System.out.println("photosize=" + photosize + + "testphoto.size()=" + testphoto.size()); + // 已下完 + if (photosize == testphoto.size()) { + System.out.println(testphoto1.toString()); + photohandler.sendEmptyMessage(0); + } else { + isdownloadphoto = true; + } + + } + // else{ + // + // savephotoURLBean bean = new savephotoURLBean(); + // bean.setPhotourl(""); + // bean.setPid(pid); + // + // testphoto1.add(bean); + // isdownloadphoto = true; + // + // if (photosize == testphoto.size()) { + // System.out.println(testphoto1.toString()); + // + // photohandler.sendEmptyMessage(0); + // + // } + // } + // iv.setImageBitmap(container.getBitmap()); + } + }); + + // // 创建一个Request + // Request request = null; + // + // request = new Request.Builder().url(url).build(); + // + // // 请求加入调度 + // okclient.newCall(request).enqueue(new Callback() { + // @Override + // public void onFailure(Call arg0, IOException throwable) { + // + // // System.out.println("下载失败"); + // // exitTitle.show(webviewActivity.this, "下载失败"+url); + // + // if (downloadnum >= downloadsum) { + // photosize++; + // savephotoURLBean bean = new savephotoURLBean(); + // bean.setPhotourl(""); + // bean.setPid(pid); + // + // testphoto1.add(bean); + // isdownloadphoto = true; + // + // if (photosize == testphoto.size()) { + // System.out.println(testphoto1.toString()); + // + // photohandler.sendEmptyMessage(0); + // + // } + // } else { + // download(photourl, pid); + // } + // + // throwable.printStackTrace(); + // } + // + // @SuppressWarnings("resource") + // @Override + // public void onResponse(Call arg0, Response response) + // throws IOException { + // System.out.println("-------------"); + // // long length = response.body().contentLength(); + // + // if (response.code() == 200) {// 正常下载 + // System.out.println("正常下载"); + // InputStream is = null; + // byte[] buf = new byte[2048]; + // int len = 0; + // FileOutputStream fos = null; + // is = response.body().byteStream(); + // photofile1 = new File(urlpath + File.separator + "bmp"); + // + // if (!photofile1.exists()) { + // photofile1.mkdirs(); + // } + // + // System.out.println(photofile1.getAbsolutePath()); + // long time = System.currentTimeMillis(); + // + // int random = (int) (Math.random() * 9000 + 1000); + // // 829972 + // + // String photname = File.separator + "bmp" + File.separator + // + time + "" + random + ".png"; + // + // String photname1 = "bmp" + File.separator + time + "" + // + random + ".png"; + // + // File file2 = new File(urlpath + photname); + // + // fos = new FileOutputStream(file2); + // int count = 0; + // while ((len = is.read(buf)) != -1) { + // fos.write(buf, 0, len); + // count += len; + // } + // + // fos.flush(); + // fos.close(); + // + // savephotoURLBean bean = new savephotoURLBean(); + // bean.setPhotourl(photname1); + // bean.setPid(pid); + // testphoto1.add(bean); + // + // System.out.println(file2.getAbsolutePath()); + // photosize++; + // isdownloadphoto = true; + // + // // 已下完 + // if (photosize == testphoto.size()) { + // System.out.println(testphoto1.toString()); + // photohandler.sendEmptyMessage(0); + // } else { + // isdownloadphoto = true; + // } + // + // } else { + // System.out.println("下载失败"); + // if (downloadnum >= downloadsum) { + // photosize++; + // savephotoURLBean bean = new savephotoURLBean(); + // bean.setPhotourl(""); + // bean.setPid(pid); + // + // testphoto1.add(bean); + // isdownloadphoto = true; + // System.out.println("photosize=" + photosize); + // + // if (photosize == testphoto.size()) { + // + // System.out.println(testphoto1.toString()); + // + // photohandler.sendEmptyMessage(0); + // + // } + // } else { + // System.out.println("重新下载photourl=" + photourl); + // download(photourl, pid); + // } + // + // } + // + // } + // }); + } + + public void post() { + + Map map = new HashMap(); + + register.PostJsonrequest(map, "http://localhost:4477/testurl", + new Volleyinterface(this, Volleyinterface.mlistener, + Volleyinterface.mErrorLisener) { + + @Override + public void onsuccess(String result) { + + } + + @Override + public void onerror(VolleyError arg0) { + // TODO Auto-generated method stub + + } + }); + } + + String ip; + public void start() { + ip = NetUtil.getLocalIPAddress(); + // 使用新的HTTP服务器替换AndServer + NewWebServerInstance.getInstance().create(apputil.photoPort1); + } + + + + @PermissionSuccess(requestCode = 16) + public void filstsucces() { + + initdate(savedInstanceState); + } + + @PermissionFail(requestCode = 16) + public void filstfail() { + + if (ActivityCompat.shouldShowRequestPermissionRationale( + NewwebviewActivity.this, + Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + // 未勾选不再提示 + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("提示"); + builder.setMessage("亲,当前应用缺少必要权限。不打开将无法使用"); + + // 拒绝, 退出应用 + builder.setNegativeButton("退出", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + + } + }); + + builder.setPositiveButton("打开", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + PermissionGen.needPermission( + NewwebviewActivity.this, 11, + Manifest.permission.WRITE_EXTERNAL_STORAGE); + } + }); + builder.show(); + System.out.println("拒绝"); + } else { + // 勾选不再提示 + if (ContextCompat.checkSelfPermission(this, + Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) { + showMissingPermissionDialog(); + } + } + } + + RelativeLayout imageLayout; + ProgressBar progressBar; + TextView textView1, inittext; + String gamedirectory1; + String orientation; + String gameid; + + + private void initdate(Bundle savedInstanceState) { + + imageLayout = (RelativeLayout) findViewById(R.id.imageLayout); + progressBar = (ProgressBar) findViewById(R.id.progressBar1); + + textView1 = (TextView) findViewById(R.id.textView1); + inittext = (TextView) findViewById(R.id.inittext); + + inittext.setText("正在检验新版本..."); + Shared = SpUtil.getSharePerference(NewwebviewActivity.this); + + Intent in = getIntent(); + if(savedInstanceState!=null){ + + gamedirectory1= savedInstanceState.getString("gamedirectory"); + gameid= savedInstanceState.getString("gameid"); + data= savedInstanceState.getString("data"); + orientation= savedInstanceState.getString("orientation"); + // Settingutil.initgame=savedInstanceState.getString("initgame"); + Gamesettingurl.configofficialurl=savedInstanceState.getString("configofficialurl"); + + System.out.println("恢复=====gameid=" + gameid); + System.out.println("恢复=====gamedirectory=" + gamedirectory1); + + }else{ + gamedirectory1 = in.getStringExtra("gamedirectory"); + gameid = in.getStringExtra("gamedownloadurl"); + data = in.getStringExtra("data"); + + System.out.println("游戏id=" + gameid); + orientation = in.getStringExtra("orientation"); + System.out.println("orientation="+orientation); + + } + + if(!pmutil.isnullorEmpty(orientation)){ + // orientation = 2; 竖屏 + // orientation = 3; 横屏 + if(orientation.equals("2")){ + //设置为竖屏 + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + } + + + /** + * 判断游戏是否存在 + */ + + String url = SpUtil.getStringSharedPerference(Shared, "urlpath"); + + final String starturl = url + File.separator + gamedirectory1; + if (!pmutil.isnullorEmpty(gamedirectory1)&&!pmutil.isnullorEmpty(gameid)) { + + if (isgamedirectory(gamedirectory1)) { + System.out.println("找到目录"); + int type = 1; + updategamezip(starturl, gameid, type); + + } else { + System.out.println("没有找到目录"); + System.out.println("starturl=" + starturl); + int type = 2; + System.out.println("gamedownloadurl=" + starturl); + updategamezip(starturl, gameid, type); + + + + } + +// new Thread() { +// public void run() { +// if (isgamedirectory(gamedirectory1)) { +// System.out.println("找到目录"); +// int type = 1; +// updategamezip(starturl, gameid, type); +// +// } else { +// System.out.println("没有找到目录"); +// System.out.println("starturl=" + starturl); +// int type = 2; +// System.out.println("gamedownloadurl=" + starturl); +// updategamezip(starturl, gameid, type); +// +// +// +// } +// }; +// }.start(); + } + + // getinit(); + inithandler(); + } + + private void getinit() { + + // m_progressDlg = new ProgressDialog(this); + // m_progressDlg.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + // // 设置ProgressDialog 的进度条是否不明确 false 就是不设置为不明确 + // m_progressDlg.setIndeterminate(false); + // m_progressDlg.setCanceledOnTouchOutside(false); + + // m_mainHandler = new Handler(); + + Shared = SpUtil.getSharePerference(NewwebviewActivity.this); + + api = WXAPIFactory.createWXAPI(this, Constants.APP_ID); +// xlapi = SGAPIFactory.createSGAPI(this, XLConstants.SG_APPID); + + /** + * 微信 + */ + req = new PayReq(); + sb = new StringBuffer(); + //msgApi.registerApp(Constants.APP_ID); + + initwebview(); + + mDialogManager = new DialogManager(NewwebviewActivity.this); +// //修改路径为app路径 +// if (Environment.getExternalStorageState().equals( +// Environment.MEDIA_MOUNTED)) { +// // 获取SDCard的路径 +// dirs = Environment.getExternalStorageDirectory().getAbsoluteFile() +// + File.separator + "nickming_recorder_audioss"; +// // Toast.makeText(application, sdFile.getAbsolutePath(), 1).show(); +// } else { +// dirs = Environment.getDataDirectory().getAbsolutePath() +// + File.separator + "nickming_recorder_audioss"; +// } + dirs = Util.GetFileAbsolutePath() + File.separator + "nickming_recorder_audioss"; + mAudioManager = AudioManager.getInstance(dirs); + mAudioManager.setOnAudioStageListener(NewwebviewActivity.this); + + } + + boolean iswebviewerror = false; + + + + class mwebviewclient extends BridgeWebViewClient { + public mwebviewclient(BridgeWebView webView) { + super(webView); + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { +// if (url.startsWith("tel:")) { +// Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); +// startActivity(intent); +// } else { +// view.loadUrl(url); +// } +// return false; + if (url.startsWith("tel:")) { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + startActivity(intent); + } + + return super.shouldOverrideUrlLoading(view, url); + } + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + + } + + @Override + public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { + super.onReceivedError(view, request, error); + + } + + + @Override + public void onReceivedHttpAuthRequest( + WebView webview, + com.tencent.smtt.export.external.interfaces.HttpAuthHandler httpAuthHandlerhost, + String host, String realm) { + + boolean flag = httpAuthHandlerhost.useHttpAuthUsernamePassword(); + } + + + }; + + boolean isloddingfinish = false; + + class mchromeClient extends WebChromeClient { + + @Override + public void onProgressChanged(WebView arg0, int arg1) { + System.out.println(arg1); + if (arg1 == 100) { + isfinsh = true; + + // + ObjectAnimator firstAlphaAnim = ObjectAnimator.ofFloat( + imageLayout, "alpha", 1.0f, 0.3f); + firstAlphaAnim.setDuration(500); + firstAlphaAnim.start(); + + firstAlphaAnim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + // TODO Auto-generated method stub + super.onAnimationEnd(animation); + + imageLayout.setVisibility(View.GONE); + } + }); + + if (!isloddingfinish) { + isloddingfinish = true; + +// String getWebdata = "javascript:getWebdata(" + "'" + data +// + "'" + ");"; +// webviewjh(getWebdata); +// System.out.println("getWebdata"); + x5webview.callHandler("getWebdata", data, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + + //动态设置截图分享 + //String photourl="http://localhost:"+apputil.photoPort1+"/testurl"; + String photourl="http://"+ip+":"+apputil.photoPort1+"/testurl"; + x5webview.callHandler("setPostUrl", photourl, new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); +// String setPostUrl = "javascript:setPostUrl(" + "'" +// + photourl + "'" + ");"; +// +// webviewjh(setPostUrl); + } + + } else { + + isloddingfinish = false; + // webdialog.setProgress(arg1); + } + // super.onProgressChanged(arg0, arg1); + } + + // protected void updates() { + // Map map = new HashMap(); + // map.put("app", "youle"); + // map.put("route", "platform"); + // map.put("rpc", "appversion"); + // map.put("date", "appversion"); + // register.PostJsonrequest(map, + // "http://120.25.60.74:1089/index.html", new Volleyinterface( + // NewwebviewActivity.this, Volleyinterface.mlistener, + // Volleyinterface.mErrorLisener) { + // @Override + // public void onsuccess(String result) { + // System.out.println("result=" + result); + // Gson gson = new Gson(); + // // gson.fromJson("", new Type() { + // + // // }); + // + // try { + // JSONObject json = new JSONObject(result); + // + // JSONObject date = json.optJSONObject("data"); + // + // int version = date.getInt("version"); + // String name = date.getString("name"); + // String download = date.getString("download"); + // + // if (version > getAppinfo.getAppVersioncode()) { + // + // doNewVersionUpdate(name, version, download); + // + // } else { + // + // /* + // * Toast.makeText(mainActivity1.this, + // * "已是最新版本", 1) .show(); + // */ + // } + // + // } catch (JSONException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + // + // } + // + // @Override + // public void onerror(VolleyError arg0) { + // System.out.println("arg0=" + arg0); + // + // } + // }); + // + // // register.StringGETrequest(map, + // // "http://120.25.60.74:1089/index.html", new + // // + // Volleyinterface1(webviewActivity.this,Volleyinterface1.mlistener,Volleyinterface1.mErrorLisener) + // // { + // // + // // @Override + // // public void onsuccess(String result) { + // // + // // System.out.println("result="+result); + // // } + // // + // // @Override + // // public void onerror(VolleyError arg0) { + // // + // // System.out.println("arg0="+arg0); + // // } + // // }); + // + // // register.Getjsonrequest(null, + // // "http://120.25.60.74:1089/index.html"); + // + // } + + @Override + public boolean onJsConfirm(WebView arg0, String arg1, String arg2, + JsResult arg3) { + return super.onJsConfirm(arg0, arg1, arg2, arg3); + } + + /** + * webview 的窗口转移 + */ + @Override + public boolean onCreateWindow(WebView arg0, boolean arg1, boolean arg2, + Message msg) { + // TODO Auto-generated method stub + + return true; + } + + @Override + public boolean onJsAlert(WebView arg0, String arg1, String arg2, + JsResult arg3) { + /** + * 这里写入你自定义的window alert + */ + + Log.i("yuanhaizhou", "setX5webview = null"); + return super.onJsAlert(null, "www.baidu.com", "aa", arg3); + } + + /** + * 对应js 的通知弹框 ,可以用来实现js 和 android之间的通信 + */ + @Override + public boolean onJsPrompt(WebView arg0, String arg1, String arg2, + String arg3, JsPromptResult arg4) { + // 在这里可以判定js传过来的数据,用于调起android native 方法 + + return super.onJsPrompt(arg0, arg1, arg2, arg3, arg4); + } + + @Override + public void onReceivedTitle(WebView arg0, final String arg1) { + super.onReceivedTitle(arg0, arg1); + Log.i("yuanhaizhou", "webpage title is " + arg1); + + } + + }; + class myHadlerCallBack extends DefaultHandler { + + @Override + public void handler(String data, CallBackFunction function) { + + } + } + + @SuppressLint({ "SetJavaScriptEnabled", "ClickableViewAccessibility" }) + private void initwebview() { + + // x5webview.setBackgroundColor(Color.parseColor("#000000")); + x5webview.setWebViewClient(new mwebviewclient(x5webview)); + x5webview.setDefaultHandler(new myHadlerCallBack()); + x5webview.setWebChromeClient(new mchromeClient()); + WebView.setWebContentsDebuggingEnabled(true); + + initWebViewSettings(); + + x5webview.setOnLongClickListener(new OnLongClickListener() { + + @Override + public boolean onLongClick(View v) { + return true; + } + }); + + if (savedInstanceState != null) { + x5webview.restoreState(savedInstanceState); + } else { + // webdialog = WebviewProgressDialog.createDialog(this); + // webdialog.show(); + Intent inient = getIntent(); + // Toast.makeText(NewwebviewActivity.this, "url1"+url1, 1).show(); + x5webview.loadUrl("file://" + loadurl); + + } + + + initwebjh(); + //x5webview.addJavascriptInterface(new settings(), "settings"); + x5webview.setOnTouchListener(new OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + int action = event.getAction(); + int x = (int) event.getX(); + int y = (int) event.getY(); + switch (action) { + case MotionEvent.ACTION_DOWN: + System.out.println("MotionEvent.ACTION_DOWN"); + isDown = true; + changeState(STATE_RECORDING); + + x1 = (int) event.getX(); + y1 = (int) event.getY(); + break; + + case MotionEvent.ACTION_MOVE: + System.out.println("MotionEvent.ACTION_MOVE"); + if (isRecording) { + // TODO + // 根据x,y来判断用户是否想要取消 + if (wantToCancel(x, y, x1, y1)) { + changeState(STATE_WANT_TO_CANCEL);// 取消发送 + } else { + changeState(STATE_RECORDING);// 继续 + } + } + + break; + case MotionEvent.ACTION_UP: + isDown = false; + if (isRecording) { + + if (isautio) { + System.out.println("***********"); + if (mTime < 0.8f) { + System.out.println("小于0.8"); + mDialogManager.tooShort(); + mAudioManager.cancel(); + mhandler.sendEmptyMessageDelayed( + MSG_DIALOG_DIMISS, 1300);// 持续1.3s + + } else if (mCurrentState == STATE_RECORDING) {// 正常录制结束 + System.out.println("正常录制结束"); + mDialogManager.dimissDialog(); + mAudioManager.release();// release释放一个mediarecorder + String amrpath = mAudioManager + .getCurrentFilePath(); + upload(amrpath, mTime); + // localityplay(amrpath);//本地播放 + } else if (mCurrentState == STATE_WANT_TO_CANCEL) { + + mAudioManager.cancel(); + mDialogManager.dimissDialog(); + } + reset(); + } else { + mhandler.sendEmptyMessageDelayed( + MSG_DIALOG_Audio_DIMISS, 400);// 持续1.3s + } + } else { + System.out.println("isautio=" + isautio); + mhandler.sendEmptyMessageDelayed( + MSG_DIALOG_Audio_DIMISS, 400);// 持续1.3s + } + + break; + case MotionEvent.ACTION_CANCEL: + if (isautio) { + mhandler.sendEmptyMessageDelayed( + MSG_DIALOG_Audio_DIMISS, 400);// 持续1.3s + } + break; + + } + + return false; + } + }); + + UserStrategy strategy = new UserStrategy(getApplicationContext()); + strategy.setDeviceID("jxhd"); + strategy.setAppChannel("dhxj"); //设置渠道 + strategy.setAppVersion("3.4.4"); //App的版本 + strategy.setAppPackageName("com.jx.jyhd"); //App的包名 + strategy.setAppReportDelay(10000); + strategy.setCrashHandleCallback(new CrashReport.CrashHandleCallback() { + public Map onCrashHandleStart(int crashType, + String errorType, String errorMessage, String errorStack) { + LinkedHashMap map = new LinkedHashMap(); + String x5CrashInfo = WebView.getCrashExtraMessage(getApplicationContext()); + map.put("x5crashInfo", x5CrashInfo); + return map; + } + + @Override + public byte[] onCrashHandleStart2GetExtraDatas(int crashType, + String errorType, String errorMessage, String errorStack) { + try { + return "Extra data.".getBytes(StandardCharsets.UTF_8); + } catch (Exception e) { + return null; + } + } + + }); + CrashReport.initCrashReport(getApplicationContext(), BuglyUtil.appid, + true, strategy); + + CrashReport.WebViewInterface webViewInterface = new CrashReport.WebViewInterface() { + /** + * 获取WebView URL. + * + * @return WebView URL + */ + @Override + public String getUrl() { + // 下面仅为例子,请用真正逻辑代替 + return x5webview.getUrl(); + } + + /** + * 开启JavaScript. + * + * @param flag + * true表示开启,false表示关闭 + */ + @Override + public void setJavaScriptEnabled(boolean flag) { + // 下面仅为例子,请用真正逻辑代替 + WebSettings webSettings = x5webview.getSettings(); + webSettings.setJavaScriptEnabled(flag); + } + + /** + * 加载URL. + * + * @param url + * 要加载的URL + */ + @Override + public void loadUrl(String url) { + // 下面仅为例子,请用真正逻辑代替 + x5webview.loadUrl(url); + } + + /** + * 添加JavaScript接口对象. + * + * @param jsInterface + * JavaScript接口对象 + * @param name + * JavaScript接口对象名称 + */ + @Override + public void addJavascriptInterface( + H5JavaScriptInterface jsInterface, String name) { + // 下面仅为例子,请用真正逻辑代替 + x5webview.addJavascriptInterface(jsInterface, name); + } + + /** + * 获取WebView的内容描述. + * + * @return WebView的内容描述. + */ + @Override + public CharSequence getContentDescription() { + // 下面仅为例子,请用真正逻辑代替 + return x5webview.getContentDescription(); + } + }; + // 调用Bugly设置JS异常捕获接口,传入创建的WebView接口对象 + CrashReport.setJavascriptMonitor(webViewInterface, true); + + } + public void shareurl(String sharetype, String url) { + final String type = sharetype; + + System.out.println(url); + + if (Wxistrue.isphotoshare) { + Wxistrue.isphotoshare = false; + + ImageRequest imageRequest = new ImageRequest( + url, + new com.android.volley.Response.Listener() { + @Override + public void onResponse(Bitmap response) { + System.out.println("图片下载成功"); + File file; + + if (Environment.getExternalStorageState() + .equals(Environment.MEDIA_MOUNTED)) { + // sd卡存储(/mnt/sdcard/cache) + file = Environment + .getExternalStorageDirectory();// 获取跟目录 + } else { + // 没有SD卡,缓存到系统存储 + file = Environment.getDataDirectory(); + } + file = Util.GetDirectory(); + bitmappath = file.getAbsolutePath() + + File.separator + "photo.png"; + + try { + FileOutputStream fos = new FileOutputStream( + bitmappath); + // bitmap.compress(CompressFormat.PNG, 100, + // fos); + // 压缩bitmap到输出流中 + response.compress(CompressFormat.PNG, 100, + fos); + fos.flush(); + fos.close(); + // Wxistrue.isshare = true; + + Message msg = new Message(); + Bundle data = new Bundle(); + data.putString("bitpath", bitmappath); + data.putString("type", type); + System.out.print("bitmappath"+bitmappath+"type"+type); + msg.setData(data); + + savehandler.sendMessage(msg); + + } catch (FileNotFoundException e) { + throw new InvalidParameterException(); + } catch (IOException e) { + + e.printStackTrace(); + } + + } + }, 0, 0, Config.RGB_565, + new com.android.volley.Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + Wxistrue.isphotoshare = true; + } + }); + volleymanager.getInstance().getmRequestQueue() + .add(imageRequest); + } else { + + } + } + public void initwebjh() { + + //js调用Android方法 如果页面上面有多个的话,可以注册多个方法 + //submitFromWeb 要和js那边定义的一样就可以了 + + x5webview.registerHandler("accreditlogin", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + //Toast.makeText(webviewActivity.this, data, Toast.LENGTH_LONG).show(); + //如果js那边调用后又 进行回调的话可以在这里进行回调的 + System.out.println("jsBradge调用登录=" + data); + Wxistrue.islogin = false;// 暂停授权登陆 + apputil.wxtype = 2; + // 全局回调类,游戏自行实现 + if (!pmutil.isnullorEmpty(data)) { + if (data.equals("1")) { + //QQ登录 + // QQLogin(); + } else { + //微信登录 + WXLogin(); + } + } else { + WXLogin(); + } + + + } + }); + + //图片下载图片下载 + x5webview.registerHandler("getphoto", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + + // if (!pmutil.isnullorEmpty(photo)) { +// System.out.println("isdownloadphoto=" + isdownloadphoto); +// if (getphotoistrue) { +// savephoto(photo); +// } else { +// System.out.println("#############"); +// +// Message msg = new Message(); +// msg.what = 1; +// Bundle bundel = new Bundle(); +// bundel.putString("photo", photo); +// msg.setData(bundel); +// photohandler.sendMessageDelayed(msg, 200); +// } +// } else { +// String msg = "传递头像json数组为空"; +// String procket = "nn"; +// +// // commitLog.commitLog(NewwebviewActivity.this, msg, procket); +// } + System.out.println("调用图片下载"+data); + + if (!pmutil.isnullorEmpty(data)) { + System.out.println("isdownloadphoto=" + isdownloadphoto); + if (getphotoistrue) { + savephoto(data); + } else { + System.out.println("#############"); + + Message msg = new Message(); + msg.what = 1; + Bundle bundel = new Bundle(); + bundel.putString("photo", data); + msg.setData(bundel); + photohandler.sendMessageDelayed(msg, 200); + } + } else { + String msg = "传递数组为空"; + String procket = "nn"; + + // commitLog.commitLog(webviewActivity.this, msg, procket); + } + + + } + }); + + + /*** + * 调用分享 + * js 调用微信分享 朋友圈或好友 + * type 1 普通分享 2截图分享 3 图片分享 + * + * webpageUrl 分享链接地址 title 分享标题 description 分享描述 + * + * Sharefriend 1 好友 2 朋友圈 + * return "sharetypeBean{" + + * "sharefriend='" + sharefriend + '\'' + + * ", type='" + type + '\'' + + * ", webpageUrl='" + webpageUrl + '\'' + + * ", sharetype='" + sharetype + '\'' + + * ", title='" + title + '\'' + + * ", description='" + description + '\'' + + * '}'; + */ +/*** + * js 调用微信分享 朋友圈或好友 + * type 1 普通分享 2截图分享 3 图片分享 + * + * webpageUrl 分享链接地址 title 分享标题 description 分享描述 + * + * Sharefriend 1 好友 2 朋友圈 + */ + x5webview.registerHandler("friendsSharetypeUrlToptitleDescript", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + //特殊处理朋友圈的分享 + Gson gson = new Gson(); + sharetypeBean currentShareData = gson.fromJson(data, sharetypeBean.class); + String scene = currentShareData.getSharefriend(); + if (scene.equals("2")){ + //朋友圈分享 + //直接调用微信分享 + WeChatShareHelper.doWeChatShare(NewwebviewActivity.this, data); + }else if (scene.equals("1")){ + //好友分享 + SharePanelHelper.showSharePanel(NewwebviewActivity.this, data); + } + + } + }); +// x5webview.registerHandler("friendsSharetypeUrlToptitleDescript", new BridgeHandler() { +// @Override +// public void handler(String data, CallBackFunction function) { +// System.out.println("调用分享=" + data); +// +// Gson gson = new Gson(); +// +// bean = gson.fromJson(data, sharetypeBean.class); +// System.out.println(bean); +// if(bean.getSharetype()==null){ +// bean.setSharetype(""); +// } +// if(bean.getType()==null){ +// bean.setType(""); +// } +// +// if(bean.getSharefriend()==null){ +// +// bean.setSharefriend(""); +// } +// +// // bean.setWebpageUrl("https://gameotherwork.ld2sw.cn/image_ewm/ewm_key3.png"); +// // bean.setSharetype("3"); +// WXEntryActivity.setshareHandler(handler); +//// SGEntryActivity.setshareHandler(handler); +// +// if (bean.getType().equals("3")) { +// if(bean.getSharetype().equals("3")){ +// shareurl(bean.getSharetype(), bean.getWebpageUrl());//图片链接分享 +// }else{ +// shareurl(bean.getSharefriend(), bean.getWebpageUrl());//图片链接分享 +// } +// +// +// +// } else {//普通分享 +// +// if (Wxistrue.isshare) {//不能重复点击 +// +// +// +// +// if(bean.getSharetype().equals("3")){ +//// if(!xlapi.isSGAppInstalled()){ +//// +//// Toast.makeText(NewwebviewActivity.this, "闲聊没有安装,请先安装闲聊", Toast.LENGTH_LONG).show(); +//// +//// }else{ +//// xlfriend(); +//// Wxistrue.isshare = false; +//// } +// }else{ +// if (bean.getSharefriend().equals("1")) { +// friend(); +// } else{ +// sharefriends(); +// } +// } +// +// +// +// +// }else{ +// h5handler.postDelayed(new Runnable() { +// @Override +// public void run() { +// Wxistrue.isshare = true; +// } +// },3000); +// } +// +// } +// +// +// } +// }); + /* + x5webview.registerHandler("friendsSharetypeUrlToptitleDescript", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + //在这里调用qq分享用来测试 // 显示分享面板,而不是立即执行分享 + SharePanelHelper.showSharePanel(NewwebviewActivity.this, data); + +// System.out.println("调用分享=" + data); +// +// Gson gson = new Gson(); +// +// bean = gson.fromJson(data, sharetypeBean.class); +// System.out.println(bean); +// if(bean.getSharetype()==null){ +// bean.setSharetype(""); +// } +// if(bean.getType()==null){ +// bean.setType(""); +// } +// +// if(bean.getSharefriend()==null){ +// +// bean.setSharefriend(""); +// } +// +// WXEntryActivity.setshareHandler(handler); +// +// +// if (bean.getType().equals("3")) { +// if(bean.getSharetype().equals("3")){ +// shareurl(bean.getSharetype(), bean.getWebpageUrl());//图片链接分享 +// }else{ +// shareurl(bean.getSharefriend(), bean.getWebpageUrl());//图片链接分享 +// } +// +// +// +// } else {//普通分享 +// +// if (Wxistrue.isshare) {//不能重复点击 +// +// +// +// +// if(bean.getSharetype().equals("3")){ +// +// }else{ +// if (bean.getSharefriend().equals("1")) { +// friend(); +// } else{ +// sharefriends(); +// } +// } +// +// +// +// +// }else{ +// h5handler.postDelayed(new Runnable() { +// @Override +// public void run() { +// Wxistrue.isshare = true; +// } +// },3000); +// } +// +// } + + + } + }); + + */ + //发送通知 + x5webview.registerHandler("notification", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + //Toast.makeText(NewwebviewActivity.this, data, Toast.LENGTH_LONG).show(); + //如果js那边调用后又 进行回调的话可以在这里进行回调的 + + System.out.println("jsBradge调用登录=" + data); + + + + + } + }); + //获取系统时间 + x5webview.registerHandler("getTime", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + //Toast.makeText(NewwebviewActivity.this, data, Toast.LENGTH_LONG).show(); + //如果js那边调用后又 进行回调的话可以在这里进行回调的 + + + function.onCallBack(""+System.currentTimeMillis()); + + } + }); + + //横竖屏切换 + x5webview.registerHandler("orientation", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + //Toast.makeText(NewwebviewActivity.this, data, Toast.LENGTH_LONG).show(); + //如果js那边调用后又 进行回调的话可以在这里进行回调的 + /** + * 1 为横屏 2 为竖屏 + */ + int Orientation=1; + + try { + Orientation= Integer.parseInt(data); + }catch(Exception e){ + + } + + if (Orientation == 1) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + } else { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + + } + }); + + + + //1.普通震动 time 震动时间 单位毫秒 + x5webview.registerHandler("vibrator", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + // Toast.makeText(webviewActivity.this, data, Toast.LENGTH_LONG).show(); + //如果js那边调用后又 进行回调的话可以在这里进行回调的 + long time=Long.parseLong(data); + VibratorUtil.getInstance(NewwebviewActivity.this).vibrate(time); + + } + }); + //是否重复震动 repeat -1 否 1 重复震动 + x5webview.registerHandler("repeatvibrator", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + //Toast.makeText(webviewActivity.this, data, Toast.LENGTH_LONG).show(); + //如果js那边调用后又 进行回调的话可以在这里进行回调的 + int repeat= Integer.parseInt(data); + VibratorUtil.getInstance(NewwebviewActivity.this).repeatVibrate( + repeat); + + } + }); + + //取消震动 + x5webview.registerHandler("canclevibrator", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + // Toast.makeText(webviewActivity.this, data, Toast.LENGTH_LONG).show(); + //如果js那边调用后又 进行回调的话可以在这里进行回调的 + + VibratorUtil.getInstance(NewwebviewActivity.this).cancle(); + + } + }); + //退出游戏 + x5webview.registerHandler("finsh", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + //Toast.makeText(NewwebviewActivity.this, data, Toast.LENGTH_LONG).show(); + //如果js那边调用后又 进行回调的话可以在这里进行回调的 + + exitApp(); + + } + }); + + //返回电话状态 0 无任何状态时(挂电话) 1 接起电话时 2 + x5webview.registerHandler("getphonestate", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + //Toast.makeText(NewwebviewActivity.this, data, Toast.LENGTH_LONG).show(); + //如果js那边调用后又 进行回调的话可以在这里进行回调的 + int state=phonestate(); + function.onCallBack(""+state); + + + } + }); + // + + //长按打开音屏录音 + x5webview.registerHandler("prepareaudio", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + //Toast.makeText(NewwebviewActivity.this, data, Toast.LENGTH_LONG).show(); + + paprehandler.sendEmptyMessage(1); + + } + }); + + //播放声音audiourl 音频地址 type 1 普通 2 历史 user 用户动画位置 + x5webview.registerHandler("mediaTypeAudio", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + //Toast.makeText(NewwebviewActivity.this, data, Toast.LENGTH_LONG).show(); + + JSONObject json= null; + try { + json = new JSONObject(data); + String audiourl=json.getString("audiourl"); + String type=json.getString("type"); + String user=json.getString("user"); + System.out.println(json.toString()); + Boolean boo = MediaFile.isAudioFileType(audiourl); + + if (!pmutil.isnullorEmpty(audiourl)) { + if (boo) { + if (type.equals("1")) { + + /** + * 防止 播放多次调用 + */ + if (!isPlayaudio) { + + // playautio(audiourl, user); + play(audiourl, user); + } else { + Message msg = new Message(); + Bundle bundel = new Bundle(); + bundel.putString("audiourl", audiourl); + bundel.putString("user", user); + msg.setData(bundel); + playhandler.sendMessageDelayed(msg, 200); + + // playautio(audiourl, user); + } + } else { + if (!isPlayaudio) { + // isPlaying = true; + play(audiourl, user); + } + } + } + } + + + } catch (JSONException e) { + e.printStackTrace(); + } + + } + }); + + //调用手机默认浏览器打开链接 + x5webview.registerHandler("browser", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + Intent intent = new Intent(); + intent.setAction("android.intent.action.VIEW"); + + Uri content_url = Uri.parse(data); + if(BrowserUtil.isQQBrowserInstalled()){ + intent.setClassName("com.tencent.mtt","com.tencent.mtt.MainActivity");//打开QQ浏览器 + }else{ + } + intent.setData(content_url); + startActivity(intent); + + } + }); + + // 主动获取电量 + x5webview.registerHandler("getbattery", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + //Toast.makeText(NewwebviewActivity.this, data, Toast.LENGTH_LONG).show(); + + IntentFilter ifilter = new IntentFilter( + Intent.ACTION_BATTERY_CHANGED); + Intent batteryStatus = registerReceiver(null, ifilter); + + // 当前剩余电量 + int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, + -1); + // 电量最大值 + int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, + -1); + // 电量百分比 + float batteryPct = (level / (float) scale); + + + x5webview.callHandler("getBattery", ""+batteryPct, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + //这里也是可以进行js回传的 + } + }); + + + + } + }); + + + // 主动获取wifi信号 + x5webview.registerHandler("getwifiLevel", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + getWifiInfo(); + + JSONObject json = new JSONObject(); + try { + + json.put("ssidname", wifibean.getSsid()); + + json.put("signalLevel", wifibean.getSignalLevel()); + + System.out.println("---" + json.toString()); + x5webview.callHandler("getwifiLevel", json.toString(), new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + + } catch (JSONException e) { + e.printStackTrace(); + } + + } + }); + // 主动获取网络状态 + x5webview.registerHandler("getnetwork", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + String type = "1"; + + boolean isnetwork = apputil + .isNetworkConnected(NewwebviewActivity.this); + if (isnetwork) { + + boolean iswifi = apputil + .isNetworkAvailable(NewwebviewActivity.this); + if (iswifi) { + type = "2"; + + } else { + type = "3"; + } + } + function.onCallBack(type); + } + }); + + //获取本地apk版本号是否大于网络返回版本号 + //* code 返回 1 apk版本号>网络返回版本号 + // 0 apk版本号<=网络返回版本号 + x5webview.registerHandler("getcompareCode", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + + function.onCallBack(""+apputil.code); + } + }); + //摇一摇开始接口 + x5webview.registerHandler("startshake", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + isShake = true; + mShakeListener.start(); + + } + }); + //摇一摇震动声音打开关闭接口 + x5webview.registerHandler("SwitchShake", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + if (data.equals("1")) { + apputil.Voicetype = 1;// 打開 + } else { + apputil.Voicetype = 0;// 關閉 + } + + } + }); + //摇一摇震动声音打开关闭接口 + x5webview.registerHandler("stopshake", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + isShake = false; + mShakeListener.stop(); + + } + }); + //打开扫一扫 + x5webview.registerHandler("opensaoma", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + permissionHandler.sendEmptyMessage(1); + + + } + }); + //开启定位 type 1 连续定位 2 定位1次(三秒内精度最高一次) + + x5webview.registerHandler("startlocation", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + if (data.equals("1")) { + iscontinuouslocation = true; + } else { + iscontinuouslocation = false; + } + handellocation.sendEmptyMessage(2); + + + } + }); + + // 主动获取用户定位信息 返回定位数据 + x5webview.registerHandler("getlocationinfo", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + + String json = null; + + if (location != null) { + Gson gson = new Gson(); + json = gson.toJson(location); + } + System.out.println(json); + function.onCallBack(json); + + } + }); + //切换子游戏 + // webtype 2 竖屏 + //3横屏 + //Gamedirectory 目录判断游戏是否存在 + //gamedownloadurl 游戏id + //data 数据交换 + + x5webview.registerHandler("SwitchOverGameData", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + try { + JSONObject obj=new JSONObject(data); + String webtype=obj.getString("webtype"); + String Gamedirectory=obj.getString("Gamedirectory"); + String gamedownloadurl=obj.getString("gamedownloadurl"); + String data1=obj.getString("data"); + + System.out.println("webtype" + webtype + "Gamedirectory=" + + Gamedirectory + "gamedownloadurl=" + gamedownloadurl); + + initgame(webtype, Gamedirectory, gamedownloadurl, data1); + + } catch (JSONException e) { + e.printStackTrace(); + } + + + } + }); + + //判断是否安装 子游戏   返回 1 安装  0未安装 data 目录名 + + x5webview.registerHandler("getGameinstall", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + int i = 0; + + if (isgamedirectory(data)) { + i = 1; + } + function.onCallBack(""+i); + + } + }); + //支付 +// +// x5webview.registerHandler("getGameplay", new BridgeHandler() { +// @Override +// public void handler(String data, CallBackFunction function) { +// +// startpay(data); +// +// } +// }); + //4.打开网页//数据格式 url 网页地址 title 标题 data 交互数据 orientation = 0; 横屏 1竖屏 + x5webview.registerHandler("OpenurlTitleData", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + try { + JSONObject obj=new JSONObject(data); + String url= obj.optString("url"); + String title= obj.optString("title"); + String data1=obj.optString("data"); + + Intent in = new Intent(); + + in.putExtra("url", url); + in.putExtra("title", title); + in.putExtra("data", data1); + in.setClass(NewwebviewActivity.this, openwebActivity1.class); + // startActivity(in); + startActivityForResult(in, 1001); + + } catch (JSONException e) { + e.printStackTrace(); + } + + + } + }); + + //复制接口 + + x5webview.registerHandler("gameCopytext", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + ClipboardManager copy = (ClipboardManager) NewwebviewActivity.this + .getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clipData = ClipData.newPlainText("TextLabel", data); + copy.setPrimaryClip(clipData); + + + } + }); + + //粘贴接口 + + x5webview.registerHandler("gamepastetext", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + ClipboardManager clipboardManager = (ClipboardManager) NewwebviewActivity.this + .getSystemService(Context.CLIPBOARD_SERVICE); + String message = (String) clipboardManager.getPrimaryClip() + .getItemAt(0).getText(); + + function.onCallBack(message); + + } + }); + + //获取市场id接口 + x5webview.registerHandler("getmarketname", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + String market=getAllFilename("market"); + + + function.onCallBack(market); + + } + }); + + //返回获得自定义文件夹名 + x5webview.registerHandler("getothername", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + String name=getAllFilename(data); + + + function.onCallBack(name); + + } + }); + //返回获得other指定文件夹 + x5webview.registerHandler("getOther", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + String name=getAllFilename("other"); + + + function.onCallBack(name); + + } + }); + //播放游戏声音srcIsloop + + x5webview.registerHandler("srcIsloop", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + try { + System.out.println(data); + JSONObject obj=new JSONObject(data); + String src=obj.optString("src"); + String isloop=obj.optString("isloop"); + + System.out.println("isloop==" + isloop); + + Message msg = new Message(); + System.out.println("src==" + src); + Bundle bun = new Bundle(); + bun.putString("src", src); + bun.putString("type", ""+isloop); + msg.setData(bun); + playwav.sendMessage(msg); + + } catch (JSONException e) { + e.printStackTrace(); + } + + + } + }); + //语音播放开关 + x5webview.registerHandler("voicePlaying", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + if (data.equals("1")) { + Settingutil.voicePlaying = true; + + } else { + Settingutil.voicePlaying = false; + } + + + } + }); + //打开安装应用 + x5webview.registerHandler("openApplyDownloadpath", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + String downloadpath=""; + try { + JSONObject obj=new JSONObject(data); + String packagename=obj.optString("packagename"); + downloadpath=obj.optString("downloadpath"); + PackageManager packageManager = getPackageManager(); + Intent intent = new Intent(); + + intent = packageManager.getLaunchIntentForPackage(packagename); + startActivity(intent); + } catch (Exception e) { + e.printStackTrace(); + Intent viewIntent = new Intent("android.intent.action.VIEW", + Uri.parse(downloadpath)); + startActivity(viewIntent); + } + + + } + }); + //当前用户加入房间或者创建房间(频道) + x5webview.registerHandler("createRoom", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + System.out.println("调用创建加入频道--" + data); + System.out.println("控件数量=" + containerFrame.getChildCount()); + if (data != null) { + Message msg = new Message(); + msg.what = 1; + msg.obj = data; + h5handler.sendMessage(msg); + } + } + }); + //2.退出房间 + x5webview.registerHandler("exitRoom", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + System.out.println("退出房间--" + data); + + if (data != null) { + Message msg = new Message(); + msg.what = 2; + msg.obj = data; + h5handler.sendMessage(msg); + } + } + }); + //3.返回当前用户视频窗口信息(左上角坐标及宽高) + x5webview.registerHandler("getVideoinfo", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + if (data != null) { + System.out.println(data); + Message msg = new Message(); + msg.what = 0; + msg.obj = data; + h5handler.sendMessage(msg); + } + + } + }); + + + //用户点击视频是否出现悬浮框type值(默认不显示) 1显示悬浮框 2隐藏悬浮框 + x5webview.registerHandler("DragViewvideoIsshow", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + if (data.equals("1")) { + mDragViewvideoIsshow = true; + } else { + mDragViewvideoIsshow = false; + } + + } + }); + //获取手机基本配置信息 + x5webview.registerHandler("getphoneInfo", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + h5handler.sendEmptyMessage(3); + } }); + //获取手机通讯录 - 已注释 + x5webview.registerHandler("getAddressBook", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + h5handler.sendEmptyMessage(4); + } + }); + //支付调用打开浏览器 + x5webview.registerHandler("paybrowser", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + Message msg = new Message(); + msg.what = 1; + Bundle bundle = new Bundle(); + bundle.putString("browserurl", data); + msg.setData(bundle); + mpaybrow.sendMessage(msg); + } + }); + // opencamera + x5webview.registerHandler("opencamera", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + permissionHandler.sendEmptyMessage(2); + } + }); + + x5webview.registerHandler("backgameData", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + Intent in = new Intent(); + Bundle bundle = new Bundle(); + bundle.putString("data", data); + + in.putExtras(bundle); + in.setClass(NewwebviewActivity.this, webviewActivity.class); + in.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + setResult(101, in); + + exitApp(); + } + }); + + + + + + } + + + + protected void localityplay(String amrpath) { + Message msg = new Message(); + Bundle bundel = new Bundle(); + bundel.putString("audiourl", amrpath); + bundel.putString("user", String.valueOf(0)); + msg.setData(bundel); + playhandler.sendMessageDelayed(msg, 10); + + } + + public boolean isfinsh = false; + @SuppressLint("SetJavaScriptEnabled") + private void initWebViewSettings() { + + // x5webview.setLayerType(WebView.LAYER_TYPE_HARDWARE, null); + + // if (Build.VERSION.SDK_INT >= 11) { + // x5webview.setLayerType(WebView.LAYER_TYPE_SOFTWARE, null); + // } + + // if (Build.VERSION.SDK_INT >= 19) {//硬件加速器的使用 + // x5webview.setLayerType(View.LAYER_TYPE_HARDWARE, null); + // } else { + + // x5webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null); + // } + + if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) { + x5webview.getSettings().setAllowUniversalAccessFromFileURLs(true); + } + + WebSettings webSetting = x5webview.getSettings(); + IX5WebViewExtension x5WebViewExtension = x5webview.getX5WebViewExtension(); + if (x5WebViewExtension != null) { + x5WebViewExtension.setScrollBarFadingEnabled(false); + } + webSetting.setAllowFileAccess(true); + webSetting.setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS); + // 设置WebView可触摸放大缩小 + webSetting.setSupportZoom(false); + + webSetting.setBuiltInZoomControls(false); + // WebView双击变大,再双击后变小,当手动放大后,双击可以恢复到原始大小//设置此属性,可任意比例缩放 + webSetting.setUseWideViewPort(false); + + webSetting.setSupportMultipleWindows(false); + + // webSetting.setJavaScriptCanOpenWindowsAutomatically(true); + + webSetting.setDatabaseEnabled(true); + webSetting.setDomStorageEnabled(true); + webSetting.setJavaScriptEnabled(true); + + // 确保JS桥接功能在44286版本中正常工作 + webSetting.setJavaScriptCanOpenWindowsAutomatically(false); + + // 兼容新版本的混合内容设置 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + webSetting.setMixedContentMode(android.webkit.WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); + } + + // webSetting.setCacheMode(WebSettings.LOAD_DEFAULT);//根据cache-control决定是否从网络上取数据。 + + webSetting.setCacheMode(WebSettings.LOAD_NO_CACHE);// 不使用缓存 + webSetting.setAppCacheEnabled(false);// 是否设置缓存 + webSetting.setGeolocationEnabled(true);// //设置定位的数据库路径 + // webSetting.setAppCacheMaxSize(Long.MAX_VALUE);//设置缓存最大容量,默认为Max + // Integer + // webSetting.setAppCachePath(this.getDir("appcache", + // 0).getPath());//设置缓存的路径 + // webSetting.setDatabasePath(this.getDir("databases", 0).getPath()); + // webSetting.setGeolocationDatabasePath(this.getDir("geolocation", 0) + // .getPath()); + // webSetting.setPageCacheCapacity(IX5WebSettings.DEFAULT_CACHE_CAPACITY); + // webSetting.setPluginState(WebSettings.PluginState.ON_DEMAND); + + } + + @Override + protected void onStart() { + System.out.println("onStart"); + super.onStart(); + } + + public boolean isAppOnForeground() { + ActivityManager activityManager = (ActivityManager) getApplicationContext() + .getSystemService(Context.ACTIVITY_SERVICE); + String packageName = getApplicationContext().getPackageName(); + /** + * 获取Android设备中所有正在运行的App + */ + List appProcesses = activityManager + .getRunningAppProcesses(); + if (appProcesses == null) + + return false; + for (RunningAppProcessInfo appProcess : appProcesses) { + // The name of the process that this object is associated with. + if (appProcess.processName.equals(packageName) + && appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { + return true; + } + } + return false; + } + + @Override + protected void onResume() { + super.onResume(); + + Wxistrue.isshare = true; + Wxistrue.isphotoshare = true; + + if (isShake) { + mShakeListener.start(); + } + if (m_wklk != null) { + m_wklk.acquire(); // 保持唤醒 + } + +// if (x5webview != null) { +// if (isfinsh) { +// //x5webview.loadUrl("javascript:playmediaAudio();"); +// } +// +// } + + if (x5webview != null) { + + x5webview.onResume(); + } + + if (isForeground == false) { + + if (x5webview != null) { + service = 1; +// Wxistrue.isshare = true; +// Wxistrue.isphotoshare = true; + + if (isfinsh) { +// String appservice = "javascript:appservice(" + "'" +// + service + "'" + ");"; +// webviewjh(appservice); + + runOnUiThread(new Runnable() { + @Override + public void run() { + + try { + x5webview.callHandler("appservice", ""+service, new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + System.out.println("appservice交互调用成功"); + } catch (Exception e) { + System.out.println("appservice交互调用失败"); + + } + } + }); + } + + } + + isForeground = true; + } + MobclickAgent.onPageStart("NewwebviewAcivity"); + // 统计页面(仅有Activity的应用中SDK自动调用,不 + + // 集成基本统计分析,初始化 Session + UMGameAgent.onResume(this); + } + + @Override + protected void onPause() { + + if (x5webview != null) { + x5webview.onPause(); + mShakeListener.stop(); + if (m_wklk != null) { + try { + m_wklk.release(); // 解除保持唤醒 + } catch (Exception e) { + // TODO: handle exception + } + } + + /** + * 失去焦点停止声音播放 + */ + isForeground = false; + service = 2; + if (isfinsh) { +// String appservice = "javascript:appservice(" + "'" + service +// + "'" + ");"; +// webviewjh(appservice); + x5webview.callHandler("appservice", ""+service, new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + } + } + + super.onPause(); + MobclickAgent.onPageEnd("NewwebviewAcivity"); + // //集成基本统计分析, 结束 Session + UMGameAgent.onPause(this); + } + + @Override + protected void onStop() { + super.onStop(); + + mShakeListener.stop(); + + Wxistrue.islogin = true; + Wxistrue.isshare = true; + Wxistrue.isphotoshare = true; + + if (!isAppOnForeground()) { + + isForeground = false; + service = 2; + if (isfinsh) { +// String appservice = "javascript:appservice(" + "'" + service +// + "'" + ");"; +// webviewjh(appservice); + x5webview.callHandler("appservice", ""+service, new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + } + } + } + + private void jieping() { + + File file; + + if (Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED)) { + // sd卡存储(/mnt/sdcard/cache) + file = Environment.getExternalStorageDirectory();// 获取跟目录 + } else { + // 没有SD卡,缓存到系统存储 + file = Environment.getDataDirectory(); + } + file = Util.GetDirectory(); + bitmappath = file.getAbsolutePath() + File.separator + "tes.png"; + View cv = NewwebviewActivity.this.getWindow().getDecorView(); + getScreenHot(cv, bitmappath); + + } + + /** + * 截取webView快照(webView加载的整个内容的大小) + * + * @param webView + * @return + */ + // public static Bitmap captureWebView1(WebView webView) { + // webView.setDrawingCacheEnabled(true); + // webView.buildDrawingCache(); + // Picture snapShot = webView.capturePicture(); + // Bitmap bmp = Bitmap.createBitmap(snapShot.getWidth(), + // snapShot.getHeight(), Bitmap.Config.ARGB_8888); + // Canvas canvas = new Canvas(bmp); + // snapShot.draw(canvas); + // canvas.save(); + // canvas.restore(); + // // webView.dispatchDraw(canvas); + // webView.destroyDrawingCache(); + // return bmp; + // } + + private Bitmap captureWebView(WebView webView) { + Picture picture = webView.capturePicture(); + Bitmap bmp = Bitmap.createBitmap(picture.getWidth(), + picture.getHeight(), Bitmap.Config.RGB_565); + Canvas c = new Canvas(bmp); + picture.draw(c); + return bmp; + } + + private void getbitmap(Bitmap bitmap2, String bitmappath2) { + + File file1 = new File(bitmappath2); + try { + file1.createNewFile(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + bitmap2.compress(Bitmap.CompressFormat.PNG, 100, baos); + + int options = 100; + while (baos.toByteArray().length / 1024 > 100 && options != 10) { // 循环判断如果压缩后图片是否大于100kb,大于继续压缩 + baos.reset();// 重置baos即清空baos + bitmap2.compress(Bitmap.CompressFormat.PNG, options, baos);// 这里压缩options%,把压缩后的数据存放到baos中 + options -= 10;// 每次都减少10 + } + + ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把压缩后的数据baos存放到ByteArrayInputStream中 + // 据baos存放到ByteArrayInputStream中 + Bitmap bit = BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream数据生成图片 + + System.out.println(baos.toByteArray().length); + + try { + FileOutputStream fos = new FileOutputStream(file1); + bit.compress(CompressFormat.PNG, 100, fos); + + fos.flush(); + fos.close(); + } catch (FileNotFoundException e) { + + } catch (IOException e) { + + e.printStackTrace(); + } + + } + + protected void friend() { + apputil.wxtype = 1; + Wxistrue.sharetype = 1; + + if (bean.getType().equals("1")) { + + WXWebpageObject webpage = new WXWebpageObject(); + webpage.webpageUrl = bean.getWebpageUrl(); + WXMediaMessage msg = new WXMediaMessage(webpage); + msg.title = bean.getTitle(); + msg.description = bean.getDescription(); + // Toast.makeText(this, bean.getDescription(), 1).show(); + Bitmap bt = BitmapFactory.decodeResource(getResources(), + R.drawable.sharelogo3); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + bt.compress(Bitmap.CompressFormat.PNG, 100, out); + + // Toast.makeText(webviewActivity.this, "" + + // out.toByteArray().length, + // 1).show(); + + if (out.toByteArray().length > 32000) { + // int a=out.toByteArray().length/30000; + BitmapFactory.Options newOpts = new BitmapFactory.Options(); + newOpts.inJustDecodeBounds = true; + + // Toast.makeText(webviewActivity.this, "压缩", 1).show(); + + BitmapFactory.decodeResource(getResources(), + R.drawable.sharelogo3, newOpts); + + newOpts.inJustDecodeBounds = false; + int inSampleSize = 2;// 大小缩小一半 + + newOpts.inSampleSize = inSampleSize; + Bitmap bitmap = BitmapFactory.decodeResource(getResources(), + R.drawable.sharelogo3, newOpts); + + msg.thumbData = Util.bmpToByteArray(bitmap, true); + } else { + msg.thumbData = Util.bmpToByteArray(bt, true); + } + + SendMessageToWX.Req req = new SendMessageToWX.Req(); + req.transaction = buildTransaction("webpage"); + req.message = msg; + req.scene = SendMessageToWX.Req.WXSceneSession; + api.sendReq(req); + } else if (bean.getType().equals("2")) { + + try{ + + photosharefriend(); + + }catch(Exception e){ + Wxistrue.isshare = true; + } + + } + } + + + + protected void xlfriend() { + apputil.wxtype = 1; + Wxistrue.sharetype = 3; + + if (bean.getType().equals("1")) { + + //显示的图标(可选) + Bitmap bt = BitmapFactory.decodeResource(getResources(),R.drawable.sharelogo3); + +// ByteArrayOutputStream out = new ByteArrayOutputStream(); +// bt.compress(Bitmap.CompressFormat.PNG, 100, out); +// +// +// if (out.toByteArray().length > 32000) { +// // int a=out.toByteArray().length/30000; +// BitmapFactory.Options newOpts = new BitmapFactory.Options(); +// newOpts.inJustDecodeBounds = true; +// +// // Toast.makeText(webviewActivity.this, "压缩", 1).show(); +// +// BitmapFactory.decodeResource(getResources(), +// R.drawable.sharelogo3, newOpts); +// +// newOpts.inJustDecodeBounds = false; +// int inSampleSize = (out.toByteArray().length / 32768 + 1) / 2 + 2; +// if (inSampleSize < 2) { +// inSampleSize = 2; +// } +// +// newOpts.inSampleSize = inSampleSize; +// bt= BitmapFactory.decodeResource(getResources(), +// R.drawable.sharelogo3, newOpts); +// +// +// } + + + //初始化一个SGLinkObject对象,并设置一个分享图标 +// SGLinkObject linkObject = new SGLinkObject(bt); +// +// //要分享的链接,必填 +// linkObject.shareUrl = bean.getWebpageUrl(); +// +// //用SGImageObject对象初始化一个SGMediaMessage对象 +// SGMediaMessage msg = new SGMediaMessage(); +// msg.mediaObject = linkObject; +// msg.title = bean.getTitle(); //链接标题 +// msg.description = bean.getDescription(); //链接描述 +// +// //构造一个Req +// SendMessageToSG.Req req = new SendMessageToSG.Req(); +// req.transaction = SGConstants.T_LINK; +// req.mediaMessage = msg; +// req.scene = SendMessageToSG.Req.SGSceneSession; //代表分享到会话列表 +// +// //调用api接口发送数据到闲聊 +// xlapi.sendReq(req); + + + } else if (bean.getType().equals("2")) { + try { + + // photosharefriend(); + + } catch (Exception e) { + Wxistrue.isshare = true; + } + + + } + } + + private void photoshareurlfriend(String url) { + + } + private void xlphotosharefriend(){ + apputil.wxtype = 1; + Wxistrue.sharetype = 3; + + Bitmap bitmap = BitmapFactory.decodeFile(bitmappath); + +// //初始化一个SGImageObject对象,设置所分享的图片内容 +// SGImageObject imageObject = new SGImageObject(bitmap); +// +// //用SGImageObject对象初始化一个SGMediaMessage对象 +// SGMediaMessage msg = new SGMediaMessage(); +// msg.mediaObject = imageObject; +// +// //构造一个Req +// SendMessageToSG.Req req = new SendMessageToSG.Req(); +// req.transaction = SGConstants.T_IMAGE; +// req.mediaMessage = msg; +// req.scene = SendMessageToSG.Req.SGSceneSession; //代表分享到会话列表 +// +// //调用api接口发送数据到闲聊 +// xlapi.sendReq(req); + + } + + private void photosharefriend() { + // 使用新的微信分享辅助类替换原有的直接API调用 + apputil.wxtype = 1; + Wxistrue.sharetype = 2; + + // 获取微信分享工具实例 + WeChatShareUtil weChatShareUtil = WeChatShareUtil.getInstance(this); + + // 设置分享回调 + weChatShareUtil.setShareCallback(new WeChatShareUtil.WeChatShareCallback() { + @Override + public void onSuccess() { + // 分享成功后的处理逻辑保持不变 + runOnUiThread(() -> { + // 可以添加成功提示或其他逻辑 + }); + } + + @Override + public void onError(int code, String message) { + // 分享失败后的处理逻辑 + runOnUiThread(() -> { + // 可以添加失败提示或其他逻辑 + }); + } + + @Override + public void onCancel() { + // 分享取消后的处理逻辑 + runOnUiThread(() -> { + // 可以添加取消提示或其他逻辑 + }); + } + }); + + // 使用getCanvasBase64FromWebView获取Canvas内容并分享 + WebViewScreenshotUtil.getCanvasBase64FromWebView(x5webview,null, new WebViewScreenshotUtil.CanvasToBase64Callback() { @Override + public void onSuccess(String base64Data) { + // getCanvasBase64FromWebView直接返回base64数据,不需要复杂的JSON解析 + try { + if (base64Data != null && !base64Data.isEmpty()) { + + + // 直接使用获取到的base64数据分享 + weChatShareUtil.shareImage(NewwebviewActivity.this, base64Data, 0); + } else { + + // 回退到原来的方法 + weChatShareUtil.shareImage(NewwebviewActivity.this, bitmappath, 0); + } + } catch (Exception e) { + + // 异常时回退到原来的方法 + weChatShareUtil.shareImage(NewwebviewActivity.this, bitmappath, 0); + } + } + + @Override + public void onError(String error) { +// Toast.makeText(NewwebviewActivity.this, "截图失败成功"+error, Toast.LENGTH_SHORT).show(); + // Canvas获取失败,回退到原来的方法 + weChatShareUtil.shareImage(NewwebviewActivity.this, bitmappath, 0); + } + }); + } + + protected void sharefriends() { + apputil.wxtype = 1; + + Wxistrue.sharetype = 2; + + if (bean.getType().equals("1")) { + System.out.println("hhhhhhh"); + WXWebpageObject webpage = new WXWebpageObject(); + webpage.webpageUrl = bean.getWebpageUrl(); + WXMediaMessage msg = new WXMediaMessage(webpage); + msg.title = bean.getTitle(); + msg.description = bean.getDescription(); + // Toast.makeText(this, bean.getDescription(), 1).show(); + + Bitmap bt = BitmapFactory.decodeResource(getResources(), + R.drawable.sharelogo3); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + bt.compress(Bitmap.CompressFormat.PNG, 100, out); + + // Toast.makeText(webviewActivity.this, "" + + // out.toByteArray().length, + // 1).show(); + + if (out.toByteArray().length > 32000) { + // int a=out.toByteArray().length/30000; + BitmapFactory.Options newOpts = new BitmapFactory.Options(); + newOpts.inJustDecodeBounds = true; + BitmapFactory.decodeResource(getResources(), + R.drawable.sharelogo3, newOpts); + newOpts.inJustDecodeBounds = false; + int inSampleSize = 2;// 大小缩小一半 + newOpts.inSampleSize = inSampleSize; + + Bitmap bitmap = BitmapFactory.decodeResource(getResources(), + R.drawable.sharelogo3, newOpts); + + msg.thumbData = Util.bmpToByteArray(bitmap, true); + } else { + msg.thumbData = Util.bmpToByteArray(bt, true); + } + + SendMessageToWX.Req req = new SendMessageToWX.Req(); + req.transaction = buildTransaction("webpage"); + req.message = msg; + req.scene = SendMessageToWX.Req.WXSceneTimeline; + api.sendReq(req); + + } else if (bean.getType().equals("2")) { + photosharefriends(); + System.out.println("ssssssssssss"); + } + + } + private void photosharefriends() { + // 使用新的微信分享辅助类替换原有的直接API调用 + apputil.wxtype = 1; + Wxistrue.sharetype = 2; + + // 获取微信分享工具实例 + WeChatShareUtil weChatShareUtil = WeChatShareUtil.getInstance(this); + + // 设置分享回调 + weChatShareUtil.setShareCallback(new WeChatShareUtil.WeChatShareCallback() { + @Override + public void onSuccess() { + // 分享成功后的处理逻辑保持不变 + runOnUiThread(() -> { + // 可以添加成功提示或其他逻辑 + }); + } + + @Override + public void onError(int code, String message) { + // 分享失败后的处理逻辑 + runOnUiThread(() -> { + // 可以添加失败提示或其他逻辑 + }); + } + + @Override + public void onCancel() { + // 分享取消后的处理逻辑 + runOnUiThread(() -> { + // 可以添加取消提示或其他逻辑 + }); + } + }); + + // 使用新的分享方法分享图片到微信朋友圈(scene = 1) + weChatShareUtil.shareImage(this, bitmappath, 1); + + System.out.println(bitmappath); + } + + // 进行质量压缩,文件大小改变 ,bitmap 不变 + public void compressBmpFromBmp(Bitmap thumb) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int options = 100; + thumb.compress(Bitmap.CompressFormat.PNG, options, baos); + // Toast.makeText(MainActivity.this, "%%%%%%" + + // baos.toByteArray().length, + // 1).show(); + while (baos.toByteArray().length > 30000 && options != 10) { + baos.reset(); // 清空baos + thumb.compress(Bitmap.CompressFormat.PNG, options, baos);// 这里压缩options%,把压缩后的数据存放到baos中 + options -= 10; + } + thumb.recycle(); + + byte[] result = baos.toByteArray(); + + try { + baos.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // Toast.makeText(MainActivity.this, "&&&&&&" + result.length, + // 1).show(); + Bitmap bit = BitmapFactory.decodeByteArray(baos.toByteArray(), 0, + baos.toByteArray().length); + } + @Override + protected void onDestroy() { + + try { + if (x5webview != null) { + x5webview.removeAllViews(); + x5webview.destroy(); + x5webview = null; + } + } catch (Exception e) { + e.printStackTrace(); + } + + if (mLocationClient != null) { + mLocationClient.onDestroy(); + } + + // 停止HTTP服务器 + NewWebServerInstance.getInstance().stop(); + + // Toast.makeText(this, "onDestroy", 1).show(); + + + + System.out.println("onDestroy"); + + if (webdialog != null) { + webdialog.dismiss(); + } + + unregisterReceiver(mMessageReceiver); + unregisterReceiver(batteryReceiver); + unregisterReceiver(WifiChangeReceiver); + unregisterReceiver(myNetReceiver); + screen.unregisterListener(); + if (m_wklk != null) { + try { + m_wklk.release(); // 解除保持唤醒 + } catch (Exception e) { + // TODO: handle exception + } + } + super.onDestroy(); + + } + + // 硬件加速 + private void hardwareAccelerate() { + if (this.getPhoneSDKInt() >= 14) { + getWindow().setFlags(0x1000000, 0x1000000); + } + } + + public int getPhoneSDKInt() { + int version = 0; + try { + version = Integer.valueOf(android.os.Build.VERSION.SDK); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + return version; + } + + protected void upload(String amrpath, final float time) { + + uploadManager = new UploadManager(); + + Auth auth = Auth.create("ngN3rFW1j8dn7ZGpATKl7mreaNmp2Ei_l9AIhkIf", + "6VXav9eqUCORJTYvTFOeTVRonAyk4Hrs-PIZ8jmZ"); + String auth1 = auth.uploadToken("gameaudio"); + + String filename = amrpath.substring(amrpath.lastIndexOf("/") + 1); + + uploadManager.put(amrpath, filename, auth1, new UpCompletionHandler() { + @Override + public void complete(String key, ResponseInfo rinfo, + JSONObject response) { + String s = key + ", " + rinfo + ", " + response; + String filepath = "http://gameaudio.daoqi88.cn/" + key; + JSONObject json = new JSONObject(); + try { + json.put("audiourl", filepath); + + json.put("time", time); + x5webview.callHandler("getaudiourl", json.toString(), new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + }catch (Exception ignored){ + ignored.printStackTrace(); + } + } + }, new UploadOptions(null, null, true, null, null)); + } + + public void run(final String url) throws Exception { + + Request request = new Request.Builder().url(url).build(); + okclient.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(Call arg0, IOException throwable) { + throwable.printStackTrace(); + } + + @SuppressWarnings("resource") + @Override + public void onResponse(Call arg0, Response response) + throws IOException { + + if (!response.isSuccessful()) + throw new IOException("Unexpected code " + response); + Headers responseHeaders = response.headers(); + for (int i = 0; i < responseHeaders.size(); i++) { + System.out.println(responseHeaders.name(i) + ": " + + responseHeaders.value(i)); + } + InputStream is = null; + byte[] buf = new byte[2048]; + int len = 0; + FileOutputStream fos = null; + + is = response.body().byteStream(); + + if (Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED)) { + // 获取SDCard的路径 + destFileDir = Environment.getExternalStorageDirectory() + .getAbsoluteFile() + + File.separator + + "dowlod_audioss"; + // Toast.makeText(application, sdFile.getAbsolutePath(), + // 1).show(); + } else { + destFileDir = Environment.getDataDirectory() + .getAbsolutePath() + + File.separator + + "dowlod_audioss"; + } + destFileDir = Util.GetFileAbsolutePath()+ File.separator + + "dowlod_audioss"; + File dir = new File(destFileDir); + if (!dir.exists()) { + dir.mkdirs(); + } + + File file = new File(dir, getFileName(url)); + + System.out.println(file.getAbsolutePath()); + fos = new FileOutputStream(file); + while ((len = is.read(buf)) != -1) { + fos.write(buf, 0, len); + } + fos.flush(); + + System.out.println(file.getAbsolutePath()); + // play(file.getAbsolutePath()); + + } + + }); + } + + /** + * + * @param filePathString + * 音频名 + * @param user + * 动画 + */ + protected void play(String filePathString, String user) { + isPlayaudio = true; + uservoice = user; +// String call = "javascript:gameui_play_voice(" + "'" + uservoice + "'" +// + ");"; +// +// webviewjh(call); + x5webview.callHandler("gameui_play_voice", ""+uservoice, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + + MediaManager.playSound(filePathString, new OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + // if (isPlaying) { + + // Toast.makeText(webviewActivity.this, "播放完成", 0).show(); + +// String sw = "javascript:gameui_stop_voice(" + "'" + uservoice +// + "'" + ");"; +// webviewjh(sw); + if(x5webview!=null){ + x5webview.callHandler("gameui_stop_voice", ""+uservoice, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + } + + isPlayaudio = false; + uservoice = ""; + + // } + + } + }); + + } + + private String getFileName(String path) { + int separatorIndex = path.lastIndexOf("/"); + + int lastIndex = path.lastIndexOf("?"); + + return (separatorIndex < 0) ? path : path.substring(separatorIndex + 1, + lastIndex); + } + + protected void DownloadUrl(String filepath) { + + Auth auth = Auth.create("ngN3rFW1j8dn7ZGpATKl7mreaNmp2Ei_l9AIhkIf", + "6VXav9eqUCORJTYvTFOeTVRonAyk4Hrs-PIZ8jmZ"); + String DownloadUrl = auth.privateDownloadUrl(filepath); + + // Toast.makeText(webviewActivity.this, DownloadUrl, 1).show(); + try { + run(DownloadUrl); + + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + /** + * 登录微信 + */ + private void WXLogin() { + + String access_token = SpUtil.getStringSharedPerference(Shared, + "access_token"); + + String refresh_token = SpUtil.getStringSharedPerference(Shared, + "refresh_token"); + // Toast.makeText(webviewActivity.this, "access_token="+access_token, + // 1).show(); + + if (!api.isWXAppInstalled()) { + Toast.makeText(NewwebviewActivity.this, "n您还未安装微信客户端", Toast.LENGTH_LONG).show(); + return; + } + + // if (pmutil.isnullorEmpty(access_token)) { + + login(); + + // } else { + + // Toast.makeText(this, "第二次", 1).show(); + // isaccess_token(); + + // } + + } + + public void refresh_token(String refresh_token) { + + Map map = new HashMap(); + map.put("appid", Constants.APP_ID); + map.put("grant_type", "refresh_token"); + map.put("refresh_token", refresh_token); + + register.StringGETrequest(map, WX_Myurl.refresh_token, + new Volleyinterface1(this, Volleyinterface1.mlistener, + Volleyinterface1.mErrorLisener) { + + @Override + public void onsuccess(String result) { + try { + JSONObject object = new JSONObject(result); + + String access_token = object + .optString("access_token"); + + int errcode = object.optInt("errcode"); + if (errcode == 40030) { + login(); + + } else if (!pmutil.isnullorEmpty(access_token)) { + + if (!pmutil.isnullorEmpty(access_token)) { + SpUtil.setStringSharedPerference(Shared, + "access_token", access_token); + } + + int expires_in = object.optInt("expires_in"); + + String refresh_token = object + .optString("refresh_token"); + + if (!pmutil.isnullorEmpty(refresh_token)) { + SpUtil.setStringSharedPerference(Shared, + "refresh_token", refresh_token); + } + + String openid = object.optString("openid"); + + if (!pmutil.isnullorEmpty(openid)) { + SpUtil.setStringSharedPerference(Shared, + "openid", openid); + } + // Toast.makeText(MainActivity.this, result, 1) + // .show(); + aSd = 2; + isaccess_token(); + } + + } catch (Exception e) { + + e.printStackTrace(); + } + + } + + @Override + public void onerror(VolleyError arg0) { + + } + }); + } + + public void login() { + if (!api.isWXAppInstalled()) { + Toast.makeText(NewwebviewActivity.this, "l您还未安装微信客户端", Toast.LENGTH_LONG).show(); + return; + } + + api = WXAPIFactory.createWXAPI(NewwebviewActivity.this, + Constants.APP_ID, true); + api.registerApp(Constants.APP_ID); + SendAuth.Req req = new SendAuth.Req(); + req.scope = "snsapi_userinfo"; + req.state = "wechat_sdk_demo"; + api.sendReq(req); + + WXEntryActivity.setshareHandler(handler); + + } + + public void isaccess_token() { + + final String access_token = SpUtil.getStringSharedPerference(Shared, + "access_token"); + + final String refresh_token = SpUtil.getStringSharedPerference(Shared, + "refresh_token"); + + final String openid = SpUtil + .getStringSharedPerference(Shared, "openid"); + Map map = new HashMap(); + map.put("openid", openid); + map.put("access_token", access_token); + + register.StringGETrequest(map, WX_Myurl.isaccess_token, + new Volleyinterface1(this, Volleyinterface1.mlistener, + Volleyinterface1.mErrorLisener) { + @Override + public void onsuccess(String result) { + try { + JSONObject object = new JSONObject(result); + String errmsg = object.optString("errmsg"); + + // Toast.makeText(webviewActivity.this, + // "result=" + result, 1).show(); + if (errmsg.equals("ok")) { + + getUserInfo(access_token, openid); + } else { + // Toast.makeText(MainActivity.this, + // "access_token 失效重新获取", 1).show(); + refresh_token(refresh_token); + } + + } catch (Exception e) { + e.printStackTrace(); + } + + } + + @Override + public void onerror(VolleyError arg0) { + + } + }); + } + + public void getuser1(String accessToken, String openId) { + Map map = new HashMap(); + map.put("openid", openId); + map.put("access_token", accessToken); + register.StringGETrequest(map, WX_Myurl.getwxuserinfo, + new Volleyinterface1(this, Volleyinterface1.mlistener, + Volleyinterface1.mErrorLisener) { + @Override + public void onsuccess(String result) { + try { + JSONObject object = new JSONObject(result); + String url = object.optString("headimgurl"); + String unionid = object.optString("unionid"); + String openid = object.optString("openid"); + String nickname = object.optString("nickname"); + String sex = object.optString("sex"); + String city = object.optString("city"); + SpUtil.setStringSharedPerference(Shared, "unionid", + unionid); + SpUtil.setStringSharedPerference(Shared, + "headimgurl", url); + SpUtil.setStringSharedPerference(Shared, "openid", + openid); + SpUtil.setStringSharedPerference(Shared, + "nickname", nickname); + SpUtil.setStringSharedPerference(Shared, "sex", sex); + SpUtil.setStringSharedPerference(Shared, "city", + city); + handler.sendEmptyMessage(1); + + } catch (Exception e) { + + e.printStackTrace(); + } + + } + + @Override + public void onerror(VolleyError arg0) { + + } + }); + }; + + private class GetPrepayIdTask extends + AsyncTask> { + + @Override + protected void onPreExecute() { + } + + @Override + protected void onPostExecute(Map result) { + + // Toast.makeText(MaiobdActivity.this, result.toString(), 1).show(); + if (result != null) { + sb.append("prepay_id\n" + result.get("prepay_id") + "\n\n"); + + resultunifiedorder = result; + wxpay(); + } + // String err=resultunifiedorder.get("err_code"); + // Toast.makeText(MaishopActivity.this, err, 1).show(); + } + + @Override + protected void onCancelled() { + super.onCancelled(); + } + + @Override + protected Map doInBackground(Void... params) { + + // String shopname=params[0]; + // String pice=params[1]; + // String ordernum=params[2]; + + String url = String + .format("https://api.mch.weixin.qq.com/pay/unifiedorder"); + String entity = genProductArgs(); + Log.e("orion", entity); + byte[] buf = Util.httpPost(url, entity); + + Map xml = null; + if (buf != null) { + String content = new String(buf); + Log.e("orion", content); + xml = decodeXml(content); + + } + + return xml; + } + } + + public Map decodeXml(String content) { + + try { + Map xml = new HashMap(); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(new StringReader(content)); + int event = parser.getEventType(); + while (event != XmlPullParser.END_DOCUMENT) { + + String nodeName = parser.getName(); + switch (event) { + case XmlPullParser.START_DOCUMENT: + + break; + case XmlPullParser.START_TAG: + + if ("xml".equals(nodeName) == false) { + // 实例化student对象 + xml.put(nodeName, parser.nextText()); + } + break; + case XmlPullParser.END_TAG: + break; + } + event = parser.next(); + } + + return xml; + } catch (Exception e) { + Log.e("orion", e.toString()); + } + return null; + + } + + /** + * + * 生成商户订单号 + */ + private String genNonceStr() { + Random random = new Random(); + return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)) + .getBytes()); + } + + private long genTimeStamp() { + return System.currentTimeMillis() / 1000; + } + + /** + * + * 生成商户订单号 + */ + private String genOutTradNo(String number) { + Random random = new Random(); + // number.getBytes() + // String.valueOf(random.nextInt(10000)).getBytes() + return MD5.getMessageDigest(number.getBytes()); + } + + @SuppressWarnings("deprecation") + private String genProductArgs() { + StringBuffer xml = new StringBuffer(); + try { + String nonceStr = genNonceStr(); + xml.append(""); + List packageParams = new LinkedList(); + packageParams + .add(new BasicNameValuePair("appid", Constants.APP_ID)); + packageParams.add(new BasicNameValuePair("body", "")); + // packageParams.add(new BasicNameValuePair("detail", "服务")); + packageParams + .add(new BasicNameValuePair("mch_id", Constants.MCH_ID)); + packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));// 随机字符串 + packageParams.add(new BasicNameValuePair("notify_url", + "http://sevencar.gogotoo.net/WeChatPay/NotifyUrl"));// 回调通知地址 + packageParams.add(new BasicNameValuePair("out_trade_no", ""));// 商户订单号 + packageParams.add(new BasicNameValuePair("spbill_create_ip", + "127.0.0.1"));// 终端IP + packageParams.add(new BasicNameValuePair("total_fee", "1"));// 价格 + packageParams.add(new BasicNameValuePair("trade_type", "APP"));// 支付类型 + String sign = genPackageSign(packageParams); + packageParams.add(new BasicNameValuePair("sign", sign)); + String xmlstring = toXml(packageParams); + return xmlstring; + } catch (Exception e) { + //Log.e(TAG, "genProductArgs fail, ex = " + e.getMessage()); + return null; + } + } + + @SuppressWarnings("deprecation") + private void genPayReq() { + + req.appId = Constants.APP_ID;// 应用id + req.partnerId = Constants.MCH_ID;// 商户号 + req.prepayId = resultunifiedorder.get("prepay_id");// 预支付交易会话ID + req.packageValue = "Sign=WXPay";// 扩展字段 + req.nonceStr = genNonceStr();// 随机字符串 + req.timeStamp = String.valueOf(genTimeStamp());// 时间戳 + + List signParams = new LinkedList(); + signParams.add(new BasicNameValuePair("appid", req.appId)); + signParams.add(new BasicNameValuePair("noncestr", req.nonceStr)); + signParams.add(new BasicNameValuePair("package", req.packageValue)); + signParams.add(new BasicNameValuePair("partnerid", req.partnerId)); + signParams.add(new BasicNameValuePair("prepayid", req.prepayId)); + signParams.add(new BasicNameValuePair("timestamp", req.timeStamp)); + + req.sign = genAppSign(signParams);// 支付签名 + sb.append("sign\n" + req.sign + "\n\n"); + + Log.e("orion", signParams.toString()); + + } + + /** + * 生成下单签名 + */ + @SuppressWarnings("deprecation") + private String genPackageSign(List params) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < params.size(); i++) { + sb.append(params.get(i).getName()); + sb.append('='); + sb.append(params.get(i).getValue()); + sb.append('&'); + } + sb.append("key="); + sb.append(Constants.API_KEY); + String packageSign = MD5.getMessageDigest(sb.toString().getBytes()) + .toUpperCase(); + Log.e("orion", packageSign); + return packageSign; + } + + @SuppressLint("DefaultLocale") + @SuppressWarnings("deprecation") + private String genAppSign(List params) { + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < params.size(); i++) { + sb.append(params.get(i).getName()); + sb.append('='); + sb.append(params.get(i).getValue()); + sb.append('&'); + } + sb.append("key="); + sb.append(Constants.API_KEY); + + this.sb.append("sign str\n" + sb.toString() + "\n\n"); + String appSign = MD5.getMessageDigest(sb.toString().getBytes()) + .toUpperCase(); + Log.e("orion", appSign); + return appSign; + } + + @SuppressWarnings("deprecation") + private String toXml(List params) { + StringBuilder sb = new StringBuilder(); + sb.append(""); + for (int i = 0; i < params.size(); i++) { + sb.append("<" + params.get(i).getName() + ">"); + + sb.append(params.get(i).getValue()); + sb.append(""); + } + sb.append(""); + + Log.e("orion", sb.toString()); + try { + return new String(sb.toString().getBytes(), "ISO8859-1"); + } catch (Exception e) { + e.printStackTrace(); + } + return sb.toString(); + } + + private void sendPayReq() { + msgApi.registerApp(Constants.APP_ID); + msgApi.sendReq(req); + } + + /** + * 微信支付 + */ + private void wxpay() { + genPayReq(); + sendPayReq(); + } + + static Map map = new HashMap(); + Handler playwav = new Handler() { + public void handleMessage(Message msg) { + Bundle bundel = msg.getData(); + String src = bundel.getString("src"); + String type = bundel.getString("type"); + String urlpath = SpUtil + .getStringSharedPerference(Shared, "urlpath"); + // type 0 播放一次 type 1 背景音乐(重复播放) -1 停止背景音乐 + String purl = urlpath + File.separator + gamedirectory1; + + String wavpath = purl + "/assets/wav/" + src; + + File file = new File(wavpath); + + // Toast.makeText(NewwebviewActivity.this, + // "wavpath" + wavpath + "type" + type, 0).show(); + + if (file.exists() && file.isFile()) { + + int isloop = Integer.parseInt(type); + if (isloop > 0 || map.containsKey(src)) { + // msoundpoolUtil.playSound(wavpath, isloop); + if (!map.containsKey(src)) { + + mediaplayer1 me = new mediaplayer1(); + map.put(src, me); + + // new Thread() { + // public void run() { + + me.play(wavpath, isloop, new OnCompletionListener() { + + @Override + public void onCompletion(MediaPlayer mp) { + + System.out.println("播放完成"); + } + }); + + // }; + // }.start(); + + } else { + mediaplayer1 me1 = map.get(src); + + // new Thread() { + // public void run() { + + me1.play(wavpath, isloop, new OnCompletionListener() { + + @Override + public void onCompletion(MediaPlayer mp) { + System.out.println("播放完成"); + } + }); + + // }; + // }.start(); + + }// lifj7328309 + + } else { + // soundpoolUtil.playSound(wavpath, isloop); + + SoundPoolUtils.playSound(wavpath, isloop); + } + + System.out.println(wavpath); + } + + }; + }; + + Handler mpaybrow=new Handler(){ + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what){ + case 1: + String browserurl=msg.getData().getString("browserurl"); + final Intent intent = new Intent(); + intent.setAction("android.intent.action.VIEW"); + Uri content_url = Uri.parse(browserurl); + intent.setData(content_url); + + if(!BrowserUtil.isQQBrowserInstalled()){ + dialogexit.show(NewwebviewActivity.this, "建议安装QQ浏览器进行购买", new onexitlistener() { + @Override + public void paylistener() { + + } + + @Override + public void cancellistener() { + intent.setClassName("com.android.browser","com.android.browser.BrowserActivity"); + startActivity(intent); + } + }); + }else{ + intent.setClassName("com.tencent.mtt","com.tencent.mtt.MainActivity");//打开QQ浏览器 + + startActivity(intent); + } + + + break; + + } + } + }; + + public void phoneInfo(){ + phoneInfoBean phoneinfobean=new phoneInfoBean(); + phoneutil util=new phoneutil(this); + String AdresseMAC=util.getAdresseMAC();//mac 地址 + String ProvidersName=util.getProvidersName();//手机服务商信息 + String DeviceBrand=phoneutil.getDeviceBrand();//手机品牌 + String phoneIMEI=phoneutil.getIMEI(this);//手机IMEI 串号 + String phoneIMSI=phoneutil.getIMsI(this);//手机IMEI 串号 + String phoneModel=phoneutil.getSystemModel();//手机型号 + String phoneVersion=phoneutil.getSystemVersion();//手机系统版本号 + + phoneinfobean.setPhoneAdresseMAC(AdresseMAC); + phoneinfobean.setPhoneDeviceBrand(DeviceBrand); + phoneinfobean.setPhoneIMEI(phoneIMEI); + phoneinfobean.setPhoneIMSI(phoneIMSI); + phoneinfobean.setPhoneModel(phoneModel); + phoneinfobean.setPhoneProvidersName(ProvidersName); + phoneinfobean.setPhoneVersion(phoneVersion); + Gson gson=new Gson(); + String inf0=gson.toJson(phoneinfobean); + System.out.println(inf0); + +// String Level = "javascript:getphoneinfo(" + "'" +// + inf0 + "'"+ ");"; +// System.out.println(Level); +// webviewjh(Level); + + x5webview.callHandler("getphoneinfo", inf0, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + } + // 注释掉通讯录权限申请相关代码 + // public String[] AddressBookpermission = new String[] { + // Manifest.permission.WRITE_CONTACTS}; + Handler h5handler=new Handler(){ + public void handleMessage(Message msg) { + switch (msg.what) { + case 1: + videouserinfo=(String)msg.obj; + + + if (!hasPermission(vidopermission)) { + + PermissionGen.needPermission(NewwebviewActivity.this, 111, + vidopermission); + } else { + + Gson gson1=new Gson(); + + try { + mvideoinfobean=gson1.fromJson(videouserinfo, videoinfobean.class); + + if(!pmutil.isnullorEmpty(mvideoinfobean.getRoomid())){ + initAgoraEngineAndJoinChannel(); + } + + } catch (Exception e) { + // TODO: handle exception + } + + + } + + break; + case 0: + + othervideoinfo=(String)msg.obj; + Gson gson1=new Gson(); + + try { + + mOthervideoinfo=gson1.fromJson(othervideoinfo, Othervideoinfo.class); + if(mOthervideoinfo!=null&&mOthervideoinfo.getPlayerid()!=null){ + System.out.println("调用setupRemoteVideo()"); + setupRemoteVideo(Integer.parseInt(mOthervideoinfo.getPlayerid()),mOthervideoinfo); + + } + + } catch (Exception e) { + // TODO: handle exception + } + + break; + case 2: + + runOnUiThread(new Runnable() { + @Override + public void run() { + + exitRoom(); + } + }); + + break; + case 3: + + phoneInfo(); + + break; case 4: + // 注释掉通讯录权限申请逻辑 + // if (!hasPermission(AddressBookpermission)) { + // PermissionGen.needPermission(NewwebviewActivity.this, 23, + // AddressBookpermission); + // } else { + // getAddressBook(); + // } + + break; + default: + break; + } + + } + }; + // 注释掉通讯录权限申请成功和失败的回调方法 + // @PermissionSuccess(requestCode = 23) + // public void AddressBooklocation() { + // getAddressBook(); + // } + // @PermissionFail(requestCode = 23) + // public void errorAddressBook() { + // + // } + // public void getAddressBook(){ + // String listaddress=phoneutil.getPhoneContacts(this); + // x5webview.callHandler("getAddressbook", listaddress, new CallBackFunction() { + // @Override + // public void onCallBack(String data) { + // + // } + // }); + // } + + + + TextView videotext; + DragViewGroup mDragViewvideo; + + LinearLayout mlinearvideo; + + ImageView mvideoimg; + ImageView mvoiceimg; + RelativeLayout containerFrame; + RelativeLayout mvideoimgGroup; + public void initvideo(){ + + videotext=(TextView)findViewById(R.id.videotext); + mDragViewvideo= (DragViewGroup) findViewById(R.id.DragViewvideo); + mlinearvideo= (LinearLayout) findViewById(R.id.linearvideo); + mvideoimg=(ImageView)findViewById(R.id.videoimg); + mvideoimgGroup=(RelativeLayout)findViewById(R.id.videoimgGroup); + + mvoiceimg=(ImageView)findViewById(R.id.voiceimg); + + containerFrame = (RelativeLayout)findViewById(R.id.Frame); + } + videoinfobean mvideoinfobean=null; + + Othervideoinfo mOthervideoinfo=null; + + String videouserinfo; + String othervideoinfo; + /** + * 频道权限 + */ + public String[] vidopermission = new String[] { + Manifest.permission.RECORD_AUDIO, + Manifest.permission.CAMERA }; + + + public void initvideodata(){ + if(videomap1!=null){ + videomap1=null; + } + + mlinearvideo.removeAllViews(); + mvideoimg.setImageResource(R.mipmap.a2); + mvoiceimg.setImageResource(R.mipmap.a4); + mDragViewvideo.setVisibility(View.GONE); + } + + public void exitRoom(){ + try{ + + + + }catch(Exception e){ + + } + + + if(mvideoinfobean!=null){ + if(mRtcEngine!=null){ + + + initvideodata(); + + // mRtcEngine.muteLocalVideoStream(true); + videotext.setText(videotext.getText()+"\n 控件数量="+containerFrame.getChildCount()); + System.out.println("控件数量="+containerFrame.getChildCount()); + + //Toast.makeText(webviewActivity.this,"控件数量="+containerFrame.getChildCount(),Toast.LENGTH_SHORT).show(); + if(containerFrame.getChildCount()>3){ + int lenth=containerFrame.getChildCount()-1; + + //Toast.makeText(webviewActivity.this,"lenth="+lenth,Toast.LENGTH_SHORT).show(); + + for(int index = lenth;index > 2;index--){ + + //Toast.makeText(webviewActivity.this,"index="+index,Toast.LENGTH_SHORT).show(); + System.out.println("index="+index); + + + try { + LinearLayout lineat1 = (LinearLayout)containerFrame.getChildAt(index); + if(lineat1==null){ + Toast.makeText(NewwebviewActivity.this,"view为空",Toast.LENGTH_SHORT).show(); + }else{ + + lineat1.removeAllViews(); + //lineat1.setVisibility(View.GONE); + containerFrame.removeView(lineat1); + } + + + + }catch (Exception e){ + System.out.println("出现异常==="+e.toString()); + Toast.makeText(NewwebviewActivity.this,"出现异常",Toast.LENGTH_SHORT).show(); + } + + } + + } + mRtcEngine.leaveChannel(); + + + } + + + } + } + + private void initAgoraEngineAndJoinChannel() { + + + runOnUiThread(new Runnable() { + @Override + public void run() { + if(videomap1!=null&&videomap1.size()>0){ + videomap1.clear(); + + }else{ + videomap1=new HashMap(); + } + mymDragVideoinfoBean=new DragVideoinfoBean(); + + initializeAgoraEngine(); // Tutorial Step 1 + setupVideoProfile(); // Tutorial Step 2 + setupLocalVideo(); // Tutorial Step 3 + joinChannel(); // Tutorial Step 4 + } + }); + + + } + + + + int myuid; + + + private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() { // Tutorial Step 1 + @Override + public void onFirstRemoteVideoDecoded(final int uid, int width, int height, int elapsed) { // Tutorial Step 5 +// runOnUiThread(new Runnable() { +// @Override +// public void run() { +// System.out.println("远端视频接收解码回调otheruid=="+uid); +// +// videotext.setText(videotext.getText()+"\n uid="+uid); +// +// // setupRemoteVideo(uid); +// +// String Level = "javascript:getVideoinfo(" + "'" +// + uid + "'"+ ");"; +// +// webviewjh(Level); +// +// } +// }); + } + //onFirstRemoteVideoFrame + // 远端视频显示回调 + @Override + public void onFirstRemoteVideoFrame(int uid, int width, int height, int elapsed) { + super.onFirstRemoteVideoFrame(uid, width, height, elapsed); + System.out.println("远端视频显示回调=="+uid); + } + //本地视频显示回调 + + @Override + public void onFirstLocalVideoFrame(int width, int height, int elapsed) { + super.onFirstLocalVideoFrame(width, height, elapsed); + } + + @Override + public void onUserOffline(final int uid, int reason) { // Tutorial Step 7 + runOnUiThread(new Runnable() { + @Override + public void run() { + + System.out.println("其他用户离开频道回调"+uid); + onRemoteUserLeft(uid); + } + }); + } + + @Override + public void onUserMuteVideo(final int uid, final boolean muted) { // Tutorial Step 10 + System.out.println("其他用户已停发已重发视频流uid=="+uid+"---"+muted); + + runOnUiThread(new Runnable() { + @Override + public void run() { + if(!muted){ + //videotext.setVisibility(View.VISIBLE); + }else{ + //videotext.setVisibility(View.GONE); + } + onRemoteUserVideoMuted(uid, muted); + } + }); + } + + @Override + public void onUserEnableVideo(int uid, boolean enabled) { + super.onUserEnableVideo(uid, enabled); + //提示有其他用户启用/关闭了视频功能。 + // 关闭视频功能是指该用户只能进行语音通话,不能显示、发送自己的视频,也不能接收、显示别人的视频。 + + } + + @Override + public void onJoinChannelSuccess(String channel, int uid, int elapsed) { + NewwebviewActivity.this.myuid=uid; + + System.out.println("加入频道回调myuid="+NewwebviewActivity.this.myuid); + + super.onJoinChannelSuccess(channel, uid, elapsed); + } + @Override + public void onRejoinChannelSuccess(String channel, int uid, int elapsed) { + System.out.println("网络状况下重新加入频道回调myuid="+NewwebviewActivity.this.myuid); + + } + + @Override + public void onUserJoined(final int uid, int elapsed) { + System.out.println("其他用户加入频道回调"+uid); + runOnUiThread(new Runnable() { + @Override + public void run() { + + + videotext.setText(videotext.getText()+"\n uid="+uid); + + // setupRemoteVideo(uid); + +// String Level = "javascript:getVideoinfo(" + "'" +// + uid + "'"+ ");"; +// +// webviewjh(Level); + x5webview.callHandler("getVideoinfo", "" + uid, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + + } + }); + super.onUserJoined(uid, elapsed); + } + + @Override + public void onLeaveChannel(RtcStats stats) { + + System.out.println("用户离开频道回调"); + } + }; + + private void onRemoteUserLeft(int uid) { + if(mRtcEngine!=null){ + if(videomap1!=null){ + try{ + int uindex= videomap1.get(uid); + LinearLayout view=(LinearLayout) containerFrame.getChildAt(uindex); + System.out.println("containerFrame控件数量"+containerFrame.getChildCount()); + System.out.println("view"+view.getChildCount()); + view.removeAllViews(); + + // SurfaceView surfaceView= (SurfaceView) view.getChildAt(0); + + // view.indexOfChild(child) 获取当前view再父容器下标 + + if(view!=null&& view.getChildCount()>0){ + System.out.println("getChildCount()"+view.getChildCount()); + view.setVisibility(View.GONE); + } + if(view!=null){ + containerFrame.removeView(view); + } + System.out.println("containerFrame控件数量"+containerFrame.getChildCount()); + + if(mDragViewvideo.getVisibility()==View.VISIBLE){ + int did=(int)mDragViewvideo.getTag(); + if(did==uid){ + if(mlinearvideo.getChildCount()>0){ + mlinearvideo.removeAllViews(); + } + mDragViewvideo.setVisibility(View.GONE); + } + } + + }catch (Exception e){ + + } + + + + //RelativeGroup.removeViewAt(uindex); + } + } + + } + + + private void onRemoteUserVideoMuted(int uid, boolean muted){ + if(mRtcEngine!=null){ + if(videomap1!=null){ + if(videomap1.containsKey(uid)){ + int uindex= videomap1.get(uid); + LinearLayout view=(LinearLayout) containerFrame.getChildAt(uindex); + + + // view.indexOfChild(child) 获取当前view再父容器下标 + + if(view!=null&& view.getChildCount()>0){ + //mDragViewvideo没有显示 + SurfaceView surfaceView= (SurfaceView) view.getChildAt(0); + + if(!muted){ + surfaceView.setVisibility(View.VISIBLE); + }else{ + + surfaceView.setVisibility(View.GONE); + } + } + if(view!=null){//mDragViewvideo显示 + + if(mDragViewvideo.getVisibility()==View.VISIBLE){ + + + int did=(int)mDragViewvideo.getTag(); + if(did==uid){ + if(mlinearvideo.getChildCount()>0){ + SurfaceView surfaceView=(SurfaceView)mlinearvideo.getChildAt(0); + + if(!muted){ + surfaceView.setVisibility(View.VISIBLE); + }else{ + surfaceView.setVisibility(View.GONE); + } + } + +// operatevideo1(uid); + +// if(mlinearvideo.getChildCount()>0){ +// mlinearvideo.removeAllViews(); +// } +// +// // mDragViewvideo.setVisibility(View.GONE); + } + } + + } + + } + + + //RelativeGroup.removeViewAt(uindex); + } + } + + + } + + Map videomap1;//uid index父控件下标 + + //Map videomap;//uid index父控件下标 + + // Tutorial Step 5 + private void setupRemoteVideo(int uid,Othervideoinfo mOthervideoinfo) { + if(videomap1!=null){ + System.out.println("videomap1不为空"); +// if(!videomap1.containsKey(uid)){ + if(videomap1.containsKey(uid)){ + System.out.println("videomap1含有uid="+uid); + }else{ + System.out.println("videomap1不含有uid="+uid); + } + initotherviiodeo(uid,mOthervideoinfo); + + }else{ + System.out.println("videomap1为空"); + } + + + + + } + private boolean mDragViewvideoIsshow=false; + private void initotherviiodeo(int uid,Othervideoinfo mOthervideoinfo){ + System.out.println("containerFram子控件数量"+containerFrame.getChildCount()); + + LinearLayout autoviewGroup=new LinearLayout(this); + int w=Stringtoint(mOthervideoinfo.getWidth()); + int h=Stringtoint(mOthervideoinfo.getHeight()); + w=getsizeh(w); + h=getsizeh(h); + RelativeLayout.LayoutParams lay=new RelativeLayout.LayoutParams(w, h); + + int left=Stringtoint(mOthervideoinfo.getLeft()); + int top=Stringtoint(mOthervideoinfo.getTop()); + left=getsizew(left); + top=getsizeh(top); + + System.out.println("---w="+w+"h="+h+"left="+left+"top="+top); + + lay.leftMargin=left; + + lay.topMargin=top; + autoviewGroup.setLayoutParams(lay); + + SurfaceView surfaceView = RtcEngine.CreateRendererView(getBaseContext()); + + surfaceView.setZOrderMediaOverlay(true); + LinearLayout.LayoutParams itempicparams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1); + + surfaceView.setLayoutParams(itempicparams); + + mRtcEngine.setupRemoteVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_HIDDEN, uid)); + + surfaceView.setTag(uid); + autoviewGroup.setTag(uid); + + //surfaceView.setClickable(false); + //autoviewGroup.setClickable(true); + autoviewGroup.addView(surfaceView); + surfaceView.setClickable(false); + autoviewGroup.setClickable(true); + + autoviewGroup.setOnClickListener(new View.OnClickListener(){ + + @Override + public void onClick(View v) { + + // Toast.makeText(webviewActivity.this, containerFrame.getChildCount()+"点击", Toast.LENGTH_LONG).show(); + try { + int uid1=(int)v.getTag(); + + if(mDragViewvideoIsshow){ + updatevideo(uid1); + } + + + }catch(Exception e){ + + } + + } + }); + +// //autoviewGroup.setBackgroundColor(Color.parseColor("#F5F5DC")); + + containerFrame.addView(autoviewGroup); + + int uindex=containerFrame.getChildCount()-1; + + videomap1.put(uid, uindex); + // videomap.put(String.valueOf(uid),String.valueOf(uindex)); +// }else{ +// System.out.println("videomap1含有uid="+uid); +// } + } + + private RtcEngine mRtcEngine;// Tutorial Step 1 + + // Tutorial Step 1 + private void initializeAgoraEngine() { + try { + + if(mRtcEngine==null){ + mRtcEngine = RtcEngine.create(getBaseContext(), getString(R.string.agora_app_id), mRtcEventHandler); + } + + } catch (Exception e) { + Log.e("", Log.getStackTraceString(e)); + + throw new RuntimeException("NEED TO check rtc sdk init fatal error\n" + Log.getStackTraceString(e)); + } + } + + // Tutorial Step 2 + private void setupVideoProfile() { + mRtcEngine.enableVideo(); + mRtcEngine.setVideoProfile(io.agora.rtc.Constants.VIDEO_PROFILE_360P, false); + } + public static int getScreenWidth(Activity activity) { + return activity.getWindowManager().getDefaultDisplay().getWidth(); + } + public static int getScreenHeight(Activity activity) { + return activity.getWindowManager().getDefaultDisplay().getHeight(); + } + int pmw=0; + int pmh=0; + + public void getAndroiodScreenProperty() { + if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.JELLY_BEAN_MR1){ + DisplayMetrics dm1= new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getRealMetrics(dm1); + + pmw = dm1.widthPixels; // 屏幕宽 + pmh = dm1.heightPixels; // 屏幕高 + + }else{ + + Display display = getWindowManager().getDefaultDisplay(); + DisplayMetrics dm = new DisplayMetrics(); + @SuppressWarnings("rawtypes") + Class c; + try { + c = Class.forName("android.view.Display"); + @SuppressWarnings("unchecked") + Method method = c.getMethod("getRealMetrics", DisplayMetrics.class); + method.invoke(display, dm); + pmh = dm.heightPixels; + pmw = dm.widthPixels; + } catch (Exception e) { + e.printStackTrace(); + } + + } + + + + +//不含虚拟状态栏宽高 +// WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE); +// DisplayMetrics dm = new DisplayMetrics(); +// wm.getDefaultDisplay().getMetrics(dm); +// int width = dm.widthPixels; // 屏幕宽度(像素) +// +// int height = dm.heightPixels; // 屏幕高度(像素) +// +// float density = dm.density; // 屏幕密度(0.75 / 1.0 / 1.5) +// int densityDpi = dm.densityDpi; // 屏幕密度dpi(120 / 160 / 240) +// // 屏幕宽度算法:屏幕宽度(像素)/屏幕密度 +// int screenWidth = (int) (width / density); // 屏幕宽度(dp) +// int screenHeight = (int) (height / density);// 屏幕高度(dp) +// +// +// pmh=height; +// pmw=width; +// System.out.println("屏幕宽度(像素):" + width); +// System.out.println("屏幕高度(像素):" + height); +// System.out.println("屏幕密度(0.75 / 1.0 / 1.5):" + density); +// System.out.println("屏幕密度dpi(120 / 160 / 240):" + densityDpi); +// System.out.println("屏幕宽度(dp):" + screenWidth); +// System.out.println("屏幕高度(dp):" + screenHeight); +// +// Log.d("h_bl", "屏幕宽度(像素):" + width); +// Log.d("h_bl", "屏幕高度(像素):" + height); +// Log.d("h_bl", "屏幕密度(0.75 / 1.0 / 1.5):" + density); +// Log.d("h_bl", "屏幕密度dpi(120 / 160 / 240):" + densityDpi); +// Log.d("h_bl", "屏幕宽度(dp):" + screenWidth); +// Log.d("h_bl", "屏幕高度(dp):" + screenHeight); + } + + + /** + * + * @param length 长度 + * @return 返回根据比例缩放长度 + */ + public int getsizeh(int length){ + double scale=(double)pmh/720; + System.out.println("scale=="+scale); + double size=scale*length; + System.out.println("size=="+size); + return (int)size; + } + + /** + * + * @param length 长度 + * @return 返回根据比例缩放长度 + */ + public int getsizew(int length){ + double scale=(double)pmw/1280; + System.out.println("scale=="+scale); + double size=scale*length; + System.out.println("size=="+size); + return (int)size; + } + + + // Tutorial Step 3 + private void setupLocalVideo() { + + System.out.println("w="+getScreenWidth(this)+"h="+getScreenHeight(this)); + + System.out.println(mvideoinfobean.toString()); + + + LinearLayout autoviewGroup=new LinearLayout(this); + int w=Stringtoint(mvideoinfobean.getWidth()); + int h=Stringtoint(mvideoinfobean.getHeight()); + w=getsizeh(w); + h=getsizeh(h); + + RelativeLayout.LayoutParams lay=new RelativeLayout.LayoutParams(w,h); + int left=Stringtoint(mvideoinfobean.getLeft()); + int top=Stringtoint(mvideoinfobean.getTop()); + System.out.println("---w="+w+"h="+h+"left="+left+"top="+top); + + left=getsizew(left); + top=getsizeh(top); + lay.leftMargin=left; + lay.topMargin=top; + System.out.println("---w="+w+"h="+h+"left="+left+"top="+top); + + autoviewGroup.setLayoutParams(lay); + + SurfaceView surfaceView = RtcEngine.CreateRendererView(getBaseContext()); + surfaceView.setZOrderMediaOverlay(true); + LinearLayout.LayoutParams itempicparams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1); + + surfaceView.setLayoutParams(itempicparams); + + int uid=Integer.parseInt(mvideoinfobean.getPlayerid()); + + + + + autoviewGroup.setOnClickListener(new View.OnClickListener(){ + + @Override + public void onClick(View v) { + + // Toast.makeText(webviewActivity.this, containerFrame.getChildCount()+"点击", Toast.LENGTH_LONG).show(); + try { + int uid1=(int)v.getTag(); + + if(mDragViewvideoIsshow){ + updatevideo(uid1); + } + }catch(Exception e){ + + } + + } + }); + autoviewGroup.setTag(uid); + surfaceView.setTag(uid); +/** + * 当前用户视频移动悬浮框数据初始化 + */ + mymDragVideoinfoBean.setUid(uid); + mymDragVideoinfoBean.setVideoimg(true); + mymDragVideoinfoBean.setVoiceimg(true); + + autoviewGroup.addView(surfaceView); + containerFrame.addView(autoviewGroup); + System.out.println("显示本地视频"); + int uindex1=containerFrame.getChildCount()-1; + videomap1.put(uid,uindex1); + surfaceView.setClickable(false); + autoviewGroup.setClickable(true); + + //autoviewGroup.setFocusable(true); + mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_HIDDEN, uid)); + } + + + public void updatevideo(int uid){ + if(mDragViewvideo.getTag()==null){ + mDragViewvideo.setTag(uid); + mvideoimg.setTag(uid); + mvoiceimg.setTag(uid); + + }else{ + int vuid=(int)mDragViewvideo.getTag(); + mDragViewvideo.setTag(uid); + + mvideoimg.setTag(uid); + mvoiceimg.setTag(uid); + + if(vuid==uid){ + //mDragViewvideo显示和用户视频信息一致 + if(mDragViewvideo.getVisibility()==View.GONE){ + mDragViewvideo.setVisibility(View.VISIBLE); + + System.out.println("key444444"+videomap1.get(vuid)); + operatevideo(vuid); + }else{ + mDragViewvideo.setVisibility(View.GONE); + operatevideo1(vuid); + } + + }else{ + //mDragViewvideo显示和用户视频信息不一致 + if(mDragViewvideo.getVisibility()==View.GONE){ + //mDragViewvideo必须隐藏之后再显示其他用户视频信息 + mDragViewvideo.setVisibility(View.VISIBLE); + operatevideo(uid); + }else{ + //mDragViewvideo + operatevideo1(vuid); + operatevideo(uid); + } + } + } + + } + + DragVideoinfoBean mymDragVideoinfoBean; + + + public void videoimgClicked(View view){ + if(view.getTag()!=null){ + int uid=(int)view.getTag(); + if(mymDragVideoinfoBean.getUid()==uid){ + ImageView imageview=(ImageView)view; + int isok=-1; + SurfaceView surfaceView=(SurfaceView)mlinearvideo.getChildAt(0); + + if(mymDragVideoinfoBean.isVideoimg()){ + + isok=mRtcEngine.muteLocalVideoStream(true);//暂停本地视频 + + if(isok==0){ + imageview.setImageResource(R.mipmap.a1); + if(surfaceView!=null){ + surfaceView.setVisibility(View.INVISIBLE); + } + + mymDragVideoinfoBean.setVideoimg(false); + } + + + }else{ + isok=mRtcEngine.muteLocalVideoStream(false);//开始本地视频 + if(isok==0){ + if(surfaceView!=null){ + surfaceView.setVisibility(View.VISIBLE); + } + + imageview.setImageResource(R.mipmap.a2); + mymDragVideoinfoBean.setVideoimg(true); + } + + + } + + + } + + } + + + } + + public void voiceimgClicked(View view){ + if(view.getTag()!=null){ + int uid=(int)view.getTag(); + if(mymDragVideoinfoBean.getUid()==uid){ + ImageView imageview=(ImageView)view; + + if(mymDragVideoinfoBean.isVoiceimg()){ + int isok=-1; + isok=mRtcEngine.muteLocalAudioStream(true);//暂停本地音频 + + if(isok==0){ + imageview.setImageResource(R.mipmap.a3); + + mymDragVideoinfoBean.setVoiceimg(false); + } + + + }else{ + int isok=-1; + isok=mRtcEngine.muteLocalAudioStream(false);//开始本地音频 + if(isok==0){ + imageview.setImageResource(R.mipmap.a4); + mymDragVideoinfoBean.setVoiceimg(true); + } + + } + + + } + + } + + } + + @PermissionSuccess(requestCode = 111) + public void videosuccess() { + Gson gson1=new Gson(); + + try { + mvideoinfobean=gson1.fromJson(videouserinfo, videoinfobean.class); + + if(!pmutil.isnullorEmpty(mvideoinfobean.getRoomid())){ + initAgoraEngineAndJoinChannel(); + } + + } catch (Exception e) { + // TODO: handle exception + } + } + + @PermissionFail(requestCode = 111) + public void videofail(){ + List nopermission = new ArrayList(); + for (int i = 0; i < vidopermission.length; i++) { + if (ActivityCompat.shouldShowRequestPermissionRationale( + NewwebviewActivity.this, vidopermission[i])) { + // 未勾选不再提示 + System.out.println("拒绝"); + nopermission.add(vidopermission[i]); + + + } else { + // 勾选不再提示 + if (ContextCompat.checkSelfPermission(this, vidopermission[i]) == PackageManager.PERMISSION_DENIED) { + showMissingPermissionDialog(); + break; + } + } + } + + + if (nopermission.size() > 0) { + + final String[] persions = new String[nopermission.size()]; + + for (int i = 0; i < nopermission.size(); i++) { + persions[i] = nopermission.get(i); + } + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("提示"); + builder.setMessage("亲,当前应用缺少必要权限。不打开将无法使用功能"); + + // 拒绝, 退出应用 + builder.setNegativeButton("退出", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + + } + }); + + builder.setPositiveButton("打开", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + PermissionGen.needPermission(NewwebviewActivity.this, + 111, persions); + } + }); + builder.show(); + } + + } + + + public void operatevideo(int uid){ + + + initDragvideo(uid); + + if(videomap1!=null){ + System.out.println("key1111111111"+videomap1.get(uid)); + int uindex=videomap1.get(uid); + + + + LinearLayout autoviewGroup=(LinearLayout)containerFrame.getChildAt(uindex); + + SurfaceView surfaceView=(SurfaceView)autoviewGroup.getChildAt(0); + autoviewGroup.removeAllViews(); + + if(mlinearvideo.getChildCount()>0){ + mlinearvideo.removeAllViews(); + } + if(mymDragVideoinfoBean.getUid()==uid){ + mvideoimgGroup.setVisibility(View.VISIBLE); + }else{ + mvideoimgGroup.setVisibility(View.GONE); + } + surfaceView.setClickable(false); + mlinearvideo.addView(surfaceView); + } + } + + /** + * + * @param uid 初始化视频悬浮按钮 + */ + public void initDragvideo(int uid){ + if(mymDragVideoinfoBean.getUid()==uid){ + if(mymDragVideoinfoBean.isVideoimg()){ + mvideoimg.setImageResource(R.mipmap.a2); + + }else{ + mvideoimg.setImageResource(R.mipmap.a1); + } + + if(mymDragVideoinfoBean.isVoiceimg()){ + mvoiceimg.setImageResource(R.mipmap.a4); + }else{ + mvoiceimg.setImageResource(R.mipmap.a3); + } + + } + + } + public void operatevideo1(int uid){ + if(videomap1!=null){ + + if(mlinearvideo.getChildCount()>0){ + + SurfaceView surfaceView=(SurfaceView)mlinearvideo.getChildAt(0); + mlinearvideo.removeAllViews(); + int uindex=videomap1.get(uid); + LinearLayout autoviewGroup=(LinearLayout)containerFrame.getChildAt(uindex); + + + if(autoviewGroup.getChildCount()>0){ + autoviewGroup.removeAllViews(); + } + + if(mymDragVideoinfoBean.getUid()==uid){ + if(!mymDragVideoinfoBean.isVideoimg()){ + surfaceView.setVisibility(View.GONE); + }else{ + surfaceView.setVisibility(View.VISIBLE); + } + + } + autoviewGroup.addView(surfaceView); + + } + } + } + + // Tutorial Step 4 + private void joinChannel() { + + String str=mvideoinfobean.getAgentid()+mvideoinfobean.getGameid()+mvideoinfobean.getRoomid(); + //String Channel=str.substring(str.length()-64); + String Channel=MD5(str); + + + int uid=Integer.parseInt(mvideoinfobean.getPlayerid()); + + mRtcEngine.joinChannel(null, Channel, "Extra Optional Data", uid); // if you do not specify the uid, we will generate the uid for you + } + private String MD5(String sourceStr) { + String result = ""; + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + md.update(sourceStr.getBytes()); + byte b[] = md.digest(); + int i; + StringBuffer buf = new StringBuffer(""); + for (int offset = 0; offset < b.length; offset++) { + i = b[offset]; + if (i < 0) + i += 256; + if (i < 16) + buf.append("0"); + buf.append(Integer.toHexString(i)); + } + result = buf.toString(); + System.out.println("MD5(" + sourceStr + ",32) = " + result); + + System.out.println("MD5(" + sourceStr + ",16) = " + buf.toString().substring(8, 24)); + } catch (NoSuchAlgorithmException e) { + System.out.println(e); + } + + return result; + } + + public int Stringtoint(String d){ + int a=(int)Double.parseDouble(d); + + return a; + + } + private static Long papredate=System.currentTimeMillis(); + + class settings { + /*** + * js 调用授权登陆 + */ +// @JavascriptInterface +// public void accreditlogin() { +// // Toast.makeText(webviewActivity.this, "调用授权", 1).show(); +// System.out.println("newwebview调用授权"); +// if (Wxistrue.islogin) { +// Wxistrue.islogin = false;// 暂停授权登陆 +// apputil.wxtype = 2; +// WXLogin(); +// } +// } +// @JavascriptInterface +// public void accreditlogin(String logintype) { +// System.out.println("调用登录="+logintype); +// Wxistrue.islogin = false;// 暂停授权登陆 +// apputil.wxtype = 2; +// // 全局回调类,游戏自行实现 +// +// if (logintype.equals("1")) { +// //QQ登录 +// // QQLogin(); +// }else{ +// //微信登录 +// WXLogin(); +// } +// } + + +// @JavascriptInterface +// public void getphoneInfo() { +// +// h5handler.sendEmptyMessage(3); +// +// } + /*** + * 进入或者创建房间(聊天频道) + */ +// @JavascriptInterface +// public void createRoom(String userinfo) { +// System.out.println("调用创建加入频道--"+userinfo); +// System.out.println("控件数量="+containerFrame.getChildCount()); +// if(userinfo!=null){ +// Message msg=new Message(); +// msg.what=1; +// msg.obj=userinfo; +// h5handler.sendMessage(msg); +// } +// +// } + + /*** + * 点击视频框 是否显示悬浮框 1 显示悬浮框 2 不显示 + */ + +// @JavascriptInterface +// public void DragViewvideoIsshow(String type) { +// if(type.equals("1")){ +// mDragViewvideoIsshow=true; +// }else{ +// mDragViewvideoIsshow=false; +// } +// +// +// } + + /*** + * 退出房间(聊天频道) + */ +// @JavascriptInterface +// public void exitRoom(String userinfo){ +// System.out.println("退出房间--"+userinfo); +// +// +// +// if(userinfo!=null){ +// Message msg=new Message(); +// msg.what=2; +// msg.obj=userinfo; +// h5handler.sendMessage(msg); +// } +// +// } + +// @JavascriptInterface +// public void getVideoinfo(String videoinfo){ +// if(videoinfo!=null){ +// Message msg=new Message(); +// msg.what=0; +// msg.obj=videoinfo; +// h5handler.sendMessage(msg); +// } +// +// } + /*** + * 打开第三方应用 + */ +// @JavascriptInterface +// public void openApplyDownloadpath(String packagename, +// String downloadpath) { +// try { +// PackageManager packageManager = getPackageManager(); +// Intent intent = new Intent(); +// intent = packageManager.getLaunchIntentForPackage(packagename); +// startActivity(intent); +// } catch (Exception e) { +// e.printStackTrace(); +// Intent viewIntent = new Intent("android.intent.action.VIEW", +// Uri.parse(downloadpath)); +// startActivity(viewIntent); +// } +// +// } + +// /** +// * +// * @param type +// */ +// @JavascriptInterface +// public void voicePlaying(String type) { +// +// if (type.equals("1")) { +// Settingutil.voicePlaying = true; +// +// } else { +// Settingutil.voicePlaying = false; +// } +// +// } + +// @JavascriptInterface +// public void srcIsloop(String src, String type) { +// +// Message msg = new Message(); +// +// Bundle bun = new Bundle(); +// bun.putString("src", src); +// bun.putString("type", type); +// msg.setData(bun); +// playwav.sendMessage(msg); +// +// } + +// @JavascriptInterface +// public String getOther() { +// return getAllFilename("other"); +// } +// +// @JavascriptInterface +// public String getothername(String name) { +// return getAllFilename(name); +// } +// +// /*** +// * 复制到剪切板 +// * +// * @param text +// */ +// @JavascriptInterface +// public void gameCopytext(String text) { +// ClipboardManager copy = (ClipboardManager) NewwebviewActivity.this +// .getSystemService(Context.CLIPBOARD_SERVICE); +// ClipData clipData = ClipData.newPlainText("TextLabel", text); +// copy.setPrimaryClip(clipData); +// } +// +// /*** +// * +// * 获取粘贴内容 +// * +// */ +// @JavascriptInterface +// public String gamepastetext() { +// +// ClipboardManager clipboardManager = (ClipboardManager) NewwebviewActivity.this +// .getSystemService(Context.CLIPBOARD_SERVICE); +// String message = (String) clipboardManager.getPrimaryClip() +// .getItemAt(0).getText(); +// +// return message; +// +// } + +// @JavascriptInterface +// public String getmarketname() { +// System.out.println(getAllFilename("market")); +// return getAllFilename("market"); +// } + +// @JavascriptInterface +// public void browser(String browserurl) { +// +// +// Intent intent = new Intent(); +// intent.setAction("android.intent.action.VIEW"); +// Uri content_url = Uri.parse(browserurl); +// if(BrowserUtil.isQQBrowserInstalled()){ +// intent.setClassName("com.tencent.mtt","com.tencent.mtt.MainActivity");//打开QQ浏览器 +// }else{ +// } +// intent.setData(content_url); +// startActivity(intent); +// +// +// } + +// @JavascriptInterface +// public void paybrowser(String browserurl) { +// Message msg=new Message(); +// msg.what=1; +// Bundle bundle=new Bundle(); +// bundle.putString("browserurl",browserurl); +// msg.setData(bundle); +// mpaybrow.sendMessage(msg); +// +// +// } + + + +// @JavascriptInterface +// public void getphoto(String photo) { +// +// System.out.println(photo); +// if (!pmutil.isnullorEmpty(photo)) { +// System.out.println("isdownloadphoto=" + isdownloadphoto); +// if (getphotoistrue) { +// savephoto(photo); +// } else { +// System.out.println("#############"); +// +// Message msg = new Message(); +// msg.what = 1; +// Bundle bundel = new Bundle(); +// bundel.putString("photo", photo); +// msg.setData(bundel); +// photohandler.sendMessageDelayed(msg, 200); +// } +// } else { +// String msg = "传递头像json数组为空"; +// String procket = "nn"; +// +// // commitLog.commitLog(NewwebviewActivity.this, msg, procket); +// } +// } + + /*** + * js 调用微信分享 朋友圈或好友 + * + * webpageUrl 分享链接地址 title 分享标题 description 分享描述 + */ + +// @JavascriptInterface +// public void friendsSharetypeUrlToptitleDescript(String friendtype, +// String type, String webpageUrl, String title, String description) { +// +// System.out.println("分享"); +// +// if(mandServer.isRunning()){ +// System.out.println("构建AndServer并启动服务器"); +// }else{ +// System.out.println("构建AndServer并启动服务器失败"); +// } +// +// // Toast.makeText(webviewActivity.this, "调用分享"+description, +// // Toast.LENGTH_LONG) +// // .show(); +// +// System.out.println("Wxistrue.isshare=" + Wxistrue.isshare +// + "friendtype=" + friendtype); +// +// System.out.println("type=" + type); +// System.out.println("webpageUrl=" + webpageUrl); +// +// /** +// * 不能重复点击 +// * +// */ +// savehandler.postDelayed(new Runnable() { +// @Override +// public void run() { +// Wxistrue.isshare=true; +// +// } +// },3000); +// +// +// if (Wxistrue.isshare) { +// Wxistrue.isshare = false; +// +// WXEntryActivity.setshareHandler(handler); +// bean = new sharetypeBean(); +// bean.setSharefriend(friendtype); +// bean.setTitle(title); +// bean.setWebpageUrl(webpageUrl); +// bean.setDescription(description); +// bean.setType(type); +// System.out.println(bean.toString()); +// +// if (bean.getSharefriend().equals("1")) { +// friend(); +// System.out.println("friend分享"); +// } else { +// sharefriends(); +// System.out.println("sharefriends分享"); +// } +// +// if (bean.getType().equals("2")) { +// System.out.println("图片分享"); +// // photo(); +// +// } +// } +// +// } +// +// @JavascriptInterface +// public long getTime() { +// return System.currentTimeMillis(); +// } +// +// @JavascriptInterface +// public void vibrator(long time) { +// VibratorUtil.getInstance(NewwebviewActivity.this).vibrate(time); +// } +// +// @JavascriptInterface +// public int getcompareCode() { +// +// return apputil.code; +// } + +// @JavascriptInterface +// public String getnetwork() { +// String type = "1"; +// +// boolean isnetwork = apputil +// .isNetworkConnected(NewwebviewActivity.this); +// if (isnetwork) { +// +// boolean iswifi = apputil +// .isNetworkAvailable(NewwebviewActivity.this); +// if (iswifi) { +// type = "2"; +// +// } else { +// type = "3"; +// } +// } +// +// +// +// return type; +// +// } +// +// @JavascriptInterface +// public void repeatvibrator(int repeat) { +// +// VibratorUtil.getInstance(NewwebviewActivity.this).repeatVibrate( +// repeat); +// } +// +// /** +// * 取消震动 +// */ +// @JavascriptInterface +// public void canclevibrator() { +// VibratorUtil.getInstance(NewwebviewActivity.this).cancle(); +// } +// +// @JavascriptInterface +// public void orientation(int Orientation) { +// /** +// * 1 为横屏 2 为竖屏 +// */ +// if (Orientation == 1) { +// setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); +// } else { +// setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); +// } +// +// } +// /** +// * 获取通讯录联系人列表 +// */ +// @JavascriptInterface +// public void getAddressBook(){ +// h5handler.sendEmptyMessage(4); +// } +// +// @JavascriptInterface +// public void cancleAudio() { +// System.out.println("取消"); +// +// } +// +// @JavascriptInterface +// public int getphonestate() { +// // Toast.makeText(webviewActivity.this, "*****" + phonestate(), 1) +// // .show(); +// return phonestate(); +// } +// +// /** +// * 截屏 +// */ +// @JavascriptInterface +// public void jieping(String photo) { +// System.out.println(photo); +// saveBase64(photo); +// +// } + + /** + * 获取电量 + * + */ +// @JavascriptInterface +// public float getbattery() { +// IntentFilter ifilter = new IntentFilter( +// Intent.ACTION_BATTERY_CHANGED); +// Intent batteryStatus = registerReceiver(null, ifilter); +// +// // 当前剩余电量 +// int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, +// -1); +// // 电量最大值 +// int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, +// -1); +// // 电量百分比 +// float batteryPct = (level / (float) scale); +// return batteryPct; +// } +// +// @JavascriptInterface +// public void sharephotourl(String sharetype, String url) { +// // Toast.makeText(webviewActivity.this, url, 1).show(); +// +// final String type = sharetype; +// if (Wxistrue.isphotoshare) { +// Wxistrue.isphotoshare = false; +// +// ImageRequest imageRequest = new ImageRequest( +// url, +// new com.android.volley.Response.Listener() { +// @Override +// public void onResponse(Bitmap response) { +// +// File file; +// +// if (Environment.getExternalStorageState() +// .equals(Environment.MEDIA_MOUNTED)) { +// // sd卡存储(/mnt/sdcard/cache) +// file = Environment +// .getExternalStorageDirectory();// 获取跟目录 +// } else { +// // 没有SD卡,缓存到系统存储 +// file = Environment.getDataDirectory(); +// } +// bitmappath = file.getAbsolutePath() +// + File.separator + "photo.png"; +// +// try { +// FileOutputStream fos = new FileOutputStream( +// bitmappath); +// // bitmap.compress(CompressFormat.PNG, 100, +// // fos); +// // 压缩bitmap到输出流中 +// response.compress(CompressFormat.PNG, 100, +// fos); +// fos.flush(); +// fos.close(); +// // Wxistrue.isshare = true; +// +// Message msg = new Message(); +// Bundle data = new Bundle(); +// data.putString("bitpath", bitmappath); +// data.putString("type", type); +// +// msg.setData(data); +// +// savehandler.sendMessage(msg); +// +// } catch (FileNotFoundException e) { +// throw new InvalidParameterException(); +// } catch (IOException e) { +// +// e.printStackTrace(); +// } +// +// } +// }, 0, 0, Config.RGB_565, +// new com.android.volley.Response.ErrorListener() { +// @Override +// public void onErrorResponse(VolleyError error) { +// Wxistrue.isphotoshare = true; +// } +// }); +// volleymanager.getInstance().getmRequestQueue() +// .add(imageRequest); +// } else { +// +// } +// +// } + +// @JavascriptInterface +// public void prepareaudio() { +// +// +// paprehandler.sendEmptyMessage(1); +// +// +// } + +// @JavascriptInterface +// public void backgameData(String data) { +// Intent in = new Intent(); +// Bundle bundle = new Bundle(); +// bundle.putString("data", data); +// +// in.putExtras(bundle); +// in.setClass(NewwebviewActivity.this, webviewActivity.class); +// in.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); +// setResult(101, in); +// +// exitApp(); +// } + +// @JavascriptInterface +// public void SwitchOverGameData(String webtype, String Gamedirectory, +// String gamedownloadurl, String data) { +// +// // Toast.makeText( +// // webviewActivity.this, +// // "webtype" + webtype + "Gamedirectory=" + Gamedirectory +// // + "gamedownloadurl=" + gamedownloadurl, 1).show(); +// initgame(webtype, Gamedirectory, gamedownloadurl, data); +// +// } + +// @JavascriptInterface +// public void OpenurlTitleData(String url, String title, String data) { +// +// +// Intent in = new Intent(); +// +// in.putExtra("url", url); +// in.putExtra("title", title); +// in.putExtra("data", data); +// +// +// in.setClass(NewwebviewActivity.this, openwebActivity1.class); +// startActivityForResult(in, 1002); +// +// } + +// @JavascriptInterface +// public void OpenurlTitleData(String url, String title, String data,String orientation) { +// //int orientation = 0; 横屏 +// // int orientation = 1; 竖屏 +// Intent in = new Intent(); +// +// in.putExtra("url", url); +// in.putExtra("orientation", orientation); +// in.putExtra("title", title); +// in.putExtra("data", data); +// System.out.println("orientation="+orientation); +// +// System.out.println("url="+url+"title="+title+"data="+data); +// +// in.setClass(NewwebviewActivity.this, openwebActivity1.class); +// startActivityForResult(in, 1002); +// +// } +// @JavascriptInterface +// public void SwitchShake(String Voicetype) { +// +// // if(shaketype.equals("1")){ +// // apputil.shaketype=1;//關閉 +// // }else{ +// // apputil.shaketype=0;//打開 +// // } +// +// if (Voicetype.equals("1")) { +// apputil.Voicetype = 1;// 打開 +// } else { +// apputil.Voicetype = 0;// 關閉 +// } +// } + +// @JavascriptInterface +// public void startshake() { +// +// // if(shaketype.equals("1")){ +// // apputil.shaketype=1;//關閉 +// // }else{ +// // apputil.shaketype=0;//打開 +// // } +// // +// // if(Voicetype.equals("1")){ +// // apputil.Voicetype=1;//關閉 +// // }else{ +// // apputil.Voicetype=0;//打開 +// // } +// +// isShake = true; +// mShakeListener.start(); +// +// } +// +// @JavascriptInterface +// public void stopshake() { +// isShake = false; +// mShakeListener.stop(); +// +// } +// +// public void opensaoma() { +// permissionHandler.sendEmptyMessage(1); +// } +// +// @JavascriptInterface +// public void opencamera() { +// permissionHandler.sendEmptyMessage(2); +// } + +// @JavascriptInterface +// public String getlocationinfo() { +// String json = null; +// +// if (location != null) { +// Gson gson = new Gson(); +// json = gson.toJson(location); +// } +// +// return json; +// } + +// @JavascriptInterface +// public void startlocation(String locationtype) { +// +// if (locationtype.equals("1")) { +// iscontinuouslocation = true; +// } else { +// iscontinuouslocation = false; +// } +// +// if (!hasPermission(locationpermission)) { +// +// PermissionGen.needPermission(NewwebviewActivity.this, 19, +// locationpermission); +// +// } else { +// +// initlocation(); +// } +// } + +// @JavascriptInterface +// public void getwifisignalLevel() { +// +// getWifiInfo(); +// +// if (isfinsh) { +// String Level = "javascript:getwifiLevel(" + "'" +// + wifibean.getSsid() + "'" + ",'" +// + wifibean.getSignalLevel() + "'" + ");"; +// webviewjh(Level); +// } +// } + +// @JavascriptInterface +// public void mediaTypeAudio(String audiourl, String type, String user) { +// +// Boolean boo = MediaFile.isAudioFileType(audiourl); +// +// if (!pmutil.isnullorEmpty(audiourl)) { +// if (boo) { +// if (type.equals("1")) { +// +// /** +// * 防止 播放多次调用 +// */ +// if (!isPlayaudio) { +// +// // playautio(audiourl, user); +// play(audiourl, user); +// } else { +// Message msg = new Message(); +// Bundle bundel = new Bundle(); +// bundel.putString("audiourl", audiourl); +// bundel.putString("user", user); +// msg.setData(bundel); +// playhandler.sendMessageDelayed(msg, 200); +// +// // playautio(audiourl, user); +// } +// } else { +// if (!isPlayaudio) { +// // isPlaying = true; +// play(audiourl, user); +// } +// } +// } +// } +// } + +// @JavascriptInterface +// public String getchannelName() { +// return getAllFilename("channel"); +// } + +// @JavascriptInterface +// public void finsh() { +// +// exitApp(); +// } + } + + @PermissionSuccess(requestCode = 19) + public void succeslocation() { + initlocation(); + } + + public String webtype = "1"; + + public String datas = null; + + public void initgame(String webtype, String gamedirectory, + String gamedownloadurl, String data) { + + Settingutil.initgame = gamedirectory; + //int orientation = 3; 横屏 + // int orientation = 2; 竖屏 + Intent in = new Intent(); + in.putExtra("data", data); + in.putExtra("orientation", webtype); + in.putExtra("gamedirectory", gamedirectory); + in.putExtra("gamedownloadurl", gamedownloadurl); + in.setClass(NewwebviewActivity.this, NewwebviewActivity.class); + startActivityForResult(in, 100); + + this.data = data; + + + + } + + private void Downloadgame(String gamedirectory, String gamedownloadurl) { + + try { + runzip(gamedownloadurl, this, gamedirectory); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void runzip(final String url, Context context, + final String gamedirectory) throws Exception { + + // + + System.out.println("url="+url+"gamedirectory="+gamedirectory); + + Request request = new Request.Builder().url(url).build(); + okclient.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(Call arg0, IOException throwable) { + throwable.printStackTrace(); + titlemsg="3852"; + handlerd.sendEmptyMessage(2); + } + + @SuppressWarnings("resource") + @Override + public void onResponse(Call arg0, Response response) + throws IOException { + if (response.code() == 200) { + + long length = response.body().contentLength(); + progressBar.setMax((int) length);// 设置进度条的最大值 + + if (!response.isSuccessful()) + throw new IOException("Unexpected code " + response); + Headers responseHeaders = response.headers(); + for (int i = 0; i < responseHeaders.size(); i++) { + System.out.println(responseHeaders.name(i) + ": " + + responseHeaders.value(i)); + } + + InputStream is = null; + byte[] buf = new byte[2048]; + int len = 0; + FileOutputStream fos = null; + is = response.body().byteStream(); + if (Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED)) { + // 获取SDCard的路径 + destFileDir = Environment.getExternalStorageDirectory() + .getAbsoluteFile() + + File.separator + + "dowlod_zip"; + } else { + destFileDir = Environment.getDataDirectory() + .getAbsolutePath() + + File.separator + + "dowlod_zip"; + } + destFileDir = Util.GetFileAbsolutePath()+ File.separator + + "dowlod_zip"; + File dir = new File(destFileDir); + if (!dir.exists()) { + + dir.mkdirs(); + } + + final File file = new File(dir, System.currentTimeMillis() + + ".zip"); + System.out.println(file.getAbsolutePath()); + fos = new FileOutputStream(file); + int count = 0; + + NumberFormat nf = NumberFormat.getInstance(); + nf.setMaximumFractionDigits(2);// 保留一位小数 + + double msum = ((int) length / 1024.0 / 1024.0); + final String msums = nf.format(msum) + " MB"; + + while ((len = is.read(buf)) != -1) { + fos.write(buf, 0, len); + count += len; + + final int num = count; + + if (length > 0) { + progressBar.setProgress(num); + progresshanler.post(new Runnable() { + + @Override + public void run() { + + NumberFormat nf = NumberFormat + .getInstance(); + nf.setMaximumFractionDigits(2);// 保留一位小数 + double num1 = (num / 1024.0 / 1024.0); + final String nums = nf.format(num1) + " MB"; + + textView1.setText("" + nums + "/" + msums); + } + }); + } + + // Message message2 = new Message(); + // message2.what = 2; + // message2.arg1 = progre; + // progresshanler.sendMessageDelayed(message2, 10); + + } + + fos.flush(); + fos.close(); + + final String urls = SpUtil.getStringSharedPerference( + Shared, "urlpath"); + + progresshanler.post(new Runnable() { + + @Override + public void run() { + + textView1.setText("解压中..."); + + } + }); + + try { + + new Thread() { + public void run() { + + + Fileutils.deleteDir(gamedirectory);// 删除解压文件 + + try { + ZipUtils.upZipFile1(file, urls + + File.separator); + + Fileutils.deleteDir(destFileDir);// 删除游戏zip包 + Message msg = new Message(); + msg.what = 1; + Bundle data = new Bundle(); + data.putString("gamedirectory", + gamedirectory); + + msg.setData(data); + + progresshanler.sendMessage(msg); + + } catch (ZipException e) { + titlemsg="3982"; + handlerd.sendEmptyMessage(2); + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + titlemsg="3987"; + handlerd.sendEmptyMessage(2); + // TODO Auto-generated catch block + e.printStackTrace(); + }catch (Exception e) { + titlemsg="3992"; + handlerd.sendEmptyMessage(2); + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + }.start(); + + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + titlemsg="4004"; + handlerd.sendEmptyMessage(2); + } + + // progresshanler.post(new Runnable() { + // @Override + // public void run() { + // textView1.setText("加载中..."); + // + // } + // }); + + // progresshanler.postDelayed(new Runnable() { + // @Override + // public void run() { + // + // + // } + // }, 100); + } else { + titlemsg="4025"; + handlerd.sendEmptyMessage(2); + } + + } + + }); + } + + public void updategamezip(String strurl, String gameid, int type) { + jsongame1(strurl, gameid, type); + + } + + private void jsongame1(String strurl, String gameid, int type) { + + + String gameconfig = getAllFilename("gameconfig"); + gameconfig = gameconfig.replaceAll("-", "/"); + + if (!pmutil.isnullorEmpty(gameconfig)) { + Gamesettingurl.configofficialurl = "http://" + gameconfig + ".txt"; + System.out.println("Gamesettingurl.configofficialurl=" + + Gamesettingurl.configofficialurl); + + Gamesettingurl.configofficialurl = "http://" + + gameconfig + ".txt"; + } + + String url = Gamesettingurl.configofficialurl; + + + + url = url + "?a=" + System.currentTimeMillis(); + + + Long gameconfigtime=SpUtil.getLongSharedPerference(sp,"gameconfigtime"); + Long time=System.currentTimeMillis(); + long time1=1000*60*10;//10分钟 + + + try { + Gson fson = new Gson(); + String s=SpUtil.getStringSharedPerference(sp,"gameconfig"); + + mJsonRootBean = fson.fromJson(s, + JsonRootBean.class); + + + + + if(time-gameconfigtime>time1){ + //获取配置文件频率大于10分钟重新获取 + System.out.println("获取配置文件频率大于10分钟重新获取"); + updateapk2(url, strurl, gameid, type,1); + }else{ + if(mJsonRootBean.getGamelist()!=null){ + //处理2.0配置 + chulisuoyin(strurl,gameid,type); + }else{ + //处理1.0配置 + gameversiontxt = fson.fromJson(s, + Gameversiontxt.class); + + if (type == 1) { + downloadgame3(strurl, gameid); + } else { + + downloadgame2(strurl, gameid); + + + } + + + } + } + + }catch(Exception e){ + + } + + + + + + } + + + + public void chulisuoyin(String gamedirectory,String gameid,int type){ + apputil.Showmessage = ""; + String agentid = getAllFilename("agent"); + + + setshowmessage(mJsonRootBean.getShowmessage()); + if(!pmutil.isnullorEmpty(gameid)&&!pmutil.isnullorEmpty(agentid)){ + for(int i=0;i versionagentinfo = gameversiontxt.getAgentlist(); + //String urlpath = SpUtil.getStringSharedPerference(sp, "urlpath"); + String purl = mulu; + System.out.println("purl=" + purl); + + versionbean versd = pullxml1(purl); + + if (versd == null || pmutil.isnullorEmpty(versd.getVersion())) { + + uptadata1++; + if(uptadata>uptadata1){ + int type = 2; + System.out.println("gamedownloadurl=" + mulu); + updategamezip(mulu, gameid, type);//重新下载 + }else{ + showMissingsettingDialog1("解压失败含中文,请退出重新进入"); + } + + + } else { + System.out.println(versd.toString()); + String agentid = getAllFilename("agent"); + String channel = getAllFilename("channel"); + String marketname = getAllFilename("market"); + System.out.println(getAllFilename("market")); + System.out.println("channel===" + channel); + int xmlgamecode = 0; + try { + xmlgamecode = Integer.parseInt(versd.getVersion()); + } catch (Exception e) { + + } + if (!pmutil.isnullorEmpty(channel)) { + versd.setChannelid(channel); + } + + boolean isgameutil = false; + + System.out.println("进入配置文件"); + + for (int k = 0; k < versionagentinfo.size(); k++) { + + if (versionagentinfo.get(k).getAgentid().equals(agentid)) { + + System.out.println("代理id匹配"); + setshowmessage(versionagentinfo.get(k).getShowmessage()); + + List info = gameversiontxt.getAgentlist() + .get(k).getGamelist(); + + for (int i = 0; i < info.size(); i++) { + gamelistTxt gamelistfo = info.get(i); + + if (gamelistfo.getGameid() + .equals(versd.getGameid())) { + System.out.println("游戏id匹配"); + + setshowmessage(gamelistfo.getShowmessage()); + + String newgame_zip = ""; + String newgame_version = ""; + + if (!pmutil.isnullorEmpty(gamelistfo + .getGame_zip())) { + newgame_zip = gamelistfo.getGame_zip(); + } + + if (!pmutil.isnullorEmpty(gamelistfo + .getGame_version()) + && !gamelistfo.getGame_version() + .equals("0")) { + newgame_version = gamelistfo + .getGame_version(); + } + System.out.println("游戏newgame_version=" + + newgame_version + "newgame_zip=" + + newgame_zip); + List info1 = gamelistfo + .getChannellist(); + for (int j = 0; j < info1.size(); j++) { + channellistTxt info2 = info1.get(j); + + String Channelid = info2.getChannelid(); + + if (Channelid.equals(versd.getChannelid())) { + List marketlist = info2 + .getMarketlist(); + + setshowmessage(info2.getShowmessage()); + + System.out.println("渠道id匹配"); + + if (!pmutil.isnullorEmpty(info2 + .getGame_zip())) { + newgame_zip = info2.getGame_zip(); + + } + + if (!pmutil.isnullorEmpty(info2 + .getGame_version()) + && !info2.getGame_version() + .equals("0")) { + newgame_version = info2 + .getGame_version(); + } + + System.out.println("渠道newgame_version=" + + newgame_version + + "newgame_zip=" + newgame_zip); + for (int f = 0; f < marketlist.size(); f++) { + marketlistTxt marketinfo = marketlist + .get(f); + + System.out.println("marketname=" + + marketname); + System.out.println(marketinfo + .toString()); + + if (marketinfo.getMarketid() + .equals(marketname)) { + System.out.println("市场id 匹配"); + + setshowmessage(marketinfo + .getShowmessage()); + + if (!pmutil + .isnullorEmpty(apputil.Showmessage)) { + + showMissingsettingDialog(apputil.Showmessage); + + } else { + + isgameutil = true; + + int gameversioncode = 0; + + try { + if (!pmutil + .isnullorEmpty(newgame_version)) { + gameversioncode = Integer + .parseInt(newgame_version); + + } + + } catch (Exception e) { + + } + + // 版本 + if (!pmutil + .isnullorEmpty(marketinfo + .getGame_version()) + && !marketinfo + .getGame_version() + .equals("0")) { + gameversioncode = Integer + .parseInt(marketinfo + .getGame_version());// 游戏 + } + + boolean isupdate = false; + System.out + .println("gameversioncode=" + + gameversioncode + + "xmlgamecode=" + + xmlgamecode); + if (gameversioncode > xmlgamecode) { + + String gamezipurl = ""; + + if (!pmutil + .isnullorEmpty(marketinfo + .getGame_zip())) { + gamezipurl = marketinfo + .getGame_zip(); + + } else { + + gamezipurl = newgame_zip; + + } + + try { + if (!pmutil + .isnullorEmpty(gamezipurl)) { + + + progressBar.setVisibility(View.VISIBLE); + runzip(gamezipurl + + "?a=" + + System.currentTimeMillis(), + NewwebviewActivity.this, + mulu); + System.out + .println("游戏下载" + + gamezipurl); + } else { + System.out + .println("游戏下载地址为空"); + titlemsg="4408"; + handlerd.sendEmptyMessage(2); + + } + + } catch (Exception e) { + // TODO + // Auto-generated + // catch block + e.printStackTrace(); + } + + } else { + + handlerend1(mulu); + + } + + } + + break; + } + + } + + // + } + + } + } + + } + + } else { + + } + + } + + if (!isgameutil) { + if (!pmutil.isnullorEmpty(apputil.Showmessage)) { + showMissingsettingDialog(apputil.Showmessage); + } else { + titlemsg="4452"; + handlerd.sendEmptyMessage(2); + } + + } + } + } + + + protected void downloadgame2(String gamedirectory, String gameid) { + + + + + + try { + boolean isdown = false; + + + System.out.println("gameid=" + gameid); + + String marketname = getAllFilename("market"); + + String agentid = getAllFilename("agent"); + String channelID = getAllFilename("channel"); + List versionagentinfo = gameversiontxt.getAgentlist(); + String download = ""; + for (int k = 0; k < versionagentinfo.size(); k++) { + + if (versionagentinfo.get(k).getAgentid().equals(agentid)) { + System.out.println("agentid匹配"); + List info = gameversiontxt.getAgentlist() + .get(k).getGamelist(); + for (int i = 0; i < info.size(); i++) { + gamelistTxt gamelistfo = info.get(i); + System.out.println("游戏id" + gamelistfo.getGameid()); + if (gamelistfo.getGameid().equals(gameid)) { + System.out.println("游戏id匹配"); + if (!pmutil.isnullorEmpty(gamelistfo.getGame_zip())) { + download = gamelistfo.getGame_zip(); + System.out.println("download----" + download); + } + List info1 = gamelistfo + .getChannellist(); + + for (int j = 0; j < info1.size(); j++) { + channellistTxt info2 = info1.get(j); + System.out.println(info2.toString()); + if (info2.getChannelid().equals(channelID)) { + + if (!pmutil.isnullorEmpty(info2 + .getGame_zip())) { + download = info2.getGame_zip(); + System.out.println("download----" + + download); + } + System.out.println("渠道id匹配"); + List marketlist = info2 + .getMarketlist(); + + for (int f = 0; f < marketlist.size(); f++) { + marketlistTxt text = marketlist.get(f); + if (text.getMarketid().equals( + marketname)) { + System.out.println("市场id匹配"); + + if (!pmutil.isnullorEmpty(text + .getGame_zip())) { + + download = text.getGame_zip(); + System.out + .println("download----" + + download); + } + if (!pmutil.isnullorEmpty(download)) { + isdown = true; + + progressBar.setVisibility(View.VISIBLE); + + Downloadgame( + gamedirectory, + download + + "?a=" + + System.currentTimeMillis()); + + System.out + .println("gamedirectory=" + + gamedirectory + + "下载地址" + + download); + } else { + + titlemsg="4972"; + handlerd.sendEmptyMessage(2); + + } + + break; + } + } + + } + + } + + } + + } + + } + } + + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + titlemsg="4998"; + handlerd.sendEmptyMessage(2); + + } + + } + + private void updateapk2(String url, final String gamedirectory, + final String gameid, final int type,final int what) { + + CacheControl.Builder builder = new CacheControl.Builder(); + builder.noCache();// 不使用缓存,全部走网络 + CacheControl cacheControl = builder.build(); + + Request request1 = new Request.Builder().cacheControl(cacheControl) + .url(url).build(); + Request request = new Request.Builder().url(url).build(); + okclient.newCall(request1).enqueue(new Callback() { + + @Override + public void onResponse(Call arg0, Response response) + throws IOException { + + System.out.println(response.code() + "sddddd" + + response.body().toString()); + + if (response.code() == 200) { + + InputStream is = null; + byte[] buf = new byte[1024]; + is = response.body().byteStream(); + StringBuilder sb = new StringBuilder(""); + int lens = 0; + //读取文件内容,当文件内容长度大于0时, + while ((lens = is.read(buf)) > 0) { + //把字条串连接到尾部 + sb.append(new String(buf, 0, lens)); + } + is.close(); + + String jsonstring = sb.toString(); + + + + + + try { + JSONObject json = new JSONObject(jsonstring); + System.out.println("---" + json.toString()); + +// Gson fson = new Gson(); +// +// gameversiontxt = fson.fromJson(jsonstring, +// Gameversiontxt.class); + + + + + System.out.println("---" + json.toString()); + Message msg=new Message(); + msg.what=what; + Bundle bundle=new Bundle(); + bundle.putString("msg",jsonstring); + bundle.putString("gamedirectory",gamedirectory); + bundle.putString("gameid",gameid); + bundle.putInt("type",type); + Logger.t("msg").v(jsonstring); + msg.setData(bundle); + hanlerq2.sendMessage(msg); + +// if (type == 1) { +// Message message = new Message(); +// message.what = 1; +// Bundle bun = new Bundle(); +// bun.putString("mulu", gamedirectory); +// bun.putString("gameid", gameid); +// +// message.setData(bun); +// +// hanlerq1.sendMessage(message); +// } else { +// Message msg = new Message(); +// msg.what = 1; +// +// Bundle bun = new Bundle(); +// bun.putString("gamedirectory", gamedirectory); +// bun.putString("gameid", gameid); +// msg.setData(bun); +// handlerd.sendMessage(msg); +// +// +// +// } + + } catch (Exception e) { + e.printStackTrace(); + + } + } else { + titlemsg="4155"; + handlerd.sendEmptyMessage(2); + + } + + } + + @Override + public void onFailure(Call arg0, IOException arg1) { + titlemsg="4169"; + titlemsg=titlemsg+arg1.getMessage()+"\n"+arg1.toString(); + handlerd.sendEmptyMessage(2); + } + }); + } + + public void inith5data(String url){ + + + + + url = url + File.separator+"app_data.js"; + + System.out.println("初始化前数据"+Fileutils.readFile(url)); + + + StringBuffer buffer=new StringBuffer(); + + + String app_version="var app_version=1;";//初始化框架加载方式 + buffer.append(app_version); + + + + String app_gameconfig = getAllFilename("gameconfig"); + app_gameconfig="var app_gameconfig='"+app_gameconfig+"';"; + buffer.append(app_gameconfig); + + String app_gamedir = getAllFilename("gamedir"); + app_gamedir="var app_gamedir='"+app_gamedir+"';"; + buffer.append(app_gamedir); + + + String app_gamestart = getAllFilename("gamestart"); + app_gamestart="var app_gamestart='"+app_gamestart+"';"; + buffer.append(app_gamestart); + + + String app_agent = getAllFilename("agent"); + app_agent="var app_agent='"+app_agent+"';"; + buffer.append(app_agent); + + + String app_appversion = getAllFilename("appversion"); + app_appversion="var app_appversion='"+app_appversion+"';"; + buffer.append(app_appversion); + + + String app_market = getAllFilename("market"); + app_market="var app_market='"+app_market+"';"; + buffer.append(app_market); + + + String app_channel = getAllFilename("channel"); + app_channel="var app_channel='"+app_channel+"';"; + buffer.append(app_channel); + + String app_invitationcode = getAllFilename("tuiguang"); + if(!pmutil.isnullorEmpty(app_invitationcode)){ + app_invitationcode="var app_invitationcode='"+app_invitationcode+"';"; + + }else{ + app_invitationcode="var app_invitationcode='';"; + System.out.println("app_invitationcode"+app_invitationcode); + } + + buffer.append(app_invitationcode); + + + String app_Launchtype = "1"; + app_Launchtype="var app_Launchtype='"+app_Launchtype+"';"; + buffer.append(app_Launchtype); + + + String app_gamename = getAllFilename("gamestart"); + app_gamename="var app_gamename='"+app_gamename+"';"; + buffer.append(app_gamename); + + String app_getwifisignalLevel="var app_getwifisignalLevel=1;"; + buffer.append(app_getwifisignalLevel); + + + //Fileutils.writeToFile(buffer.toString(),url); + + Fileutils.modifyFile(url,buffer.toString(),false); + + System.out.println("初始化后数据"+Fileutils.readFile(url)); + + + } + Handler progresshanler = new Handler() { + public void handleMessage(Message msg) { + switch (msg.what) { + case 1: + + String gamedirectory = msg.getData().getString("gamedirectory"); + + handlerend1(gamedirectory); + break; + // case 2: + // Downloadprogress.setProgress(msg.arg1); + // break; + // case 3: + // Downloadprogress.setText("下载已完成,解压中"); + // + // break; + // case 4: + // Downloadprogress.dismiss(); + // + // break; + case 5: + + break; + default: + break; + } + }; + }; + + public void setshowmessage(String Showmessage) { + if (!pmutil.isnullorEmpty(Showmessage)) { + apputil.Showmessage = Showmessage; + + } + } + + private int uptadata=3;//解压失败之后重新下载次数 + + private int uptadata1=0; + + + + + ConfigData mconfigData; + + public ConfigData getConfigData(){ + if(mconfigData==null){ + mconfigData=new ConfigData(); + mconfigData.setAgentid(getAllFilename("agent")); + mconfigData.setGameid(gameid); + mconfigData.setChannelid(getAllFilename("channel")); + String marketname = getAllFilename("market"); + mconfigData.setMarketid(marketname); + } + return mconfigData; + + + } + + @SuppressLint("HandlerLeak") + Handler hanlerq1 = new Handler() { + @Override + public void handleMessage(Message msg) { + apputil.Showmessage = ""; + Bundle bundle = msg.getData(); + + String mulu = bundle.getString("mulu"); + String gameid = bundle.getString("gameid"); + + int type = bundle.getInt("type");//游戏是否下载 1 已下载 2 未下载 + + + + String purl = mulu; + System.out.println("purl=" + purl); + + + Gson fson = new Gson(); + String s=SpUtil.getStringSharedPerference(sp,"magentlist"); + Agentlist magentlist=fson.fromJson(s, Agentlist.class); + + String s1=SpUtil.getStringSharedPerference(sp,"mgamelist"); + Gamelist mgamelist1=fson.fromJson(s1, Gamelist.class); + + ConfigData mconfigData=getConfigData(); + mconfigData.setGameid(gameid); + + GameupdateUtil util=new GameupdateUtil(); + + gameversionUtil agentconfig=util.agentUtil(mconfigData,magentlist,null); + gameversionUtil gameconfig=util.agentUtil(mconfigData,null,mgamelist1); + + + + + versionbean versd=null; + if(type==1){ + versd = pullxml1(purl); + + if (versd == null || pmutil.isnullorEmpty(versd.getVersion())) { + + uptadata1++; + if(uptadata>uptadata1){ + int typet = 2; + System.out.println("gamedownloadurl=" + mulu); + updategamezip(mulu, gameid, typet);//重新下载 + }else{ + showMissingsettingDialog1("解压失败含中文,请退出重新进入"); + } + + + }else{ + chulipeizhi(gameconfig,agentconfig,versd,mulu,type); + } + + }else{ + chulipeizhi(gameconfig,agentconfig,versd,mulu,type); + } + + + super.handleMessage(msg); + + } + }; + + public void chulipeizhi(gameversionUtil gameversionutil,gameversionUtil agentversionutil,versionbean versd,String mulu,int type){ + + String gamedownloadurl=""; + int gamedownloadversion=0; + + + //处理自游戏升级 + if(!pmutil.isnullorEmpty(gameversionutil.getGame_download())&&!pmutil.isnullorEmpty(agentversionutil.getGame_download())){ + //两个配置文件都配置了子游戏升级 取配置版本最高 + try{ + gamedownloadversion=Integer.parseInt(gameversionutil.getGame_version()); + gamedownloadurl=gameversionutil.getGame_download(); + if(Integer.parseInt(agentversionutil.getGame_version())>gamedownloadversion){ + gamedownloadversion=Integer.parseInt(agentversionutil.getGame_version()); + gamedownloadurl=agentversionutil.getGame_download(); + + }; + }catch (Exception e){ + + Logger.e("子游戏配置version格式版本问题",e); + } + + + + }else{ + try{ + if(!pmutil.isnullorEmpty(gameversionutil.getGame_download())){ + //两个配置文件都配置了app升级取配置版本最高都 + gamedownloadversion=Integer.parseInt(gameversionutil.getGame_version()); + gamedownloadurl=gameversionutil.getGame_download(); + } + }catch (Exception e){ + Logger.e("gameversionutil配置子游戏 version格式版本问题",e); + } + try{ + + if(!pmutil.isnullorEmpty(agentversionutil.getGame_download())){ + gamedownloadversion=Integer.parseInt(agentversionutil.getGame_version()); + gamedownloadurl=agentversionutil.getGame_download(); + } + }catch (Exception e){ + Logger.e("gameversionutil配置子游戏 version格式版本问题",e); + } + } + if(type==1){ + int xmlgamecode = Integer.parseInt(versd.getVersion()); + + if (gamedownloadversion > xmlgamecode) { + + + + progressBar.setVisibility(View.VISIBLE); + + + + + try{ + runzip(gamedownloadurl+"?a="+System.currentTimeMillis(),NewwebviewActivity.this,mulu); + }catch (Exception e){ + Logger.e("runzip",e); + + } + + + + + } else { + + handlerend1(mulu); + + } + }else{ + try{ + runzip(gamedownloadurl+"?a="+System.currentTimeMillis(),NewwebviewActivity.this,mulu); + }catch (Exception e){ + Logger.e("runzip",e); + + } + } + + + + + } + + // 配置缺失提示 + private void showMissingsettingDialog(final String title) { + runOnUiThread(new Runnable() { + @Override + public void run() { + AlertDialog.Builder builder = new AlertDialog.Builder(NewwebviewActivity.this); + builder.setTitle("提示"); + builder.setMessage(title); + + builder.setPositiveButton("退出", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + AlertDialog menuDialog = builder.create(); + // menuDialog.setCanceledOnTouchOutside(false); + menuDialog.setCancelable(false); + if (!NewwebviewActivity.this.isFinishing()) { + menuDialog.show(); + } + } + }); + + // builder.show(); + } + // 配置缺失提示 + private void showMissingsettingDialog1(final String title) { + runOnUiThread(new Runnable() { + @Override + public void run() { + AlertDialog.Builder builder = new AlertDialog.Builder(NewwebviewActivity.this); + builder.setTitle("提示"); + builder.setMessage(title); + + builder.setPositiveButton("退出", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + AlertDialog menuDialog = builder.create(); + // menuDialog.setCanceledOnTouchOutside(false); + menuDialog.setCancelable(false); + if (!NewwebviewActivity.this.isFinishing()) { + menuDialog.show(); + } + } + }); + + // builder.show(); + } + + + // 配置缺失提示 + private void showMissingsettingDialog() { + // AlertDialog menuDialog = new AlertDialog.Builder(this).create(); + runOnUiThread(new Runnable() { + @Override + public void run() { + AlertDialog.Builder builder = new AlertDialog.Builder(NewwebviewActivity.this); + builder.setTitle("提示"); + builder.setMessage("您好,获取配置信息失败,请重新启动应用code="+titlemsg); + + builder.setPositiveButton("退出", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + // builder.setCancelable(false); + AlertDialog menuDialog = builder.create(); + // menuDialog.setCanceledOnTouchOutside(false); + menuDialog.setCancelable(false); + menuDialog.show(); + }}); + } + + versionbean version1; + + private versionbean pullxml1(String urlpath) { + + try { + version1 = new versionbean(); + File file = new File(urlpath + File.separator + "version.xml"); + if (file.exists()) { + FileInputStream inputStream = new FileInputStream(file); + // 得到解析器 + XmlPullParser parser = Xml.newPullParser(); + // 2.设置解析的文件流 + parser.setInput(inputStream, "utf-8"); + // 3.得到事件类型(START_DOCUMENT,END_DOCUMENT,START_TAG, END_TAG, + // TEXT, etc.) + int type = parser.getEventType(); + // 一直读到文档结尾 + + while (type != XmlPullParser.END_DOCUMENT) { + + switch (type) { + case XmlPullParser.START_TAG: + // 得到标签的名字 + String tag_name = parser.getName(); + if ("agent".equals(tag_name)) { + // + String agentid = parser.getAttributeValue(null, + "id"); + System.out.println("agentid=" + agentid); + version1.setAgentid(agentid); + // String id = parser.getAttributeValue(0); + // 得到属性值id + } else if ("game".equals(tag_name)) { + String gameid = parser + .getAttributeValue(null, "id"); + System.out.println("gameid=" + gameid); + version1.setGameid(gameid); + } else if ("version".equals(tag_name)) { + + String version = parser.getAttributeValue(null, + "value"); + System.out.println("version=" + version); + version1.setVersion(version); + + } else if ("channel".equals(tag_name)) { + + String channelid = parser.getAttributeValue(null, + "id"); + version1.setChannelid(channelid); + } + break; + default: + break; + } + // 继续往下一个事件解析 + type = parser.next(); + } + } + } catch (IOException e) { + e.printStackTrace(); + } catch (XmlPullParserException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return version1; + + } + + String loadurl = ""; + + protected void handlerend1(String urlpath) { + inith5data(urlpath); + + progressBar.setMax(100); + progressBar.setProgress(100); + loadurl = urlpath + File.separator + "index.html?Launchtype=1"; + getinit(); + } + versionagentlist list1; + + Handler handlerd = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case 1: +// Bundle bun = msg.getData(); +// String gamedirectory = bun.getString("gamedirectory"); +// String gameid = bun.getString("gameid"); +// downloadgame2(gamedirectory, gameid); + break; + case 2: + if (!NewwebviewActivity.this.isFinishing()) { + showMissingsettingDialog(); + } + break; + default: + break; + } + + super.handleMessage(msg); + } + }; + + + private versionbean pullassetxml(InputStream inputStream) { + versionbean version2 = new versionbean(); + try { + XmlPullParser parser = Xml.newPullParser(); + // 2.设置解析的文件流 + parser.setInput(inputStream, "utf-8"); + // 3.得到事件类型(START_DOCUMENT,END_DOCUMENT,START_TAG, END_TAG, + // TEXT, etc.) + int type = parser.getEventType(); + // 一直读到文档结尾 + while (type != XmlPullParser.END_DOCUMENT) { + + switch (type) { + case XmlPullParser.START_TAG: + // 得到标签的名字 + String tag_name = parser.getName(); + if ("agent".equals(tag_name)) { + + String agentid = parser.getAttributeValue(null, "id"); + System.out.println("agentid=" + agentid); + version2.setAgentid(agentid); + + } else if ("game".equals(tag_name)) { + String gameid = parser.getAttributeValue(null, "id"); + System.out.println("gameid=" + gameid); + version2.setGameid(gameid); + } else if ("version".equals(tag_name)) { + + String version = parser + .getAttributeValue(null, "value"); + System.out.println("version=" + version); + version2.setVersion(version); + } + + break; + default: + break; + + } + // 继续往下一个事件解析 + type = parser.next(); + } + + } catch (XmlPullParserException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return version2; + } + + private boolean isgamedirectory(String gamedirectory) { + + boolean isdirectory = false; + + /** + * 获得解压目录 + */ + String url = SpUtil.getStringSharedPerference(Shared, "urlpath"); + File rile = new File(url); + + if (rile.exists()) { + + String[] path = rile.list(); + + for (int i = 0; i < path.length; i++) { + System.out.println(path[i]); + if (gamedirectory.equals(path[i])) { + isdirectory = true; + break; + } + } + + } + + return isdirectory; + + } + + @PermissionFail(requestCode = 19) + public void errorlocation() { + List nopermission = new ArrayList(); + // String[] nopermission=null; + for (int i = 0; i < locationpermission.length; i++) { + if (ActivityCompat.shouldShowRequestPermissionRationale(this, + locationpermission[i])) { + + nopermission.add(locationpermission[i]); + + // final String permission = carpermission[i]; + // 未勾选不再提示 + + System.out.println("拒绝"); + } else { + // 勾选不再提示 + if (ContextCompat.checkSelfPermission(this, + locationpermission[i]) == PackageManager.PERMISSION_DENIED) { + // showMissingPermissionDialog(); + break; + } + } + } + // if (nopermission.size() > 0) { + // + // final String[] persions = new String[nopermission.size()]; + // + // for (int i = 0; i < nopermission.size(); i++) { + // persions[i] = nopermission.get(i); + // } + // + // AlertDialog.Builder builder = new AlertDialog.Builder(this); + // builder.setTitle("提示"); + // builder.setMessage("亲,当前应用缺少必要权限。不打开将无法使用"); + // + // // 拒绝, 退出应用 + // builder.setNegativeButton("退出", + // new DialogInterface.OnClickListener() { + // @Override + // public void onClick(DialogInterface dialog, int which) { + // finish(); + // + // } + // }); + // + // builder.setPositiveButton("打开", + // new DialogInterface.OnClickListener() { + // @Override + // public void onClick(DialogInterface dialog, int which) { + // + // PermissionGen.needPermission( + // NewwebviewActivity.this, 19, persions); + // } + // }); + // builder.show(); + // } + + } + + public void playautio(String audiourl, String user) { + Message msg = new Message(); + Bundle bundel = new Bundle(); + bundel.putString("audiourl", audiourl); + bundel.putString("user", user); + msg.setData(bundel); + playhandler.sendMessageDelayed(msg, 100); + } + + public void initlocation() { + + // TODO Auto-generated method stub + // 初始化定位 + mLocationClient = new AMapLocationClient(getApplicationContext()); + + // 设置定位模式 + mLocationOption.setLocationMode(AMapLocationMode.Hight_Accuracy); + + if (!iscontinuouslocation) { + // 设置定位次数(在这里采用单次定位,true 单次定位false 连续定位) + mLocationOption.setOnceLocation(true); + // 设置为true,那么会返回最近3秒内定位精度最高的一次 + mLocationOption.setOnceLocationLatest(true); + } else { + mLocationOption.setOnceLocation(false); + mLocationOption.setInterval(5000); // 设置连续定位时间间隔 + } + + // 设置是否返回地理信息 + mLocationOption.setNeedAddress(true); + mLocationClient.setLocationOption(mLocationOption); + // 设置定位监听 + mLocationClient.setLocationListener(this); + mLocationClient.startLocation(); + } + + public void open() { + + startActivityForResult(new Intent(this, CaptureActivity.class), 100); + + } + + @PermissionSuccess(requestCode = 18) + public void succes() { + open(); + } + + @PermissionFail(requestCode = 18) + public void error() { + + if (ActivityCompat.shouldShowRequestPermissionRationale(this, + Manifest.permission.CAMERA)) { + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("提示"); + builder.setMessage("亲,扫一扫需要打开相机权限哦"); + + // 拒绝, 退出应用 + builder.setNegativeButton("不打开", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + } + }); + + builder.setPositiveButton("打开", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + PermissionGen.needPermission( + NewwebviewActivity.this, 18, + camerapermission); + } + }); + builder.show(); + + System.out.println("拒绝"); + } else { + // 勾选不再提示 + if (ContextCompat.checkSelfPermission(this, + Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED) { + showMissingPermissionDialog(); + } + } + + } + + public void saveBase64(String iconBase64) { + File file; + String bitmappath; + + if (Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED)) { + // sd卡存储(/mnt/sdcard/cache) + file = Environment.getExternalStorageDirectory();// 获取跟目录 + } else { + // 没有SD卡,缓存到系统存储 + file = Environment.getDataDirectory(); + } + file = Util.GetDirectory(); + bitmappath = file.getAbsolutePath() + File.separator + "photo.png"; + + // Bitmap sd=BitmapFactory.decodeResource(getResources(), + // R.drawable.ddd); + // Bitmap bit1=stringtoBitmap(bitmaptoString(sd)); + + Bitmap bit1 = stringtoBitmap(iconBase64); + + getScreenHot(bit1, bitmappath); + + } + + private void getScreenHot(Bitmap b1, String filePath) { + System.out.println(filePath); + if (b1 == null) { + System.out.println("-----"); + } + File file1 = new File(filePath); + try { + file1.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + + try { + try { + + FileOutputStream fos = new FileOutputStream(file1); + b1.compress(CompressFormat.PNG, 100, fos); + fos.flush(); + fos.close(); + } catch (FileNotFoundException e) { + throw new InvalidParameterException(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public Bitmap stringtoBitmap(String string) { + // 将字符串转换成Bitmap类型 + Bitmap bitmap = null; + try { + byte[] bitmapArray; + System.out.println(string); + bitmapArray = Base64.decode(string, Base64.DEFAULT); + bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0, + bitmapArray.length); + + } catch (Exception e) { + e.printStackTrace(); + } + return bitmap; + + } + + public String bitmaptoString(Bitmap bitmap) { + // 将Bitmap转换成字符串 + String string = null; + ByteArrayOutputStream bStream = new ByteArrayOutputStream(); + bitmap.compress(CompressFormat.PNG, 100, bStream); + byte[] bytes = bStream.toByteArray(); + string = Base64.encodeToString(bytes, Base64.DEFAULT); + return string; + } + + public void photo() { + jieping(); + } + + protected int dp2px(int dpval) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, + dpval, getResources().getDisplayMetrics()); + } + + protected int sp2px(int spval) { + + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, + spval, getResources().getDisplayMetrics()); + + } + + private void getScreenHot(View v1, String filePath) { + + View view1 = this.getWindow().getDecorView(); + view1.setDrawingCacheEnabled(true); + view1.buildDrawingCache(); + Bitmap b1 = view1.getDrawingCache(); + + File file1 = new File(filePath); + try { + file1.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + + try { + try { + FileOutputStream fos = new FileOutputStream(file1); + // bitmap.compress(CompressFormat.PNG, 100, fos); + // 压缩bitmap到输出流中 + b1.compress(CompressFormat.PNG, 100, fos); + fos.flush(); + fos.close(); + } catch (FileNotFoundException e) { + throw new InvalidParameterException(); + } + } catch (Exception e) { + e.printStackTrace(); + } + view1.setDrawingCacheEnabled(false); + } + + public static Bitmap changeColor(Bitmap bitmap) { + if (bitmap == null) { + return null; + } + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + int[] colorArray = new int[w * h]; + int n = 0; + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + int color = getMixtureWhite(bitmap.getPixel(j, i)); + colorArray[n++] = color; + } + } + return Bitmap.createBitmap(colorArray, w, h, Bitmap.Config.ARGB_8888); + } + + // 获取和白色混合颜色 + private static int getMixtureWhite(int color) { + int alpha = Color.alpha(color); + int red = Color.red(color); + int green = Color.green(color); + int blue = Color.blue(color); + return Color.rgb(getSingleMixtureWhite(red, alpha), + getSingleMixtureWhite(green, alpha), + getSingleMixtureWhite(blue, alpha)); + } + + // 获取单色的混合值 + private static int getSingleMixtureWhite(int color, int alpha) { + int newColor = color * alpha / 255 + 255 - alpha; + return newColor > 255 ? 255 : newColor; + } + + public Bitmap ratio(Bitmap image, float pixelW, float pixelH) { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + image.compress(Bitmap.CompressFormat.PNG, 100, os); + if (os.toByteArray().length / 1024 > 100) {// 判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出 + os.reset();// 重置baos即清空baos + image.compress(Bitmap.CompressFormat.PNG, 40, os);// 这里压缩50%,把压缩后的数据存放到baos中 + } + ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); + BitmapFactory.Options newOpts = new BitmapFactory.Options(); + // 开始读入图片,此时把options.inJustDecodeBounds 设回true了 + newOpts.inJustDecodeBounds = true; + newOpts.inPreferredConfig = Config.ARGB_8888; + Bitmap bitmap = BitmapFactory.decodeStream(is, null, newOpts); + newOpts.inJustDecodeBounds = false; + int w = newOpts.outWidth; + int h = newOpts.outHeight; + float hh = pixelH;// 设置高度为240f时,可以明显看到图片缩小了 + float ww = pixelW;// 设置宽度为120f,可以明显看到图片缩小了 + // 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可 + int be = 1;// be=1表示不缩放 + + if (w > h && w > ww) {// 如果宽度大的话根据宽度固定大小缩放 + be = (int) (newOpts.outWidth / ww); + } else if (w < h && h > hh) {// 如果高度高的话根据宽度固定大小缩放 + be = (int) (newOpts.outHeight / hh); + } + if (be <= 0) + be = 1; + newOpts.inSampleSize = be;// 设置缩放比例 + // 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了 + is = new ByteArrayInputStream(os.toByteArray()); + bitmap = BitmapFactory.decodeStream(is, null, newOpts); + // 压缩好比例大小后再进行质量压缩 + // return compress(bitmap, maxSize); // 这里再进行质量压缩的意义不大,反而耗资源,删除 + return bitmap; + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + switch (keyCode) { + + case KeyEvent.KEYCODE_BACK: + if (x5webview != null) { + + if (x5webview.canGoBack()) { + x5webview.goBack(); + } else { + + // moveTaskToBack(true);//不销毁当前activity + dialogexit.show(NewwebviewActivity.this, "是否返回游戏大厅", + new onexitlistener() { + @Override + public void paylistener() { + //String name = "javascript:backgameData();"; + + if (iswebviewerror) { + finish(); + + } else { + //webviewjh(name); + x5webview.callHandler("backgameData-", "", new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + + mhandler.postDelayed(new Runnable() { + @Override + public void run() { + + if (!NewwebviewActivity.this.isFinishing()) { + finish(); + } + + } + },500); + + } + + + + } + + @Override + public void cancellistener() { + + } + }); + } + } else { + exitApp(); + } + return true; + + default: + break; + } + + return super.onKeyDown(keyCode, event); + } + + public interface OnGetUserInfoListener { + void onGetUserInfo(String userInfo); // json字符串 + + void onNetError(); + } + + static class GetUserInfoTask extends AsyncTask { + + private OnGetUserInfoListener mListener; + private String mUrl; + + public GetUserInfoTask(OnGetUserInfoListener listener, + String getUserInfoUrl) { + mListener = listener; + mUrl = getUserInfoUrl; + } + + @Override + protected void onPreExecute() { + + super.onPreExecute(); + } + + @Override + protected String doInBackground(Object... params) { + HttpURLConnection conn = null; + BufferedReader in = null; + StringBuilder result = new StringBuilder(); + + try { + conn = (HttpURLConnection) new URL(mUrl).openConnection(); + in = new BufferedReader(new InputStreamReader( + conn.getInputStream(), "UTF-8")); + String buf; + while ((buf = in.readLine()) != null) + result.append(buf); + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (conn != null) + conn.disconnect(); + + // FileUtils.close(in); + } + return result.toString(); + } + + @Override + protected void onPostExecute(String s) { + Log.d("", "onPostExecute " + s); + mListener.onGetUserInfo(s); + } + } + + /** + * 查找JSON字符串中对应的结束引号,考虑转义字符 + */ + private int findClosingQuote(String json, int startPos) { + int pos = startPos; + while (pos < json.length()) { + char c = json.charAt(pos); + if (c == '"') { + // 检查是否是转义的引号 + int backslashCount = 0; + int checkPos = pos - 1; + while (checkPos >= 0 && json.charAt(checkPos) == '\\') { + backslashCount++; + checkPos--; + } + // 如果反斜杠数量是偶数,则这个引号没有被转义 + if (backslashCount % 2 == 0) { + return pos; + } + } + pos++; + } + return -1; // 没有找到结束引号 + } + + /** + * 从dataUrl中提取base64部分 + * dataUrl格式: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA... + */ + private String extractBase64FromDataUrl(String dataUrl) { + if (dataUrl == null || dataUrl.isEmpty()) { + return null; + } + + // 查找base64,标识符 + String base64Prefix = "base64,"; + int base64Start = dataUrl.indexOf(base64Prefix); + if (base64Start == -1) { + // 如果没有找到base64,前缀,可能整个字符串就是base64数据 + if (dataUrl.startsWith("data:image/")) { + return null; // 这是一个dataUrl但格式不正确 + } else { + // 假设整个字符串就是base64数据 + return dataUrl; + } + } + + // 提取base64部分 + String base64Data = dataUrl.substring(base64Start + base64Prefix.length()); + + // 验证base64数据的基本格式 + if (base64Data.length() > 0 && isValidBase64(base64Data)) { + return base64Data; + } + + return null; + } + + /** + * 简单验证base64字符串的格式 + */ + private boolean isValidBase64(String base64) { + if (base64 == null || base64.isEmpty()) { + return false; + } + + // base64只包含A-Z, a-z, 0-9, +, /, = 字符 + String base64Pattern = "^[A-Za-z0-9+/]*={0,2}$"; + return base64.matches(base64Pattern) && base64.length() % 4 == 0; + } + + /** + * 获取通话状态 + */ + public int phonestate() { + TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); + int phonestate = 0; + /** + * 返回电话状态 + * + * CALL_STATE_IDLE 无任何状态时 CALL_STATE_OFFHOOK 接起电话时 CALL_STATE_RINGING + * 电话进来时 + * + * + */ + if (tm.getCallState() == TelephonyManager.CALL_STATE_IDLE) { + Log.d("test", "call state idle..."); + phonestate = 0; + + } else if (tm.getCallState() == TelephonyManager.CALL_STATE_OFFHOOK) { + Log.d("test", "call state offhook..."); + phonestate = 1; + } else if (tm.getCallState() == TelephonyManager.CALL_STATE_RINGING) { + Log.d("test", "call state ringing..."); + phonestate = 2; + + } + return phonestate; + } + + private void getUserInfo(String accessToken, String openId) { + String url = "https://api.weixin.qq.com/sns/userinfo?" + + "access_token=" + accessToken + "&openid=" + openId; + GetUserInfoTask mGetUserInfoTask = new GetUserInfoTask( + new OnGetUserInfoListener() { + + @Override + public void onNetError() { + + } + + @Override + public void onGetUserInfo(String userInfo) { + // text.setText(userInfo); + // Toast.makeText(webviewActivity.this, userInfo, 1) + // .show(); + JSONObject object; + try { + object = new JSONObject(userInfo); + String url = object.optString("headimgurl"); + + String unionid = object.optString("unionid"); + String openid = object.optString("openid"); + String nickname = object.optString("nickname"); + String sex = object.optString("sex"); + String city = object.optString("city"); + + String country = object.optString("country"); + SpUtil.setStringSharedPerference(Shared, "country", + country); + + String province = object.optString("province"); + SpUtil.setStringSharedPerference(Shared, + "province", province); + + SpUtil.setStringSharedPerference(Shared, "unionid", + unionid); + SpUtil.setStringSharedPerference(Shared, + "headimgurl", url); + + SpUtil.setStringSharedPerference(Shared, "openid", + openid); + SpUtil.setStringSharedPerference(Shared, + "nickname", nickname); + SpUtil.setStringSharedPerference(Shared, "sex", sex); + SpUtil.setStringSharedPerference(Shared, "city", + city); + + handler.sendEmptyMessage(1); + + } catch (JSONException e) { + e.printStackTrace(); + } + + } + }, url); + + mGetUserInfoTask.execute(); + } + + /** + * 退出程序 + */ + private void exitApp() { + deleteAllFiles(); + finish(); + // System.exit(0); + } + + +// public String getAllFilename1(String name) { +// +// String channelname = ""; +// System.out.println("name=" + name); +// try { +// String[] filename = Myapplication.application.getAssets() +// .list(name); +// +// if (filename.length > 0) { +// +// System.out.println("目录长度" + filename.length); +// +// for (int i = 0; i < filename.length; i++) { +// +// System.out.println("=====" + filename[i]); +// +// if (filename[i].equals("BoolTest.java")) { +// String[] filename1 = Myapplication.application +// .getAssets().list( +// name + File.separator + filename[i]); +// System.out.println("0--" + filename1.length); +// } else { +// +// String[] name1 = Myapplication.application.getAssets() +// .list(name + File.separator + filename[i]); +// System.out.println("name1--" + name1.length); +// +// if (name1.length > 0) { +// channelname = filename[i]; +// } +// +// } +// +// } +// +// } else { +// System.out.println("找不到目录"); +// } +// +// } catch (IOException e) { +// +// e.printStackTrace(); +// } +// +// return channelname; +// +// } + + public String getAllFilename(String name) { + + String channelname = ""; + System.out.println("目录名" + name); + try { + String[] filename = Myapplication.application.getAssets() + .list(name); + + if (filename.length > 0) { + + System.out.println("目录长度" + filename.length); + + for (int i = 0; i < filename.length; i++) { + + System.out.println("=====" + filename[i]); + + if (filename[i].equals("BoolTest.java")) { + String[] filename1 = Myapplication.application + .getAssets().list( + name + File.separator + filename[i]); + System.out.println("0--" + filename1.length); + } else { + + String[] name1 = Myapplication.application.getAssets() + .list(name + File.separator + filename[i]); + System.out.println("name1--" + name1.length); + + if(name1.length>=1){ + System.out.println("name1--" + name1[0]); + } + + if (name1.length >= 0) { + channelname = filename[i]; + } + + } + + + } + + } else { + System.out.println("找不到目录"); + } + + } catch (IOException e) { + + e.printStackTrace(); + } + + return channelname; + + } + + public void deleteAllFiles() { + + try { + /** + * 删除下载音频文件 + */ + + if (destFileDir != null) { + Fileutils.deleteDir(destFileDir); + } + /** + * 删除录音音频文件 + */ + if (dirs != null) { + Fileutils.deleteDir(dirs); + } + + } catch (Exception e) { + // TODO: handle exception + } + + /** + * 删除下载头像图片 + * + */ + try { + if (photofile1 != null) { + + if (photofile1.exists()) { + System.out.println("-----" + photofile1.getAbsolutePath()); + File[] audiofiles = photofile1.listFiles(); + for (File file1 : audiofiles) { + file1.delete(); + } + } + } + }catch (Exception e) { + // TODO: handle exception + } + + + } + + protected void changeState(int stateWantToCancel) { + + if (mCurrentState != stateWantToCancel) { + mCurrentState = stateWantToCancel; + switch (mCurrentState) { + case STATE_NORMAL: + + break; + case STATE_RECORDING: + + if (isRecording) { + mDialogManager.recording(); + } + break; + + case STATE_WANT_TO_CANCEL: + mDialogManager.wantToCancel(); + break; + } + } + } + + protected boolean wantToCancel(int x, int y, int x1, int y1) { + + int mx = Math.abs(x1 - x); + int my = Math.abs(y1 - y); + + if (mx > 100 || my > 100) { + return true; + } + + return false; + + } + + private String buildTransaction(final String type) { + return (type == null) ? String.valueOf(System.currentTimeMillis()) + : type + System.currentTimeMillis(); + } + + // 获取音量大小的runnable + private Runnable mGetVoiceLevelRunnable = new Runnable() { + + @Override + public void run() { + + while (isRecording) { + try { + Thread.sleep(100); + mTime += 0.1f; + mhandler.sendEmptyMessage(MSG_VOICE_CHANGE); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + }; + + WeakHandler mhandler = new WeakHandler(new Handler.Callback() { + + @Override + public boolean handleMessage(Message msg) { + switch (msg.what) { + case MSG_AUDIO_PREPARED: + // 显示应该是在audio end prepare之后回调 + + isRecording = true; + + if (mDialogManager != null) { + try { + mDialogManager.showRecordingDialog(); + } catch (Exception e) { + // TODO: handle exception + } + + } + + System.out.println("isRecording" + isRecording); + new Thread(mGetVoiceLevelRunnable).start(); + + // 需要开启一个线程来变换音量 + break; + case MSG_VOICE_CHANGE: + mDialogManager.updateVoiceLevel(mAudioManager.getVoiceLevel(7)); + + break; + case MSG_DIALOG_DIMISS: + + mDialogManager.dimissDialog(); + + break; + case MSG_DIALOG_Audio_DIMISS: + + if (isRecording) { + System.out.println("重新关闭"); + mDialogManager.dimissDialog(); + mAudioManager.cancel(); + reset(); + + } else if (!isRecording && isautio) { + mhandler.sendEmptyMessageDelayed(MSG_DIALOG_Audio_DIMISS, + 1000);// 持续1.3 + } + + break; + + } + return false; + } + + }); + + /** + * 回复标志位以及状态 + */ + private void reset() { + // TODO Auto-generated method stub + + if (isStopPlay) { + isPlayaudio = false;// 可以继续播放 + } + + isStopPlay = false; + + isRecording = false; + mTime = 0; + isautio = false; + changeState(STATE_NORMAL); + +// String getaudiourl = "javascript:getaudiourl(" + "'" + 0 + "'" + ",'" +// + 0 + "'" + ");"; +// +// webviewjh(getaudiourl); + JSONObject json = new JSONObject(); + try { + json.put("audiourl", ""); + + json.put("time", 0); + x5webview.callHandler("getaudiourl", json.toString(), new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + + + }catch (Exception e){ + + } + + } + + public void webviewjh(final String name) { + runOnUiThread(new Runnable() { + @Override + public void run() { + + try { + if (x5webview != null) { + x5webview.loadUrl(name); + } + + } catch (Exception e) { + + // Toast.makeText(NewwebviewActivity.this, "" + + // e.toString(), 1) + // .show(); + commitLog.commitLog(NewwebviewActivity.this, "android登陆" + + name, e.toString()); + System.out.println(e.toString()); + } + } + }); + } + + // 在onStart() 之后 + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + + super.onRestoreInstanceState(savedInstanceState); + } + + // 当activity 被销毁时 + // 在onStop()之前调用, 文档中说并不保证在onPause()的之前还是之后 + // 我的试验中一般是在onPause()之后 + @Override + protected void onSaveInstanceState(Bundle outState) { + + // TODO Auto-generated method stub + super.onSaveInstanceState(outState); + System.out.println("调用onSaveInstanceState-----Newviewactivity"); + //Myapplication.getInstance().exit();//退出应用 + + outState.putString("configofficialurl",Gamesettingurl.configofficialurl); + + // outState.putString("initgame",Settingutil.initgame); + outState.putString("gamedirectory",gamedirectory1); + outState.putString("data",data); + + outState.putString("gameid",gameid); + outState.putString("gameid",gameid); + outState.putString("orientation",orientation); + + if (x5webview != null) { + + x5webview.saveState(outState); + } + } + + // 在这里面发送一个handler的消息 + @Override + public void wellPrepared() { + + System.out.println("wellPrepared"); + mhandler.sendEmptyMessage(MSG_AUDIO_PREPARED); + } + + @Override + public void onClick(View v) { + + } + + public MessageReceiver mMessageReceiver; + public static String ACTION_INTENT_RECEIVER = "com.gc.broadcast.receiver"; + + /** + * 动态注册广播 + */ + + public void registerMessageReceiver() { + mMessageReceiver = new MessageReceiver(); + IntentFilter filter = new IntentFilter(); + + filter.addAction(ACTION_INTENT_RECEIVER); + registerReceiver(mMessageReceiver, filter); + } + + public class MessageReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + // TODO Auto-generated method stub + if (intent.getAction().equals(ACTION_INTENT_RECEIVER)) { + int state = intent.getIntExtra("message", 0); + + // Toast.makeText(context, "---" + state, 1).show(); + +// String user = "javascript:phonestate(" + "'" + state + "'" +// + ");"; +// +// webviewjh(user); + + x5webview.callHandler("phonestate", ""+state, new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + + // x5webview.loadUrl("javascript:phonestate(" + "'" + state + // + "'" + ");"); + + } + } + + } + + @PermissionSuccess(requestCode = 101) + public void success() { + if (isDown) { + prepareAudio(); + } + } + + public void prepareAudio() { + + if (isPlayaudio) { + if (!pmutil.isnullorEmpty(uservoice)) { + isStopPlay = true; + MediaManager.release(); +// String gameui_stop_voice = "javascript:gameui_stop_voice(" +// + "'" + uservoice + "'" + ");"; +// webviewjh(gameui_stop_voice); + if(x5webview!=null){ + x5webview.callHandler("gameui_stop_voice", ""+uservoice, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + } + + + uservoice = ""; + + } + } + + long backPressed = System.currentTimeMillis(); + // + if (backPressed - lastBackPressed > QUIT_INTERVAL) { + lastBackPressed = backPressed; + System.out.println("准备录制"); + isautio = true; + mAudioManager.prepareAudio(); + }else{ + lastBackPressed = backPressed; + } + } + + @PermissionFail(requestCode = 101) + public void fail() { + + for (int i = 0; i < carpermission.length; i++) { + if (ActivityCompat.shouldShowRequestPermissionRationale( + NewwebviewActivity.this, carpermission[i])) { + // 未勾选不再提示 + System.out.println("拒绝"); + } else { + // 勾选不再提示 + if (ContextCompat.checkSelfPermission(this, carpermission[i]) == PackageManager.PERMISSION_DENIED) { + showMissingPermissionDialog(); + break; + } + } + } + } + + // 显示缺失权限提示 + private void showMissingPermissionDialog() { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("提示"); + builder.setMessage("当前应用缺少必要权限。请点击\"设置\"-\"权限\"-打开所需权限。"); + + // 拒绝, 退出应用 + builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + } + }); + + builder.setPositiveButton("设置", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + startAppSettings(); + } + }); + + builder.show(); + } + + // 启动应用的设置 + private void startAppSettings() { + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.parse(PACKAGE_URL_SCHEME + getPackageName())); + startActivity(intent); + } + + /** + * 为子类提供一个检查权限的方法 + * + * @param permissions + * @return + */ + public boolean hasPermission(String... permissions) { + for (String permission : permissions) { + if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { + return false; + + } + } + return true; + } + + @Override + public void onRequestPermissionsResult(int requestCode, + String[] permissions, int[] grantResults) { + + PermissionGen.onRequestPermissionsResult(this, requestCode, + permissions, grantResults); + } + + class BatteryReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + // 判断它是否是为电量变化的Broadcast Action + if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) { + // 获取当前电量 + int level = intent.getIntExtra("level", 0); + // 电量的总刻度 + int scale = intent.getIntExtra("scale", 100); + + // int Battery = ((level * 100) / scale); + // Toast.makeText(webviewActivity.this, Battery, 1).show(); + float batteryPct = (level / (float) scale); +// String getBattery = "javascript:getBattery(" + "'" + batteryPct +// + "'" + ");"; + if (isfinsh) { +// webviewjh(getBattery); + + x5webview.callHandler("getBattery", ""+batteryPct, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + //这里也是可以进行js回传的 + } + }); + + + } + + } + } + + } + + class WifiChangeBroadcastReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + System.out.println("Wifi发生变化"); + getWifiInfo(); + +// if (isfinsh) { +// String Level = "javascript:getwifiLevel(" + "'" +// + wifibean.getSsid() + "'" + ",'" +// + wifibean.getSignalLevel() + "'" + ");"; +// webviewjh(Level); +// } + + JSONObject json = new JSONObject(); + try { + json.put("ssidname", wifibean.getSsid()); + + json.put("signalLevel", wifibean.getSignalLevel()); + + System.out.println("---" + json.toString()); + if(x5webview!=null){ + x5webview.callHandler("getwifiLevel", json.toString(), new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + } + + + } catch (JSONException e) { + e.printStackTrace(); + } + + } + + } + + private class MyNetReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + + String action = intent.getAction(); + if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { + + mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + netInfo = mConnectivityManager.getActiveNetworkInfo(); + int type = 1; + + if (netInfo != null && netInfo.isAvailable()) { + + // ///////////网络连接 + String name = netInfo.getTypeName(); + + if (netInfo.getType() == ConnectivityManager.TYPE_WIFI) { + // ///WiFi网络 + type = 2; + } + // else + // if(netInfo.getType()==ConnectivityManager.TYPE_ETHERNET){ + // /////有线网络 + // + // } + else if (netInfo.getType() == ConnectivityManager.TYPE_MOBILE) { + // ///////3g网络 + type = 3; + } + } else { + // //////网络断开 + type = 1; + } + + // Toast.makeText(webviewActivity.this, "类型:"+type, 1).show(); + +// if (isfinsh) { +// String getnetwork = "javascript:getnetwork(" + "'" + type +// + "'" + ");"; +// webviewjh(getnetwork); +// } + if(x5webview!=null){ + x5webview.callHandler("getnetwork", ""+type, new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + } + + + } + + } + + } + + private void getWifiInfo() { + + WifiManager wifiManager = (WifiManager) this.getApplicationContext() + .getSystemService(WIFI_SERVICE); + WifiInfo wifiInfo = wifiManager.getConnectionInfo(); + if (wifiInfo.getBSSID() != null) { + // wifi名称 + String ssid = wifiInfo.getSSID(); + // wifi信号强度 0-4 弱到强 + + wifibean.setSsid(ssid); + + int signalLevel = WifiManager.calculateSignalLevel( + wifiInfo.getRssi(), 5); + + wifibean.setSignalLevel(signalLevel); + // Toast.makeText(this, "wifi 信号强度"+signalLevel , 1).show(); + + // wifi速度 + int speed = wifiInfo.getLinkSpeed(); + // wifi速度单位 + String units = WifiInfo.LINK_SPEED_UNITS; + System.out.println("ssid=" + ssid + ",signalLevel=" + signalLevel + + ",speed=" + speed + ",units=" + units); + } + } + + private ConnectivityManager mConnectivityManager; + private NetworkInfo netInfo; + + // private BroadcastReceiver myNetReceiver = new BroadcastReceiver() { + // + // @Override + // public void onReceive(Context context, Intent intent) { + // + // String action = intent.getAction(); + // if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { + // + // mConnectivityManager = (ConnectivityManager) + // getSystemService(Context.CONNECTIVITY_SERVICE); + // netInfo = mConnectivityManager.getActiveNetworkInfo(); + // int type = 1; + // + // if (netInfo != null && netInfo.isAvailable()) { + // + // // ///////////网络连接 + // String name = netInfo.getTypeName(); + // + // if (netInfo.getType() == ConnectivityManager.TYPE_WIFI) { + // // ///WiFi网络 + // type = 2; + // } + // // else + // // if(netInfo.getType()==ConnectivityManager.TYPE_ETHERNET){ + // // /////有线网络 + // // + // // } + // else if (netInfo.getType() == ConnectivityManager.TYPE_MOBILE) { + // // ///////3g网络 + // type = 3; + // } + // } else { + // // //////网络断开 + // type = 1; + // } + // + // // Toast.makeText(webviewActivity.this, "类型:"+type, 1).show(); + // + // x5webview.loadUrl("javascript:getnetwork(" + "'" + type + "'" + // + ");"); + // } + // + // } + // }; + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent date) { + super.onActivityResult(requestCode, resultCode, date); + if (requestCode == RESULT_OK) { + Bundle bu = date.getExtras(); + String text = bu.getString("result"); +// String webjh = "javascript:getsaomaData(" + "'" + text + "'" + ");"; +// webviewjh(webjh); + if(x5webview!=null){ + x5webview.callHandler("getsaomaData",text,new CallBackFunction(){ + @Override + public void onCallBack(String data) { + + } + }); + } + + } + if (resultCode == 101) { + Bundle bu = date.getExtras(); + String text = bu.getString("data"); + System.out.println("网页回调给字游戏=" + text); + if(x5webview!=null){ + x5webview.callHandler("getWebdata", text, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + } + +// String getWebdata = "javascript:getWebdata(" + "'" + text + "'" +// + ");"; +// webviewjh(getWebdata); + + } + } + + @Override + public void onLocationChanged(AMapLocation amapLocation) { + + getuserlocationinfo(amapLocation); + } + + MaplocationInfo location; + + private void getuserlocationinfo(AMapLocation amapLocation) { + location = new MaplocationInfo(); + + location.setLatitude(amapLocation.getLatitude());// 获取纬度 + + amapLocation.getLocationType();// 获取当前定位结果来源,如网络定位结果,详见定位类型表 + + location.setLongitude(amapLocation.getLongitude());// 获取经度 + + amapLocation.getAccuracy();// 获取精度信息 + location.setAddress(amapLocation.getAddress());// 地址,如果option中设置isNeedAddress为false,则没有此结果,网络定位结果中会有地址信息,GPS定位不返回地址信息。 + location.setCountry(amapLocation.getCountry());// 国家信息 + location.setProvince(amapLocation.getProvince());// 省信息 + location.setCity(amapLocation.getCity());// 城市信息 + location.setDistrict(amapLocation.getDistrict());// 城区信息 + location.setStreet(amapLocation.getStreet());// 街道信息 + location.setCityCode(amapLocation.getCityCode());// 城市编码 + + // amapLocation.getStreetNum();//街道门牌号信息 + + // amapLocation.getAdCode();//地区编码 + // location.setAltitude(amapLocation.getAltitude());// 海拔 + + amapLocation.getAoiName();// 获取当前定位点的AOI信息 + amapLocation.getBuildingId();// 获取当前室内定位的建筑物Id + amapLocation.getFloor();// 获取当前室内定位的楼层 + + handellocation.sendEmptyMessage(1); + } + + Handler handellocation = new Handler() { + @Override + public void dispatchMessage(Message msg) { + + + switch (msg.what) { + case 1: + Gson gson = new Gson(); + String json = gson.toJson(location); + System.out.println(json); + // x5webview.loadUrl("javascript:getlocationinfo(" + "'" + json + // + + // "'" + // + ");"); +// String getlocationinfo = "javascript:getlocationinfo(" + "'" +// + json + "'" + ");"; +// webviewjh(getlocationinfo); + + + if(x5webview!=null){ + x5webview.callHandler("getlocationinfo", json, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + } + + break; + case 2: + if (!hasPermission(locationpermission)) { + + PermissionGen.needPermission(NewwebviewActivity.this, 19, + locationpermission); + } else { + initlocation(); + } + break; + default: + break; + } + + + + super.dispatchMessage(msg); + + } + }; + + @Override + public void resetPrepared() { + reset(); + + } +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/OkHttpPhotoServer.java b/app/src/main/java/com/tagmae/tsgame_erwang/OkHttpPhotoServer.java new file mode 100644 index 0000000..c2c6ba4 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/OkHttpPhotoServer.java @@ -0,0 +1,265 @@ +package com.tagmae.tsgame_erwang; + +import android.graphics.Bitmap; +import android.graphics.Bitmap.CompressFormat; +import android.graphics.BitmapFactory; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.Message; +import android.util.Base64; + +import com.jx.jyhd.simcpux.Util; +import com.jx.jyhd.simcpux.Wxistrue; +import com.nickming.view.listener.savelistener; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.InvalidParameterException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import fi.iki.elonen.NanoHTTPD; + +public class OkHttpPhotoServer extends NanoHTTPD { + + private static savelistener listener1; + public static Handler handler; + private static String bitmappath; + private ExecutorService executor; + + public OkHttpPhotoServer(int port) { + super(port); + executor = Executors.newFixedThreadPool(4); + } + + public static void setPhotoListener(savelistener listener) { + listener1 = listener; + } + + public static void setPhotoHandler(Handler hanler1) { + handler = hanler1; + } + @Override + public Response serve(IHTTPSession session) { + String uri = session.getUri(); + + // 只处理 /testurl 路径的请求 + if (!"/testurl".equals(uri)) { + return newFixedLengthResponse(Response.Status.NOT_FOUND, "text/plain", "Not Found"); + } + +// if (!Wxistrue.isphotoshare) { // 避免重复点击 + System.out.println("8888888888"); + if (Method.POST.equals(session.getMethod())) { + if (handler != null) { + handler.postDelayed(new Runnable() { + @Override + public void run() { + Wxistrue.isphotoshare = true; + } + }, 3000); + } + + Wxistrue.isphotoshare = false; try { + // 简化POST数据读取 + String postData = readPostData(session); + + System.out.println(postData); + + String photo = ""; + String type = ""; + + try { + // 尝试解析JSON格式 + JSONObject object = new JSONObject(postData); + photo = object.optString("name"); + + // 从原始数据中提取type + if (postData.contains("data")) { + int dataIndex = postData.indexOf("data"); + if (dataIndex > 0) { + type = postData.substring(dataIndex - 1, dataIndex); + } + } + + //photo = deleteHeader(photo); + System.out.println("json格式"); + } catch (JSONException e) { + //photo = deleteHeader(postData); + System.out.println("不是json格式"); + e.printStackTrace(); + } + + //saveBase64(photo); + Message msg = new Message(); + + Bundle data = new Bundle(); + data.putString("bitmap", photo); + data.putString("bitpath", bitmappath); + data.putString("type", type); + System.out.println(type); + msg.setData(data); + + if (handler != null) { + handler.sendMessage(msg); + } + + } catch (Exception e) { + e.printStackTrace(); + return newFixedLengthResponse(Response.Status.INTERNAL_ERROR, "text/plain", "服务器错误"); + } + + } else if (Method.GET.equals(session.getMethod())) { + // 处理GET请求参数 + Map params = session.getParms(); + StringBuilder stringBuilder = new StringBuilder(); + for (Map.Entry entry : params.entrySet()) { + System.out.println(entry.getKey() + ": " + entry.getValue()); + stringBuilder.append(entry.getKey() + ": " + entry.getValue() + "\r\n"); + } + System.out.println("客户端提交的参数:" + stringBuilder.toString()); + } + + return newFixedLengthResponse(Response.Status.OK, "text/plain; charset=utf-8", "请求成功。"); +// } +// +// return newFixedLengthResponse(Response.Status.TOO_MANY_REQUESTS, "text/plain", "请求过于频繁"); + } + private String getPostDataFromStream(IHTTPSession session) { + try { + Map headers = session.getHeaders(); + String contentLength = headers.get("content-length"); + if (contentLength != null) { + int length = Integer.parseInt(contentLength); + if (length > 0) { + byte[] buffer = new byte[length]; + InputStream inputStream = session.getInputStream(); + int totalRead = 0; + while (totalRead < length) { + int read = inputStream.read(buffer, totalRead, length - totalRead); + if (read <= 0) break; + totalRead += read; + } + return new String(buffer, 0, totalRead, "UTF-8"); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + // 提供一个更简单的POST数据读取方法 + private String readPostData(IHTTPSession session) { + try { + Map parms = session.getParms(); + // 如果是表单提交,参数会在parms中 + if (!parms.isEmpty()) { + // 如果有name参数,直接返回 + if (parms.containsKey("name")) { + return parms.get("name"); + } + // 否则返回第一个参数的值 + return parms.values().iterator().next(); + } + + // 如果不是表单提交,尝试读取原始POST数据 + return getPostDataFromStream(session); + } catch (Exception e) { + e.printStackTrace(); + return ""; + } + } + + private String deleteHeader(String photo) { + int start = photo.indexOf(","); + if (start != -1) { + photo = photo.substring(start + 1); + } + System.out.println(photo); + return photo; + } + + public void saveBase64(String iconBase64) { + File file; + + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + // sd卡存储(/mnt/sdcard/cache) + file = Environment.getExternalStorageDirectory();// 获取跟目录 + } else { + // 没有SD卡,缓存到系统存储 + file = Environment.getDataDirectory(); + } + file = Util.GetDirectory(); + bitmappath = file.getAbsolutePath() + File.separator + "photo.png"; + Bitmap bit1 = stringtoBitmap(iconBase64); + if (bit1 == null) { + System.out.println("图片为空"); + } + getScreenShot(bit1, bitmappath); + } + + private void getScreenShot(Bitmap b1, String filePath) { + System.out.println(filePath); + if (b1 == null) { + System.out.println("-----"); + } + File file1 = new File(filePath); + try { + file1.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + + try { + try { + FileOutputStream fos = new FileOutputStream(file1); + b1.compress(CompressFormat.PNG, 100, fos); + fos.flush(); + fos.close(); + } catch (FileNotFoundException e) { + throw new InvalidParameterException(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public Bitmap stringtoBitmap(String string) { + // 将字符串转换成Bitmap类型 + Bitmap bitmap = null; + try { + byte[] bitmapArray; + System.out.println(string); + bitmapArray = Base64.decode(string, Base64.DEFAULT); + bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0, bitmapArray.length); + } catch (Exception e) { + e.printStackTrace(); + } + return bitmap; + } + + public String bitmaptoString(Bitmap bitmap) { + // 将Bitmap转换成字符串 + String string = null; + ByteArrayOutputStream bStream = new ByteArrayOutputStream(); + bitmap.compress(CompressFormat.PNG, 100, bStream); + byte[] bytes = bStream.toByteArray(); + string = Base64.encodeToString(bytes, Base64.DEFAULT); + return string; + } + + interface savePhotoListener { + void success(); + } +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/QQIntentShareHelper.java b/app/src/main/java/com/tagmae/tsgame_erwang/QQIntentShareHelper.java new file mode 100644 index 0000000..627a25b --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/QQIntentShareHelper.java @@ -0,0 +1,218 @@ +package com.tagmae.tsgame_erwang; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; +import android.widget.Toast; + +import com.google.gson.Gson; +import com.tagmae.tsgame_erwang.utils.Base64ImageUtil; +import com.tsgame.tsgame_niuniu.simcpux.bean.sharetypeBean; +import com.tsgame.tsgame_niuniu.util.QQIntentShareUtil; + +import java.io.File; +import java.io.FileOutputStream; + +/** + * QQ分享助手类 - 不依赖QQ SDK,使用Intent实现 + */ +public class QQIntentShareHelper { + + /** + * 执行QQ分享 + * + * @param context 上下文 + * @param jsonData 分享数据JSON字符串 + */ + public static void doQQShare(Context context, String jsonData) { + try { + // 初始化QQ分享工具 + QQIntentShareUtil qqIntentShareUtil = QQIntentShareUtil.getInstance(context); + + // 解析JSON数据 + Gson gson = new Gson(); + sharetypeBean bean = gson.fromJson(jsonData, sharetypeBean.class); + + // 获取分享类型和目标平台 + String type = bean.getType(); + String scene = bean.getSharefriend(); + + +// +// if (target == null || target.isEmpty()) { +// target = "qq"; // 默认分享到QQ好友 +// } + + // 显示开始分享提示 + //Toast.makeText(context, "正在分享到QQ", Toast.LENGTH_SHORT).show(); + shareToQQ(context, qqIntentShareUtil, type, bean); + // 根据目标平台执行不同的分享操作 +// if ("2".equals(scene)) { +// // 分享到QQ空间 +// shareToQZone(context, qqIntentShareUtil, type, bean); +// } else { +// // 分享到QQ好友 +// shareToQQ(context, qqIntentShareUtil, type, bean); +// } + } catch (Exception e) { + e.printStackTrace(); + //Toast.makeText(context, "QQ分享出错: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + + /** + * 分享到QQ好友 + */ + private static void shareToQQ(Context context, QQIntentShareUtil qqIntentShareUtil, String type, sharetypeBean bean) { + // 设置分享回调 + qqIntentShareUtil.setShareCallback(new QQIntentShareUtil.QQShareCallback() { + @Override + public void onSuccess() { +// ((Activity) context).runOnUiThread(() -> +// Toast.makeText(context, "分享到QQ成功", Toast.LENGTH_SHORT).show() +// ); + } + + @Override + public void onError(int code, String msg) { +// ((Activity) context).runOnUiThread(() -> +// Toast.makeText(context, "分享到QQ失败: " + msg, Toast.LENGTH_SHORT).show() +// ); + } + + @Override + public void onCancel() { +// ((Activity) context).runOnUiThread(() -> +// Toast.makeText(context, "分享到QQ已取消", Toast.LENGTH_SHORT).show() +// ); + } + }); + + // 根据分享类型执行不同的分享操作 + if ("1".equals(type)) { + StringBuilder sb = new StringBuilder(); + String title = bean.getTitle(); + String description = bean.getDescription(); + if (!TextUtils.isEmpty(bean.getTitle())) { + sb.append(title).append("\n\n"); + } + if (!TextUtils.isEmpty(description)) { + sb.append(description).append("\n\n"); + } + String text = sb.toString().trim(); + // 纯文本分享 + qqIntentShareUtil.shareTextToQQ((Activity) context, text); + } else if ("2".equals(type)) { + // 图片分享 +// String description = bean.getDescription(); +// //captureAndShareToQQ((Activity) context); +// //Base64ImageUtil.base64ToImageFile((Activity) context,description, null); +// Bitmap bitmap = Base64ImageUtil.base64ToBitmap(description); +// qqIntentShareUtil.shareBitmapToQQ((Activity) context,bitmap,false); +// bitmap.recycle(); + + // 图片分享 - 使用Canvas截图 + GlobalWebViewHelper.getCanvasBase64(new WebViewScreenshotUtil.CanvasToBase64Callback() { + @Override + public void onSuccess(String canvasBase64) { + // 使用Canvas截图的base64数据 + Bitmap bitmap = Base64ImageUtil.base64ToBitmap(canvasBase64); + qqIntentShareUtil.shareBitmapToQQ((Activity) context,bitmap,false); + bitmap.recycle(); + } + + @Override + public void onError(String error) { + // Canvas截图失败,回退到原有的图片数据 + // String imagebitmapString = bean.getDescription(); + // weChatShareUtil.shareImage( + // (Activity) context, + // imagebitmapString, // 回退到原有数据 + // scene + // ); + } + }); + } else { + // 网页链接分享 + qqIntentShareUtil.shareWebPageToQQ( + (Activity) context, + bean.getTitle(), + bean.getDescription(), + "", + "", + false // 不是QQ空间 + ); + } + } + + /** + * 分享到QQ空间 + */ + private static void shareToQZone(Context context, QQIntentShareUtil qqIntentShareUtil, String type, sharetypeBean bean) { + // 设置分享回调 + qqIntentShareUtil.setShareCallback(new QQIntentShareUtil.QQShareCallback() { + @Override + public void onSuccess() { +// ((Activity) context).runOnUiThread(() -> +// Toast.makeText(context, "分享到QQ空间成功", Toast.LENGTH_SHORT).show() +// ); + } + + @Override + public void onError(int code, String msg) { +// ((Activity) context).runOnUiThread(() -> +// Toast.makeText(context, "分享到QQ空间失败: " + msg, Toast.LENGTH_SHORT).show() +// ); + } + + @Override + public void onCancel() { +// ((Activity) context).runOnUiThread(() -> +// Toast.makeText(context, "分享到QQ空间已取消", Toast.LENGTH_SHORT).show() +// ); + } + }); + + // 根据分享类型执行不同的分享操作 + if ("1".equals(type)) { + // 纯文本分享 + StringBuilder sb = new StringBuilder(); + String title = bean.getTitle(); + String description = bean.getDescription(); + if (!TextUtils.isEmpty(bean.getTitle())) { + sb.append(title).append("\n\n"); + } + if (!TextUtils.isEmpty(description)) { + sb.append(description).append("\n\n"); + } + String text = sb.toString().trim(); + qqIntentShareUtil.shareTextToQZone((Activity) context, text); + } else if ("2".equals(type)) { + // 图片分享 + String description = bean.getDescription(); + Bitmap bitmap = Base64ImageUtil.base64ToBitmap(description); + if (bitmap != null) { + qqIntentShareUtil.shareBitmapToQQ((Activity) context, bitmap, true); // true表示QQ空间 + bitmap.recycle(); + } else { + // 如果图片处理失败,回退到纯文本分享 + String title = bean.getTitle(); + qqIntentShareUtil.shareTextToQZone((Activity) context, title != null ? title : ""); + } + } else { + // 网页链接分享 + qqIntentShareUtil.shareWebPageToQQ( + (Activity) context, + bean.getTitle(), + bean.getDescription(), + "", + "", + true // 是QQ空间 + ); + } + } +} + diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/ShareActivityPatch.java b/app/src/main/java/com/tagmae/tsgame_erwang/ShareActivityPatch.java new file mode 100644 index 0000000..ec95019 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/ShareActivityPatch.java @@ -0,0 +1,53 @@ +package com.tagmae.tsgame_erwang; + +import android.content.Intent; + +import com.bytedance.sdk.open.aweme.common.handler.IApiEventHandler; +import com.bytedance.sdk.open.aweme.common.model.BaseReq; +import com.bytedance.sdk.open.aweme.common.model.BaseResp; +import com.tsgame.tsgame_niuniu.util.DouYinIntentShareUtil; +import com.tsgame.tsgame_niuniu.util.QQIntentShareUtil; + +/** + * 这是一个补丁类,用于在 NewwebviewActivity 中添加分享功能 + * 将下面的代码添加到 NewwebviewActivity 类中 + */ +public class ShareActivityPatch implements IApiEventHandler { + + /** + * 在 NewwebviewActivity 的 onCreate 方法中添加以下代码 + */ + public static void initInOnCreate(NewwebviewActivity activity) { + // 注册 QQ 和抖音分享的 JavascriptInterface + activity.x5webview.addJavascriptInterface( + new ShareJavascriptInterface(activity), "NativeShare"); + } + + /** + * 在 NewwebviewActivity 的 onActivityResult 方法中添加以下代码 + */ + public static void handleActivityResult(NewwebviewActivity activity, + int requestCode, int resultCode, Intent data) { + // 处理QQ分享回调 +// QQIntentShareUtil.getInstance(activity).(requestCode, resultCode, data); + } + + /** + * 在 NewwebviewActivity 的 onReq 方法中实现,用于处理抖音分享请求 + */ + @Override + public void onReq(BaseReq req) { + // 可以处理抖音的请求,如果有必要 + } + + /** + * 在 NewwebviewActivity 的 onResp 方法中实现,用于处理抖音分享响应 + */ + @Override + public void onResp(BaseResp resp) { + // 处理抖音分享的回调结果 + if (resp != null) { + DouYinIntentShareUtil.getInstance(null).handleShareResult(null, resp); + } + } +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/ShareJavascriptInterface.java b/app/src/main/java/com/tagmae/tsgame_erwang/ShareJavascriptInterface.java new file mode 100644 index 0000000..270b8b7 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/ShareJavascriptInterface.java @@ -0,0 +1,216 @@ +package com.tagmae.tsgame_erwang; + +import android.app.Activity; +import android.content.Context; +import android.text.TextUtils; +import android.webkit.JavascriptInterface; +import android.widget.Toast; + +import com.google.gson.Gson; +import com.tsgame.tsgame_niuniu.simcpux.bean.sharetypeBean; +import com.tsgame.tsgame_niuniu.util.DouYinIntentShareUtil; +import com.tsgame.tsgame_niuniu.util.QQIntentShareUtil; + +import org.json.JSONObject; + +/** + * 处理QQ分享和抖音分享的JavaScript接口 + */ +public class ShareJavascriptInterface { + + private Context mContext; + private boolean isShareInProgress = false; + + public ShareJavascriptInterface(Context context) { + this.mContext = context; + } + + /** + * QQ分享 + * @param data JSON格式数据 + * { + * "type": "1", // 1-普通分享, 2-截图分享, 3-图片分享 + * "webpageUrl": "链接", // 网页链接或图片路径 + * "title": "标题", // 分享标题 + * "description": "描述", // 分享描述 + * "sharefriend": "1" // 1-QQ好友, 2-QQ空间 + * } + */ + @JavascriptInterface + public void shareToQQ(String data) { + try { + if (isShareInProgress) { + return; + } + + isShareInProgress = true; + + // 使用主线程执行UI操作 + ((Activity)mContext).runOnUiThread(() -> { + try { + Gson gson = new Gson(); + sharetypeBean bean = gson.fromJson(data, sharetypeBean.class); + + if (bean.getType() == null) { + bean.setType(""); + } + if (bean.getSharefriend() == null) { + bean.setSharefriend(""); + } + + // 图片分享 + if ("3".equals(bean.getType())) { + shareQQImage(bean.getSharefriend(), bean.getWebpageUrl()); + } else { + // 普通分享 + shareQQWebpage(bean.getSharefriend(), bean.getWebpageUrl(), bean.getTitle(), bean.getDescription()); + } + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(mContext, "QQ分享数据解析错误", Toast.LENGTH_SHORT).show(); + } + + // 3秒后重置分享状态 + new android.os.Handler().postDelayed(() -> { + isShareInProgress = false; + }, 3000); + }); + } catch (Exception e) { + e.printStackTrace(); + isShareInProgress = false; + } + } + + /** + * 抖音分享 + * @param data JSON格式数据 + * { + * "type": "1", // 1-图片分享, 2-视频分享 + * "filePath": "路径", // 图片或视频文件路径 + * "hashTag": "话题" // 话题标签(可选) + * } + */ + @JavascriptInterface + public void shareToDouYin(String data) { + try { + if (isShareInProgress) { + return; + } + + isShareInProgress = true; + + // 使用主线程执行UI操作 + ((Activity)mContext).runOnUiThread(() -> { + try { + JSONObject jsonObject = new JSONObject(data); + String type = jsonObject.optString("type", "1"); + String filePath = jsonObject.optString("filePath", ""); + String hashTag = jsonObject.optString("hashTag", ""); + + // 分享到抖音 + boolean isImage = "1".equals(type); + shareToDouYinInternal(filePath, hashTag, isImage); + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(mContext, "抖音分享数据解析错误", Toast.LENGTH_SHORT).show(); + } + + // 3秒后重置分享状态 + new android.os.Handler().postDelayed(() -> { + isShareInProgress = false; + }, 3000); + }); + } catch (Exception e) { + e.printStackTrace(); + isShareInProgress = false; + } + } + + // QQ分享网页链接 + private void shareQQWebpage(String shareType, String webpageUrl, String title, String description) { + if (TextUtils.isEmpty(title)) { + title = "分享"; + } + if (TextUtils.isEmpty(description)) { + description = "来自应用的分享"; + } + + QQIntentShareUtil qqShareUtil = QQIntentShareUtil.getInstance(mContext); + if (!qqShareUtil.isQQInstalled()) { + Toast.makeText(mContext, "请先安装QQ客户端", Toast.LENGTH_SHORT).show(); + return; + } + + try { + // 创建临时文件用于分享 + // 注:由于QQShareUtil仅支持图片分享,我们将网页信息添加到分享标题中 + // 实际项目中应考虑创建一个包含网页预览的图片 + String sharePath = ((Activity)mContext).getExternalFilesDir(null) + "/share_tmp.png"; + + // 分享标题包含描述和链接 + String shareTitle = title; + if (!TextUtils.isEmpty(description)) { + shareTitle += "\n" + description; + } + if (!TextUtils.isEmpty(webpageUrl)) { + shareTitle += "\n" + webpageUrl; + } + + // 分享给QQ + qqShareUtil.shareImageToQQ((Activity)mContext, sharePath); + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(mContext, "分享失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + + // QQ分享图片 + private void shareQQImage(String shareType, String imagePath) { + QQIntentShareUtil qqShareUtil = QQIntentShareUtil.getInstance(mContext); + if (!qqShareUtil.isQQInstalled()) { + Toast.makeText(mContext, "请先安装QQ客户端", Toast.LENGTH_SHORT).show(); + return; + } + + // 不管是QQ好友还是QQ空间,都使用同一个分享方法 + // QQShareUtil类中只有shareImageToQQ方法,没有专门的QQ空间分享方法 + // 实际上用户可以在QQ分享界面选择分享到QQ空间或好友 + qqShareUtil.shareImageToQQ((Activity)mContext, imagePath); + } + + // 分享到抖音 + private void shareToDouYinInternal(String filePath, String hashTag, boolean isImage) { + DouYinIntentShareUtil douYinIntentShareUtil = DouYinIntentShareUtil.getInstance(mContext); + // HarmonyOS compatibility: Remove strict check + // if (!douYinIntentShareUtil.isDouyinInstalled()) { + // Toast.makeText(mContext, "请先安装抖音客户端", Toast.LENGTH_SHORT).show(); + // return; + // } + + douYinIntentShareUtil.setShareCallback(new DouYinIntentShareUtil.DouYinShareCallback() { + @Override + public void onSuccess() { + ((Activity)mContext).runOnUiThread(() -> + Toast.makeText(mContext, "抖音分享成功", Toast.LENGTH_SHORT).show()); + } + + @Override + public void onError(int errorCode, String errorMsg) { + ((Activity)mContext).runOnUiThread(() -> + Toast.makeText(mContext, "抖音分享失败: " + errorMsg, Toast.LENGTH_SHORT).show()); + } + + @Override + public void onCancel() { + ((Activity)mContext).runOnUiThread(() -> + Toast.makeText(mContext, "抖音分享取消", Toast.LENGTH_SHORT).show()); + } + }); + + if (isImage) { + douYinIntentShareUtil.shareImageToDouyin((Activity)mContext, filePath); + } else { + douYinIntentShareUtil.shareVideoToDouyin((Activity)mContext, filePath); + } + } +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/SharePanelHelper.java b/app/src/main/java/com/tagmae/tsgame_erwang/SharePanelHelper.java new file mode 100644 index 0000000..d245d44 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/SharePanelHelper.java @@ -0,0 +1,288 @@ +package com.tagmae.tsgame_erwang; + +import android.app.Activity; +import android.view.View; +import android.widget.Toast; + +import com.google.gson.Gson; +import com.tsgame.tsgame_niuniu.simcpux.bean.sharetypeBean; + +/** + * 分享面板控制辅助类 + */ +public class SharePanelHelper { + + // 保存当前分享的数据 + private static sharetypeBean currentShareData; /** + * 显示分享面板并保存分享数据 + * @param activity 当前活动 + * @param shareData 分享数据 + */ + public static void showSharePanel(Activity activity, String shareData) { + try { + // 保存分享数据 + Gson gson = new Gson(); + currentShareData = gson.fromJson(shareData, sharetypeBean.class); + + // 显示分享面板 + final View sharePanel = activity.findViewById(com.jx.jyhd.R.id.share_panel); + if (sharePanel != null) { + // 确保每次显示面板都重新设置点击事件 + setupPanelClickListeners(activity); + + // 确保先初始化面板上的按钮 + initSharePanelButtons(activity); + + // 兼容低版本,使用AlphaAnimation代替setAlpha + sharePanel.setVisibility(View.VISIBLE); + if (android.os.Build.VERSION.SDK_INT >= 11) { + // API 11+使用View.setAlpha + sharePanel.setAlpha(0f); + sharePanel.animate().alpha(1f).setDuration(300).start(); + } else { + // 低版本使用Animation + android.view.animation.AlphaAnimation animation = new android.view.animation.AlphaAnimation(0f, 1f); + animation.setDuration(300); + animation.setFillAfter(true); + sharePanel.startAnimation(animation); + } + } + } catch (Exception e) { + e.printStackTrace(); + //Toast.makeText(activity, "打开分享面板失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + + /** + * 设置面板点击事件处理 + */ + private static void setupPanelClickListeners(final Activity activity) { + try { + // 获取面板和内容容器 + final View sharePanel = activity.findViewById(com.jx.jyhd.R.id.share_panel); + final View container = activity.findViewById(com.jx.jyhd.R.id.share_panel_container); + + if (sharePanel == null || container == null) return; + + // 重要:先移除所有已存在的点击监听器,避免重复添加 + if (android.os.Build.VERSION.SDK_INT >= 16) { + sharePanel.setOnClickListener(null); + container.setOnClickListener(null); + } + + // 设置点击面板空白区域关闭面板 + sharePanel.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // 当点击到面板空白区域时,关闭面板 + //Toast.makeText(activity, "关闭分享面板", Toast.LENGTH_SHORT).show(); + hideSharePanel(activity); + } + }); + + // 防止点击事件传递到下层视图(重要:这里使用onClickListener来消费事件) + container.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // 点击内容区域不关闭面板,消费掉事件 + // 空实现即可,目的是阻止事件传递到sharePanel + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 隐藏分享面板 + * @param activity 当前活动 + */ + public static void hideSharePanel(Activity activity) { + final View sharePanel = activity.findViewById(com.jx.jyhd.R.id.share_panel); + if (sharePanel != null) { + if (android.os.Build.VERSION.SDK_INT >= 11) { + // API 11+使用View.animate().alpha + sharePanel.animate().alpha(0f).setDuration(300).withEndAction(new Runnable() { + @Override + public void run() { + sharePanel.setVisibility(View.GONE); + } + }).start(); + } else { + // 低版本使用Animation + android.view.animation.AlphaAnimation animation = new android.view.animation.AlphaAnimation(1f, 0f); + animation.setDuration(300); + animation.setFillAfter(true); + animation.setAnimationListener(new android.view.animation.Animation.AnimationListener() { + @Override + public void onAnimationStart(android.view.animation.Animation animation) {} + + @Override + public void onAnimationEnd(android.view.animation.Animation animation) { + sharePanel.setVisibility(View.GONE); + } + + @Override + public void onAnimationRepeat(android.view.animation.Animation animation) {} + }); + sharePanel.startAnimation(animation); + } + } + } + + /** + * 初始化分享面板 + * @param activity 当前活动 + */ + public static void initSharePanel(final Activity activity) { + try { + final View sharePanel = activity.findViewById(com.jx.jyhd.R.id.share_panel); + if (sharePanel == null) return; + + // 点击面板背景区域关闭面板 + sharePanel.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + hideSharePanel(activity); + } + }); + + // 防止点击事件传递到下层视图 + activity.findViewById(com.jx.jyhd.R.id.share_panel_container).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // 拦截点击事件,防止关闭面板 + } + }); + + // 微信分享按钮点击事件 + activity.findViewById(com.jx.jyhd.R.id.btn_share_wechat).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (currentShareData != null) { + // 调用微信分享 + Toast.makeText(activity, "微信分享", Toast.LENGTH_SHORT).show(); + hideSharePanel(activity); + } + } + }); + + // QQ分享按钮点击事件 + activity.findViewById(com.jx.jyhd.R.id.btn_share_qq).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (currentShareData != null) { + // 调用QQ分享 + QQIntentShareHelper.doQQShare(activity, new Gson().toJson(currentShareData)); + Toast.makeText(activity, "QQ分享", Toast.LENGTH_SHORT).show(); + hideSharePanel(activity); + } + } + }); + + // 抖音分享按钮点击事件 + activity.findViewById(com.jx.jyhd.R.id.btn_share_douyin).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (currentShareData != null) { + // 调用抖音分享 + DouYinIntentShareHelper.doDouYinShare(activity, new Gson().toJson(currentShareData)); + Toast.makeText(activity, "抖音分享", Toast.LENGTH_SHORT).show(); + hideSharePanel(activity); + } + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 初始化分享面板按钮 + * @param activity 当前活动 + */ + private static void initSharePanelButtons(final Activity activity) { + try { + final View wechatBtn = activity.findViewById(com.jx.jyhd.R.id.btn_share_wechat); + final View qqBtn = activity.findViewById(com.jx.jyhd.R.id.btn_share_qq); + final View douyinBtn = activity.findViewById(com.jx.jyhd.R.id.btn_share_douyin); + + // 确保找到所有按钮 + if (wechatBtn == null || qqBtn == null || douyinBtn == null) { + Toast.makeText(activity, "初始化分享按钮失败,找不到按钮资源", Toast.LENGTH_SHORT).show(); + return; + } + + // 微信分享按钮点击事件 + wechatBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + //Toast.makeText(activity, "微信分享按钮已点击", Toast.LENGTH_SHORT).show(); + if (currentShareData != null) { try { + WeChatShareHelper.doWeChatShare(activity, new Gson().toJson(currentShareData)); +// // 实现微信分享功能 +// if (currentShareData.getType() != null && currentShareData.getType().equals("3")) { +// // 图片分享 +// Toast.makeText(activity, "调用微信图片分享", Toast.LENGTH_SHORT).show(); +// } else { +// // 网页分享 +// Toast.makeText(activity, "调用微信网页分享", Toast.LENGTH_SHORT).show(); +// } + } catch (Exception e) { + e.printStackTrace(); + //Toast.makeText(activity, "微信分享失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + hideSharePanel(activity); + } + } + }); + + // QQ分享按钮点击事件 + qqBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + //Toast.makeText(activity, "QQ分享按钮已点击", Toast.LENGTH_SHORT).show(); + if (currentShareData != null) { + try { + // 调用QQ分享 + QQIntentShareHelper.doQQShare(activity, new Gson().toJson(currentShareData)); + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(activity, "QQ分享失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + hideSharePanel(activity); + } + } + }); + + // 抖音分享按钮点击事件 + douyinBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + //Toast.makeText(activity, "抖音分享按钮已点击", Toast.LENGTH_SHORT).show(); + if (currentShareData != null) { + try { + // 调用抖音分享 + DouYinIntentShareHelper.doDouYinShare(activity, new Gson().toJson(currentShareData)); + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(activity, "抖音分享失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + hideSharePanel(activity); + } + } + }); + + } catch (Exception e) { + e.printStackTrace(); + //Toast.makeText(activity, "初始化分享按钮失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + + /** + * 获取当前分享数据 + */ + public static sharetypeBean getCurrentShareData() { + return currentShareData; + } +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/SoundPoolUtils.java b/app/src/main/java/com/tagmae/tsgame_erwang/SoundPoolUtils.java new file mode 100644 index 0000000..b126bb6 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/SoundPoolUtils.java @@ -0,0 +1,103 @@ +package com.tagmae.tsgame_erwang; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import android.annotation.SuppressLint; +import android.media.AudioAttributes; +import android.media.AudioManager; +import android.media.SoundPool; +import android.media.SoundPool.OnLoadCompleteListener; +import android.os.Build; +import android.os.Handler; + +@SuppressLint("NewApi") +public class SoundPoolUtils { + private static SoundPool sp = null;// 声明一个SoundPool的引用 + private static SoundPool sp1 = null;// 声明一个SoundPool的引用 + static Map map = new HashMap(); + Handler hand = new Handler(); + List list = new ArrayList(); + private static int num = 0;// 声明一个SoundPool的引用 + + + // loop 是否循环 0不循环 -1循环 + public static void playSound(final String sound, final int loop) { + if (sp == null) { + if (Build.VERSION.SDK_INT >= 21) { + SoundPool.Builder builder = new SoundPool.Builder(); + builder.setMaxStreams(10);// 传入音频数量 + // AudioAttributes是一个封装音频各种属性的方法 + AudioAttributes.Builder attrBuilder = new AudioAttributes.Builder(); + attrBuilder.setLegacyStreamType(AudioManager.STREAM_MUSIC);// 设置音频流的合适的属性 + builder.setAudioAttributes(attrBuilder.build());// 加载一个AudioAttributes + sp = builder.build(); + } else { + sp = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);// 创建SoundPool对象 + } + } + + if (loop >= 0) { + + sp.load(sound, 1); + + sp.setOnLoadCompleteListener(new OnLoadCompleteListener() { + + @Override + public void onLoadComplete(SoundPool soundPool, int sampleId, + int status) { + int currentStreamId; + + + if (loop == 0) { + currentStreamId = soundPool.play(sampleId, (float) 1, + (float) 1, 1, 0, 1.0f); + map.put(sound, currentStreamId); + num++; + if(num>80){ + num=0; + dismisSoundPool(); + } + String log = "playSound currentStreamId:" + + String.valueOf(currentStreamId); + System.out.println(log); + } + + } + }); + + } else if (loop < 0) { + if (map.containsKey(sound)) { + int streamID = map.get(sound); + try { + sp.pause(streamID); + } catch (Exception e) { + + } + + // sp.release(); + + // 暂停声音 + } + + } + + } + + /** + * @Title: dismisSoundPool @Description: 释放播放池 @param 设定文件 @return void 返回类型 @throws + */ + public static void dismisSoundPool() { + if (sp != null) { + try { + sp.release(); + sp = null; + } catch (Exception e) { + // TODO: handle exception + } + + } + } +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/SoundPools.java b/app/src/main/java/com/tagmae/tsgame_erwang/SoundPools.java new file mode 100644 index 0000000..1a9ea07 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/SoundPools.java @@ -0,0 +1,192 @@ +package com.tagmae.tsgame_erwang; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +import android.content.Context; +import android.media.SoundPool; +import android.util.Log; + +public class SoundPools { + private static final String TAG = "SoundPools"; + + private static final int MAX_STREAMS_PER_POOL = 15; + + private List containers; + + public SoundPools() { + containers = Collections + .synchronizedList(new ArrayList()); + } + + public void loadSound(Context context, String id, String file) { + Log.d(TAG, "SouldPools load sound " + file); + try { + for (SoundPoolContainer container : containers) { + if (container.contains(id)) { + return; + } + } + for (SoundPoolContainer container : containers) { + if (!container.isFull()) { + container.load(context, id, file); + return; + } + } + SoundPoolContainer container = new SoundPoolContainer(); + containers.add(container); + container.load(context, id, file); + } catch (Exception e) { + Log.w(TAG, "Load sound error", e); + } + } + + public void playSound(Context context, String id, String file) { + Log.d(TAG, "SouldPools play sound " + file); + try { + for (SoundPoolContainer container : containers) { + if (container.contains(id)) { + container.play(context, id, file); + return; + } + } + for (SoundPoolContainer container : containers) { + if (!container.isFull()) { + container.play(context, id, file); + return; + } + } + SoundPoolContainer container = new SoundPoolContainer(); + containers.add(container); + + container.play(context, id, file); + } catch (Exception e) { + Log.w(TAG, "Play sound error", e); + } + } + + public void onPause() { + for (SoundPoolContainer container : containers) { + container.onPause(); + } + } + + public void onPause(String fileid) { + for (SoundPoolContainer container : containers) { + container.onPause(fileid); + } + } + + public void onResume() { + for (SoundPoolContainer container : containers) { + container.onResume(); + } + } + + private static class SoundPoolContainer { + SoundPool soundPool; + Map soundMap; + Map soundMap1; + AtomicInteger size; + + public SoundPoolContainer() { + this.soundPool = new SoundPool(MAX_STREAMS_PER_POOL, + android.media.AudioManager.STREAM_MUSIC, 0); + this.soundMap = new ConcurrentHashMap( + MAX_STREAMS_PER_POOL); + this.soundMap1= new ConcurrentHashMap( + MAX_STREAMS_PER_POOL);; + this.size = new AtomicInteger(0); + } + + public void load(Context context, String id, String file) { + try { + this.size.incrementAndGet(); + // soundMap.put(id, + // soundPool.load(context.getAssets().openFd(file), 1)); + soundMap.put(id, soundPool.load(file, 1)); + } catch (Exception e) { + this.size.decrementAndGet(); + Log.w(TAG, "Load sound error", e); + } + } + + public void play(Context context, final String id, String file) { + android.media.AudioManager audioManager = (android.media.AudioManager) context + .getSystemService(Context.AUDIO_SERVICE); + final int streamVolume = audioManager + .getStreamVolume(android.media.AudioManager.STREAM_MUSIC); + Integer soundId = soundMap.get(id); + if (soundId == null) { + soundPool + .setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() { + @Override + public void onLoadComplete(SoundPool soundPool, + int sampleId, int status) { + int a=soundPool.play(sampleId, streamVolume, + streamVolume, 1, 0, 1f); + soundMap1.put(id, a); + } + }); + try { + this.size.incrementAndGet(); + // soundPool.load(context.getAssets().openFd(file), 1); + // soundPool.load(file, 1); + soundMap.put(id, soundPool.load(file, 1)); + } catch (Exception e) { + this.size.decrementAndGet(); + Log.w(TAG, "Load/Play sound error", e); + } + } else { + try { + int a=soundPool.play(soundId, streamVolume, streamVolume, 1, 0, + 1f); + soundMap1.put(id, a); + + } catch (Exception e) { + Log.w(TAG, "Play sound error", e); + } + } + } + + public boolean contains(String id) { + return soundMap.containsKey(id); + } + + public boolean isFull() { + return this.size.get() >= MAX_STREAMS_PER_POOL; + } + + public void onPause() { + try { + soundPool.autoPause(); + } catch (Exception e) { + Log.w(TAG, "Pause SoundPool error", e); + } + } + public void onPause(String file) { + try { + if(soundMap1.containsKey(file)){ + soundPool.pause(soundMap1.get(file)); + } + + + } catch (Exception e) { + Log.w(TAG, "Pause SoundPool error", e); + } + } + public void onResume() { + try { + soundPool.autoResume(); + } catch (Exception e) { + Log.w(TAG, "Resume SoundPool error", e); + } + } + } + +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/WeChatShareHelper.java b/app/src/main/java/com/tagmae/tsgame_erwang/WeChatShareHelper.java new file mode 100644 index 0000000..30581de --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/WeChatShareHelper.java @@ -0,0 +1,148 @@ +package com.tagmae.tsgame_erwang; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.os.Bundle; +import android.os.Environment; +import android.os.Message; +import android.widget.Toast; + +import com.android.volley.VolleyError; +import com.android.volley.toolbox.ImageRequest; +import com.game.webgame.network.volleymanager; +import com.google.gson.Gson; +import com.jx.jyhd.simcpux.Util; +import com.jx.jyhd.simcpux.Wxistrue; +import com.jx.jyhd.simcpux.util.WeChatShareUtil; +import com.tsgame.tsgame_niuniu.simcpux.bean.sharetypeBean; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.security.InvalidParameterException; + +/** + * 微信分享辅助类 + */ +public class WeChatShareHelper { + + private static String bitmappath; /** + * 微信分享 + * + * @param context 上下文 + * @param jsonData 分享数据JSON字符串 + */ + public static void doWeChatShare(Context context, String jsonData) { + doWeChatShare(context, jsonData, false); + } + + /** + * 微信分享(支持Canvas截图) + * + * @param context 上下文 + * @param jsonData 分享数据JSON字符串 + * @param useCanvas 是否使用Canvas截图(仅对图片分享type=2有效) + */ + public static void doWeChatShare(Context context, String jsonData, boolean useCanvas) { + try { + // 解析JSON数据 + Gson gson = new Gson(); + sharetypeBean bean = gson.fromJson(jsonData, sharetypeBean.class); + + // 初始化微信分享工具 + WeChatShareUtil weChatShareUtil = WeChatShareUtil.getInstance(context); + + // 检查微信是否已安装 + if (!weChatShareUtil.isWeChatInstalled()) { + Toast.makeText(context, "微信未安装,无法进行微信分享", Toast.LENGTH_SHORT).show(); + return; + } + + // 设置分享回调 + weChatShareUtil.setShareCallback(new WeChatShareUtil.WeChatShareCallback() { + @Override + public void onSuccess() { +// ((Activity) context).runOnUiThread(() -> +// Toast.makeText(context, "微信分享成功", Toast.LENGTH_SHORT).show() +// ); + } + + @Override + public void onError(int code, String message) { +// ((Activity) context).runOnUiThread(() -> +// Toast.makeText(context, "微信分享失败: " + message, Toast.LENGTH_SHORT).show() +// ); + } + + @Override + public void onCancel() { +// ((Activity) context).runOnUiThread(() -> +// Toast.makeText(context, "微信分享已取消", Toast.LENGTH_SHORT).show() +// ); + } + }); + + // 处理分享类型字段 + if (bean.getType() == null) { + bean.setType(""); + } + + // 处理分享对象字段(朋友或朋友圈) + if (bean.getSharefriend() == null) { + bean.setSharefriend(""); + } + + // 处理分享类型字段 + if (bean.getSharetype() == null) { + bean.setSharetype(""); + } + + // 确定分享场景(0:好友, 1:朋友圈) + int scene = bean.getSharefriend().equals("1") ? 0 : 1; // 根据类型进行不同的分享处理 + if (bean.getType().equals("2")) { + // 图片分享 - 使用Canvas截图 + GlobalWebViewHelper.getCanvasBase64(new WebViewScreenshotUtil.CanvasToBase64Callback() { + @Override + public void onSuccess(String canvasBase64) { + // 使用Canvas截图的base64数据 + weChatShareUtil.shareImage( + (Activity) context, + canvasBase64, // Canvas截图的base64数据 + scene + ); + } + + @Override + public void onError(String error) { + // Canvas截图失败,回退到原有的图片数据 + // String imagebitmapString = bean.getDescription(); + // weChatShareUtil.shareImage( + // (Activity) context, + // imagebitmapString, // 回退到原有数据 + // scene + // ); + } + }); + //Toast.makeText(context, "分享图片到微信" + (scene == 0 ? "好友" : "朋友圈"), Toast.LENGTH_SHORT).show(); + } else { + // 网页分享 + weChatShareUtil.shareWebPage( + (Activity) context, + bean.getWebpageUrl(), // 网页链接 + bean.getTitle(), // 标题 + bean.getDescription(), // 描述 + scene + ); +// Toast.makeText(context, "分享网页到微信" + (scene == 0 ? "好友" : "朋友圈"), Toast.LENGTH_SHORT).show(); + } + + } catch (Exception e) { + e.printStackTrace(); + //Toast.makeText(context, "微信分享异常: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/WebViewScreenshotUtil.java b/app/src/main/java/com/tagmae/tsgame_erwang/WebViewScreenshotUtil.java new file mode 100644 index 0000000..662494f --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/WebViewScreenshotUtil.java @@ -0,0 +1,565 @@ +package com.tagmae.tsgame_erwang; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Picture; +import android.os.Build; +import android.util.Base64; +import android.util.Log; +import android.view.View; +import android.webkit.WebView; +import com.tencent.smtt.sdk.ValueCallback; + +import com.tagmae.jsbridge.BridgeWebView; + +import java.io.ByteArrayOutputStream; + +/** + * WebView截图工具类,专门用于截取WebView内容 + */ +public class WebViewScreenshotUtil { + private static final String TAG = "WebViewScreenshotUtil"; + + /** + * Canvas转base64回调接口 + */ + public interface CanvasToBase64Callback { + void onSuccess(String base64Data); + void onError(String error); + } + + static { + // 在静态初始化块中启用整个文档绘制模式(for Android 5.0+) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + try { + WebView.enableSlowWholeDocumentDraw(); + Log.d(TAG, "启用了WebView慢速整页绘制模式"); + } catch (Exception e) { + Log.e(TAG, "启用WebView慢速绘制模式失败: " + e.getMessage()); + } + } + } + + /** + * 截取BridgeWebView的内容(简单直接的方法) + * + * @param webView 要截图的BridgeWebView + * @return 截图Bitmap,失败返回null + */ + public static Bitmap captureWebView(BridgeWebView webView) { + if (webView == null) { + Log.e(TAG, "WebView is null"); + return null; + } + + if (webView.getWidth() == 0 || webView.getHeight() == 0) { + Log.e(TAG, "WebView dimensions are zero"); + return null; + } + + try { + // 创建与WebView相同大小的位图 + Bitmap bitmap = Bitmap.createBitmap(webView.getWidth(), webView.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + + // 绘制WebView内容 + webView.draw(canvas); + + // 检查是否为空白或黑屏 + if (isBitmapEmpty(bitmap)) { + Log.d(TAG, "Simple capture resulted in empty bitmap, trying other methods"); + return captureBridgeWebView(webView); + } + + return bitmap; + } catch (Exception e) { + Log.e(TAG, "Error in captureWebView: " + e.getMessage()); + return captureBridgeWebView(webView); + } + } + + /** + * 截取BridgeWebView的内容 + * 尝试多种方法,确保能够获取到有效的截图 + * + * @param webView 要截图的BridgeWebView + * @return 截图Bitmap,失败返回null + */ + public static Bitmap captureBridgeWebView(BridgeWebView webView) { + if (webView == null) { + Log.e(TAG, "WebView is null"); + return null; + } + + // 首先使用直接绘制的方式(适用于大多数情况) + Bitmap bitmap = captureWebViewDirectly(webView); + if (bitmap != null && !isBitmapEmpty(bitmap)) { + Log.d(TAG, "Direct capture succeeded"); + return bitmap; + } + + // 如果直接绘制方式失败,尝试禁用硬件加速后再截图 + Log.d(TAG, "Direct capture failed or empty, trying with hardware acceleration disabled"); + bitmap = captureWebViewWithHardwareAccelerationDisabled(webView); + if (bitmap != null && !isBitmapEmpty(bitmap)) { + Log.d(TAG, "Capture with hardware acceleration disabled succeeded"); + return bitmap; + } + + // 如果前两种方法都失败,尝试使用Picture方式 + Log.d(TAG, "Previous methods failed, trying with Picture method"); + bitmap = captureWebViewUsingPicture(webView); + if (bitmap != null && !isBitmapEmpty(bitmap)) { + Log.d(TAG, "Picture method succeeded"); + return bitmap; + } + + Log.e(TAG, "All screenshot methods failed"); + return null; + } + + /** + * 判断Bitmap是否为空(全黑或透明) + */ + private static boolean isBitmapEmpty(Bitmap bitmap) { + if (bitmap == null || bitmap.getWidth() == 0 || bitmap.getHeight() == 0) { + return true; + } + + // 采样检查bitmap是否全黑或全透明 + int[] pixels = new int[10]; // 只采样几个点 + int width = bitmap.getWidth(); + int height = bitmap.getHeight(); + + // 获取中心区域的几个像素点 + bitmap.getPixels(pixels, 0, 1, width/2, height/2, 1, 1); + bitmap.getPixels(pixels, 1, 1, width/3, height/3, 1, 1); + bitmap.getPixels(pixels, 2, 1, width*2/3, height*2/3, 1, 1); + + // 检查这些像素点是否全是黑色或全透明 + boolean allBlackOrTransparent = true; + for (int i = 0; i < 3; i++) { + int pixel = pixels[i]; + int alpha = (pixel >> 24) & 0xff; + int red = (pixel >> 16) & 0xff; + int green = (pixel >> 8) & 0xff; + int blue = pixel & 0xff; + + // 如果不是黑色或透明,那么bitmap不是空的 + if (alpha > 20 && (red > 10 || green > 10 || blue > 10)) { + allBlackOrTransparent = false; + break; + } + } + + return allBlackOrTransparent; + } + + /** + * 直接绘制WebView到Bitmap + */ + private static Bitmap captureWebViewDirectly(BridgeWebView webView) { + try { + if (webView.getWidth() == 0 || webView.getHeight() == 0) { + Log.e(TAG, "WebView has not been laid out yet"); + return null; + } + + Bitmap bitmap = Bitmap.createBitmap(webView.getWidth(), webView.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + webView.draw(canvas); + + return bitmap; + } catch (Exception e) { + Log.e(TAG, "Error in captureWebViewDirectly: " + e.getMessage()); + return null; + } + } + + /** + * 暂时禁用硬件加速并绘制WebView + */ + private static Bitmap captureWebViewWithHardwareAccelerationDisabled(BridgeWebView webView) { + try { + if (webView.getWidth() == 0 || webView.getHeight() == 0) { + Log.e(TAG, "WebView has not been laid out yet"); + return null; + } + + boolean wasHardwareAccelerated = false; + + // 只在Android 3.0(API 11)及以上版本调用isHardwareAccelerated方法 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + try { + wasHardwareAccelerated = webView.isHardwareAccelerated(); + } catch (Exception e) { + Log.e(TAG, "Error checking hardware acceleration: " + e.getMessage()); + } + } + + // 临时禁用硬件加速 + if (wasHardwareAccelerated) { + try { + webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); + } catch (Exception e) { + Log.e(TAG, "Error disabling hardware acceleration: " + e.getMessage()); + } + } + + Bitmap bitmap = Bitmap.createBitmap(webView.getWidth(), webView.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + + // 强制绘制 + webView.computeScroll(); + webView.draw(canvas); + + // 恢复硬件加速状态 + if (wasHardwareAccelerated) { + try { + webView.setLayerType(View.LAYER_TYPE_HARDWARE, null); + } catch (Exception e) { + Log.e(TAG, "Error restoring hardware acceleration: " + e.getMessage()); + } + } + + return bitmap; + } catch (Exception e) { + Log.e(TAG, "Error in captureWebViewWithHardwareAccelerationDisabled: " + e.getMessage()); + return null; + } + } + + /** + * 使用Picture方式截取WebView + */ + private static Bitmap captureWebViewUsingPicture(BridgeWebView webView) { + try { + if (webView.getWidth() == 0 || webView.getHeight() == 0) { + Log.e(TAG, "WebView has not been laid out yet"); + return null; + } + + // 确保WebView已经加载完成 + webView.measure(View.MeasureSpec.makeMeasureSpec(webView.getWidth(), View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(webView.getHeight(), View.MeasureSpec.EXACTLY)); + webView.layout(0, 0, webView.getWidth(), webView.getHeight()); + + // 获取WebView内容 + Picture picture = webView.capturePicture(); + if (picture != null && picture.getWidth() > 0 && picture.getHeight() > 0) { + Bitmap bitmap = Bitmap.createBitmap(picture.getWidth(), picture.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + picture.draw(canvas); + return bitmap; + } + + return null; + } catch (Exception e) { + Log.e(TAG, "Error in captureWebViewUsingPicture: " + e.getMessage()); + return null; + } + } + + /** + * 从Activity中获取并截取BridgeWebView + * + * @param activity 包含BridgeWebView的Activity + * @return 截图Bitmap,失败返回null + */ + public static Bitmap captureWebViewFromActivity(Activity activity) { + if (activity == null) { + Log.e(TAG, "Activity is null"); + return null; + } + + BridgeWebView webView = null; // 对NewwebviewActivity特别处理 - 直接使用静态变量 + if (activity instanceof NewwebviewActivity) { + webView = NewwebviewActivity.x5webview; + if (webView != null) { + Log.d(TAG, "Found WebView in NewwebviewActivity using static field"); + } else { + Log.w(TAG, "Static x5webview is null in NewwebviewActivity"); + } + } + // 对webviewActivity特别处理 + else if (activity.getClass().getSimpleName().equals("webviewActivity")) { + try { + java.lang.reflect.Field field = activity.getClass().getDeclaredField("x5webview"); + field.setAccessible(true); + webView = (BridgeWebView) field.get(activity); + Log.d(TAG, "Found WebView in webviewActivity"); + } catch (Exception e) { + Log.e(TAG, "Failed to get WebView from webviewActivity: " + e.getMessage()); + } + } + + // 如果找到了WebView,进行截图 + if (webView != null) { + Log.d(TAG, "Capturing WebView: width=" + webView.getWidth() + ", height=" + webView.getHeight()); + // 使用新的简化截图方法 + return captureWebView(webView); + } + + Log.e(TAG, "No WebView found in activity"); return null; + } + + /** + * 将Bitmap转换为base64编码 + * + * @param bitmap 要转换的bitmap + * @param quality 压缩质量(0-100) + * @return base64编码字符串,失败返回null + */ + public static String bitmapToBase64(Bitmap bitmap, int quality) { + if (bitmap == null) { + Log.e(TAG, "Bitmap is null"); + return null; + } + + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.PNG, quality, outputStream); + byte[] byteArray = outputStream.toByteArray(); + return Base64.encodeToString(byteArray, Base64.NO_WRAP); + } catch (Exception e) { + Log.e(TAG, "Error converting bitmap to base64: " + e.getMessage()); + return null; + } + } + + /** + * 截取WebView并直接转换为base64编码 + * + * @param webView 要截图的BridgeWebView + * @param quality 压缩质量(0-100) + * @return base64编码字符串,失败返回null + */ + public static String captureWebViewToBase64(BridgeWebView webView, int quality) { + Bitmap bitmap = captureWebView(webView); + if (bitmap != null) { + String base64 = bitmapToBase64(bitmap, quality); + bitmap.recycle(); // 释放bitmap内存 + return base64; + } + return null; + } + + /** + * 截取WebView并转换为base64编码(默认质量90) + * + * @param webView 要截图的BridgeWebView + * @return base64编码字符串,失败返回null + */ + public static String captureWebViewToBase64(BridgeWebView webView) { + return captureWebViewToBase64(webView, 90); + } + + /** + * 通过JavaScript获取WebView中的Canvas内容并转为base64 + * 这个方法专门用于获取HTML5 Canvas元素的内容 + * + * @param webView 包含Canvas的WebView + * @param canvasId Canvas元素的ID,如果为null或空则获取第一个Canvas + * @param callback 获取结果的回调 + */ + public static void getCanvasBase64FromWebView(BridgeWebView webView, String canvasId, CanvasToBase64Callback callback) { + if (webView == null) { + if (callback != null) { + callback.onError("WebView is null"); + } + return; + } + + // 构建JavaScript代码 + String javascript; + if (canvasId != null && !canvasId.trim().isEmpty()) { + // 根据ID获取指定Canvas + javascript = "(function() {" + + "try {" + + "var canvas = document.getElementById('" + canvasId + "');" + + "if (!canvas) return 'Canvas not found';" + + "if (canvas.tagName.toLowerCase() !== 'canvas') return 'Element is not a canvas';" + + "return canvas.toDataURL('image/png');" + + "} catch(e) {" + + "return 'Error: ' + e.message;" + + "}" + + "})();"; + } else { + // 获取页面中第一个Canvas元素 + javascript = "(function() {" + + "try {" + + "var canvas1 = document.createElement('canvas');"+ + "canvas1.width=720,canvas1.height=405;"+ + "var g=canvas1.getContext('2d');"+ + "g.drawImage(iui.canvas,0,0,720,405);"+ + "return canvas1.toDataURL('image/jpeg',1);"+ + "} catch(e) {" + + "return 'Error: ' + e.message;" + + "}" + + "})();"; + } + + // 执行JavaScript代码 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + webView.evaluateJavascript(javascript, new ValueCallback() { + @Override + public void onReceiveValue(String value) { + if (callback != null) { + if (value != null && value.startsWith("\"data:image/")) { + // 移除引号和data:image/png;base64,前缀 + String base64 = value.substring(1, value.length() - 1); // 移除引号 + if (base64.startsWith("data:image/png;base64,")) { + base64 = base64.substring("data:image/png;base64,".length()); + } + callback.onSuccess(base64); + } else { + String error = value != null ? value.replace("\"", "") : "Unknown error"; + callback.onError(error); + } + } + } + }); + } else { + if (callback != null) { + callback.onError("Android version too low (requires API 19+)"); + } + } + } + + /** + * 获取WebView中所有Canvas元素的内容 + * + * @param webView 包含Canvas的WebView + * @param callback 获取结果的回调 + */ + public static void getAllCanvasBase64FromWebView(BridgeWebView webView, CanvasToBase64Callback callback) { + if (webView == null) { + if (callback != null) { + callback.onError("WebView is null"); + } + return; + } + + String javascript = "(function() {" + + "try {" + + "var canvases = document.getElementsByTagName('canvas');" + + "if (canvases.length === 0) return 'No canvas found';" + + "var results = [];" + + "for (var i = 0; i < canvases.length; i++) {" + + "try {" + + "var canvas = canvases[i];" + + "var dataUrl = canvas.toDataURL('image/png');" + + "results.push({" + + "index: i," + + "id: canvas.id || 'canvas_' + i," + + "width: canvas.width," + + "height: canvas.height," + + "dataUrl: dataUrl" + + "});" + + "} catch(e) {" + + "results.push({" + + "index: i," + + "error: e.message" + + "});" + + "}" + + "}" + + "return JSON.stringify(results);" + + "} catch(e) {" + + "return 'Error: ' + e.message;" + + "}" + + "})();"; + + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + webView.evaluateJavascript(javascript, new ValueCallback() { + @Override + public void onReceiveValue(String value) { + if (callback != null) { + if (value != null && value.startsWith("\"[")) { + // 移除引号 + String jsonResult = value.substring(1, value.length() - 1) + .replace("\\\"", "\"") + .replace("\\\\", "\\"); + callback.onSuccess(jsonResult); + } else { + String error = value != null ? value.replace("\"", "") : "Unknown error"; + callback.onError(error); + } + } + } + }); + } else { + if (callback != null) { + callback.onError("Android version too low (requires API 19+)"); + } + } + } + + /** + * 高级Canvas截图方法 - 组合使用多种技术 + * 1. 首先尝试JavaScript获取Canvas内容 + * 2. 如果失败,则回退到传统截图方法 + * + * @param webView 包含Canvas的WebView + * @param canvasId Canvas元素ID,可以为null + * @param callback 获取结果的回调 + */ + public static void captureCanvasAdvanced(BridgeWebView webView, String canvasId, CanvasToBase64Callback callback) { + // 首先尝试JavaScript方法 + getCanvasBase64FromWebView(webView, canvasId, new CanvasToBase64Callback() { + @Override + public void onSuccess(String base64Data) { + Log.d(TAG, "Successfully captured canvas using JavaScript method"); + if (callback != null) { + callback.onSuccess(base64Data); + } + } + + @Override + public void onError(String error) { + Log.d(TAG, "JavaScript method failed: " + error + ", trying fallback method"); + // JavaScript方法失败,使用传统截图方法作为后备 + String fallbackBase64 = captureWebViewToBase64(webView); + if (fallbackBase64 != null) { + Log.d(TAG, "Fallback method succeeded"); + if (callback != null) { + callback.onSuccess(fallbackBase64); + } + } else { + Log.e(TAG, "All methods failed"); + if (callback != null) { + callback.onError("All capture methods failed: " + error); + } + } + } + }); + } + + /** + * 便捷方法:直接从全局WebView获取Canvas base64数据 + * + * @param canvasId Canvas元素的ID,如果为null则获取第一个Canvas + * @param callback 获取结果的回调 + */ + public static void getCanvasBase64FromGlobalWebView(String canvasId, CanvasToBase64Callback callback) { + BridgeWebView webView = NewwebviewActivity.getWebView(); + if (webView == null) { + if (callback != null) { + callback.onError("Global WebView is not available"); + } + return; + } + getCanvasBase64FromWebView(webView, canvasId, callback); + } + + /** + * 便捷方法:直接从全局WebView获取Canvas base64数据(使用默认Canvas) + * + * @param callback 获取结果的回调 + */ + public static void getCanvasBase64FromGlobalWebView(CanvasToBase64Callback callback) { + getCanvasBase64FromGlobalWebView(null, callback); + } +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/commitLog.java b/app/src/main/java/com/tagmae/tsgame_erwang/commitLog.java new file mode 100644 index 0000000..55fea49 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/commitLog.java @@ -0,0 +1,135 @@ +package com.tagmae.tsgame_erwang; + +import android.content.Context; +import android.util.Xml; + +import com.android.volley.VolleyError; +import com.game.webgame.network.Volleyinterface; +import com.game.webgame.network.register; +import com.google.gson.Gson; +import com.tsgame.tsgame_niuniu.Bean.logbean; +import com.tsgame.tsgame_niuniu.Bean.sittingversion; +import com.tsgame.tsgame_niuniu.Bean.versionbean; +import com.tsgame.tsgame_niuniu.system.Myapplication; +import com.tsgame.tsgame_niuniu.util.Settingutil; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +public class commitLog { + + + public static void commitLog(Context con, String msg, String Packet) { + + versionbean ver = null; + try { + ver = pullassetxml(con.getAssets().open( + Settingutil.kfile + File.separator + "version.xml")); + } catch (IOException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + Map map = new HashMap(); + map.put("app", "youle"); + map.put("route", "agent"); + map.put("rpc", "submit_error"); + + logbean date = new logbean(); + date.setAgentid(ver.getAgentid()); + date.setGameid(ver.getGameid()); + date.setMsg(msg); + date.setPacket(Packet); + date.setPlayerid("android"); + + sittingversion sitting = new sittingversion(); + sitting.setApp("youle"); + sitting.setRoute("agent"); + sitting.setRpc("submit_error"); + sitting.setData(date); + + Gson gson = new Gson(); + String data = gson.toJson(sitting); + + System.out.println(data); + // http://ylyxservice1.0791ts.cn?{"app":"youle","data":{"agentid":"00bA05haB0d9ZC0fwGD09Q2OA30insbQ","gameid":"8x4l0rGjf026f60c48h0mbUAhK5vV16f","msg":"ffffff","packet":"牛牛","playerid":"android"},"route":"agent","rpc":"submit_error"} + register.PostJsonrequest1(data, + "", + new Volleyinterface(Myapplication.application, + Volleyinterface.mlistener, + Volleyinterface.mErrorLisener) { + @Override + public void onsuccess(String result) { + System.out.println("result=" + result); + Gson gson = new Gson(); + + } + + @Override + public void onerror(VolleyError arg0) { + System.out.println("arg0=" + arg0); + + } + }); + + } + + private static versionbean pullassetxml(InputStream inputStream) { + versionbean version2 = new versionbean(); + try { + XmlPullParser parser = Xml.newPullParser(); + // 2.设置解析的文件流 + parser.setInput(inputStream, "utf-8"); + // 3.得到事件类型(START_DOCUMENT,END_DOCUMENT,START_TAG, END_TAG, + // TEXT, etc.) + int type = parser.getEventType(); + // 一直读到文档结尾 + while (type != XmlPullParser.END_DOCUMENT) { + + switch (type) { + case XmlPullParser.START_TAG: + // 得到标签的名字 + String tag_name = parser.getName(); + if ("agent".equals(tag_name)) { + + String agentid = parser.getAttributeValue(null, "id"); + System.out.println("agentid=" + agentid); + version2.setAgentid(agentid); + + } else if ("game".equals(tag_name)) { + String gameid = parser.getAttributeValue(null, "id"); + System.out.println("gameid=" + gameid); + version2.setGameid(gameid); + } else if ("version".equals(tag_name)) { + + String version = parser + .getAttributeValue(null, "value"); + System.out.println("version=" + version); + version2.setVersion(version); + } + + break; + default: + break; + + } + // 继续往下一个事件解析 + type = parser.next(); + } + + } catch (XmlPullParserException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return version2; + } +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/gameactivity.java b/app/src/main/java/com/tagmae/tsgame_erwang/gameactivity.java new file mode 100644 index 0000000..c98f6a6 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/gameactivity.java @@ -0,0 +1,38 @@ +package com.tagmae.tsgame_erwang; + + +import com.jx.jyhd.R; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.view.View.OnClickListener; + +@SuppressLint("NewApi") public class gameactivity extends AppCompatActivity{ + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + + super.onCreate(savedInstanceState); + setContentView(R.layout.mainactivity); + findViewById(R.id.button1).setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + Intent in = new Intent(); + in.setClass(gameactivity.this, webviewActivity.class); + startActivity(in); + finish(); + + + } + }); + } +@Override +protected void onResume() { + // TODO Auto-generated method stub + super.onResume(); +} +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/mediaplayer1.java b/app/src/main/java/com/tagmae/tsgame_erwang/mediaplayer1.java new file mode 100644 index 0000000..9f9f1a7 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/mediaplayer1.java @@ -0,0 +1,99 @@ +package com.tagmae.tsgame_erwang; + +import java.io.IOException; + +import android.media.AudioManager; +import android.media.MediaPlayer; +import android.media.MediaPlayer.OnCompletionListener; +import android.media.MediaPlayer.OnErrorListener; +import android.media.MediaPlayer.OnPreparedListener; + +public class mediaplayer1 { + private MediaPlayer mp; + + private boolean ispause = false; + + public void play(String path, int loop, + OnCompletionListener OncompletionListener) { + + if (mp == null) { + mp = new MediaPlayer(); + mp.setOnErrorListener(new OnErrorListener() { + @Override + public boolean onError(MediaPlayer mp, int what, int extra) { + // TODO Auto-generated method stub + mp.reset(); + return false; + } + }); + } else { + mp.reset();// 可以使播放器从Error状态中恢复过来,重新会到Idle状态 + + } + try { + if (loop == 1) { + mp.setAudioStreamType(AudioManager.STREAM_MUSIC);// 准备完成后才可以播放 + mp.setOnCompletionListener(OncompletionListener); + mp.setDataSource(path); + + mp.prepareAsync();//异步缓存 + // mPlayer.prepare(); + mp.setOnPreparedListener(new OnPreparedListener() { + + @Override + public void onPrepared(MediaPlayer mp) { + // TODO Auto-generated method stub + mp.start(); + } + }); + mp.setLooping(true);// 循环播放 + + } else if (loop < 0) { + pause(); + + } else { + + mp.setLooping(false);// 单曲 + } + + } catch (IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (SecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalStateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + }catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // me.prepareAsync(); //异步缓冲 + } + + public void pause() { + if (mp != null && mp.isPlaying()) { + mp.pause(); + ispause = true; + } + } + + public void resume() { + if (mp != null && ispause) { + mp.start(); + ispause = false; + } + } + + public void release() { + if (mp != null) { + mp.stop(); + mp.release(); + mp = null; + } + } +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/openwebActivity1.java b/app/src/main/java/com/tagmae/tsgame_erwang/openwebActivity1.java new file mode 100644 index 0000000..14bb228 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/openwebActivity1.java @@ -0,0 +1,972 @@ +package com.tagmae.tsgame_erwang; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.app.ActivityManager; +import android.app.ActivityManager.RunningTaskInfo; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.ActivityNotFoundException; +import android.content.ComponentName; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.PixelFormat; +import android.net.Uri; +import android.os.Build; +import android.os.Build.VERSION_CODES; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AppCompatActivity; +import android.util.Log; +import android.view.KeyEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.view.WindowManager; +import android.webkit.JavascriptInterface; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.game.webgame.view.SpUtil; +import com.game.webgame.view.dialogexit; +import com.game.webgame.view.pmutil; +import com.lsjwzh.widget.materialloadingprogressbar.WebviewProgressDialog; +import com.tencent.smtt.export.external.interfaces.JsPromptResult; +import com.tencent.smtt.export.external.interfaces.JsResult; +import com.tencent.smtt.export.external.interfaces.WebResourceRequest; +import com.tencent.smtt.export.external.interfaces.WebResourceResponse; +import com.tencent.smtt.sdk.WebChromeClient; +import com.tencent.smtt.sdk.WebSettings; +import com.tencent.smtt.sdk.WebSettings.LayoutAlgorithm; +import com.tencent.smtt.sdk.WebView; +import com.tencent.smtt.sdk.WebViewClient; +import com.jx.jyhd.R; +import com.tsgame.tsgame_niuniu.system.Myapplication; +import com.tsgame.tsgame_niuniu.util.QQIntentShareUtil; +import com.tsgame.tsgame_niuniu.util.apputil; +import com.tsgame.tsgame_niuniu.util.DouYinIntentShareUtil; + +import java.util.List; + +import kr.co.namee.permissiongen.PermissionFail; +import kr.co.namee.permissiongen.PermissionGen; +import kr.co.namee.permissiongen.PermissionSuccess; + +public class openwebActivity1 extends AppCompatActivity { + + String[] permissons = new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }; + Bundle savedInstanceState; + static SharedPreferences Shared; + String loadurl = ""; + String data; + WebView x5webview; + ProgressDialog m_progressDlg; + WebviewProgressDialog webdialog; + private boolean isbackfaiish=true; + + // 添加分享按钮引用和分享工具类 + private ImageView btnShareQQ; + private ImageView btnShareDouyin; + private QQIntentShareUtil qqShareUtil; + private DouYinIntentShareUtil douYinIntentShareUtil; + // 分享测试图片路径 + private String shareImagePath; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + hideNavigationBar(); + /** + * 方法一 保持屏幕唤醒 + */ + + + setContentView(R.layout.openwebview); + x5webview = (WebView) findViewById(R.id.x5webview); + + try{ + AndroidBug5497Workaround.assistActivity(this); + }catch(Exception e){ + e.printStackTrace(); + } + + Myapplication.getInstance().addActivity(openwebActivity1.this); + + /* + * + * + * 方法二 + */ + + getWindow().setFormat(PixelFormat.TRANSLUCENT); + this.savedInstanceState = savedInstanceState; + + // initdate(save); + if (!hasPermission(permissons)) { + + PermissionGen.needPermission(openwebActivity1.this, 56, permissons); + + } else { + + initdate(savedInstanceState); + } + try{ + getclassname(); + }catch(Exception e){ + e.printStackTrace(); + } + + } + + @PermissionSuccess(requestCode = 56) + public void filstsucces() { + + initdate(savedInstanceState); + } + + @PermissionFail(requestCode = 56) + public void filstfail() { + + if (ActivityCompat.shouldShowRequestPermissionRationale( + openwebActivity1.this, + Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + // 未勾选不再提示 + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("提示"); + builder.setMessage("亲,当前应用缺少必要权限。不打开将无法使用"); + + // 拒绝, 退出应用 + builder.setNegativeButton("退出", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + + } + }); + + builder.setPositiveButton("打开", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + PermissionGen.needPermission(openwebActivity1.this, + 11, + Manifest.permission.WRITE_EXTERNAL_STORAGE); + } + }); + builder.show(); + System.out.println("拒绝"); + } else { + // 勾选不再提示 + if (ContextCompat.checkSelfPermission(this, + Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) { + + } + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + // Myapplication.getInstance().exit();//退出应用 + } + + // 隐藏虚拟按键 + public void hideNavigationBar() + { + // 只在API级别11及以上执行此功能(Android 3.0+) + if (android.os.Build.VERSION.SDK_INT >= 11) { + int uiFlags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar + | View.SYSTEM_UI_FLAG_FULLSCREEN; // hide status bar + + if (android.os.Build.VERSION.SDK_INT >= 19) { + uiFlags |= 0x00001000; //SYSTEM_UI_FLAG_IMMERSIVE_STICKY: hide navigation bars - compatibility: building API level is lower thatn 19, use magic number directly for higher API target level + } else { + uiFlags |= View.SYSTEM_UI_FLAG_LOW_PROFILE; + } + getWindow().getDecorView().setSystemUiVisibility(uiFlags); + } + } + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + if (hasFocus) { + hideNavigationBar(); + } + } + + private void getclassname() { + ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); + List runningTasks = manager.getRunningTasks(1); + RunningTaskInfo cinfo = runningTasks.get(0); + ComponentName component = cinfo.topActivity; + System.out.println("current activity is " + component.getClassName()); + apputil.activityname = component.getClassName(); + + } + private void initdate(Bundle savedInstanceState) { + Intent intent1 = getIntent(); + Uri uri=intent1.getData(); + if(uri!=null){ + String scheme= uri.getScheme(); + if(!pmutil.isnullorEmpty(scheme)){ + finish(); + } + } + Shared = SpUtil.getSharePerference(openwebActivity1.this); + + Intent in = getIntent(); + + loadurl = in.getStringExtra("url"); + + String orientation = in.getStringExtra("orientation"); + + System.out.println("orientation="+orientation); + if(!pmutil.isnullorEmpty(orientation)){ + // orientation = 1; 竖屏 + // orientation = 2; 横屏 + if(orientation.equals("1")){ + //设置为竖屏 + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + }else{ + //默认横屏 + } + }else{ + + } + + String title = in.getStringExtra("title"); + + if (!pmutil.isnullorEmpty(title)) { + RelativeLayout rela = (RelativeLayout) findViewById(R.id.relative1); + rela.setVisibility(View.VISIBLE); + } + + TextView heardtitle = (TextView) findViewById(R.id.heardtitle); + heardtitle.setText(title); + TextView text = (TextView) findViewById(R.id.backtext); + + text.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + finish(); + } + }); + + ImageView backimage = (ImageView) findViewById(R.id.backimage); + backimage.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + finish(); + } + }); + + data = in.getStringExtra("data"); + + getinit(); + + // 初始化分享按钮和分享工具类 + initShareComponents(); + } + + /** + * 初始化分享相关组件 + */ + private void initShareComponents() { + // 初始化分享工具类 + qqShareUtil = QQIntentShareUtil.getInstance(this); + douYinIntentShareUtil = DouYinIntentShareUtil.getInstance(this); + + // 设置分享测试图片路径(使用应用内部存储或外部存储中的图片) + shareImagePath = getExternalFilesDir(null) + "/share_test.png"; + + // 初始化测试图片(如果需要分享测试图片,应该在这里创建一个测试图片文件) + createTestShareImage(); + + // 找到按钮控件 + btnShareQQ = findViewById(R.id.btn_share_qq); + btnShareDouyin = findViewById(R.id.btn_share_douyin); + + // 设置QQ分享按钮点击事件 + btnShareQQ.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + shareToQQ(); + } + }); + + // 设置抖音分享按钮点击事件 + btnShareDouyin.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + shareToDouYin(); + } + }); + } + + /** + * 创建测试分享图片 + */ + private void createTestShareImage() { + try { + // 创建一个测试图片文件 + Bitmap bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888); + bitmap.eraseColor(android.graphics.Color.BLUE); + + java.io.FileOutputStream out = new java.io.FileOutputStream(shareImagePath); + bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); + out.flush(); + out.close(); + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(this, "创建测试分享图片失败", Toast.LENGTH_SHORT).show(); + } + } + + /** + * QQ分享 + */ + private void shareToQQ() { + qqShareUtil.setShareCallback(new QQIntentShareUtil.QQShareCallback() { + @Override + public void onSuccess() { + Toast.makeText(openwebActivity1.this, "QQ分享成功", Toast.LENGTH_SHORT).show(); + } + + @Override + public void onError(int code, String message) { + Toast.makeText(openwebActivity1.this, "QQ分享失败: " + message, Toast.LENGTH_SHORT).show(); + } + + @Override + public void onCancel() { + Toast.makeText(openwebActivity1.this, "QQ分享已取消", Toast.LENGTH_SHORT).show(); + } + }); + + qqShareUtil.shareImageToQQ(this, shareImagePath); + } + + /** + * 抖音分享 + */ + private void shareToDouYin() { + douYinIntentShareUtil.setShareCallback(new DouYinIntentShareUtil.DouYinShareCallback() { + @Override + public void onSuccess() { + Toast.makeText(openwebActivity1.this, "抖音分享成功", Toast.LENGTH_SHORT).show(); + } + + @Override + public void onError(int code, String message) { + Toast.makeText(openwebActivity1.this, "抖音分享失败: " + message, Toast.LENGTH_SHORT).show(); + } + + @Override + public void onCancel() { + Toast.makeText(openwebActivity1.this, "抖音分享已取消", Toast.LENGTH_SHORT).show(); + } + }); + + douYinIntentShareUtil.shareImageToDouyin(this, shareImagePath); + } + + private void getinit() { + // inithandler(); + + m_progressDlg = new ProgressDialog(this); + m_progressDlg.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + // 设置ProgressDialog 的进度条是否不明确 false 就是不设置为不明确 + m_progressDlg.setIndeterminate(false); + m_progressDlg.setCanceledOnTouchOutside(false); + + Shared = SpUtil.getSharePerference(openwebActivity1.this); + + initwebview(); + + } + + @SuppressLint({ "SetJavaScriptEnabled", "ClickableViewAccessibility" }) + private void initwebview() { + + + setWebViewClient(); + //x5webview.setWebViewClient(new mwebviewclient()); + x5webview.setWebChromeClient(new mchromeClient()); + + initWebViewSettings(); + //setWebViewProperty(); + x5webview.setOnLongClickListener(new View.OnLongClickListener() { + + @Override + public boolean onLongClick(View v) { + + return true; + } + }); + + x5webview.loadUrl(loadurl); + + x5webview.addJavascriptInterface(new settings(), "settings"); + + } + + protected void setWebViewClient() { + x5webview.setWebViewClient(new WebViewClient() { + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + + if (url.startsWith("weixin:") || url.startsWith("alipayqr:") + || url.startsWith("alipays:")) { + try { + + startActivity(new Intent( + "android.intent.action.VIEW", Uri.parse(url))); + } catch (ActivityNotFoundException localActivityNotFoundException) { + Toast.makeText(openwebActivity1.this, "请检查是否安装客户端", Toast.LENGTH_SHORT) + .show(); + + } + return true; + }else if (url.startsWith("tel:")) { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + startActivity(intent); + return super.shouldOverrideUrlLoading(view, url); + } else { + + return super.shouldOverrideUrlLoading(view, url); + } + } + + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + super.onPageStarted(view, url, favicon); + + } + + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + } + + @Override + public void onReceivedError(WebView view, int errorCode, + String description, String failingUrl) { + super.onReceivedError(view, errorCode, description, failingUrl); + + } + + @TargetApi(23) + @Override + public void onReceivedHttpError(WebView view, + WebResourceRequest request, + WebResourceResponse errorResponse) { + super.onReceivedHttpError(view, request, errorResponse); + + } + }); + } + + // 配置webview + @SuppressLint({ "SetJavaScriptEnabled", "JavascriptInterface" }) + protected void setWebViewProperty() { + WebSettings settings = x5webview.getSettings(); + // 支持JavaScript + settings.setJavaScriptEnabled(true); + // 支持通过js打开新的窗口 + settings.setJavaScriptCanOpenWindowsAutomatically(true); + settings.setDomStorageEnabled(true); + + settings.setCacheMode(android.webkit.WebSettings.LOAD_NO_CACHE);// 不使用缓存,只从网络获取数据 + settings.setAppCacheEnabled(false);// 是否设置缓存 + + } + @SuppressLint({ "SetJavaScriptEnabled", "JavascriptInterface" }) + private void initWebViewSettings() { + + if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) { + + x5webview.getSettings().setAllowUniversalAccessFromFileURLs(true); + } + + WebSettings webSetting = x5webview.getSettings(); + + x5webview.requestFocus(); + //x5webview.setWebViewClient(new WebViewClient()); + + webSetting.setAllowFileAccess(true); + webSetting.setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS); + // 设置WebView可触摸放大缩小 + webSetting.setSupportZoom(false); + webSetting.setBuiltInZoomControls(false); + // WebView双击变大,再双击后变小,当手动放大后,双击可以恢复到原始大小//设置此属性,可任意比例缩放 + webSetting.setUseWideViewPort(false); + webSetting.setSupportMultipleWindows(false); + webSetting.setDatabaseEnabled(true); + webSetting.setDomStorageEnabled(true); + webSetting.setJavaScriptEnabled(true); + + if(apputil.isNetworkConnected(this)){ + webSetting.setCacheMode(WebSettings.LOAD_DEFAULT);// cache-control决定是否从网络上取数据。 + }else{ + webSetting.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);// 使用缓存 + } + + webSetting.setAppCacheEnabled(true);// 是否设置缓存 + webSetting.setGeolocationEnabled(true);// //设置定位的数据库路径 + + } + + /** + * 退出程序 + */ + private void exitApp() { + finish(); + } + + class mwebviewclient extends WebViewClient { + + @Override + public void onPageStarted(WebView arg0, String arg1, Bitmap arg2) { + // TODO Auto-generated method stub + super.onPageStarted(arg0, arg1, arg2); + } + + @Override + public void onPageFinished(WebView arg0, String arg1) { + // TODO Auto-generated method stub + super.onPageFinished(arg0, arg1); + } + + @Override + public void onLoadResource(WebView webView, String s) { + super.onLoadResource(webView, s); + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + if (url.startsWith("weixin:") || url.startsWith("alipayqr:") + || url.startsWith("alipays:")) { + try { + //LogUtil.d("启动微信客户端", "-------"); + // hideProgressDialog(); + startActivity(new Intent( + "android.intent.action.VIEW", Uri.parse(url))); + } catch (ActivityNotFoundException localActivityNotFoundException) { + Toast.makeText(openwebActivity1.this, "请检查是否安装客户端", Toast.LENGTH_SHORT) + .show(); + + } + return true; + }else if (url.startsWith("tel:")) { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + startActivity(intent); + return super.shouldOverrideUrlLoading(view, url); + } else { + view.loadUrl(url); + return super.shouldOverrideUrlLoading(view, url); + } + + } + + @Override + public void onReceivedError(WebView webView, int i, String s, String s1) { + super.onReceivedError(webView, i, s, s1); + iswebviewerror = true; + } + + @Override + public void onReceivedHttpError(WebView webView, WebResourceRequest webResourceRequest, WebResourceResponse webResourceResponse) { + super.onReceivedHttpError(webView, webResourceRequest, webResourceResponse); + } + + @Override + public void onReceivedHttpAuthRequest( + WebView webview, + com.tencent.smtt.export.external.interfaces.HttpAuthHandler httpAuthHandlerhost, + String host, String realm) { + + boolean flag = httpAuthHandlerhost.useHttpAuthUsernamePassword(); + } + + } + + boolean isloddingfinish = false; + boolean isAamionfinish = false; + + public void webviewjh(final String name) { + runOnUiThread(new Runnable() { + @Override + public void run() { + + try { + x5webview.loadUrl(name); + } catch (Exception e) { + System.out.println(e.toString()); + } + } + }); + } + boolean iswebviewerror = false; + @SuppressLint("HandlerLeak") + Handler handler = new Handler() { + @SuppressLint({ "NewApi", "InlinedApi" }) + public void handleMessage(Message msg) { + switch (msg.what) { + case 1: + int pre = msg.getData().getInt("pre"); + + if (hasWindowFocus()) { + if (webdialog == null) { + webdialog = WebviewProgressDialog + .createDialog(openwebActivity1.this); + webdialog.setCanceledOnTouchOutside(false); + + } + + if (!openwebActivity1.this.isFinishing() + && !webdialog.isShowing()) { + + webdialog.show(); + } + + + + webdialog.setProgress(pre); + } + + break; + + default: + break; + } + }; + }; + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + switch (keyCode) { + + case KeyEvent.KEYCODE_BACK: + if(x5webview!=null){ + if (x5webview.canGoBack()) { + if(isbackfaiish){ + + finishweb(); + }else{ + String name = "javascript:gamebackkeydown();"; + webviewjh(name); + + x5webview.goBack(); + } + + } else { + finishweb(); + + } + }else{ + finish(); + } + + + return true; + + default: + break; + } + + return super.onKeyDown(keyCode, event); + } + + private boolean isexitdialogeshow=false; + + public void finishweb(){ + + if(isexitdialogeshow){ + dialogexit.show(openwebActivity1.this, "是否退出返回游戏", + new dialogexit.onexitlistener() { + @Override + public void paylistener() { + String name = "javascript:backgameData();"; + if (iswebviewerror) { + finish(); + } else { + webviewjh(name); + handler.postDelayed(new Runnable() { + @Override + public void run() { + + if (!openwebActivity1.this.isFinishing()) { + finish(); + } + + } + },200); + + } + + } + + @Override + public void cancellistener() { + + } + }); + }else{ + finish(); + } + } + @Override + protected void onDestroy() { + if (webdialog != null) { + if(webdialog.isShowing()){ + webdialog.dismiss(); + } + webdialog=null; + } + try { + if (x5webview != null) { + ViewParent parent = x5webview.getParent(); + if (parent != null) { + ((ViewGroup) parent).removeView(x5webview); + } + + x5webview.stopLoading(); + x5webview.setWebChromeClient(null); + x5webview.setWebViewClient(null); + // 退出时调用此方法,移除绑定的服务,否则某些特定系统会报错 + x5webview.getSettings().setJavaScriptEnabled(false); + + + x5webview.clearCache(true); + x5webview.setFocusable(true); // + x5webview.removeAllViews(); + x5webview.clearHistory(); + x5webview.clearView(); + x5webview.destroy(); + x5webview = null; + + // android.os.Process.killProcess(android.os.Process.myPid()); + } + } catch (Exception e) { + e.printStackTrace(); + } + + + super.onDestroy(); + } + + class mchromeClient extends WebChromeClient { + + @Override + public void onProgressChanged(WebView arg0, int arg1) { + + System.out.println(arg1); + if (arg1 == 100) { + // + if (!isloddingfinish) { + isloddingfinish = true; + + String getWebdata = "javascript:getWebdata(" + "'" + data + + "'" + ");"; + webviewjh(getWebdata); + System.out.println("getWebdata"); + } + + handler.postDelayed(new Runnable() { + public void run() { + if (webdialog != null) { + if (webdialog.isShowing()) { + // updates(); + webdialog.dismiss(); + } + } + + } + + }, 10); + + } else { + + // isloddingfinish=false; + if(!isloddingfinish){ + Message msg = new Message(); + Bundle bundle = new Bundle(); + bundle.putInt("pre", arg1); + msg.setData(bundle); + msg.what = 1; + handler.sendMessage(msg); + } + + + } + // super.onProgressChanged(arg0, arg1); + } + + @Override + public boolean onJsConfirm(WebView arg0, String arg1, String arg2, + JsResult arg3) { + return super.onJsConfirm(arg0, arg1, arg2, arg3); + } + + /** + * webview 的窗口转移 + */ + @Override + public boolean onCreateWindow(WebView arg0, boolean arg1, boolean arg2, + Message msg) { + // TODO Auto-generated method stub + + return true; + } + + @Override + public boolean onJsAlert(WebView arg0, String arg1, String arg2, + JsResult arg3) { + /** + * 这里写入你自定义的window alert + */ + + Log.i("yuanhaizhou", "setX5webview = null"); + return super.onJsAlert(null, "www.baidu.com", "aa", arg3); + } + + /** + * 对应js 的通知弹框 ,可以用来实现js 和 android之间的通信 + */ + @Override + public boolean onJsPrompt(WebView arg0, String arg1, String arg2, + String arg3, JsPromptResult arg4) { + // 在这里可以判定js传过来的数据,用于调起android native 方法 + + return super.onJsPrompt(arg0, arg1, arg2, arg3, arg4); + } + + @Override + public void onReceivedTitle(WebView arg0, final String arg1) { + super.onReceivedTitle(arg0, arg1); + Log.i("yuanhaizhou", "webpage title is " + arg1); + + } + + } + + /** + * 为子类提供一个检查权限的方法 + * + * @param permissions + * @return + */ + public boolean hasPermission(String... permissions) { + for (String permission : permissions) { + if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { + return false; + + } + } + return true; + } + + @Override + public void onRequestPermissionsResult(int requestCode, + String[] permissions, int[] grantResults) { + + PermissionGen.onRequestPermissionsResult(this, requestCode, + permissions, grantResults); + } + @SuppressLint("HandlerLeak") + Handler mhadler1 = new Handler() { + public void handleMessage(Message msg) { + switch (msg.what) { + case 1: + try { + if(!pmutil.isnullorEmpty(url)){ + + } + System.out.println(url); + x5webview.loadUrl(url); + } catch (Exception e) { + System.out.println(e.toString()); + + } + break; + default: + break; + } + } + }; + + private String url; + + + class settings { + + @JavascriptInterface + public void backgameData(String data) { + Intent in = new Intent(); + Bundle bundle = new Bundle(); + bundle.putString("data", data); + in.putExtras(bundle); + setResult(101, in); + exitApp(); + } + @JavascriptInterface + public void browser(String browserurl) { + Intent intent = new Intent(); + intent.setAction("android.intent.action.VIEW"); + + Uri content_url = Uri.parse(browserurl); + if(BrowserUtil.isQQBrowserInstalled()){ + intent.setClassName("com.tencent.mtt","com.tencent.mtt.MainActivity");//打开QQ浏览器 + }else{ + } + intent.setData(content_url); + startActivity(intent); + + } + @JavascriptInterface + public void finishweb() { + finish(); + } + + @JavascriptInterface + public void isexitdialogeshow() { + isexitdialogeshow=true; + } + @JavascriptInterface + public void isbackfinishweb() { + isbackfaiish=false; + } + @JavascriptInterface + public void loadurl(String urls) { + + url = urls; + System.out.println("url==" + url); + mhadler1.sendEmptyMessage(1); + + } + } + +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/soundpoolUtil.java b/app/src/main/java/com/tagmae/tsgame_erwang/soundpoolUtil.java new file mode 100644 index 0000000..05d0f56 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/soundpoolUtil.java @@ -0,0 +1,101 @@ +package com.tagmae.tsgame_erwang; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.LogRecord; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.media.AudioAttributes; +import android.media.AudioManager; +import android.media.SoundPool; +import android.media.SoundPool.OnLoadCompleteListener; +import android.os.Build; +import android.os.Handler; + +@SuppressLint("NewApi") +public class soundpoolUtil { + + private static SoundPool sp = null;// 声明一个SoundPool的引用 + + static Map map = new HashMap(); + Handler hand = new Handler(); + static List list = new ArrayList(); + + // loop 是否循环 0不循环 -1循环 + public static void playSound(final String sound, final int loop) { + if (sp == null) { + if (Build.VERSION.SDK_INT >= 21) { + SoundPool.Builder builder = new SoundPool.Builder(); + builder.setMaxStreams(10);// 传入音频数量 + // AudioAttributes是一个封装音频各种属性的方法 + AudioAttributes.Builder attrBuilder = new AudioAttributes.Builder(); + attrBuilder.setLegacyStreamType(AudioManager.STREAM_MUSIC);// 设置音频流的合适的属性 + builder.setAudioAttributes(attrBuilder.build());// 加载一个AudioAttributes + sp = builder.build(); + } else { + sp = new SoundPool(10, AudioManager.STREAM_MUSIC, 5);// 创建SoundPool对象 + } + } + + if (loop >= 0) { + + final int soundid = sp.load(sound, 1); + + sp.setOnLoadCompleteListener(new OnLoadCompleteListener() { + + @Override + public void onLoadComplete(SoundPool soundPool, int sampleId, + int status) { + int currentStreamId; + + // if(loop==1){ + // currentStreamId = sp.play(soundid, (float) 1, (float) 1, + // 1, -1, + // 1.0f); + // }else + if (loop == 0) { + currentStreamId = soundPool.play(soundid, (float) 1, + (float) 1, 1, 0, 1.0f); + map.put(sound, currentStreamId); + String log = "playSound currentStreamId:" + + String.valueOf(currentStreamId); + System.out.println(log); + } + + } + }); + + } else if (loop < 0) { + if (map.containsKey(sound)) { + int streamID = map.get(sound); + try { + sp.pause(streamID); + + } catch (Exception e) { + + } + + // sp.release(); + + // 暂停声音 + } + + } + + } + + /** + * @Title: dismisSoundPool @Description: 释放播放池 @param 设定文件 @return void 返回类型 @throws + */ + public static void dismisSoundPool() { + if (sp != null) { + sp.release(); + sp = null; + } + } + +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/utils/Base64ImageUtil.java b/app/src/main/java/com/tagmae/tsgame_erwang/utils/Base64ImageUtil.java new file mode 100644 index 0000000..0e45472 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/utils/Base64ImageUtil.java @@ -0,0 +1,215 @@ +package com.tagmae.tsgame_erwang.utils; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Environment; +import android.text.TextUtils; +import android.util.Base64; +import android.util.Log; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +/** + * Base64与图片互相转换工具类 + */ +public class Base64ImageUtil { + + private static final String TAG = "Base64ImageUtil"; + + /** + * 将Base64编码的字符串转换为Bitmap + * + * @param base64String Base64编码的字符串(不包含前缀如"data:image/jpeg;base64,") + * @return 解码后的Bitmap,失败则返回null + */ + public static Bitmap base64ToBitmap(String base64String) { + if (TextUtils.isEmpty(base64String)) { + Log.e(TAG, "Base64字符串为空"); + return null; + } + + try { + // 去除可能存在的图片前缀 + if (base64String.contains(",")) { + base64String = base64String.split(",")[1]; + } + + byte[] decodedBytes = Base64.decode(base64String, Base64.DEFAULT); + return BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length); + } catch (Exception e) { + Log.e(TAG, "Base64转Bitmap出错: " + e.getMessage()); + return null; + } + } + + /** + * 将Base64编码的字符串保存为图片文件 + * + * @param context 上下文 + * @param base64String Base64编码的字符串 + * @param fileName 文件名,如果为null则自动生成 + * @return 保存的图片文件的Uri,失败则返回null + */ + public static Uri base64ToImageFile(Context context, String base64String, String fileName) { + Bitmap bitmap = base64ToBitmap(base64String); + if (bitmap == null) { + Log.e(TAG, "Base64转图片失败"); + return null; + } + + return saveBitmapToFile(context, bitmap, fileName); + } + + /** + * 保存Bitmap到文件 + * + * @param context 上下文 + * @param bitmap 要保存的Bitmap + * @param fileName 文件名,为null则自动生成 + * @return 保存的图片Uri,失败则返回null + */ + public static Uri saveBitmapToFile(Context context, Bitmap bitmap, String fileName) { + // 创建保存的文件名 + if (TextUtils.isEmpty(fileName)) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()); + fileName = "IMG_" + sdf.format(new Date()) + ".jpg"; + } + + // 判断存储状态 + File storageDir; + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES); + } else { + storageDir = context.getFilesDir(); + } + + if (!storageDir.exists()) { + storageDir.mkdirs(); + } + + File imageFile = new File(storageDir, fileName); + try (FileOutputStream fos = new FileOutputStream(imageFile)) { + // 压缩图片到文件 + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos); + fos.flush(); + return Uri.fromFile(imageFile); + } catch (IOException e) { + Log.e(TAG, "保存图片出错: " + e.getMessage()); + return null; + } finally { + // 如果不再需要bitmap,释放内存 + if (!bitmap.isRecycled()) { + bitmap.recycle(); + } + } + } + + /** + * 将Bitmap转换为Base64编码的字符串 + * + * @param bitmap 要转换的Bitmap + * @param quality 压缩质量 (0-100) + * @return Base64编码的字符串,转换失败则返回null + */ + public static String bitmapToBase64(Bitmap bitmap, int quality) { + if (bitmap == null) { + return null; + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos); + byte[] bytes = baos.toByteArray(); + return Base64.encodeToString(bytes, Base64.DEFAULT); + } catch (Exception e) { + Log.e(TAG, "Bitmap转Base64出错: " + e.getMessage()); + return null; + } finally { + try { + baos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * 检查Base64字符串大小 + * + * @param base64String Base64编码的字符串 + * @return 字符串表示的近似大小 + */ + public static String getBase64Size(String base64String) { + if (TextUtils.isEmpty(base64String)) { + return "0 KB"; + } + + // 去除可能存在的前缀 + if (base64String.contains(",")) { + base64String = base64String.split(",")[1]; + } + + // 计算原始大小 (Base64编码会将3字节数据编码为4个字符) + float sizeInBytes = (float) (base64String.length() * 3) / 4; + + if (sizeInBytes < 1024) { + return String.format(Locale.getDefault(), "%.2f B", sizeInBytes); + } else if (sizeInBytes < 1024 * 1024) { + return String.format(Locale.getDefault(), "%.2f KB", sizeInBytes / 1024); + } else { + return String.format(Locale.getDefault(), "%.2f MB", sizeInBytes / (1024 * 1024)); + } + } + + /** + * 压缩Base64编码的图片 + * + * @param base64String 原始Base64字符串 + * @param maxSizeKB 目标大小(KB) + * @return 压缩后的Base64字符串 + */ + public static String compressBase64Image(String base64String, int maxSizeKB) { + if (TextUtils.isEmpty(base64String)) { + return null; + } + + // 转换为bitmap + Bitmap bitmap = base64ToBitmap(base64String); + if (bitmap == null) { + return null; + } + + // 初始质量为80% + int quality = 80; + String result = bitmapToBase64(bitmap, quality); + + // 如果已经小于最大大小,直接返回 + float currentSize = (result.length() * 3) / 4f / 1024f; // KB + if (currentSize <= maxSizeKB) { + return result; + } + + // 循环压缩 + while (currentSize > maxSizeKB && quality > 10) { + // 每次降低10%质量 + quality -= 10; + result = bitmapToBase64(bitmap, quality); + currentSize = (result.length() * 3) / 4f / 1024f; + } + + // 释放bitmap内存 + if (!bitmap.isRecycled()) { + bitmap.recycle(); + } + + return result; + } +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/utils/ImageProcessUtils.java b/app/src/main/java/com/tagmae/tsgame_erwang/utils/ImageProcessUtils.java new file mode 100644 index 0000000..53ea568 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/utils/ImageProcessUtils.java @@ -0,0 +1,237 @@ +package com.tagmae.tsgame_erwang.utils; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.AsyncTask; +import android.os.Environment; +import android.text.TextUtils; +import android.util.Base64; +import android.util.Log; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +/** + * 图片处理工具类 + * 提供图片保存、编码转换等功能 + */ +public class ImageProcessUtils { + + private static final String TAG = "ImageProcessUtils"; + + /** + * 图片保存回调接口 + */ + public interface ImageSaveCallback { + /** + * 图片保存成功回调 + * @param imagePath 保存的图片路径 + */ + void onSuccess(String imagePath); + + /** + * 图片保存失败回调 + * @param errorMsg 错误信息 + */ + void onError(String errorMsg); + } + + /** + * 将Base64编码的图片保存到缓存目录 + * @param context 上下文 + * @param base64Image Base64编码的图片(去掉前缀:data:image/jpeg;base64,) + * @param callback 保存结果回调 + */ + public static void saveBase64ImageToCache(final Context context, final String base64Image, final ImageSaveCallback callback) { + if (TextUtils.isEmpty(base64Image)) { + if (callback != null) { + callback.onError("图片数据为空"); + } + return; + } + + new AsyncTask() { + @Override + protected String doInBackground(Void... voids) { + try { + // 解码Base64图片数据 + String base64Data = base64Image; + // 检查并去除可能的Base64前缀 + if (base64Data.contains(",")) { + base64Data = base64Data.substring(base64Data.indexOf(",") + 1); + } + + byte[] decodedBytes = Base64.decode(base64Data, Base64.DEFAULT); + Bitmap bitmap = BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length); + if (bitmap == null) { + return null; + } + + // 保存Bitmap + return saveBitmapToCache(context, bitmap); + } catch (Exception e) { + Log.e(TAG, "保存Base64图片出错", e); + return null; + } + } + + @Override + protected void onPostExecute(String imagePath) { + if (callback != null) { + if (imagePath != null) { + callback.onSuccess(imagePath); + } else { + callback.onError("保存图片失败"); + } + } + } + }.execute(); + } + + /** + * 将Bitmap保存到缓存目录 + * @param context 上下文 + * @param bitmap 要保存的图片Bitmap对象 + * @param callback 保存结果回调 + */ + public static void saveBitmapToCache(final Context context, final Bitmap bitmap, final ImageSaveCallback callback) { + if (bitmap == null) { + if (callback != null) { + callback.onError("图片数据为空"); + } + return; + } + + new AsyncTask() { + @Override + protected String doInBackground(Void... voids) { + try { + return saveBitmapToCache(context, bitmap); + } catch (Exception e) { + Log.e(TAG, "保存Bitmap图片出错", e); + return null; + } + } + + @Override + protected void onPostExecute(String imagePath) { + if (callback != null) { + if (imagePath != null) { + callback.onSuccess(imagePath); + } else { + callback.onError("保存图片失败"); + } + } + } + }.execute(); + } + + /** + * 将Bitmap保存到缓存目录(同步方法) + * @param context 上下文 + * @param bitmap 要保存的Bitmap + * @return 保存的图片路径,失败返回null + */ + private static String saveBitmapToCache(Context context, Bitmap bitmap) { + File file; + + // 参考提供的代码,优先使用SD卡存储,如果没有SD卡则使用系统存储 + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + // sd卡存储(/mnt/sdcard/cache) + file = Environment.getExternalStorageDirectory(); // 获取根目录 + } else { + // 没有SD卡,缓存到系统存储 + file = Environment.getDataDirectory(); + } + + if (file == null) { + Log.e(TAG, "获取存储目录失败"); + return null; + } + + // 确保应用专用目录存在 + File appDir = new File(file, "tsgame_share_images"); + if (!appDir.exists()) { + if (!appDir.mkdirs()) { + Log.e(TAG, "创建应用专用目录失败"); + // 如果创建失败,尝试使用应用的缓存目录 + appDir = context.getExternalCacheDir(); + if (appDir == null) { + appDir = context.getCacheDir(); + } + if (appDir == null) { + Log.e(TAG, "获取缓存目录失败"); + return null; + } + } + } + + // 生成唯一文件名 + String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); + String imageFileName = "SHARE_" + timeStamp + ".jpg"; + File imageFile = new File(appDir, imageFileName); + + // 保存图片 + FileOutputStream fos = null; + try { + fos = new FileOutputStream(imageFile); + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos); + fos.flush(); + return imageFile.getAbsolutePath(); + } catch (IOException e) { + Log.e(TAG, "保存图片到文件出错", e); + return null; + } finally { + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + Log.e(TAG, "关闭文件流出错", e); + } + } + } + } + + /** + * 清理缓存的分享图片 + * @param context 上下文 + * @return 清理是否成功 + */ + public static boolean clearCachedShareImages(Context context) { + File cacheDir; + + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + cacheDir = context.getExternalCacheDir(); + } else { + cacheDir = context.getCacheDir(); + } + + if (cacheDir == null) { + return false; + } + + File imagesDir = new File(cacheDir, "share_images"); + if (imagesDir.exists()) { + try { + File[] files = imagesDir.listFiles(); + if (files != null) { + for (File file : files) { + if (!file.delete()) { + Log.w(TAG, "删除缓存图片失败: " + file.getAbsolutePath()); + } + } + } + return imagesDir.delete(); + } catch (Exception e) { + Log.e(TAG, "清理缓存图片出错", e); + return false; + } + } + return true; + } +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/utils/PermissionUtils.java b/app/src/main/java/com/tagmae/tsgame_erwang/utils/PermissionUtils.java new file mode 100644 index 0000000..e69de29 diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/webserverInstance.java b/app/src/main/java/com/tagmae/tsgame_erwang/webserverInstance.java new file mode 100644 index 0000000..6f1d3f9 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/webserverInstance.java @@ -0,0 +1,34 @@ +package com.tagmae.tsgame_erwang; + +/** + * 作者:YMI on 2017/12/7 16:53 + * 邮箱:18702631465@163.com + * QQ:1078561230 + * + * 已更新为使用新的HTTP服务器 + */ + +public class webserverInstance { + private static webserverInstance Instance; + + public static webserverInstance getInstance() { + if (null == Instance) { + // http://localhost:4477/testurl + Instance = new webserverInstance(); + } + return Instance; + } + + public void creat() { + // 使用新的HTTP服务器 + NewWebServerInstance.getInstance().create(4477); + } + + public boolean iscreatandrun() { + return NewWebServerInstance.getInstance().isRunning(); + } + + public void webclose() { + NewWebServerInstance.getInstance().stop(); + } +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/webviewActivity.java b/app/src/main/java/com/tagmae/tsgame_erwang/webviewActivity.java new file mode 100644 index 0000000..b0b5910 --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/webviewActivity.java @@ -0,0 +1,7386 @@ +package com.tagmae.tsgame_erwang; + +import com.tagmae.jsbridge.BridgeHandler; +import com.tagmae.jsbridge.BridgeWebView; +import com.tagmae.jsbridge.BridgeWebViewClient; +import com.tagmae.jsbridge.CallBackFunction; +import com.tagmae.jsbridge.DefaultHandler; +import com.tencent.smtt.export.external.extension.interfaces.IX5WebViewExtension; +import com.tencent.smtt.export.external.interfaces.WebResourceError; +import com.tencent.smtt.export.external.interfaces.WebResourceRequest; + + +import com.jx.jyhd.R; +import com.jx.jyhd.simcpux.Constants; +import com.jx.jyhd.simcpux.MD5; +import com.jx.jyhd.simcpux.Util; +import com.jx.jyhd.simcpux.Wxistrue; +import com.jx.jyhd.simcpux.util.WeChatShareUtil; +import com.jx.jyhd.wxapi.WXEntryActivity; +import com.jx.jyhd.wxapi.WXPayEntryActivity; +import com.tsgame.tsgame_niuniu.Bean.Othervideoinfo; +import com.tsgame.tsgame_niuniu.Bean.videoinfobean; + +import android.Manifest; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.ActivityManager; +import android.app.ActivityManager.RunningAppProcessInfo; +import android.app.ActivityManager.RunningTaskInfo; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.BroadcastReceiver; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Bitmap.CompressFormat; +import android.graphics.Bitmap.Config; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Picture; +import android.graphics.PixelFormat; +import android.media.MediaPlayer; +import android.media.MediaPlayer.OnCompletionListener; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.Uri; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.os.AsyncTask; +import android.os.BatteryManager; +import android.os.Build; +import android.os.Build.VERSION_CODES; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.Message; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; +import android.os.Vibrator; +import android.provider.MediaStore; +import android.provider.Settings; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AppCompatActivity; +import android.telephony.TelephonyManager; +import android.util.Base64; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.TypedValue; +import android.util.Xml; +import android.view.Display; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.SurfaceView; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnLongClickListener; +import android.view.View.OnTouchListener; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.view.WindowManager; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.amap.api.location.AMapLocation; +import com.amap.api.location.AMapLocationClient; +import com.amap.api.location.AMapLocationClientOption; +import com.amap.api.location.AMapLocationClientOption.AMapLocationMode; +import com.amap.api.location.AMapLocationListener; +import com.amap.api.maps2d.LocationSource.OnLocationChangedListener; +import com.android.volley.VolleyError; +import com.android.volley.toolbox.ImageLoader.ImageContainer; +import com.android.volley.toolbox.ImageLoader.ImageListener; +import com.android.volley.toolbox.ImageRequest; +import com.badoo.mobile.util.WeakHandler; +import com.ceshi.tsgame.shake.NeedForSound; +import com.ceshi.tsgame.shake.ShakeListener; +import com.ceshi.tsgame.shake.ShakeListener.OnShakeListenerCallBack; +import com.game.webgame.network.Volleyinterface; +import com.game.webgame.network.Volleyinterface1; +import com.game.webgame.network.register; +import com.game.webgame.network.volleymanager; +import com.game.webgame.view.SpUtil; +import com.game.webgame.view.dialogexit; +import com.game.webgame.view.dialogexit.onexitlistener; +import com.game.webgame.view.pmutil; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.nickming.view.AudioManager; +import com.nickming.view.AudioManager.AudioStageListener; +import com.nickming.view.DialogManager; +import com.qiniu.android.http.ResponseInfo; +import com.qiniu.android.storage.UpCompletionHandler; +import com.qiniu.android.storage.UploadManager; +import com.qiniu.android.storage.UploadOptions; +import com.qiniu.util.Auth; +import com.tencent.bugly.crashreport.CrashReport; +import com.tencent.bugly.crashreport.CrashReport.UserStrategy; +import com.tencent.bugly.crashreport.crash.h5.H5JavaScriptInterface; +import com.tencent.mm.opensdk.modelmsg.SendAuth; +import com.tencent.mm.opensdk.modelmsg.SendMessageToWX; +import com.tencent.mm.opensdk.modelmsg.WXImageObject; +import com.tencent.mm.opensdk.modelmsg.WXMediaMessage; +import com.tencent.mm.opensdk.modelmsg.WXWebpageObject; +import com.tencent.mm.opensdk.modelpay.PayReq; +import com.tencent.mm.opensdk.openapi.IWXAPI; +import com.tencent.mm.opensdk.openapi.WXAPIFactory; +import com.tencent.smtt.export.external.interfaces.JsPromptResult; +import com.tencent.smtt.export.external.interfaces.JsResult; +import com.tencent.smtt.sdk.CacheManager; +import com.tencent.smtt.sdk.QbSdk; +import com.tencent.smtt.sdk.WebChromeClient; +import com.tencent.smtt.sdk.WebSettings; +import com.tencent.smtt.sdk.WebSettings.LayoutAlgorithm; +import com.tencent.smtt.sdk.WebView; + +import com.tsgame.tsgame_niuniu.Bean.DragVideoinfoBean; +import com.tsgame.tsgame_niuniu.Bean.GamePayBean; +import com.tsgame.tsgame_niuniu.Bean.MaplocationInfo; +import com.tsgame.tsgame_niuniu.Bean.Wifinetworkbean; +import com.tsgame.tsgame_niuniu.Bean.phoneInfoBean; +import com.tsgame.tsgame_niuniu.Bean.savephotoURLBean; + +import com.tsgame.tsgame_niuniu.Volley.IamgeCache.ImageCacheManager; +import com.tsgame.tsgame_niuniu.buglyutil.BuglyUtil; + + +import com.tsgame.tsgame_niuniu.receiver.ScreenListener; +import com.tsgame.tsgame_niuniu.simcpux.bean.sharetypeBean; +import com.tsgame.tsgame_niuniu.system.Myapplication; +import com.tsgame.tsgame_niuniu.system.WX_Myurl; +import com.tsgame.tsgame_niuniu.util.MediaFile; +import com.tsgame.tsgame_niuniu.util.Settingutil; +import com.tsgame.tsgame_niuniu.util.VibratorUtil; +import com.tsgame.tsgame_niuniu.util.apputil; +import com.tsgame.tsgame_niuniu.util.phoneutil; + +import com.umeng.analytics.MobclickAgent; +import com.umeng.analytics.game.UMGameAgent; +import com.xys.libzxing.zxing.activity.CaptureActivity; +import com.yanzhenjie.nohttp.tools.NetUtil; + +import com.yue.view.DragViewGroup; + +import org.apache.http.NameValuePair; +import org.apache.http.message.BasicNameValuePair; +import org.json.JSONException; +import org.json.JSONObject; +//import org.xianliao.im.sdk.api.ISGAPI; +//import org.xianliao.im.sdk.api.SGAPIFactory; +//import org.xianliao.im.sdk.constants.SGConstants; +//import org.xianliao.im.sdk.modelmsg.SGImageObject; +//import org.xianliao.im.sdk.modelmsg.SGLinkObject; +//import org.xianliao.im.sdk.modelmsg.SGMediaMessage; +//import org.xianliao.im.sdk.modelmsg.SendMessageToSG; +import org.xmlpull.v1.XmlPullParser; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringReader; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.InvalidParameterException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +//import cn.jpush.android.api.JPushInterface; +import io.agora.rtc.IRtcEngineEventHandler; +import io.agora.rtc.RtcEngine; +import io.agora.rtc.video.VideoCanvas; +import kr.co.namee.permissiongen.PermissionFail; +import kr.co.namee.permissiongen.PermissionGen; +import kr.co.namee.permissiongen.PermissionSuccess; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Headers; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +@SuppressLint({"NewApi", "HandlerLeak"}) +public class webviewActivity extends AppCompatActivity implements + OnClickListener, AudioStageListener, AMapLocationListener { + BridgeWebView x5webview; + private static final String mHomeUrl = "http://120.25.60.74:8001/index.html"; + private final String webviewurl = "file:///android_asset/niuniu/index1.html"; + private IWXAPI api; + private IWXAPI msgApi; + Dialog dialog; + private boolean iscontinuouslocation = false;// 是否持续定位 + private UserStrategy strategy = null; + + private static final int THUMB_SIZE = 250; + private static int service = 1; + sharetypeBean bean; + public static int aSd = 1; + private DialogManager mDialogManager; + private AudioManager mAudioManager; + // 已经开始录音 + private static boolean isRecording = false; + public boolean isForeground = true;// 是否在前台 true false + private float mTime = 0; + /** + * 微信支付 + */ + PayReq req; + private StringBuffer sb; + Map resultunifiedorder; + + static SharedPreferences Shared; + private static String bitmappath; + // ImageView image; + private static final int STATE_NORMAL = 1; + private static final int STATE_RECORDING = 2; + private static final int STATE_WANT_TO_CANCEL = 3; + Handler handler1 = new Handler(); + // Bitmap bitmap; + static int x1; // 按下时的坐标 + static int y1;// 按下时的坐标 + private boolean mReady = false; + private int mCurrentState = STATE_NORMAL; + private boolean isautio = false; + private UploadManager uploadManager; + + private String destFileDir = null; + private String dirs = null; + + Bundle save; + + private SharedPreferences sp; + + File photofile1 = null; + + /** + * 权限 + */ + public String[] carpermission = new String[]{ + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.RECORD_AUDIO}; + String[] camerapermission1 = new String[]{ + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.CAMERA}; + public String[] camerapermission = new String[]{Manifest.permission.CAMERA}; + + private static final String PACKAGE_URL_SCHEME = "package:"; // 方案 + private boolean isDown = false; + + private boolean isStopPlay = false;// 是否停止了播放声音 + + private boolean isPlayaudio = false;// 是否在播放 + + // 准备三个常量 + private static final int MSG_AUDIO_PREPARED = 0X1110; + private static final int MSG_VOICE_CHANGE = 0X111; + private static final int MSG_DIALOG_DIMISS = 0X112; + private static final int MSG_DIALOG_Audio_DIMISS = 0X113; + // 升级 + + // String m_newVerName; // 最新版的版本名 版本名 + String m_appNameStr = "tsgame_niuniu.apk"; // 下载到本地要给这个APP命的名字 + + List testphoto;// 图片下载目录 + + List testphoto1 = new ArrayList();// 图片下载目录 + + private int photosize = 0; + + private Boolean getphotoistrue = true; + + BatteryReceiver batteryReceiver; + WifiChangeBroadcastReceiver WifiChangeReceiver; + MyNetReceiver myNetReceiver; + + ScreenListener screen; + private int downloadnum = 0; // 下载失败次数 + + private int downloadsum = 3; // 最多下载次数 + + private OkHttpClient okclient = new OkHttpClient(); + + List photolist = new ArrayList(); + + Wifinetworkbean wifibean = new Wifinetworkbean(); + + /** + * 上次点击返回键的时间 + */ + private long lastBackPressed; + /** + * 上次点击返回键的时间 + */ + private static final int QUIT_INTERVAL = 1000; + + private static String uservoice = "";// 用户座位动画id + + // 初始化AMapLocationClientOption对象 + AMapLocationClientOption mLocationOption = new AMapLocationClientOption(); + // 声明AMapLocationClient类对象 + public AMapLocationClient mLocationClient = null; + + OnLocationChangedListener mListener; + /** + * 权限 + */ + public String[] locationpermission = new String[]{ + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.READ_PHONE_STATE}; + + WeakHandler mhandler = new WeakHandler(new Handler.Callback() { + + @Override + public boolean handleMessage(Message msg) { + switch (msg.what) { + case MSG_AUDIO_PREPARED: + // 显示应该是在audio end prepare之后回调 + + isRecording = true; + + if (mDialogManager != null + && !webviewActivity.this.isFinishing()) { + try { + mDialogManager.showRecordingDialog(); + } catch (Exception e) { + // TODO: handle exception + } + + } + + System.out.println("isRecording" + isRecording); + new Thread(mGetVoiceLevelRunnable).start(); + + // 需要开启一个线程来变换音量 + break; + case MSG_VOICE_CHANGE: + mDialogManager.updateVoiceLevel(mAudioManager.getVoiceLevel(7)); + + break; + case MSG_DIALOG_DIMISS: + + mDialogManager.dimissDialog(); + + break; + case MSG_DIALOG_Audio_DIMISS: + + if (isRecording) { + System.out.println("重新关闭"); + mDialogManager.dimissDialog(); + mAudioManager.cancel(); + reset(); + + } else if (!isRecording && isautio) { + mhandler.sendEmptyMessageDelayed(MSG_DIALOG_Audio_DIMISS, + 1000);// 持续1.3 + } + + break; + + } + return false; + } + + }); + + @SuppressLint("HandlerLeak") + Handler photohandler = new Handler() { + public void handleMessage(Message msg) { + + int what = msg.what; + + if (what == 0) { + Gson gson = new Gson(); + // for (int i = 0; i < testphoto1.size(); i++) { + // savephotoURLBean bean = testphoto1.get(i); + // } + String json = gson.toJson(testphoto1); +// String getphoto = "javascript:getphoto(" + "'" + json + "'" +// + ");"; +// webviewjh(getphoto); + x5webview.callHandler("getphoto", json, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + getphotoistrue = true; + + } else if (what == 1) { + Bundle bundle = msg.getData(); + String photo = bundle.getString("photo"); + // savephoto(photo); + if (getphotoistrue) { + + savephoto(photo); + } else { + Message msg1 = new Message(); + msg1.what = 1; + + Bundle bundel = new Bundle(); + bundel.putString("photo", photo); + + msg1.setData(bundel); + photohandler.sendMessageDelayed(msg1, 200); + } + + } + + } + }; + + Handler playhandler = new Handler() { + public void handleMessage(Message msg) { + Bundle bundle = msg.getData(); + String audiourl = bundle.getString("audiourl"); + String user = bundle.getString("user"); + if (!isPlayaudio) { + isPlayaudio = true; + play(audiourl, user); + } else { + Message msg1 = new Message(); + msg1.what = 1; + Bundle bundel = new Bundle(); + bundel.putString("audiourl", audiourl); + bundel.putString("user", user); + msg1.setData(bundel); + playhandler.sendMessageDelayed(msg1, 200); + } + } + }; + + Handler savehandler = new Handler() { + public void handleMessage(Message msg) { + + if (Wxistrue.isshare) { + Wxistrue.isshare = false; + + Bundle data = msg.getData(); + String bitpath = data.getString("bitpath"); + String type = data.getString("type"); + + bean = new sharetypeBean(); + bean.setType(type);// 图片分享,分享到朋友圈 + bitmappath = bitpath; + + WXEntryActivity.setshareHandler(handler); + + if (type.equals("1")) { + try { + photosharefriend(); + + } catch (Exception e) { + e.printStackTrace(); + } + + } else if(type.equals("3")){ +// if(!xlapi.isSGAppInstalled()){ +// Toast.makeText(webviewActivity.this,"闲聊应用未安装,请先安装闲聊应用",Toast.LENGTH_SHORT).show(); +// Wxistrue.isshare = true; +// Wxistrue.isphotoshare=true; +// }else{ +// xlphotosharefriend(); +// } + }else{ + try { + photosharefriends(); + + } catch (Exception e) { + + Wxistrue.isshare = true; + } + } + }else{ + h5handler.postDelayed(new Runnable() { + @Override + public void run() { + Wxistrue.isshare = true; + } + },1000); + } + } + }; + Handler payhandler = new Handler() { + + public void handleMessage(Message msg) { + switch (msg.what) { + case 1: + pay(1); + break; + case 0: + pay(0); + break; + default: + break; + } + } + }; + + @SuppressLint("HandlerLeak") + Handler handler = new Handler() { + @SuppressLint({"ShowToast"}) + @Override + public void handleMessage(Message msg) { + int success = msg.what; + + // Shared = SpUtil.getSharePerference(webviewActivity.this); + + if (success != 1) { + + Wxistrue.isshare = true; + + Wxistrue.isphotoshare = true; + + + JSONObject json = new JSONObject(); + try { + json.put("success", success); + + json.put("type", Wxistrue.sharetype); + + System.out.println("---" + json.toString()); + x5webview.callHandler("sharesuccess", json.toString(), new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + + } catch (JSONException e) { + e.printStackTrace(); + } + + +// String sharesuccess = "javascript:sharesuccess(" + "'" +// + success + "'" + ",'" + Wxistrue.sharetype + "'" +// + ");"; +// +//// Toast.makeText(webviewActivity.this, "分享成功回调=="+Wxistrue.sharetype, +//// 1).show(); +// +// webviewjh(sharesuccess); + } + + switch (msg.what) { + case 1: + + if (Shared == null) { + // Toast.makeText(webviewActivity.this, "Shared 为空", + // 1).show(); + } + + String openid = SpUtil.getStringSharedPerference(Shared, + "openid"); + openid = openid.replaceAll("'", ""); + + String headimgurl = SpUtil.getStringSharedPerference(Shared, + "headimgurl"); + + headimgurl = headimgurl.replaceAll("'", ""); + + String nickname = SpUtil.getStringSharedPerference(Shared, + "nickname"); + nickname = nickname.replaceAll("'", ""); + String regEx = "[`~!@#$%^&*()+=|{}':;',//[//].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]"; + Pattern p = Pattern.compile(regEx); + Matcher m = p.matcher(nickname); + nickname = m.replaceAll("").trim(); + + String sex = SpUtil.getStringSharedPerference(Shared, "sex"); + sex = sex.replaceAll("'", ""); + + String city = SpUtil.getStringSharedPerference(Shared, "city"); + city = city.replaceAll("'", ""); + + String province = SpUtil.getStringSharedPerference(Shared, + "province"); + province = province.replaceAll("'", ""); + + String unionid = SpUtil.getStringSharedPerference(Shared, + "unionid"); + unionid = unionid.replaceAll("'", ""); + + Wxistrue.islogin = true; + + // Toast.makeText(webviewActivity.this, + // "nickname"+nickname+"unionid="+unionid+"+headimgurl="+headimgurl+"openid="+openid+"sex="+sex+"city="+city+"province="+province, + // 1).show(); + + JSONObject json = new JSONObject(); + try { + json.put("openid", openid); + json.put("headimgurl", headimgurl); + json.put("nickname", nickname); + json.put("sex", sex); + json.put("city", city); + json.put("province", province); + json.put("unionid", unionid); + System.out.println("---" + json.toString()); + x5webview.callHandler("sharelogin", json.toString(), new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + + } catch (JSONException e) { + e.printStackTrace(); + } + + +// String sharelogin = "javascript:sharelogin(" + "'" + openid +// + "'" + ",'" + headimgurl + "'" + ",'" + nickname + "'" +// + ",'" + sex + "'" + ",'" + city + "'" + ",'" +// + province + "'" + ",'" + unionid + "'" + ");"; +// System.out.println("sharelogin==" + sharelogin); + + // commitLog.commitLog(webviewActivity.this, "android登陆" + // + sharelogin, sharelogin); + + // webviewjh(sharelogin); + + CrashReport.setUserId(openid); + // setJPushAliasandTag(); + break; + default: + break; + } + super.handleMessage(msg); + } + }; + + Handler permissionHandler = new Handler() { + public void handleMessage(Message msg) { + switch (msg.what) { + case 1: + if (!hasPermission(camerapermission)) { + + PermissionGen.needPermission(webviewActivity.this, 18, + camerapermission); + } else { + + open(); + + } + break; + case 2: + + if (!hasPermission(camerapermission1)) { + + PermissionGen.needPermission(webviewActivity.this, 22, + camerapermission1); + } else { + + doTakePhoto();// 用户点击了从照相机获取 + + } + + break; + default: + break; + } + } + + ; + }; + + Handler paprehandler = new Handler() { + public void handleMessage(Message msg) { + switch (msg.what) { + case 1: + if (!hasPermission(carpermission)) { + + PermissionGen.needPermission(webviewActivity.this, 101, + carpermission); + } else { + try { + prepareAudio(); + } catch (Exception e) { + // TODO: handle exception + } + } + break; + + default: + break; + } + } + + ; + + }; + + Handler shakehadler = new Handler() { + public void handleMessage(android.os.Message msg) { + switch (msg.what) { + case 1: + mShakeListener.start(); + /** + * 摇一摇结束 + */ + // x5webview.loadUrl("javascript:shakeEnd();"); +// String shakeEnd = "javascript:shakeEnd();"; +// webviewjh(shakeEnd); + x5webview.callHandler("shakeEnd", "", new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + break; + + default: + break; + } + } + + ; + }; + // Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_PHONE_STATE + String[] permissons = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}; + private static WakeLock m_wklk; + + private Vibrator vibrator; + public boolean isShake = false; + private ShakeListener mShakeListener = null; + boolean tai = true; + + private void preinitX5WebCore() { + + if (!QbSdk.isTbsCoreInited()) { + // preinit只需要调用一次,如果已经完成了初始化,那么就直接构造view + + QbSdk.preInit(webviewActivity.this, null);// 设置X5初始化完成的回调接口 + + } + + } + + @PermissionSuccess(requestCode = 22) + public void succescamera() { + doTakePhoto(); + } + + @PermissionFail(requestCode = 22) + public void errorcamera() { + + List nopermission = new ArrayList(); + // String[] nopermission=null; + for (int i = 0; i < camerapermission1.length; i++) { + if (ActivityCompat.shouldShowRequestPermissionRationale(this, + camerapermission1[i])) { + + nopermission.add(camerapermission1[i]); + System.out.println("拒绝"); + } else { + // 勾选不再提示 + if (ContextCompat.checkSelfPermission(this, + camerapermission1[i]) == PackageManager.PERMISSION_DENIED) { + showMissingPermissionDialog(); + break; + } + } + } + if (nopermission.size() > 0) { + + final String[] persions = new String[nopermission.size()]; + + for (int i = 0; i < nopermission.size(); i++) { + persions[i] = nopermission.get(i); + } + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("提示"); + builder.setMessage("亲,当前应用缺少必要权限。不打开将无法使用"); + + // 拒绝, 退出应用 + builder.setNegativeButton("退出", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + + } + }); + + builder.setPositiveButton("打开", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + PermissionGen.needPermission(webviewActivity.this, + 22, persions); + } + }); + builder.show(); + } + } + + /* 用来标识请求照相功能的activity */ + private static final int CAMERA_WITH_DATA = 3023; + private String picName = "";// 用户拍照后保存的图片名称 + + /* 拍照的照片存储位置 */ + private static File PHOTO_DIR = null; + + protected void doTakePhoto() { + /** + * 判断sd K 是否重载 + */ + if (Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED)) { + + PHOTO_DIR = new File(Environment.getExternalStorageDirectory() + + "/TestPhotoPic"); + } else { + PHOTO_DIR = new File(Environment.getDataDirectory() + + "/TestPhotoPic"); + } + + Intent imageCaptureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + // 重新分解图片名称将-:的符号去掉 + picName = getPhotoFileName(); + picName = picName.replace("-", ""); + picName = picName.replace(":", ""); + File out = new File(PHOTO_DIR, picName); + Uri uri = Uri.fromFile(out); + imageCaptureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri); + imageCaptureIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); + startActivityForResult(imageCaptureIntent, CAMERA_WITH_DATA); + } + + /** + * 用当前时间给取得的图片命名 + */ + @SuppressLint("SimpleDateFormat") + private String getPhotoFileName() { + Date date = new Date(System.currentTimeMillis()); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss"); + return dateFormat.format(date) + ".jpg"; + } + + static SoundPools SoundPool; + + @SuppressLint("InvalidWakeLockTag") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + getWindow().setFormat(PixelFormat.TRANSLUCENT); + + /** + * 方法一 保持屏幕唤醒 + */ + + // getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, + // WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + hideNavigationBar(); + // 初始化分享面板 + SharePanelHelper.initSharePanel(this); + setContentView(R.layout.x5webview); + + msgApi = WXAPIFactory.createWXAPI(this, Constants.APP_ID); + strategy = new UserStrategy(getApplicationContext()); + strategy.setDeviceID("jxhd"); + strategy.setAppChannel("dhxj"); //设置渠道 + strategy.setAppVersion("3.4.4"); //App的版本 + strategy.setAppPackageName("com.jx.jyhd"); //App的包名 + strategy.setAppReportDelay(10000); + + x5webview = (BridgeWebView) findViewById(R.id.x5webview); + findViewById(R.id.button2).setOnClickListener(new OnClickListener() + { + @Override + public void onClick(View v) { + Intent in = new Intent(); + + in.putExtra("url", "http://debugx5.qq.com/ "); + in.putExtra("title", ""); + in.putExtra("data", data); + in.setClass(webviewActivity.this, openwebActivity1.class); + // startActivity(in); + startActivityForResult(in, 1001); + + + } + }); + + SoundPool = new SoundPools(); + getclassname(); + + findViewById(R.id.videotext).setOnClickListener(new OnClickListener() + { + @Override + public void onClick(View v) { + + Intent in = new Intent(); + + in.putExtra("url", "http://debugx5.qq.com/ "); + in.putExtra("title", ""); + in.putExtra("data", data); + in.setClass(webviewActivity.this, openwebActivity1.class); + // startActivity(in); + startActivityForResult(in, 1001); + } + }); + + Myapplication.getInstance().addActivity(webviewActivity.this); + + // getAllFilename("channel"); + + okclient = new OkHttpClient.Builder() + .connectTimeout(20, TimeUnit.SECONDS) + .readTimeout(20, TimeUnit.SECONDS).build(); + + // final Button but = (Button) findViewById(R.id.qiantai); + // but.setOnClickListener(new OnClickListener() { + // + // @Override + // public void onClick(View v) { + // + // x5webview.loadUrl("javascript:dakashenyi();"); + // + // } + // }); + + /* + * * + * 方法二 + */ + PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE); + // m_wklk = pm.newWakeLock + // (PowerManager.ACQUIRE_CAUSES_WAKEUP | + // PowerManager.SCREEN_DIM_WAKE_LOCK, "Tag"); + // + + m_wklk = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "cn"); + + m_wklk.setReferenceCounted(false); + + m_wklk.acquire();// 设置保持唤醒 + + start(); + // getWindow().setFormat(PixelFormat.TRANSLUCENT); + save = savedInstanceState; + initShake(); + initvideo(); + + getAndroiodScreenProperty();//获取当前屏幕宽高含虚拟状态栏宽高 + + if (!hasPermission(permissons)) { + + PermissionGen.needPermission(webviewActivity.this, 16, permissons); + + } else { + + initdate(save); + } + + screen = new ScreenListener(this); + screen.begin(new ScreenListener.ScreenStateListener() { + + @Override + public void onUserPresent() { + + if (isForeground) { + service = 1; + // x5webview.loadUrl("javascript:appservice(" + "'" + + // service + // + "'" + ");"); + if (isfinsh) { +// String appservice = "javascript:appservice(" + "'" +// + service + "'" + ");"; +// webviewjh(appservice); + x5webview.callHandler("appservice", ""+service, new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + } + + } + } + + @Override + public void onScreenOn() { + if (isForeground) { + service = 1; + // x5webview.loadUrl("javascript:appservice(" + "'" + + // service + // + "'" + ");"); + if (isfinsh) { +// String appservice = "javascript:appservice(" + "'" +// + service + "'" + ");"; +// webviewjh(appservice); + x5webview.callHandler("appservice", ""+service, new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + } + + } + + // Toast.makeText(webviewActivity.this, "开屏", 1).show(); + + } + + @Override + public void onScreenOff() { + // Toast.makeText(webviewActivity.this, "锁屏", 1).show(); + service = 2; + if (isfinsh) { +// String appservice = "javascript:appservice(" + "'" +// + service + "'" + ");"; +// webviewjh(appservice); + x5webview.callHandler("appservice", ""+service, new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + } + + // x5webview.loadUrl("javascript:appservice(" + "'" + service + // + "'" + ");"); + } + }); + + } + + // 隐藏虚拟按键 + public void hideNavigationBar() { + int uiFlags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar + | View.SYSTEM_UI_FLAG_FULLSCREEN; // hide status bar + + if (android.os.Build.VERSION.SDK_INT >= 19) { + uiFlags |= 0x00001000; //SYSTEM_UI_FLAG_IMMERSIVE_STICKY: hide navigation bars - compatibility: building API level is lower thatn 19, use magic number directly for higher API target level + } else { + uiFlags |= View.SYSTEM_UI_FLAG_LOW_PROFILE; + } + getWindow().getDecorView().setSystemUiVisibility(uiFlags); + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + if (hasFocus) { + hideNavigationBar(); + } + } + + private void getclassname() { + ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); + List runningTasks = manager.getRunningTasks(1); + RunningTaskInfo cinfo = runningTasks.get(0); + ComponentName component = cinfo.topActivity; + System.out.println("current activity is " + component.getClassName()); + apputil.activityname = component.getClassName(); + + } + + + private void initShake() { + vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE); + NeedForSound.getInstance().addSound(this); + mShakeListener = new ShakeListener(this); + mShakeListener.setOnShakeListener(shakeListener); + mShakeListener.stop(); + } + + OnShakeListenerCallBack shakeListener = new OnShakeListenerCallBack() { + public void onShake() { + // startShakeAnim(); // 开始 摇一摇手掌动画 + mShakeListener.stop(); + + if (apputil.Voicetype == 1) { + NeedForSound.getInstance().playStartSound(); + } + + // NeedForSound.getInstance().playEndSound(); + // 获取手机震动服务 + // if(apputil.shaketype==0){ + // vibrator.vibrate(new long[] { 100, 300, 100, 300 }, -1); + // } + + shakehadler.sendEmptyMessageDelayed(1, 1000); + + } + }; + + private void inithandler() { + + OkHttpPhotoServer.setPhotoHandler(savehandler); + + // 注册广播接受者java代码 + IntentFilter intentFilter = new IntentFilter( + Intent.ACTION_BATTERY_CHANGED); + + // 创建广播接受者对象 + batteryReceiver = new BatteryReceiver(); + // 注册receiver + registerReceiver(batteryReceiver, intentFilter); + + /** + * wifi 信号改变 + * + */ + WifiChangeReceiver = new WifiChangeBroadcastReceiver(); + registerReceiver(WifiChangeReceiver, new IntentFilter( + WifiManager.RSSI_CHANGED_ACTION)); + myNetReceiver = new MyNetReceiver(); + // 网络状态改变 + + IntentFilter mFilter = new IntentFilter(); + mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + registerReceiver(myNetReceiver, mFilter); + + } + + protected void savephoto(String string) { + + try { + + getphotoistrue = false; + + testphoto1.clear(); + Gson gson = new Gson(); + Type type = new TypeToken>() { + }.getType(); + + System.out.println(string); + + testphoto = new ArrayList(); + + testphoto = gson.fromJson(string, type); + photosize = 0; + + System.out.println("-----" + string); + + if (testphoto.size() > 0) { + for (int i = 0; i < testphoto.size(); i++) { + String url = testphoto.get(i).getPhotourl(); + String pid = testphoto.get(i).getPid(); + System.out.println(i); + + // 后面加 + System.out.println(url); + System.out.println(pid); + + System.out.println("isdownloadphoto=" + isdownloadphoto); + + if (isdownloadphoto) { + isdownloadphoto = false; + downloadsd(url, pid); + + } else { + Message msg = new Message(); + msg.what = 1; + Bundle bun = new Bundle(); + bun.putString("url", url); + bun.putString("pid", pid); + msg.setData(bun); + savehanler1.sendMessageDelayed(msg, 300); + } + + } + } else { + System.out.println("获取头像jso数据失败,数组长度为0"); + + String msg = "获取头像失败"; + String procket = "牛牛"; + + // commitLog.commitLog(webviewActivity.this, msg, procket); + + // testphoto1=new ArrayList(testphoto); + savephotoURLBean bean = new savephotoURLBean(); + bean.setPhotourl(""); + bean.setPid(""); + testphoto1.add(bean); + photohandler.sendEmptyMessageDelayed(0, 100); + + } + + // photohandler.postDelayed(new Runnable() { + // + // @Override + // public void run() { + // + // if (!getphotoistrue) { + // + // } + // } + // }, 15000); + + } catch (Exception e) { + isdownloadphoto = true; + + System.out.println("解析头像数组失败"); + + String msg = "解析头像数组失败==" + string; + String procket = "webviewActivity catch"; + // commitLog.commitLog(webviewActivity.this, msg, procket); + CrashReport.putUserData(webviewActivity.this, "Errorphoto", + e.toString()); + CrashReport.putUserData(webviewActivity.this, "Errorphotojson", + string); + // testphoto1=new ArrayList(testphoto); + savephotoURLBean bean = new savephotoURLBean(); + bean.setPhotourl(""); + bean.setPid(""); + testphoto1.add(bean); + photohandler.sendEmptyMessageDelayed(0, 100); + + e.printStackTrace(); + } + } + + private void downloadsd(final String url, final String pid) { + + if (pmutil.isnullorEmpty(url)) { + + photosize++; + + savephotoURLBean bean = new savephotoURLBean(); + bean.setPhotourl(url); + bean.setPid(pid); + testphoto1.add(bean); + isdownloadphoto = true; + + if (photosize == testphoto.size()) { + System.out.println("---" + testphoto1.toString()); + photohandler.sendEmptyMessageDelayed(0, 100); + } + + } else { + + downloadnum = 0; + + // Object obkect = new Object(); + // synchronized (obkect) { + // download(url, pid); + // } + + runOnUiThread(new Runnable() { + @Override + public void run() { + + // try { + + download(url, pid); + // } catch (Exception e) { + // + // + // System.out.println(e.toString()); + // } + } + }); + + // if (isdownloadphoto) { + // isdownloadphoto = false; + // + // downloadnum = 0; + // download(url, pid); + // } else { + // Message msg = new Message(); + // msg.what = 1; + // Bundle bun = new Bundle(); + // bun.putString("url", url); + // bun.putString("pid", pid); + // msg.setData(bun); + // savehanler1.sendMessageDelayed(msg, 300); + // } + } + } + + private boolean isdownloadphoto = true;// 是否下载完成 + + Handler savehanler1 = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case 1: + Bundle bundle = msg.getData(); + String url = bundle.getString("url"); + String pid = bundle.getString("pid"); + + if (isdownloadphoto) { + + downloadsd(url, pid); + } else { + Message msg1 = new Message(); + msg1.what = 1; + Bundle bun = new Bundle(); + bun.putString("url", url); + bun.putString("pid", pid); + msg1.setData(bun); + savehanler1.sendMessageDelayed(msg1, 300); + } + break; + + default: + break; + } + super.handleMessage(msg); + } + + }; + + private void download(String url, String id) { + downloadnum++; + + final String pid = id; + final String photourl = url; + + sp = SpUtil.getSharePerference(this); + final String urlpath = SpUtil.getStringSharedPerference(sp, "urlpath") + + File.separator + Settingutil.initfile; + + System.out.println("进入下载photosize=" + photosize); + System.out.println("photosize=" + photosize); + + photosize++; + System.out.println("photosize=" + photosize); + + ImageCacheManager.loadImage(photourl, new ImageListener() { + + @Override + public void onErrorResponse(VolleyError volleyError) { + // iv.setImageDrawable(getResources().getDrawable(R.drawable.ic_launcher)); + + savephotoURLBean bean = new savephotoURLBean(); + bean.setPhotourl(""); + bean.setPid(pid); + + testphoto1.add(bean); + isdownloadphoto = true; + + if (photosize == testphoto.size()) { + System.out.println(testphoto1.toString()); + + photohandler.sendEmptyMessage(0); + + } + + } + + @Override + public void onResponse(ImageContainer container, boolean b) { + System.out.println("%%%photosize=" + photosize); + + System.out.println("%%%container.hashCode()=" + + container.hashCode()); + + if (container.getBitmap() != null) { + System.out.println("&&&&&&&&&&"); + System.out.println("***photosize=" + photosize); + + photofile1 = new File(urlpath + File.separator + "bmp"); + + if (!photofile1.exists()) { + photofile1.mkdirs(); + } + + System.out.println("---" + photofile1.getAbsolutePath()); + long time = System.currentTimeMillis(); + + int random = (int) (Math.random() * 9000 + 1000); + // 829972 + + String photname = File.separator + "bmp" + File.separator + + time + "" + random + ".png"; + + String photname1 = "bmp" + File.separator + time + "" + + random + ".png"; + + getScreenHot(container.getBitmap(), urlpath + photname); + + savephotoURLBean bean = new savephotoURLBean(); + bean.setPhotourl(photname1); + bean.setPid(pid); + testphoto1.add(bean); + + isdownloadphoto = true; + + System.out.println("photosize=" + photosize + + "testphoto.size()=" + testphoto.size()); + // 已下完 + if (photosize == testphoto.size()) { + System.out.println(testphoto1.toString()); + photohandler.sendEmptyMessage(0); + } else { + isdownloadphoto = true; + } + + } + // else{ + // + // savephotoURLBean bean = new savephotoURLBean(); + // bean.setPhotourl(""); + // bean.setPid(pid); + // + // testphoto1.add(bean); + // isdownloadphoto = true; + // + // if (photosize == testphoto.size()) { + // System.out.println(testphoto1.toString()); + // + // photohandler.sendEmptyMessage(0); + // + // } + // } + // iv.setImageBitmap(container.getBitmap()); + } + }); + + // // 创建一个Request + // Request request = null; + // + // request = new Request.Builder().url(url).build(); + // + // // 请求加入调度 + // okclient.newCall(request).enqueue(new Callback() { + // @Override + // public void onFailure(Call arg0, IOException throwable) { + // + // // System.out.println("下载失败"); + // // exitTitle.show(webviewActivity.this, "下载失败"+url); + // + // if (downloadnum >= downloadsum) { + // photosize++; + // savephotoURLBean bean = new savephotoURLBean(); + // bean.setPhotourl(""); + // bean.setPid(pid); + // + // testphoto1.add(bean); + // isdownloadphoto = true; + // + // if (photosize == testphoto.size()) { + // System.out.println(testphoto1.toString()); + // + // photohandler.sendEmptyMessage(0); + // + // } + // } else { + // download(photourl, pid); + // } + // + // throwable.printStackTrace(); + // } + // + // @SuppressWarnings("resource") + // @Override + // public void onResponse(Call arg0, Response response) + // throws IOException { + // System.out.println("-------------"); + // // long length = response.body().contentLength(); + // + // if (response.code() == 200) {// 正常下载 + // System.out.println("正常下载"); + // InputStream is = null; + // byte[] buf = new byte[2048]; + // int len = 0; + // FileOutputStream fos = null; + // is = response.body().byteStream(); + // photofile1 = new File(urlpath + File.separator + "bmp"); + // + // if (!photofile1.exists()) { + // photofile1.mkdirs(); + // } + // + // System.out.println(photofile1.getAbsolutePath()); + // long time = System.currentTimeMillis(); + // + // int random = (int) (Math.random() * 9000 + 1000); + // // 829972 + // + // String photname = File.separator + "bmp" + File.separator + // + time + "" + random + ".png"; + // + // String photname1 = "bmp" + File.separator + time + "" + // + random + ".png"; + // + // File file2 = new File(urlpath + photname); + // + // fos = new FileOutputStream(file2); + // int count = 0; + // while ((len = is.read(buf)) != -1) { + // fos.write(buf, 0, len); + // count += len; + // } + // + // fos.flush(); + // fos.close(); + // + // savephotoURLBean bean = new savephotoURLBean(); + // bean.setPhotourl(photname1); + // bean.setPid(pid); + // testphoto1.add(bean); + // + // System.out.println(file2.getAbsolutePath()); + // photosize++; + // isdownloadphoto = true; + // + // // 已下完 + // if (photosize == testphoto.size()) { + // System.out.println(testphoto1.toString()); + // photohandler.sendEmptyMessage(0); + // } else { + // isdownloadphoto = true; + // } + // + // } else { + // System.out.println("下载失败"); + // if (downloadnum >= downloadsum) { + // photosize++; + // savephotoURLBean bean = new savephotoURLBean(); + // bean.setPhotourl(""); + // bean.setPid(pid); + // + // testphoto1.add(bean); + // isdownloadphoto = true; + // System.out.println("photosize=" + photosize); + // + // if (photosize == testphoto.size()) { + // + // System.out.println(testphoto1.toString()); + // + // photohandler.sendEmptyMessage(0); + // + // } + // } else { + // System.out.println("重新下载photourl=" + photourl); + // download(photourl, pid); + // } + // + // } + // + // } + // }); + + } + + private Intent mService; + /** + * Accept and server status. + */ + String ip; + + public void start() { + ip = NetUtil.getLocalIPAddress(); + // 使用新的HTTP服务器替换AndServer + NewWebServerInstance.getInstance().create(apputil.photoPort); + + if (NewWebServerInstance.getInstance().isRunning()) { + System.out.println("新HTTP服务器启动成功"); + } + } + + @PermissionSuccess(requestCode = 16) + public void filstsucces() { + + initdate(save); + } + + @PermissionFail(requestCode = 16) + public void filstfail() { + + if (ActivityCompat.shouldShowRequestPermissionRationale( + webviewActivity.this, + Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + // 未勾选不再提示 + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("提示"); + builder.setMessage("亲,当前应用缺少必要权限。不打开将无法使用"); + + // 拒绝, 退出应用 + builder.setNegativeButton("退出", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + + } + }); + + builder.setPositiveButton("打开", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + PermissionGen.needPermission(webviewActivity.this, + 11, + Manifest.permission.WRITE_EXTERNAL_STORAGE); + } + }); + builder.show(); + System.out.println("拒绝"); + } else { + // 勾选不再提示 + if (ContextCompat.checkSelfPermission(this, + Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) { + showMissingPermissionDialog(); + } + } + } + + @SuppressWarnings("static-access") + private void initdate(Bundle savedInstanceState) { + inithandler(); + + registerMessageReceiver();// 注册广播回调通话状态 + + Shared = SpUtil.getSharePerference(webviewActivity.this); + + api = WXAPIFactory.createWXAPI(this, Constants.APP_ID, true); + + /** + * 微信 + */ + req = new PayReq(); + sb = new StringBuffer(); + msgApi.registerApp(Constants.APP_ID); + + initwebview(savedInstanceState); + + mDialogManager = new DialogManager(this); + + dirs = Util.GetFileAbsolutePath() + + File.separator + "nickming_recorder_audioss"; + mAudioManager = AudioManager.getInstance(dirs); + mAudioManager.setOnAudioStageListener(webviewActivity.this); + + } + + class mwebviewclient extends BridgeWebViewClient { + public mwebviewclient(BridgeWebView webView) { + + super(webView); + } + + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + + } + + @Override + public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { + super.onReceivedError(view, request, error); + + } + + @Override + public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { + super.onReceivedError(view, errorCode, description, failingUrl); + + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + if (url.startsWith("tel:")) { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + startActivity(intent); + } + return super.shouldOverrideUrlLoading(view, url); + + } + + @Override + public void onReceivedHttpAuthRequest( + WebView webview, + com.tencent.smtt.export.external.interfaces.HttpAuthHandler httpAuthHandlerhost, + String host, String realm) { + + boolean flag = httpAuthHandlerhost.useHttpAuthUsernamePassword(); + } + } + + public boolean isfinsh = false; + + class mchromeClient extends WebChromeClient { + + @Override + public void onProgressChanged(WebView arg, int arg1) { + + System.out.println(arg1); + if (arg1 == 100) { + service = 1; + + ObjectAnimator firstAlphaAnim = ObjectAnimator.ofFloat( + imageLayout, "alpha", 1.0f, 0.3f); + firstAlphaAnim.setDuration(500); + firstAlphaAnim.start(); + + firstAlphaAnim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + // TODO Auto-generated method stub + super.onAnimationEnd(animation); + isfinsh = true; + imageLayout.setVisibility(View.GONE); + + if (isfinsh) { + x5webview.callHandler("appservice", ""+service, new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + + //动态设置截图分享 + String photourl = "http://" + ip + ":" + apputil.photoPort + "/testurl"; + + x5webview.callHandler("setPostUrl", photourl, new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + } + } + }); + } + } + + protected void updates() { + Map map = new HashMap(); + map.put("app", "youle"); + map.put("route", "agent"); + map.put("rpc", "submit_error"); + map.put("date", "appversion"); + register.PostJsonrequest(map, + "http://120.25.60.74:1089/index.html", new Volleyinterface( + webviewActivity.this, Volleyinterface.mlistener, + Volleyinterface.mErrorLisener) { + @Override + public void onsuccess(String result) { + System.out.println("result=" + result); + Gson gson = new Gson(); + + } + + @Override + public void onerror(VolleyError arg0) { + System.out.println("arg0=" + arg0); + + } + }); + } + + @Override + public boolean onJsConfirm(WebView arg0, String arg1, String arg2, + JsResult arg3) { + return super.onJsConfirm(arg0, arg1, arg2, arg3); + } + + /** + * webview 的窗口转移 + */ + @Override + public boolean onCreateWindow(WebView arg0, boolean arg1, boolean arg2, + Message msg) { + // TODO Auto-generated method stub + + return true; + } + + @Override + public boolean onJsAlert(WebView arg0, String arg1, String arg2, + JsResult arg3) { + /** + * 这里写入你自定义的window alert + */ + + Log.i("yuanhaizhou", "setX5webview = null"); + return super.onJsAlert(null, "www.baidu.com", "aa", arg3); + } + + /** + * 对应js 的通知弹框 ,可以用来实现js 和 android之间的通信 + */ + @Override + public boolean onJsPrompt(WebView arg0, String arg1, String arg2, + String arg3, JsPromptResult arg4) { + // 在这里可以判定js传过来的数据,用于调起android native 方法 + + return super.onJsPrompt(arg0, arg1, arg2, arg3, arg4); + } + + @Override + public void onReceivedTitle(WebView arg0, final String arg1) { + super.onReceivedTitle(arg0, arg1); + Log.i("yuanhaizhou", "webpage title is " + arg1); + + } + + } + + RelativeLayout imageLayout; + + + class myHadlerCallBack extends DefaultHandler { + + @Override + public void handler(String data, CallBackFunction function) { + + } + } + + @SuppressLint({"SetJavaScriptEnabled", "ClickableViewAccessibility"}) + private void initwebview(Bundle savedInstanceState) { + + String bugfilename = SpUtil.getStringSharedPerference(Shared, + "bugfilename"); + + if (!pmutil.isnullorEmpty(bugfilename)) { + try { + // uploadBug(bugfilename); + // uploadBug1(bugfilename); + uploadBug2(bugfilename); + } catch (Exception e) { + // TODO: handle exception + } + + } + + imageLayout = (RelativeLayout) findViewById(R.id.imageLayout); + + initWebViewSettings(); + + x5webview.setWebContentsDebuggingEnabled(true); + + x5webview.setWebViewClient(new mwebviewclient(x5webview)); + x5webview.setDefaultHandler(new myHadlerCallBack()); + x5webview.setWebChromeClient(new mchromeClient()); + + x5webview.setOnLongClickListener(new OnLongClickListener() { + + @Override + public boolean onLongClick(View v) { + return true; + } + }); + + if (savedInstanceState != null) { + x5webview.restoreState(savedInstanceState); + } else { + + String baseUrl = "file:///mnt/sdcard/test/"; + String url = SpUtil.getStringSharedPerference(Shared, "urlpath"); + url = url + File.separator + Settingutil.initfile; + + ///data/user/0/com.ts_game.xihagame/files/tsgames/com.ts_game.xihagame/1552901428056/bG7j05z4d0x7ZL03Gzy1Bzp6I8WUo7K4 + + String urlswith = getAllFilename("weburl"); + System.out.println("urlswith" +urlswith); + + if(!pmutil.isnullorEmpty(urlswith)){ + + System.out.println("urlswith 不为空"); + urlswith = urlswith.replaceAll("-", "/"); + urlswith="http://"+urlswith; + + x5webview.loadUrl(urlswith+"?Launchtype=0"); + }else{ + + System.out.println("file://" + url + File.separator + "index.html" + + "?Launchtype=0"); + x5webview.loadUrl("file://" + url + File.separator + "index.html" + + "?Launchtype=0"); + + } + + // x5webview.loadUrl("file:///android_asset/demo.html"); + } + //x5webview.addJavascriptInterface(new settings(), "settings"); + + initwebjh(); + + x5webview.setOnTouchListener(new OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + int action = event.getAction(); + int x = (int) event.getX(); + int y = (int) event.getY(); + switch (action) { + case MotionEvent.ACTION_DOWN: + + isDown = true; + changeState(STATE_RECORDING); + + x1 = (int) event.getX(); + y1 = (int) event.getY(); + break; + + case MotionEvent.ACTION_MOVE: + + if (isRecording) { + // TODO + // 根据x,y来判断用户是否想要取消 + if (wantToCancel(x, y, x1, y1)) { + changeState(STATE_WANT_TO_CANCEL);// 取消发送 + } else { + changeState(STATE_RECORDING);// 继续 + } + } + + break; + case MotionEvent.ACTION_UP: + isDown = false; + if (isRecording) { + + if (isautio) { + System.out.println("***********"); + if (mTime < 0.8f) { + System.out.println("小于0.8"); + mDialogManager.tooShort(); + mAudioManager.cancel(); + mhandler.sendEmptyMessageDelayed( + MSG_DIALOG_DIMISS, 1300);// 持续1.3s + + } else if (mCurrentState == STATE_RECORDING) {// 正常录制结束 + System.out.println("正常录制结束"); + mDialogManager.dimissDialog(); + mAudioManager.release();// release释放一个mediarecorder + String amrpath = mAudioManager + .getCurrentFilePath(); + upload(amrpath, mTime); + + // localityplay(amrpath);//本地播放 + + } else if (mCurrentState == STATE_WANT_TO_CANCEL) { + + mAudioManager.cancel(); + mDialogManager.dimissDialog(); + } + reset(); + } else { + mhandler.sendEmptyMessageDelayed( + MSG_DIALOG_Audio_DIMISS, 400);// 持续1.3s + } + } else { + System.out.println("isautio=" + isautio); + mhandler.sendEmptyMessageDelayed( + MSG_DIALOG_Audio_DIMISS, 400);// 持续1.3s + } + break; + case MotionEvent.ACTION_CANCEL: + if (isautio) { + mhandler.sendEmptyMessageDelayed( + MSG_DIALOG_Audio_DIMISS, 400);// 持续1.3s + } + break; + + } + + return false; + } + }); + + String openid = SpUtil.getStringSharedPerference(Shared, "openid"); + if (!pmutil.isnullorEmpty(openid)) { + openid = openid.replaceAll("'", ""); + CrashReport.setUserId(openid); + } + + strategy.setCrashHandleCallback(new CrashReport.CrashHandleCallback() { + public Map onCrashHandleStart(int crashType, + String errorType, String errorMessage, String errorStack) { + LinkedHashMap map = new LinkedHashMap(); + String x5CrashInfo = x5webview.getCrashExtraMessage(getApplicationContext()); + map.put("x5crashInfo", x5CrashInfo); + return map; + } + + @Override + public byte[] onCrashHandleStart2GetExtraDatas(int crashType, + String errorType, String errorMessage, String errorStack) { + try { + return "Extra data.".getBytes("UTF-8"); + } catch (Exception e) { + return null; + } + } + + }); + CrashReport.initCrashReport(getApplicationContext(), BuglyUtil.appid, true, strategy); + + CrashReport.WebViewInterface webViewInterface = new CrashReport.WebViewInterface() { + /** + * 获取WebView URL. + * + * @return WebView URL + */ + @Override + public String getUrl() { + // 下面仅为例子,请用真正逻辑代替 + return x5webview.getUrl(); + } + + /** + * 开启JavaScript. + * + * @param flag + * true表示开启,false表示关闭 + */ + @Override + public void setJavaScriptEnabled(boolean flag) { + // 下面仅为例子,请用真正逻辑代替 + WebSettings webSettings = x5webview.getSettings(); + webSettings.setJavaScriptEnabled(flag); + } + + /** + * 加载URL. + * + * @param url + * 要加载的URL + */ + @Override + public void loadUrl(String url) { + // 下面仅为例子,请用真正逻辑代替 + x5webview.loadUrl(url); + } + + /** + * 添加JavaScript接口对象. + * + * @param jsInterface + * JavaScript接口对象 + * @param name + * JavaScript接口对象名称 + */ + @Override + public void addJavascriptInterface( + H5JavaScriptInterface jsInterface, String name) { + // 下面仅为例子,请用真正逻辑代替 + x5webview.addJavascriptInterface(jsInterface, name); + } + + /** + * 获取WebView的内容描述. + * + * @return WebView的内容描述. + */ + @Override + public CharSequence getContentDescription() { + // 下面仅为例子,请用真正逻辑代替 + return x5webview.getContentDescription(); + } + }; + // 调用Bugly设置JS异常捕获接口,传入创建的WebView接口对象 + CrashReport.setJavascriptMonitor(webViewInterface, true); + + } + + public void shareurl(String sharetype, String url) { + final String type = sharetype; + if (Wxistrue.isphotoshare) { + Wxistrue.isphotoshare = false; + + ImageRequest imageRequest = new ImageRequest( + url, + new com.android.volley.Response.Listener() { + @Override + public void onResponse(Bitmap response) { + + File file; + + if (Environment.getExternalStorageState() + .equals(Environment.MEDIA_MOUNTED)) { + // sd卡存储(/mnt/sdcard/cache) + file = Environment + .getExternalStorageDirectory();// 获取跟目录 + } else { + // 没有SD卡,缓存到系统存储 + file = Environment.getDataDirectory(); + } + file = Util.GetDirectory(); + bitmappath = file.getAbsolutePath() + + File.separator + "photo.png"; + + try { + FileOutputStream fos = new FileOutputStream( + bitmappath); + // bitmap.compress(CompressFormat.PNG, 100, + // fos); + // 压缩bitmap到输出流中 + response.compress(CompressFormat.PNG, 100, + fos); + fos.flush(); + fos.close(); + // Wxistrue.isshare = true; + + Message msg = new Message(); + Bundle data = new Bundle(); + data.putString("bitpath", bitmappath); + data.putString("type", type); + + msg.setData(data); + + savehandler.sendMessage(msg); + + } catch (FileNotFoundException e) { + throw new InvalidParameterException(); + } catch (IOException e) { + + e.printStackTrace(); + } + + } + }, 0, 0, Config.RGB_565, + new com.android.volley.Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + Wxistrue.isphotoshare = true; + } + }); + volleymanager.getInstance().getmRequestQueue() + .add(imageRequest); + } else { + + } + } + + public void initwebjh() { + + //js调用Android方法 如果页面上面有多个的话,可以注册多个方法 + //submitFromWeb 要和js那边定义的一样就可以了 + + x5webview.registerHandler("accreditlogin", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + //Toast.makeText(webviewActivity.this, data, Toast.LENGTH_LONG).show(); + //如果js那边调用后又进行回调的话可以在这里进行回调的 + System.out.println("jsBradge调用登录=" + data); + Wxistrue.islogin = false;// 暂停授权登陆 + apputil.wxtype = 2; + + // 全局回调类,游戏自行实现 + /*if (!pmutil.isnullorEmpty(data)) { + if (data.equals("1")) { + //QQ登录 + // QQLogin(); + } else { + //微信登录 + login(); + } + } else { + login(); + }*/ + login(); + } + }); + + //图片下载 + x5webview.registerHandler("getphoto", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + System.out.println("调用图片下载"+data); + if (!pmutil.isnullorEmpty(data)) { + System.out.println("isdownloadphoto=" + isdownloadphoto); + if (getphotoistrue) { + savephoto(data); + } else { + System.out.println("#############"); + + Message msg = new Message(); + msg.what = 1; + Bundle bundel = new Bundle(); + bundel.putString("photo", data); + msg.setData(bundel); + photohandler.sendMessageDelayed(msg, 200); + } + } else { + String msg = "传递数组为空"; + String procket = "nn"; + + // commitLog.commitLog(webviewActivity.this, msg, procket); + } + + + } + }); + + + /*** + * js 调用微信分享 朋友圈或好友 + * type 1 普通分享 2截图分享 3 图片分享 + * + * webpageUrl 分享链接地址 title 分享标题 description 分享描述 + * + * Sharefriend 1 好友 2 朋友圈 + */ + + x5webview.registerHandler("friendsSharetypeUrlToptitleDescript", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + System.out.println("调用分享=" + data); + // 测试QQ分享 + // 显示分享面板,而不是立即执行分享 + SharePanelHelper.showSharePanel(webviewActivity.this, data); + + Gson gson = new Gson(); + + bean = gson.fromJson(data, sharetypeBean.class); + System.out.println(); + if(bean.getSharetype()==null){ + bean.setSharetype(""); + } + if(bean.getType()==null){ + bean.setType(""); + } + + if(bean.getSharefriend()==null){ + + bean.setSharefriend(""); + } + + if (bean.getType().equals("3")) { + if(bean.getSharetype().equals("3")){ + shareurl(bean.getSharetype(), bean.getWebpageUrl());//图片链接分享 + }else{ + shareurl(bean.getSharefriend(), bean.getWebpageUrl());//图片链接分享 + } + + + + } else { + //普通分享 + + if (Wxistrue.isshare) { + + + + WXEntryActivity.setshareHandler(handler); +// SGEntryActivity.setshareHandler(handler); + + if(bean.getSharetype().equals("3")){ +// if(!xlapi.isSGAppInstalled()){ +// +// Toast.makeText(webviewActivity.this, "闲聊没有安装,请先安装闲聊", Toast.LENGTH_LONG).show(); +// }else{ +// xlfriend(); +// //不能重复点击 +// Wxistrue.isshare = false; +// } + }else{ + if (bean.getSharefriend().equals("1")) { + friend(); + } else{ + sharefriends(); + } + } + }else{ + h5handler.postDelayed(new Runnable() { + @Override + public void run() { + Wxistrue.isshare = true; + } + },3000); + } + + } + + + } + }); + + //发送通知 + x5webview.registerHandler("notification", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + // Toast.makeText(webviewActivity.this, data, Toast.LENGTH_LONG).show(); + //如果js那边调用后又 进行回调的话可以在这里进行回调的 + + System.out.println("jsBradge调用登录=" + data); + + + + + } + }); + //获取系统时间 + x5webview.registerHandler("getTime", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + //Toast.makeText(webviewActivity.this, data, Toast.LENGTH_LONG).show(); + //如果js那边调用后又 进行回调的话可以在这里进行回调的 + + + function.onCallBack(""+System.currentTimeMillis()); + + } + }); + + //横竖屏切换 + x5webview.registerHandler("orientation", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + Toast.makeText(webviewActivity.this, data, Toast.LENGTH_LONG).show(); + //如果js那边调用后又 进行回调的话可以在这里进行回调的 + /** + * 1 为横屏 2 为竖屏 + */ + int Orientation=1; + + try { + Orientation= Integer.parseInt(data); + }catch(Exception e){ + + } + + if (Orientation == 1) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + } else { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + + } + }); + + + + //1.普通震动 time 震动时间 单位毫秒 + x5webview.registerHandler("vibrator", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + // Toast.makeText(webviewActivity.this, data, Toast.LENGTH_LONG).show(); + //如果js那边调用后又 进行回调的话可以在这里进行回调的 + long time=Long.parseLong(data); + VibratorUtil.getInstance(webviewActivity.this).vibrate(time); + + } + }); + //是否重复震动 repeat -1 否 1 重复震动 + x5webview.registerHandler("repeatvibrator", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + //Toast.makeText(webviewActivity.this, data, Toast.LENGTH_LONG).show(); + //如果js那边调用后又 进行回调的话可以在这里进行回调的 + int repeat= Integer.parseInt(data); + VibratorUtil.getInstance(webviewActivity.this).repeatVibrate( + repeat); + + } + }); + + //取消震动 + x5webview.registerHandler("canclevibrator", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + // Toast.makeText(webviewActivity.this, data, Toast.LENGTH_LONG).show(); + //如果js那边调用后又 进行回调的话可以在这里进行回调的 + + VibratorUtil.getInstance(webviewActivity.this).cancle(); + + } + }); + //退出游戏 + x5webview.registerHandler("finsh", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + // Toast.makeText(webviewActivity.this, data, Toast.LENGTH_LONG).show(); + //如果js那边调用后又 进行回调的话可以在这里进行回调的 + + exitApp(); + + } + }); + + //返回电话状态 0 无任何状态时(挂电话) 1 接起电话时 2 + x5webview.registerHandler("getphonestate", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + // Toast.makeText(webviewActivity.this, data, Toast.LENGTH_LONG).show(); + //如果js那边调用后又 进行回调的话可以在这里进行回调的 + int state=phonestate(); + function.onCallBack(""+state); + + + } + }); + // + + //长按打开音屏录音 + x5webview.registerHandler("prepareaudio", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + // Toast.makeText(webviewActivity.this, data, Toast.LENGTH_LONG).show(); + + paprehandler.sendEmptyMessage(1); + + } + }); + + //播放声音audiourl 音频地址 type 1 普通 2 历史 user 用户动画位置 + x5webview.registerHandler("mediaTypeAudio", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + // Toast.makeText(webviewActivity.this, data, Toast.LENGTH_LONG).show(); + + JSONObject json= null; + try { + json = new JSONObject(data); + String audiourl=json.getString("audiourl"); + String type=json.getString("type"); + String user=json.getString("user"); + + System.out.println(json.toString()); + Boolean boo = MediaFile.isAudioFileType(audiourl); + + if (!pmutil.isnullorEmpty(audiourl)) { + if (boo) { + if (type.equals("1")) { + + /** + * 防止 播放多次调用 + */ + if (!isPlayaudio) { + + // playautio(audiourl, user); + play(audiourl, user); + } else { + Message msg = new Message(); + Bundle bundel = new Bundle(); + bundel.putString("audiourl", audiourl); + bundel.putString("user", user); + msg.setData(bundel); + playhandler.sendMessageDelayed(msg, 200); + + // playautio(audiourl, user); + } + } else { + if (!isPlayaudio) { + // isPlaying = true; + play(audiourl, user); + } + } + } + } + + + } catch (JSONException e) { + e.printStackTrace(); + } + + } + }); + + //调用手机默认浏览器打开链接 + x5webview.registerHandler("browser", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + Intent intent = new Intent(); + intent.setAction("android.intent.action.VIEW"); + + Uri content_url = Uri.parse(data); + if(BrowserUtil.isQQBrowserInstalled()){ + intent.setClassName("com.tencent.mtt","com.tencent.mtt.MainActivity");//打开QQ浏览器 + }else{ + + } + intent.setData(content_url); + startActivity(intent); + } + }); + + // 主动获取电量 + x5webview.registerHandler("getbattery", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + // Toast.makeText(webviewActivity.this, data, Toast.LENGTH_LONG).show(); + + IntentFilter ifilter = new IntentFilter( + Intent.ACTION_BATTERY_CHANGED); + Intent batteryStatus = registerReceiver(null, ifilter); + + // 当前剩余电量 + int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, + -1); + // 电量最大值 + int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, + -1); + // 电量百分比 + float batteryPct = (level / (float) scale); + + + x5webview.callHandler("getBattery", ""+batteryPct, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + //这里也是可以进行js回传的 + } + }); + + + + } + }); + + + // 主动获取wifi信号 + x5webview.registerHandler("getwifiLevel", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + getWifiInfo(); + + JSONObject json = new JSONObject(); + try { + json.put("ssidname", wifibean.getSsid()); + + json.put("signalLevel", wifibean.getSignalLevel()); + + System.out.println("---" + json.toString()); + x5webview.callHandler("getwifiLevel", json.toString(), new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + + } catch (JSONException e) { + e.printStackTrace(); + } + + } + }); + // 主动获取网络状态 + x5webview.registerHandler("getnetwork", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + String type = "1"; + + boolean isnetwork = apputil + .isNetworkConnected(webviewActivity.this); + if (isnetwork) { + + boolean iswifi = apputil + .isNetworkAvailable(webviewActivity.this); + if (iswifi) { + type = "2"; + + } else { + type = "3"; + } + } + function.onCallBack(type); + } + }); + + //获取本地apk版本号是否大于网络返回版本号 + //* code 返回 1 apk版本号>网络返回版本号 + // 0 apk版本号<=网络返回版本号 + x5webview.registerHandler("getcompareCode", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + + function.onCallBack(""+apputil.code); + } + }); + //摇一摇开始接口 + x5webview.registerHandler("startshake", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + isShake = true; + mShakeListener.start(); + + } + }); + //摇一摇震动声音打开关闭接口 + x5webview.registerHandler("SwitchShake", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + if (data.equals("1")) { + apputil.Voicetype = 1;// 打開 + } else { + apputil.Voicetype = 0;// 關閉 + } + + } + }); + //摇一摇震动声音打开关闭接口 + x5webview.registerHandler("stopshake", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + isShake = false; + mShakeListener.stop(); + + } + }); + //打开扫一扫 + x5webview.registerHandler("opensaoma", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + permissionHandler.sendEmptyMessage(1); + + + } + }); + //开启定位 type 1 连续定位 2 定位1次(三秒内精度最高一次) + + x5webview.registerHandler("startlocation", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + if (data.equals("1")) { + iscontinuouslocation = true; + } else { + iscontinuouslocation = false; + } + handellocation.sendEmptyMessage(2); + + + } + }); + + // 主动获取用户定位信息 返回定位数据 + x5webview.registerHandler("getlocationinfo", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + + String json = null; + + if (location != null) { + Gson gson = new Gson(); + json = gson.toJson(location); + } + System.out.println(json); + function.onCallBack(json); + + } + }); + //切换子游戏 + // webtype 2 竖屏 + //3横屏 + //Gamedirectory 目录判断游戏是否存在 + //gamedownloadurl 游戏id + //data 数据交换 + + x5webview.registerHandler("SwitchOverGameData", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + try { + System.out.println(data); + JSONObject obj=new JSONObject(data); + String webtype=obj.getString("webtype"); + String Gamedirectory=obj.getString("Gamedirectory"); + String gamedownloadurl=obj.getString("gamedownloadurl"); + String data1=obj.getString("data"); + + System.out.println("webtype" + webtype + "Gamedirectory=" + + Gamedirectory + "gamedownloadurl=" + gamedownloadurl); + + initgame(webtype, Gamedirectory, gamedownloadurl, data1); + + } catch (JSONException e) { + e.printStackTrace(); + } + + + } + }); + + //判断是否安装 子游戏   返回 1 安装  0未安装 data 目录名 + + x5webview.registerHandler("getGameinstall", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + int i = 0; + + if (isgamedirectory(data)) { + i = 1; + } + function.onCallBack(""+i); + + } + }); + //支付 + + x5webview.registerHandler("getGameplay", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + startpay(data); + + } + }); + //4.打开网页//数据格式 url 网页地址 title 标题 data 交互数据 orientation = 0; 横屏 1竖屏 + x5webview.registerHandler("OpenurlTitleData", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + try { + JSONObject obj=new JSONObject(data); + String url= obj.optString("url"); + String title= obj.optString("title"); + String data1=obj.optString("data"); + + Intent in = new Intent(); + + in.putExtra("url", url); + in.putExtra("title", title); + in.putExtra("data", data1); + in.setClass(webviewActivity.this, openwebActivity1.class); + // startActivity(in); + startActivityForResult(in, 1001); + + } catch (JSONException e) { + e.printStackTrace(); + } + + + } + }); + + //复制接口 + + x5webview.registerHandler("gameCopytext", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + ClipboardManager copy = (ClipboardManager) webviewActivity.this + .getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clipData = ClipData.newPlainText("TextLabel", data); + copy.setPrimaryClip(clipData); + + + } + }); + + //粘贴接口 + + x5webview.registerHandler("gamepastetext", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + ClipboardManager clipboardManager = (ClipboardManager) webviewActivity.this + .getSystemService(Context.CLIPBOARD_SERVICE); + String message = (String) clipboardManager.getPrimaryClip() + .getItemAt(0).getText(); + + function.onCallBack(message); + + } + }); + + //获取市场id接口 + x5webview.registerHandler("getmarketname", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + String market=getAllFilename("market"); + + + function.onCallBack(market); + + } + }); + + //返回获得自定义文件夹名 + x5webview.registerHandler("getothername", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + String name=getAllFilename(data); + + + function.onCallBack(name); + + } + }); + //返回获得other指定文件夹 + x5webview.registerHandler("getOther", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + String name=getAllFilename("other"); + + + function.onCallBack(name); + + } + }); + //播放游戏声音srcIsloop + + x5webview.registerHandler("srcIsloop", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + System.out.println(data); + + + + try { + JSONObject obj=new JSONObject(data); + String src=obj.optString("src"); + String isloop=obj.optString("isloop"); + + System.out.println("isloop==" + isloop); + + Message msg = new Message(); + System.out.println("src==" + src); + Bundle bun = new Bundle(); + bun.putString("src", src); + bun.putString("type", ""+isloop); + msg.setData(bun); + playwav.sendMessage(msg); + + } catch (JSONException e) { + e.printStackTrace(); + } + + + + + + } + }); + //语音播放开关 + x5webview.registerHandler("voicePlaying", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + if (data.equals("1")) { + Settingutil.voicePlaying = true; + + } else { + Settingutil.voicePlaying = false; + } + + + } + }); + //打开安装应用 + x5webview.registerHandler("openApplyDownloadpath", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + String downloadpath=""; + try { + JSONObject obj=new JSONObject(data); + String packagename=obj.optString("packagename"); + downloadpath=obj.optString("downloadpath"); + PackageManager packageManager = getPackageManager(); + Intent intent = new Intent(); + + intent = packageManager.getLaunchIntentForPackage(packagename); + startActivity(intent); + } catch (Exception e) { + e.printStackTrace(); + Intent viewIntent = new Intent("android.intent.action.VIEW", + Uri.parse(downloadpath)); + startActivity(viewIntent); + } + + + } + }); + //当前用户加入房间或者创建房间(频道) + x5webview.registerHandler("createRoom", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + System.out.println("调用创建加入频道--" + data); + System.out.println("控件数量=" + containerFrame.getChildCount()); + if (data != null) { + Message msg = new Message(); + msg.what = 1; + msg.obj = data; + h5handler.sendMessage(msg); + } + } + }); + //2.退出房间 + x5webview.registerHandler("exitRoom", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + + System.out.println("退出房间--" + data); + + if (data != null) { + Message msg = new Message(); + msg.what = 2; + msg.obj = data; + h5handler.sendMessage(msg); + } + } + }); + //3.返回当前用户视频窗口信息(左上角坐标及宽高) + x5webview.registerHandler("getVideoinfo", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + if (data != null) { + System.out.println(data); + Message msg = new Message(); + msg.what = 0; + msg.obj = data; + h5handler.sendMessage(msg); + } + + } + }); + + + //用户点击视频是否出现悬浮框type值(默认不显示) 1显示悬浮框 2隐藏悬浮框 + x5webview.registerHandler("DragViewvideoIsshow", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + if (data.equals("1")) { + mDragViewvideoIsshow = true; + } else { + mDragViewvideoIsshow = false; + } + + } + }); + //获取手机基本配置信息 + x5webview.registerHandler("getphoneInfo", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + h5handler.sendEmptyMessage(3); + } + }); + //获取手机通讯录 - 已注释 + x5webview.registerHandler("getAddressBook", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + h5handler.sendEmptyMessage(4); + } + }); + //支付调用打开浏览器 + x5webview.registerHandler("paybrowser", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + Message msg = new Message(); + msg.what = 1; + Bundle bundle = new Bundle(); + bundle.putString("browserurl", data); + msg.setData(bundle); + mpaybrow.sendMessage(msg); + } + }); + // opencamera + x5webview.registerHandler("opencamera", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + permissionHandler.sendEmptyMessage(2); + } + }); + + + } + + /*private void setJPushAliasandTag() { + String unionid = SpUtil.getStringSharedPerference(Shared, "unionid"); + if (!pmutil.isnullorEmpty(unionid)) { + unionid = unionid.replaceAll("'", ""); + JPushInterface.setAlias(this, 1, unionid); + } + String channel = getAllFilename("channel"); + if (!pmutil.isnullorEmpty(channel)) { + HashSet map1 = new HashSet(); + map1.add(channel); + + JPushInterface.setTags(this, 1, map1); + } + }*/ + + protected void localityplay(String amrpath) { + Message msg = new Message(); + Bundle bundel = new Bundle(); + bundel.putString("audiourl", amrpath); + bundel.putString("user", String.valueOf(0)); + msg.setData(bundel); + playhandler.sendMessageDelayed(msg, 10); + + } + + @SuppressLint("SetJavaScriptEnabled") + private void initWebViewSettings() { + + File file = CacheManager.getCacheFileBaseDir(); + if (file != null && file.exists() && file.isDirectory()) { + System.out.println("----" + file.getAbsolutePath()); + } + + if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) { + x5webview.getSettings().setAllowUniversalAccessFromFileURLs(true); + } + IX5WebViewExtension x5WebViewExtension = x5webview.getX5WebViewExtension(); + if (x5WebViewExtension != null) { + x5WebViewExtension.setScrollBarFadingEnabled(false); + } + + WebSettings webSetting = x5webview.getSettings(); + webSetting.setAllowFileAccess(true); + webSetting.setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS); + // 设置WebView可触摸放大缩小 + webSetting.setSupportZoom(false); + + webSetting.setBuiltInZoomControls(false); + // WebView双击变大,再双击后变小,当手动放大后,双击可以恢复到原始大小//设置此属性,可任意比例缩放 + webSetting.setUseWideViewPort(false); + + webSetting.setSupportMultipleWindows(false); + + webSetting.setDatabaseEnabled(true); + webSetting.setDomStorageEnabled(true); + + webSetting.setJavaScriptEnabled(true); + + webSetting.setCacheMode(WebSettings.LOAD_NO_CACHE);// 不使用缓存,只从网络获取数据 + webSetting.setAppCacheEnabled(false);// 是否设置缓存 + webSetting.setGeolocationEnabled(true);// //设置定位的数据库路径 + + webSetting.setDatabasePath(this.getDir("databases", 0).getPath()); + System.out.println(this.getDir("databases", 0).getPath()); + // 没有的话会黑屏 支持插件 + webSetting.setPluginsEnabled(true); + + } + + @Override + protected void onStart() { + System.out.println("onStart"); + super.onStart(); + } + + public boolean isAppOnForeground() { + ActivityManager activityManager = (ActivityManager) getApplicationContext() + .getSystemService(Context.ACTIVITY_SERVICE); + String packageName = getApplicationContext().getPackageName(); + /** + * 获取Android设备中所有正在运行的App + */ + List appProcesses = activityManager + .getRunningAppProcesses(); + if (appProcesses == null) + + return false; + for (RunningAppProcessInfo appProcess : appProcesses) { + // The name of the process that this object is associated with. + if (appProcess.processName.equals(packageName) + && appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { + return true; + } + } + return false; + } + + @Override + protected void onResume() { + super.onResume(); + + + Wxistrue.isshare = true; + Wxistrue.isphotoshare = true; + Wxistrue.islogin = true; + if (isShake) { + mShakeListener.start(); + } + if (m_wklk != null) { + m_wklk.acquire(); // 保持唤醒 + } + +// if (x5webview != null) { +// if (isfinsh) { +// // x5webview.loadUrl("javascript:playmediaAudio();"); +// } +// +// } + + if (x5webview != null) { + + x5webview.onResume(); + } + + if (isForeground == false) { + + if (x5webview != null) { + +// Wxistrue.isshare = true; +// Wxistrue.isphotoshare = true; + + service = 1; + if (isfinsh) { + String appservice = "javascript:appservice(" + "'" + + service + "'" + ");"; + +// webviewjh(appservice); + System.out.println(appservice); + runOnUiThread(new Runnable() { + @Override + public void run() { + + try { + x5webview.callHandler("appservice", ""+service, new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + System.out.println("appservice交互调用成功"); + } catch (Exception e) { + System.out.println("appservice交互调用失败"); + + } + } + }); + + + } + + // x5webview.loadUrl("javascript:appservice(" + "'" + service + // + "'" + ");"); + + } + + isForeground = true; + } + MobclickAgent.onPageStart("webviewActivity"); + // 统计页面(仅有Activity的应用中SDK自动调用,不 + + // 集成基本统计分析,初始化 Session + UMGameAgent.onResume(this); + } + + @Override + protected void onPause() { + if (x5webview != null) { + x5webview.onPause(); + } + + mShakeListener.stop(); + if (m_wklk != null) { + try { + m_wklk.release(); // 解除保持唤醒 + } catch (Exception e) { + // TODO: handle exception + } + } + super.onPause(); + + /** + * 失去焦点停止声音播放 + */ + isForeground = false; + service = 2; +// String appservice = "javascript:appservice(" + "'" + service + "'" +// + ");"; +// +// webviewjh(appservice); + x5webview.callHandler("appservice", ""+service, new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + MobclickAgent.onPageEnd("welcomeactivity1"); + // //集成基本统计分析, 结束 Session + UMGameAgent.onPause(this); + } + + @Override + protected void onStop() { + super.onStop(); + + photohandler.removeCallbacksAndMessages(null); + mhandler.removeCallbacksAndMessages(null); + + mShakeListener.stop(); + + Wxistrue.isshare = true; + Wxistrue.isphotoshare = true; + + if (!isAppOnForeground()) { + + isForeground = false; + service = 2; +// String appservice = "javascript:appservice(" + "'" + service + "'" +// + ");"; +// webviewjh(appservice); + x5webview.callHandler("appservice", ""+service, new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + } + } + + private void jieping() { + + File file; + + if (Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED)) { + // sd卡存储(/mnt/sdcard/cache) + file = Environment.getExternalStorageDirectory();// 获取跟目录 + } else { + // 没有SD卡,缓存到系统存储 + file = Environment.getDataDirectory(); + } + file = Util.GetDirectory(); + bitmappath = file.getAbsolutePath() + File.separator + "tes.png"; + View cv = webviewActivity.this.getWindow().getDecorView(); + getScreenHot(cv, bitmappath); + + } + + /** + * 截取webView快照(webView加载的整个内容的大小) + * + * @param webView + * @return + */ + // public static Bitmap captureWebView1(WebView webView) { + // webView.setDrawingCacheEnabled(true); + // webView.buildDrawingCache(); + // Picture snapShot = webView.capturePicture(); + // Bitmap bmp = Bitmap.createBitmap(snapShot.getWidth(), + // snapShot.getHeight(), Bitmap.Config.ARGB_8888); + // Canvas canvas = new Canvas(bmp); + // snapShot.draw(canvas); + // canvas.save(); + // canvas.restore(); + // // webView.dispatchDraw(canvas); + // webView.destroyDrawingCache(); + // return bmp; + // } + private Bitmap captureWebView(WebView webView) { + Picture picture = webView.capturePicture(); + Bitmap bmp = Bitmap.createBitmap(picture.getWidth(), + picture.getHeight(), Bitmap.Config.RGB_565); + Canvas c = new Canvas(bmp); + picture.draw(c); + return bmp; + } + + private void getbitmap(Bitmap bitmap2, String bitmappath2) { + + File file1 = new File(bitmappath2); + try { + file1.createNewFile(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + bitmap2.compress(Bitmap.CompressFormat.PNG, 100, baos); + + int options = 100; + while (baos.toByteArray().length / 1024 > 100 && options != 10) { // 循环判断如果压缩后图片是否大于100kb,大于继续压缩 + baos.reset();// 重置baos即清空baos + bitmap2.compress(Bitmap.CompressFormat.PNG, options, baos);// 这里压缩options%,把压缩后的数据存放到baos中 + options -= 10;// 每次都减少10 + } + + ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把压缩后的数据baos存放到ByteArrayInputStream中 + // 据baos存放到ByteArrayInputStream中 + Bitmap bit = BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream数据生成图片 + + System.out.println(baos.toByteArray().length); + + try { + FileOutputStream fos = new FileOutputStream(file1); + bit.compress(CompressFormat.PNG, 100, fos); + + fos.flush(); + fos.close(); + } catch (FileNotFoundException e) { + + } catch (IOException e) { + + e.printStackTrace(); + } + + } + + protected void friend() { + apputil.wxtype = 1; + Wxistrue.sharetype = 1; + + if (bean.getType().equals("1")) { + + WXWebpageObject webpage = new WXWebpageObject(); + webpage.webpageUrl = bean.getWebpageUrl(); + WXMediaMessage msg = new WXMediaMessage(webpage); + msg.title = bean.getTitle(); + msg.description = bean.getDescription(); + // Toast.makeText(this, bean.getDescription(), 1).show(); + Bitmap bt = BitmapFactory.decodeResource(getResources(), + R.drawable.sharelogo3); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + bt.compress(Bitmap.CompressFormat.PNG, 100, out); + + // Toast.makeText(webviewActivity.this, "" + + // out.toByteArray().length, + // 1).show(); + + if (out.toByteArray().length > 32000) { + // int a=out.toByteArray().length/30000; + BitmapFactory.Options newOpts = new BitmapFactory.Options(); + newOpts.inJustDecodeBounds = true; + + // Toast.makeText(webviewActivity.this, "压缩", 1).show(); + + BitmapFactory.decodeResource(getResources(), + R.drawable.sharelogo3, newOpts); + + newOpts.inJustDecodeBounds = false; + int inSampleSize = (out.toByteArray().length / 32768 + 1) / 2 + 2; + if (inSampleSize < 2) { + inSampleSize = 2; + } + + newOpts.inSampleSize = inSampleSize; + Bitmap bitmap = BitmapFactory.decodeResource(getResources(), + R.drawable.sharelogo3, newOpts); + + msg.thumbData = Util.bmpToByteArray(bitmap, true); + } else { + msg.thumbData = Util.bmpToByteArray(bt, true); + } + + SendMessageToWX.Req req = new SendMessageToWX.Req(); + req.transaction = buildTransaction("webpage"); + req.message = msg; + req.scene = SendMessageToWX.Req.WXSceneSession; + api.sendReq(req); + } else if (bean.getType().equals("2")) { + try { + + // photosharefriend(); + + } catch (Exception e) { + Wxistrue.isshare = true; + } + + + } + } + protected void xlfriend() { + apputil.wxtype = 1; + Wxistrue.sharetype = 3; + + if (bean.getType().equals("1")) {//pu + + //显示的图标(可选) + Bitmap bt = BitmapFactory.decodeResource(getResources(),R.drawable.sharelogo3); + + + +// //初始化一个SGLinkObject对象,并设置一个分享图标 +// SGLinkObject linkObject = new SGLinkObject(bt); +// +// //要分享的链接,必填 +// linkObject.shareUrl = bean.getWebpageUrl(); +// +// //用SGImageObject对象初始化一个SGMediaMessage对象 +// SGMediaMessage msg = new SGMediaMessage(); +// msg.mediaObject = linkObject; +// msg.title = bean.getTitle(); //链接标题 +// msg.description = bean.getDescription(); //链接描述 +// +// //构造一个Req +// SendMessageToSG.Req req = new SendMessageToSG.Req(); +// req.transaction = SGConstants.T_LINK; +// req.mediaMessage = msg; +// req.scene = SendMessageToSG.Req.SGSceneSession; //代表分享到会话列表 +// +// //调用api接口发送数据到闲聊 +// xlapi.sendReq(req); + + + + + // Toast.makeText(webviewActivity.this, "" + + // out.toByteArray().length, + // 1).show(); + + + + + } else if (bean.getType().equals("2")) { + try { + + // photosharefriend(); + + } catch (Exception e) { + Wxistrue.isshare = true; + } + + + } + } + private void photoshareurlfriend(String url) { + + } + + + + private void xlphotosharefriend(){ + apputil.wxtype = 1; + Wxistrue.sharetype = 3; + + Bitmap bitmap = BitmapFactory.decodeFile(bitmappath); + +// //初始化一个SGImageObject对象,设置所分享的图片内容 +// SGImageObject imageObject = new SGImageObject(bitmap); +// +// //用SGImageObject对象初始化一个SGMediaMessage对象 +// SGMediaMessage msg = new SGMediaMessage(); +// msg.mediaObject = imageObject; +// +// //构造一个Req +// SendMessageToSG.Req req = new SendMessageToSG.Req(); +// req.transaction = SGConstants.T_IMAGE; +// req.mediaMessage = msg; +// req.scene = SendMessageToSG.Req.SGSceneSession; //代表分享到会话列表 +// +// //调用api接口发送数据到闲聊 +// xlapi.sendReq(req); + + } + + + private void photosharefriend() { + // 使用新的微信分享辅助类替换原有的直接API调用 + apputil.wxtype = 1; + Wxistrue.sharetype = 1; + + // 获取微信分享工具实例 + WeChatShareUtil weChatShareUtil = WeChatShareUtil.getInstance(this); + + // 设置分享回调 + weChatShareUtil.setShareCallback(new WeChatShareUtil.WeChatShareCallback() { + @Override + public void onSuccess() { + // 分享成功后的处理逻辑保持不变 + runOnUiThread(() -> { + // 可以添加成功提示或其他逻辑 + }); + } + + @Override + public void onError(int code, String message) { + // 分享失败后的处理逻辑 + runOnUiThread(() -> { + // 可以添加失败提示或其他逻辑 + }); + } + + @Override + public void onCancel() { + // 分享取消后的处理逻辑 + runOnUiThread(() -> { + // 可以添加取消提示或其他逻辑 + }); + } + }); + + // 使用新的分享方法分享图片到微信好友(scene = 0) + weChatShareUtil.shareImage(this, bitmappath, 0); + } + + protected void sharefriends() { + + + + apputil.wxtype = 1; + + Wxistrue.sharetype = 2; + + if (bean.getType().equals("1")) { + WXWebpageObject webpage = new WXWebpageObject(); + webpage.webpageUrl = bean.getWebpageUrl(); + WXMediaMessage msg = new WXMediaMessage(webpage); + msg.title = bean.getTitle(); + msg.description = bean.getDescription(); + // Toast.makeText(this, bean.getDescription(), 1).show(); + + Bitmap bt = BitmapFactory.decodeResource(getResources(), + R.drawable.sharelogo3); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + bt.compress(Bitmap.CompressFormat.PNG, 100, out); + + // Toast.makeText(webviewActivity.this, "" + + // out.toByteArray().length, + // 1).show(); + + if (out.toByteArray().length > 32000) { + // int a=out.toByteArray().length/30000; + BitmapFactory.Options newOpts = new BitmapFactory.Options(); + newOpts.inJustDecodeBounds = true; + BitmapFactory.decodeResource(getResources(), + R.drawable.sharelogo3, newOpts); + newOpts.inJustDecodeBounds = false; + int inSampleSize = (out.toByteArray().length / 32000 + 1) / 2 + 2; + if (inSampleSize < 2) { + inSampleSize = 2; + } + newOpts.inSampleSize = inSampleSize; + + Bitmap bitmap = BitmapFactory.decodeResource(getResources(), + R.drawable.sharelogo3, newOpts); + + msg.thumbData = Util.bmpToByteArray(bitmap, true); + } else { + msg.thumbData = Util.bmpToByteArray(bt, true); + } + + SendMessageToWX.Req req = new SendMessageToWX.Req(); + req.transaction = buildTransaction("webpage"); + req.message = msg; + req.scene = SendMessageToWX.Req.WXSceneTimeline; + api.sendReq(req); + + } else if (bean.getType().equals("2")) { + // photosharefriends(); + + } + + } + + private void photosharefriends() { + // 使用新的微信分享辅助类替换原有的直接API调用 + apputil.wxtype = 1; + Wxistrue.sharetype = 2; + + // 获取微信分享工具实例 + WeChatShareUtil weChatShareUtil = WeChatShareUtil.getInstance(this); + + // 设置分享回调 + weChatShareUtil.setShareCallback(new WeChatShareUtil.WeChatShareCallback() { + @Override + public void onSuccess() { + // 分享成功后的处理逻辑保持不变 + runOnUiThread(() -> { + // 可以添加成功提示或其他逻辑 + }); + } + + @Override + public void onError(int code, String message) { + // 分享失败后的处理逻辑 + runOnUiThread(() -> { + // 可以添加失败提示或其他逻辑 + }); + } + + @Override + public void onCancel() { + // 分享取消后的处理逻辑 + runOnUiThread(() -> { + // 可以添加取消提示或其他逻辑 + }); + } + }); + + // 使用新的分享方法分享图片到微信朋友圈(scene = 1) + weChatShareUtil.shareImage(this, bitmappath, 1); + + System.out.println(bitmappath); + } + + // 进行质量压缩,文件大小改变 ,bitmap 不变 + public void compressBmpFromBmp(Bitmap thumb) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int options = 100; + thumb.compress(Bitmap.CompressFormat.PNG, options, baos); + // Toast.makeText(MainActivity.this, "%%%%%%" + + // baos.toByteArray().length, + // 1).show(); + while (baos.toByteArray().length > 30000 && options != 10) { + baos.reset(); // 清空baos + thumb.compress(Bitmap.CompressFormat.PNG, options, baos);// 这里压缩options%,把压缩后的数据存放到baos中 + options -= 10; + } + thumb.recycle(); + + byte[] result = baos.toByteArray(); + + try { + baos.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // Toast.makeText(MainActivity.this, "&&&&&&" + result.length, + // 1).show(); + Bitmap bit = BitmapFactory.decodeByteArray(baos.toByteArray(), 0, + baos.toByteArray().length); + } + + @Override + protected void onDestroy() { + +// if(webserverInstance.getInstance().iscreatandrun()){ +// webserverInstance.getInstance().webclose(); +// } + + try { + clearWebViewCache(); + } catch (Exception e) { + System.out.println(e); + } + + photohandler.removeCallbacksAndMessages(null); + + mhandler.removeCallbacksAndMessages(null); + + try { + if (x5webview != null) { + ViewParent parent = x5webview.getParent(); + if (parent != null) { + ((ViewGroup) parent).removeView(x5webview); + } + + x5webview.stopLoading(); + x5webview.setWebChromeClient(null); + x5webview.setWebViewClient(null); + // 退出时调用此方法,移除绑定的服务,否则某些特定系统会报错 + x5webview.getSettings().setJavaScriptEnabled(false); + + x5webview.clearCache(true); + x5webview.setFocusable(true); // + x5webview.removeAllViews(); + x5webview.clearHistory(); + x5webview.clearView(); + x5webview.destroy(); + x5webview = null; + + // android.os.Process.killProcess(android.os.Process.myPid()); + } + } catch (Exception e) { + e.printStackTrace(); + } + + if (mLocationClient != null) { + mLocationClient.onDestroy(); + } + + // 停止HTTP服务器 + NewWebServerInstance.getInstance().stop(); + + // Toast.makeText(this, "onDestroy", 1).show(); + + + System.out.println("onDestroy"); + // if (webdialog != null) { + // webdialog.dismiss(); + // } + + unregisterReceiver(mMessageReceiver); + unregisterReceiver(batteryReceiver); + unregisterReceiver(WifiChangeReceiver); + unregisterReceiver(myNetReceiver); + screen.unregisterListener(); + if (m_wklk != null) { + try { + m_wklk.release(); // 解除保持唤醒 + } catch (Exception e) { + // TODO: handle exception + } + } + super.onDestroy(); + + } + + private static final String TAG = openwebActivity1.class.getSimpleName(); + private static final String APP_CACAHE_DIRNAME = "/webcache"; + + /** + * 清除WebView缓存 + */ + public void clearWebViewCache() { + + //清理Webview缓存数据库 + try { + deleteDatabase("webview.db"); + deleteDatabase("webviewCache.db"); + } catch (Exception e) { + e.printStackTrace(); + } + +// //WebView 缓存文件 +// File appCacheDir = new File(getFilesDir().getAbsolutePath()+APP_CACAHE_DIRNAME); +// Log.e(TAG, "appCacheDir path="+appCacheDir.getAbsolutePath()); +// +// File webviewCacheDir = new File(getCacheDir().getAbsolutePath()+"/webviewCache"); +// Log.e(TAG, "webviewCacheDir path="+webviewCacheDir.getAbsolutePath()); +// //删除webview 缓存 缓存目录 +// if(appCacheDir.exists()){ +// deleteFile(appCacheDir); +// } + + //data/user/0/包名/Cache + File webviewCache = new File(getCacheDir().getAbsolutePath()); + + //删除webview 缓存 缓存目录 + + if (webviewCache.exists()) { + deleteFile(webviewCache); + } + +// //删除webview 缓存目录 +// if(webviewCacheDir.exists()){ +// deleteFile(webviewCacheDir); +// } + + } + + /** + * 递归删除 文件/文件夹 + * + * @param file + */ + public void deleteFile(File file) { + + Log.i(TAG, "delete file path=" + file.getAbsolutePath()); + + if (file.exists()) { + if (file.isFile()) { + file.delete(); + } else if (file.isDirectory()) { + File files[] = file.listFiles(); + for (int i = 0; i < files.length; i++) { + deleteFile(files[i]); + } + } + file.delete(); + } else { + Log.e(TAG, "delete file no exists " + file.getAbsolutePath()); + } + } + + + // 硬件加速 + private void hardwareAccelerate() { + if (this.getPhoneSDKInt() >= 14) { + getWindow().setFlags(0x1000000, 0x1000000); + } + } + + public int getPhoneSDKInt() { + int version = 0; + try { + version = Integer.valueOf(android.os.Build.VERSION.SDK); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + return version; + } + + // protected void uploadBug(String amrpath) { + // System.out.println("上传日志地址:" + amrpath); + // Configuration config = new + // Configuration.Builder().zone(Zone.zone2).build(); + // UploadManager uploadManager = new UploadManager(config); + // + // Auth auth = Auth.create("ngN3rFW1j8dn7ZGpATKl7mreaNmp2Ei_l9AIhkIf", + // "6VXav9eqUCORJTYvTFOeTVRonAyk4Hrs-PIZ8jmZ"); + // String auth1 = auth.uploadToken("runload");//华南 + // + // String filename = amrpath.substring(amrpath.lastIndexOf("/") + 1); + // + // uploadManager.put(amrpath, filename, auth1, new UpCompletionHandler() { + // @Override + // public void complete(String key, ResponseInfo rinfo, + // JSONObject response) { + // //String s = key + ", " + rinfo + ", " + response; + // + // // File rile = new File(amrpath); + // // rile.delete(); + // + // SpUtil.setStringSharedPerference(Shared, "bugfilename", ""); + // + // } + // + // }, new UploadOptions(null, null, true, null, null)); + // } + + protected void uploadBug2(final String amrpath) { + System.out.println("上传日志地址:" + amrpath); + UploadManager uploadManager = new UploadManager(); + + Auth auth = Auth.create("ngN3rFW1j8dn7ZGpATKl7mreaNmp2Ei_l9AIhkIf", + "6VXav9eqUCORJTYvTFOeTVRonAyk4Hrs-PIZ8jmZ"); + String auth1 = auth.uploadToken("getgamebuglog"); + + String filename = amrpath.substring(amrpath.lastIndexOf("/") + 1); + + uploadManager.put(amrpath, filename, auth1, new UpCompletionHandler() { + @Override + public void complete(String key, ResponseInfo rinfo, + JSONObject response) { + // String s = key + ", " + rinfo + ", " + response; + + File rile = new File(amrpath); + rile.delete(); + + SpUtil.setStringSharedPerference(Shared, "bugfilename", ""); + + } + + }, new UploadOptions(null, null, true, null, null)); + } + + // protected void uploadBug1(String amrpath) { + // System.out.println("上传日志地址:" + amrpath); + // Configuration config = new + // Configuration.Builder().zone(Zone.zone1).build(); + // UploadManager uploadManager = new UploadManager(config); + // + // Auth auth = Auth.create("ngN3rFW1j8dn7ZGpATKl7mreaNmp2Ei_l9AIhkIf", + // "6VXav9eqUCORJTYvTFOeTVRonAyk4Hrs-PIZ8jmZ"); + // String auth1 = auth.uploadToken("getbug"); + // //华北 + // String filename = amrpath.substring(amrpath.lastIndexOf("/") + 1); + // + // uploadManager.put(amrpath, filename, auth1, new UpCompletionHandler() { + // @Override + // public void complete(String key, ResponseInfo rinfo, + // JSONObject response) { + // //String s = key + ", " + rinfo + ", " + response; + // + // // File rile = new File(amrpath); + // // rile.delete(); + // + // SpUtil.setStringSharedPerference(Shared, "bugfilename", ""); + // + // } + // + // }, new UploadOptions(null, null, true, null, null)); + // } + + protected void upload(String amrpath, final float time) { + + uploadManager = new UploadManager(); + + Auth auth = Auth.create("ngN3rFW1j8dn7ZGpATKl7mreaNmp2Ei_l9AIhkIf", + "6VXav9eqUCORJTYvTFOeTVRonAyk4Hrs-PIZ8jmZ"); + String auth1 = auth.uploadToken("gameauio"); + + System.out.println("amrpath==" + amrpath); + String filename = amrpath.substring(amrpath.lastIndexOf("/") + 1); + + uploadManager.put(amrpath, filename, auth1, new UpCompletionHandler() { + @Override + public void complete(String key, ResponseInfo rinfo, + JSONObject response) { + + String s = key + ", " + rinfo + ", " + response; + + // Toast.makeText(MainActivity.this, s+ "\n" + + // "http://ofc5os2op.bkt.clouddn.com/" + key, 1).show(); + System.out.println("上传成功:" + s + "\n" + "http://gameaudio.daoqi88.cn/" + key); + + // File rile = new File(amrpath); + // rile.delete(); + + SpUtil.setStringSharedPerference(Shared, "bugfilename", ""); + + // 发送到前端 + // String time = rinfo.headers().get("x-qn-meta-duration"); + // if (time == null) { + // time = "0"; + // } + // System.out.println("time==" + time); + + // 发送到前端 + // String filepath = "http://ofc5os2op.bkt.clouddn.com/" + key; + // String filepath = "http://ofc5os2op.bkt.clouddn.com/" + key; + + // 发送到前端 + // 发送到前端 + // String filepath = "http://gameaudio.daoqi88.cn/" + key; + // 发送到前端 + String filepath = "http://gameaudio.daoqi88.cn/" + key; + +// String getaudiourl = "javascript:getaudiourl(" + "'" + filepath +// + "'" + ",'" + time + "'" + ");"; +// webviewjh(getaudiourl); + + JSONObject json = new JSONObject(); + + try { + json.put("filepath", filepath); + } catch (Exception e) { + e.printStackTrace(); + } + try { + json.put("audiourl", filepath); + + json.put("time", time); + x5webview.callHandler("getaudiourl", json.toString(), new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + + + }catch (Exception e){ + + } + + + + + // DownloadUrl(filepath); + + } + }, new UploadOptions(null, null, true, null, null)); + } + + public void run(final String url) throws Exception { + + Request request = new Request.Builder().url(url).build(); + okclient.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(Call arg0, IOException throwable) { + throwable.printStackTrace(); + } + + @SuppressWarnings("resource") + @Override + public void onResponse(Call arg0, Response response) + throws IOException { + + if (!response.isSuccessful()) + throw new IOException("Unexpected code " + response); + Headers responseHeaders = response.headers(); + for (int i = 0; i < responseHeaders.size(); i++) { + System.out.println(responseHeaders.name(i) + ": " + + responseHeaders.value(i)); + } + InputStream is = null; + byte[] buf = new byte[2048]; + int len = 0; + FileOutputStream fos = null; + + is = response.body().byteStream(); + + if (Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED)) { + // 获取SDCard的路径 + destFileDir = Environment.getExternalStorageDirectory() + .getAbsoluteFile() + + File.separator + + "dowlod_audioss"; + // Toast.makeText(application, sdFile.getAbsolutePath(), + // 1).show(); + } else { + destFileDir = Environment.getDataDirectory() + .getAbsolutePath() + + File.separator + + "dowlod_audioss"; + } + destFileDir = Util.GetFileAbsolutePath(); + File dir = new File(destFileDir); + if (!dir.exists()) { + dir.mkdirs(); + } + + File file = new File(dir, getFileName(url)); + + System.out.println(file.getAbsolutePath()); + fos = new FileOutputStream(file); + while ((len = is.read(buf)) != -1) { + fos.write(buf, 0, len); + } + fos.flush(); + + System.out.println(file.getAbsolutePath()); + // play(file.getAbsolutePath()); + + } + + }); + } + + public void webviewjh(final String name) { + runOnUiThread(new Runnable() { + @Override + public void run() { + + try { + if (x5webview != null) { + x5webview.loadUrl(name); + } + + } catch (Exception e) { + // Toast.makeText(webviewActivity.this, "" + e.toString(), + // 1) + // .show(); + commitLog.commitLog(webviewActivity.this, "android登陆" + + name, e.toString()); + System.out.println(e.toString()); + } + } + }); + } + + /** + * @param filePathString 音频名 + * @param user 动画 + */ + protected void play(String filePathString, String user) { + + isPlayaudio = true; + uservoice = user; +// String call = "javascript:gameui_play_voice(" + "'" + uservoice + "'" +// + ");"; +// +// webviewjh(call); + x5webview.callHandler("gameui_play_voice", ""+uservoice, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + + // Toast.makeText(this, "开始uservoice="+uservoice, 0).show(); + + MediaManager.playSound(filePathString, new OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + +// String sw = "javascript:gameui_stop_voice(" + "'" + uservoice +// + "'" + ");"; +// webviewjh(sw); + if(x5webview!=null){ + x5webview.callHandler("gameui_stop_voice", ""+uservoice, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + } + + isPlayaudio = false; + uservoice = ""; + + System.out.println("播放完成"); + + } + }); + + } + + private String getFileName(String path) { + int separatorIndex = path.lastIndexOf("/"); + + int lastIndex = path.lastIndexOf("?"); + + return (separatorIndex < 0) ? path : path.substring(separatorIndex + 1, + lastIndex); + } + + protected void DownloadUrl(String filepath) { + + Auth auth = Auth.create("ngN3rFW1j8dn7ZGpATKl7mreaNmp2Ei_l9AIhkIf", + "6VXav9eqUCORJTYvTFOeTVRonAyk4Hrs-PIZ8jmZ"); + String DownloadUrl = auth.privateDownloadUrl(filepath); + + // Toast.makeText(webviewActivity.this, DownloadUrl, 1).show(); + try { + run(DownloadUrl); + + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + public void refresh_token(String refresh_token) { + + Map map = new HashMap(); + map.put("appid", Constants.APP_ID); + map.put("grant_type", "refresh_token"); + map.put("refresh_token", refresh_token); + + register.StringGETrequest(map, WX_Myurl.refresh_token, + new Volleyinterface1(this, Volleyinterface1.mlistener, + Volleyinterface1.mErrorLisener) { + + @Override + public void onsuccess(String result) { + try { + JSONObject object = new JSONObject(result); + + String access_token = object + .optString("access_token"); + + int errcode = object.optInt("errcode"); + Toast.makeText(webviewActivity.this, + "jeef errcode==" + errcode, Toast.LENGTH_LONG).show(); + if (errcode == 40030) { + login(); + + } else if (!pmutil.isnullorEmpty(access_token)) { + + if (!pmutil.isnullorEmpty(access_token)) { + SpUtil.setStringSharedPerference(Shared, + "access_token", access_token); + } + + int expires_in = object.optInt("expires_in"); + + String refresh_token = object + .optString("refresh_token"); + + if (!pmutil.isnullorEmpty(refresh_token)) { + SpUtil.setStringSharedPerference(Shared, + "refresh_token", refresh_token); + } + + String openid = object.optString("openid"); + + if (!pmutil.isnullorEmpty(openid)) { + SpUtil.setStringSharedPerference(Shared, + "openid", openid); + } + // Toast.makeText(MainActivity.this, result, 1) + // .show(); + aSd = 2; + isaccess_token(); + } + + } catch (Exception e) { + + e.printStackTrace(); + } + + } + + @Override + public void onerror(VolleyError arg0) { + + } + }); + } + + public void login() { + if (!api.isWXAppInstalled()) { + Toast.makeText(webviewActivity.this, "您还未安装微信客户端", Toast.LENGTH_SHORT).show(); + return; + } + + //api = WXAPIFactory.createWXAPI(webviewActivity.this, Constants.APP_ID, + // true); + api.registerApp(Constants.APP_ID); + SendAuth.Req req = new SendAuth.Req(); + req.scope = "snsapi_userinfo"; + req.state = "wechat_sdk_demo"; + api.sendReq(req); + + WXEntryActivity.setshareHandler(handler); + + } + + public void isaccess_token() { + + final String access_token = SpUtil.getStringSharedPerference(Shared, + "access_token"); + + final String refresh_token = SpUtil.getStringSharedPerference(Shared, + "refresh_token"); + + final String openid = SpUtil + .getStringSharedPerference(Shared, "openid"); + Map map = new HashMap(); + map.put("openid", openid); + map.put("access_token", access_token); + + register.StringGETrequest(map, WX_Myurl.isaccess_token, + new Volleyinterface1(this, Volleyinterface1.mlistener, + Volleyinterface1.mErrorLisener) { + @Override + public void onsuccess(String result) { + try { + JSONObject object = new JSONObject(result); + String errmsg = object.optString("errmsg"); + + // Toast.makeText(webviewActivity.this, + // "result=" + result, 1).show(); + if (errmsg.equals("ok")) { + + getUserInfo(access_token, openid); + } else { + // Toast.makeText(MainActivity.this, + // "access_token 失效重新获取", 1).show(); + refresh_token(refresh_token); + } + + } catch (Exception e) { + e.printStackTrace(); + } + + } + + @Override + public void onerror(VolleyError arg0) { + + } + }); + } + + public void getuser1(String accessToken, String openId) { + Map map = new HashMap(); + map.put("openid", openId); + map.put("access_token", accessToken); + register.StringGETrequest(map, WX_Myurl.getwxuserinfo, + new Volleyinterface1(this, Volleyinterface1.mlistener, + Volleyinterface1.mErrorLisener) { + @Override + public void onsuccess(String result) { + try { + JSONObject object = new JSONObject(result); + String url = object.optString("headimgurl"); + String unionid = object.optString("unionid"); + String openid = object.optString("openid"); + String nickname = object.optString("nickname"); + String sex = object.optString("sex"); + String city = object.optString("city"); + SpUtil.setStringSharedPerference(Shared, "unionid", + unionid); + SpUtil.setStringSharedPerference(Shared, + "headimgurl", url); + SpUtil.setStringSharedPerference(Shared, "openid", + openid); + SpUtil.setStringSharedPerference(Shared, + "nickname", nickname); + SpUtil.setStringSharedPerference(Shared, "sex", sex); + SpUtil.setStringSharedPerference(Shared, "city", + city); + handler.sendEmptyMessage(1); + + } catch (Exception e) { + + e.printStackTrace(); + } + + } + + @Override + public void onerror(VolleyError arg0) { + + } + }); + } + + private class GetPrepayIdTask extends + AsyncTask> { + + @Override + protected void onPreExecute() { + } + + @Override + protected void onPostExecute(Map result) { + + // Toast.makeText(MaiobdActivity.this, result.toString(), 1).show(); + if (result != null) { + sb.append("prepay_id\n" + result.get("prepay_id") + "\n\n"); + + resultunifiedorder = result; + wxpay(); + } + // String err=resultunifiedorder.get("err_code"); + // Toast.makeText(MaishopActivity.this, err, 1).show(); + } + + @Override + protected void onCancelled() { + super.onCancelled(); + } + + @Override + protected Map doInBackground(Void... params) { + + // String shopname=params[0]; + // String pice=params[1]; + // String ordernum=params[2]; + + String url = String + .format("https://api.mch.weixin.qq.com/pay/unifiedorder"); + String entity = genProductArgs(); + Log.e("orion", entity); + byte[] buf = Util.httpPost(url, entity); + + Map xml = null; + if (buf != null) { + String content = new String(buf); + Log.e("orion", content); + xml = decodeXml(content); + + } + + return xml; + } + } + + public Map decodeXml(String content) { + + try { + Map xml = new HashMap(); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(new StringReader(content)); + int event = parser.getEventType(); + while (event != XmlPullParser.END_DOCUMENT) { + + String nodeName = parser.getName(); + switch (event) { + case XmlPullParser.START_DOCUMENT: + + break; + case XmlPullParser.START_TAG: + + if ("xml".equals(nodeName) == false) { + // 实例化student对象 + xml.put(nodeName, parser.nextText()); + } + break; + case XmlPullParser.END_TAG: + break; + } + event = parser.next(); + } + + return xml; + } catch (Exception e) { + Log.e("orion", e.toString()); + } + return null; + + } + + /** + * 生成商户订单号 + */ + private String genNonceStr() { + Random random = new Random(); + return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)) + .getBytes()); + } + + private long genTimeStamp() { + return System.currentTimeMillis() / 1000; + } + + /** + * 生成商户订单号 + */ + private String genOutTradNo(String number) { + Random random = new Random(); + // number.getBytes() + // String.valueOf(random.nextInt(10000)).getBytes() + return MD5.getMessageDigest(number.getBytes()); + } + + @SuppressWarnings("deprecation") + private String genProductArgs() { + StringBuffer xml = new StringBuffer(); + try { + String nonceStr = genNonceStr(); + xml.append(""); + List packageParams = new LinkedList(); + packageParams + .add(new BasicNameValuePair("appid", Constants.APP_ID)); + packageParams.add(new BasicNameValuePair("body", "测试哦")); + // packageParams.add(new BasicNameValuePair("detail", "服务")); + packageParams + .add(new BasicNameValuePair("mch_id", Constants.MCH_ID)); + packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));// 随机字符串 + packageParams.add(new BasicNameValuePair("notify_url", + "http://ylyx.hxfzsw.cn/"));// 回调通知地址 + + String out_trade_no = System.currentTimeMillis() + "qqq"; + packageParams.add(new BasicNameValuePair("out_trade_no", + out_trade_no));// 商户订单号 + packageParams.add(new BasicNameValuePair("spbill_create_ip", + "127.0.0.1"));// 终端IP + packageParams.add(new BasicNameValuePair("total_fee", "1"));// 价格 + packageParams.add(new BasicNameValuePair("trade_type", "APP"));// 支付类型 + String sign = genPackageSign(packageParams); + packageParams.add(new BasicNameValuePair("sign", sign)); + String xmlstring = toXml(packageParams); + return xmlstring; + } catch (Exception e) { + //Log.e(TAG, "genProductArgs fail, ex = " + e.getMessage()); + return null; + } + } + + @SuppressWarnings("deprecation") + private void genPayReq() { + + req.appId = Constants.APP_ID;// 应用id + req.partnerId = Constants.MCH_ID;// 商户号 + req.prepayId = resultunifiedorder.get("prepay_id");// 预支付交易会话ID + req.packageValue = "Sign=WXPay";// 扩展字段 + req.nonceStr = genNonceStr();// 随机字符串 + req.timeStamp = String.valueOf(genTimeStamp());// 时间戳 + + List signParams = new LinkedList(); + signParams.add(new BasicNameValuePair("appid", req.appId)); + signParams.add(new BasicNameValuePair("noncestr", req.nonceStr)); + signParams.add(new BasicNameValuePair("package", req.packageValue)); + signParams.add(new BasicNameValuePair("partnerid", req.partnerId)); + signParams.add(new BasicNameValuePair("prepayid", req.prepayId)); + signParams.add(new BasicNameValuePair("timestamp", req.timeStamp)); + + req.sign = genAppSign(signParams);// 支付签名 + sb.append("sign\n" + req.sign + "\n\n"); + + Log.e("orion", signParams.toString()); + + } + + /** + * 生成下单签名 + */ + @SuppressWarnings("deprecation") + private String genPackageSign(List params) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < params.size(); i++) { + sb.append(params.get(i).getName()); + sb.append('='); + sb.append(params.get(i).getValue()); + sb.append('&'); + } + sb.append("key="); + sb.append(Constants.API_KEY); + String packageSign = MD5.getMessageDigest(sb.toString().getBytes()) + .toUpperCase(); + Log.e("orion", packageSign); + return packageSign; + } + + @SuppressLint("DefaultLocale") + @SuppressWarnings("deprecation") + private String genAppSign(List params) { + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < params.size(); i++) { + sb.append(params.get(i).getName()); + sb.append('='); + sb.append(params.get(i).getValue()); + sb.append('&'); + } + sb.append("key="); + sb.append(Constants.API_KEY); + + this.sb.append("sign str\n" + sb.toString() + "\n\n"); + String appSign = MD5.getMessageDigest(sb.toString().getBytes()) + .toUpperCase(); + Log.e("orion", appSign); + return appSign; + } + + @SuppressWarnings("deprecation") + private String toXml(List params) { + StringBuilder sb = new StringBuilder(); + sb.append(""); + for (int i = 0; i < params.size(); i++) { + sb.append("<" + params.get(i).getName() + ">"); + + sb.append(params.get(i).getValue()); + sb.append(""); + } + sb.append(""); + + Log.e("orion", sb.toString()); + try { + return new String(sb.toString().getBytes(), "ISO8859-1"); + } catch (Exception e) { + e.printStackTrace(); + } + return sb.toString(); + } + + private void sendPayReq() { + msgApi.registerApp(Constants.APP_ID); + msgApi.sendReq(req); + } + + /** + * 微信支付 + */ + private void wxpay() { + genPayReq(); + sendPayReq(); + } + + static Map map = new HashMap(); + Handler playwav = new Handler() { + public void handleMessage(Message msg) { + + + + Bundle bundel = msg.getData(); + String src = bundel.getString("src"); + String type = bundel.getString("type"); + String urlpath = SpUtil + .getStringSharedPerference(Shared, "urlpath"); + // type 0 播放一次 type 1 背景音乐(重复播放) -1 停止背景音乐 + String purl = urlpath + File.separator + Settingutil.initfile; + + String wavpath = purl + "/assets/wav/" + src; + + // if(wavpath.endsWith(".mp3")){ + // wavpath=wavpath.substring(0, wavpath.lastIndexOf("."))+".ogg"; + // } + + System.out.println("wavpath===" + wavpath); + + File file = new File(wavpath); + + // Toast.makeText(webviewActivity.this, + // "wavpath" + wavpath + "type" + type, 0).show(); + + if (file.exists() && file.isFile()) { + + int isloop = Integer.parseInt(type); + System.out.println("isloop="+isloop); + if (isloop > 0 || map.containsKey(src)) { + + if (!map.containsKey(src)) { + + mediaplayer1 me = new mediaplayer1(); + map.put(src, me); + + // new Thread() { + // public void run() { + + me.play(wavpath, isloop, new OnCompletionListener() { + + @Override + public void onCompletion(MediaPlayer mp) { + + System.out.println("播放完成"); + } + }); + + // }; + // }.start(); + + } else { + mediaplayer1 me1 = map.get(src); + + // new Thread() { + // public void run() { + + me1.play(wavpath, isloop, new OnCompletionListener() { + + @Override + public void onCompletion(MediaPlayer mp) { + System.out.println("播放完成"); + } + }); + + // }; + // }.start(); + + }// lifj732830 + + } else { + + // String path1 = getFileName1(wavpath); + // if(isloop==0){ + // //SoundPool.loadSound(webviewActivity.this, path1, + // wavpath); + // System.out.println("path1="+path1+"wavpath="+wavpath); + // SoundPool.playSound(webviewActivity.this, path1, + // wavpath); + // + // + // }else{ + // SoundPool.onPause(path1);//暂停 + // } + System.out.println("播放音效wavpath="+wavpath+"isloop="+isloop); + SoundPoolUtils.playSound(wavpath, isloop); + + } + + System.out.println(wavpath); + } + + } + + ; + }; + + public String getFileName1(String pathandname) { + int start = pathandname.lastIndexOf("/"); + int end = pathandname.lastIndexOf("."); + if (start != -1 && end != -1) { + return pathandname.substring(start + 1, end); + } else { + return null; + } + } + + Handler mpaybrow = new Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what) { + case 1: + String browserurl = msg.getData().getString("browserurl"); + final Intent intent = new Intent(); + intent.setAction("android.intent.action.VIEW"); + Uri content_url = Uri.parse(browserurl); + intent.setData(content_url); + + if (!BrowserUtil.isQQBrowserInstalled()) { + dialogexit.show(webviewActivity.this, "建议安装QQ浏览器进行购买", new onexitlistener() { + @Override + public void paylistener() { + + } + + @Override + public void cancellistener() { + intent.setClassName("com.android.browser", "com.android.browser.BrowserActivity"); + startActivity(intent); + } + }); + } else { + intent.setClassName("com.tencent.mtt", "com.tencent.mtt.MainActivity");//打开QQ浏览器 + + startActivity(intent); + } + + + break; + + } + } + }; + + + public void phoneInfo() { + phoneInfoBean phoneinfobean = new phoneInfoBean(); + phoneutil util = new phoneutil(this); + String AdresseMAC = util.getAdresseMAC();//mac 地址 + String ProvidersName = util.getProvidersName();//手机服务商信息 + String DeviceBrand = phoneutil.getDeviceBrand();//手机品牌 + String phoneIMEI = phoneutil.getIMEI(this);//手机IMEI 串号 + String phoneIMSI = phoneutil.getIMsI(this);//手机IMEI 串号 + String phoneModel = phoneutil.getSystemModel();//手机型号 + String phoneVersion = phoneutil.getSystemVersion();//手机系统版本号 + + phoneinfobean.setPhoneAdresseMAC(AdresseMAC); + phoneinfobean.setPhoneDeviceBrand(DeviceBrand); + phoneinfobean.setPhoneIMEI(phoneIMEI); + phoneinfobean.setPhoneIMSI(phoneIMSI); + phoneinfobean.setPhoneModel(phoneModel); + phoneinfobean.setPhoneProvidersName(ProvidersName); + phoneinfobean.setPhoneVersion(phoneVersion); + Gson gson = new Gson(); + String inf0 = gson.toJson(phoneinfobean); + System.out.println(inf0); +// String Level = "javascript:getphoneinfo(" + "'" +//// + inf0 + "'" + ");"; +//// System.out.println(Level); +//// webviewjh(Level); + x5webview.callHandler("getphoneinfo", inf0, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + + } + + TextView videotext; + DragViewGroup mDragViewvideo; + + LinearLayout mlinearvideo; + + ImageView mvideoimg; + ImageView mvoiceimg; + RelativeLayout containerFrame; + RelativeLayout mvideoimgGroup; + + public void initvideo() { + + videotext = (TextView) findViewById(R.id.videotext); + mDragViewvideo = (DragViewGroup) findViewById(R.id.DragViewvideo); + mlinearvideo = (LinearLayout) findViewById(R.id.linearvideo); + mvideoimg = (ImageView) findViewById(R.id.videoimg); + mvideoimgGroup = (RelativeLayout) findViewById(R.id.videoimgGroup); + + mvoiceimg = (ImageView) findViewById(R.id.voiceimg); + + containerFrame = (RelativeLayout) findViewById(R.id.Frame); + } + + + videoinfobean mvideoinfobean = null; + + Othervideoinfo mOthervideoinfo = null; + + String videouserinfo; + String othervideoinfo; + /** + * 频道权限 + */ + public String[] vidopermission = new String[]{ + Manifest.permission.RECORD_AUDIO, + Manifest.permission.CAMERA}; + + // 注释掉通讯录权限申请相关代码 + // public String[] AddressBookpermission = new String[]{ + // Manifest.permission.WRITE_CONTACTS}; + + + Handler h5handler = new Handler() { + public void handleMessage(Message msg) { + switch (msg.what) { + case 1: + videouserinfo = (String) msg.obj; + + + if (!hasPermission(vidopermission)) { + + PermissionGen.needPermission(webviewActivity.this, 111, + vidopermission); + } else { + + Gson gson1 = new Gson(); + + try { + mvideoinfobean = gson1.fromJson(videouserinfo, videoinfobean.class); + + if (!pmutil.isnullorEmpty(mvideoinfobean.getRoomid())) { + initAgoraEngineAndJoinChannel(); + } + + } catch (Exception e) { + // TODO: handle exception + } + + + } + + break; + case 0: + + othervideoinfo = (String) msg.obj; + Gson gson1 = new Gson(); + + try { + + mOthervideoinfo = gson1.fromJson(othervideoinfo, Othervideoinfo.class); + if (mOthervideoinfo != null && mOthervideoinfo.getPlayerid() != null) { + System.out.println("调用setupRemoteVideo()"); + setupRemoteVideo(Integer.parseInt(mOthervideoinfo.getPlayerid()), mOthervideoinfo); + + } + + } catch (Exception e) { + // TODO: handle exception + } + + break; + case 2: + + runOnUiThread(new Runnable() { + @Override + public void run() { + + exitRoom(); + } + }); + + break; + case 3: + + phoneInfo(); + + break; + case 4: + // 注释掉通讯录权限申请逻辑 + // if (!hasPermission(AddressBookpermission)) { + // PermissionGen.needPermission(webviewActivity.this, 23, + // AddressBookpermission); + // } else { + // getAddressBook(); + // } + + break; + default: + break; + } + + } + + }; + + // 注释掉通讯录权限申请成功和失败的回调方法 + // @PermissionSuccess(requestCode = 23) + // public void AddressBooklocation() { + // getAddressBook(); + // } + + // @PermissionFail(requestCode = 23) + // public void errorAddressBook() { + + // } + + // public void getAddressBook() { + // String listaddress = phoneutil.getPhoneContacts(this); + // x5webview.callHandler("getAddressbook", listaddress, new CallBackFunction() { + // @Override + // public void onCallBack(String data) { + + // } + // }); + // } + + public void initvideodata() { + if (videomap1 != null) { + videomap1 = null; + } + + mlinearvideo.removeAllViews(); + mvideoimg.setImageResource(R.mipmap.a2); + mvoiceimg.setImageResource(R.mipmap.a4); + mDragViewvideo.setVisibility(View.GONE); + } + + public void exitRoom() { + try { + + + } catch (Exception e) { + + } + + + if (mvideoinfobean != null) { + if (mRtcEngine != null) { + + + initvideodata(); + + // mRtcEngine.muteLocalVideoStream(true); + videotext.setText(videotext.getText() + "\n 控件数量=" + containerFrame.getChildCount()); + System.out.println("控件数量=" + containerFrame.getChildCount()); + + //Toast.makeText(webviewActivity.this,"控件数量="+containerFrame.getChildCount(),Toast.LENGTH_SHORT).show(); + if (containerFrame.getChildCount() > 3) { + int lenth = containerFrame.getChildCount() - 1; + + //Toast.makeText(webviewActivity.this,"lenth="+lenth,Toast.LENGTH_SHORT).show(); + + for (int index = lenth; index > 2; index--) { + + //Toast.makeText(webviewActivity.this,"index="+index,Toast.LENGTH_SHORT).show(); + System.out.println("index=" + index); + + + try { + LinearLayout lineat1 = (LinearLayout) containerFrame.getChildAt(index); + if (lineat1 == null) { + Toast.makeText(webviewActivity.this, "view为空", Toast.LENGTH_SHORT).show(); + } else { + + lineat1.removeAllViews(); + //lineat1.setVisibility(View.GONE); + containerFrame.removeView(lineat1); + } + + + } catch (Exception e) { + System.out.println("出现异常===" + e.toString()); + Toast.makeText(webviewActivity.this, "出现异常", Toast.LENGTH_SHORT).show(); + } + + } + + } + mRtcEngine.leaveChannel(); + + + } + + + } + } + + private void initAgoraEngineAndJoinChannel() { + + + runOnUiThread(new Runnable() { + @Override + public void run() { + if (videomap1 != null && videomap1.size() > 0) { + videomap1.clear(); + + } else { + videomap1 = new HashMap(); + } + + mymDragVideoinfoBean = new DragVideoinfoBean(); + + initializeAgoraEngine(); // Tutorial Step 1 + setupVideoProfile(); // Tutorial Step 2 + setupLocalVideo(); // Tutorial Step 3 + joinChannel(); // Tutorial Step 4 + } + }); + + + } + + + int myuid; + + + private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() { // Tutorial Step 1 + @Override + public void onFirstRemoteVideoDecoded(final int uid, int width, int height, int elapsed) { // Tutorial Step 5 +// runOnUiThread(new Runnable() { +// @Override +// public void run() { +// System.out.println("远端视频接收解码回调otheruid=="+uid); +// +// videotext.setText(videotext.getText()+"\n uid="+uid); +// +// // setupRemoteVideo(uid); +// +// String Level = "javascript:getVideoinfo(" + "'" +// + uid + "'"+ ");"; +// +// webviewjh(Level); +// +// } +// }); + } + + //onFirstRemoteVideoFrame + // 远端视频显示回调 + @Override + public void onFirstRemoteVideoFrame(int uid, int width, int height, int elapsed) { + super.onFirstRemoteVideoFrame(uid, width, height, elapsed); + System.out.println("远端视频显示回调==" + uid); + } + //本地视频显示回调 + + @Override + public void onFirstLocalVideoFrame(int width, int height, int elapsed) { + super.onFirstLocalVideoFrame(width, height, elapsed); + } + + @Override + public void onUserOffline(final int uid, int reason) { // Tutorial Step 7 + runOnUiThread(new Runnable() { + @Override + public void run() { + + System.out.println("其他用户离开频道回调" + uid); + onRemoteUserLeft(uid); + } + }); + } + + @Override + public void onUserMuteVideo(final int uid, final boolean muted) { // Tutorial Step 10 + System.out.println("其他用户已停发已重发视频流uid==" + uid + "---" + muted); + + runOnUiThread(new Runnable() { + @Override + public void run() { + if (!muted) { + //videotext.setVisibility(View.VISIBLE); + } else { + //videotext.setVisibility(View.GONE); + } + onRemoteUserVideoMuted(uid, muted); + } + }); + } + + @Override + public void onUserEnableVideo(int uid, boolean enabled) { + super.onUserEnableVideo(uid, enabled); + //提示有其他用户启用/关闭了视频功能。 + // 关闭视频功能是指该用户只能进行语音通话,不能显示、发送自己的视频,也不能接收、显示别人的视频。 + + } + + @Override + public void onJoinChannelSuccess(String channel, int uid, int elapsed) { + webviewActivity.this.myuid = uid; + + System.out.println("加入频道回调myuid=" + webviewActivity.this.myuid); + + super.onJoinChannelSuccess(channel, uid, elapsed); + } + + @Override + public void onRejoinChannelSuccess(String channel, int uid, int elapsed) { + System.out.println("网络状况下重新加入频道回调myuid=" + webviewActivity.this.myuid); + + } + + @Override + public void onUserJoined(final int uid, int elapsed) { + System.out.println("其他用户加入频道回调" + uid); + runOnUiThread(new Runnable() { + @Override + public void run() { + + + videotext.setText(videotext.getText() + "\n uid=" + uid); + + // setupRemoteVideo(uid); + x5webview.callHandler("getVideoinfo", "" + uid, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + +// String Level = "javascript:getVideoinfo(" + "'" +// + uid + "'" + ");"; +// +// webviewjh(Level); + + } + }); + super.onUserJoined(uid, elapsed); + } + + @Override + public void onLeaveChannel(RtcStats stats) { + + System.out.println("用户离开频道回调"); + } + }; + + private void onRemoteUserLeft(int uid) { + if (mRtcEngine != null) { + if (videomap1 != null) { + try { + int uindex = videomap1.get(uid); + LinearLayout view = (LinearLayout) containerFrame.getChildAt(uindex); + System.out.println("containerFrame控件数量" + containerFrame.getChildCount()); + System.out.println("view" + view.getChildCount()); + view.removeAllViews(); + + // SurfaceView surfaceView= (SurfaceView) view.getChildAt(0); + + // view.indexOfChild(child) 获取当前view再父容器下标 + + if (view != null && view.getChildCount() > 0) { + System.out.println("getChildCount()" + view.getChildCount()); + view.setVisibility(View.GONE); + } + if (view != null) { + containerFrame.removeView(view); + } + + if (mDragViewvideo.getVisibility() == View.VISIBLE) { + int did = (int) mDragViewvideo.getTag(); + if (did == uid) { + if (mlinearvideo.getChildCount() > 0) { + mlinearvideo.removeAllViews(); + } + mDragViewvideo.setVisibility(View.GONE); + } + } + + } catch (Exception e) { + + } + + + //RelativeGroup.removeViewAt(uindex); + } + } + + } + + + private void onRemoteUserVideoMuted(int uid, boolean muted) { + if (mRtcEngine != null) { + if (videomap1 != null) { + if (videomap1.containsKey(uid)) { + int uindex = videomap1.get(uid); + LinearLayout view = (LinearLayout) containerFrame.getChildAt(uindex); + + + // view.indexOfChild(child) 获取当前view再父容器下标 + + if (view != null && view.getChildCount() > 0) { + //mDragViewvideo没有显示 + SurfaceView surfaceView = (SurfaceView) view.getChildAt(0); + + if (!muted) { + surfaceView.setVisibility(View.VISIBLE); + } else { + + surfaceView.setVisibility(View.GONE); + } + } + if (view != null) {//mDragViewvideo显示 + + if (mDragViewvideo.getVisibility() == View.VISIBLE) { + + + int did = (int) mDragViewvideo.getTag(); + if (did == uid) { + if (mlinearvideo.getChildCount() > 0) { + SurfaceView surfaceView = (SurfaceView) mlinearvideo.getChildAt(0); + + if (!muted) { + surfaceView.setVisibility(View.VISIBLE); + } else { + surfaceView.setVisibility(View.GONE); + } + } + +// operatevideo1(uid); + +// if(mlinearvideo.getChildCount()>0){ +// mlinearvideo.removeAllViews(); +// } +// +// // mDragViewvideo.setVisibility(View.GONE); + } + } + + } + + } + //RelativeGroup.removeViewAt(uindex); + } + } + + + } + + Map videomap1;//uid index父控件下标 + + //Map videomap;//uid index父控件下标 + + // Tutorial Step 5 + private void setupRemoteVideo(int uid, Othervideoinfo mOthervideoinfo) { + if (videomap1 != null) { + System.out.println("videomap1不为空"); +// if(!videomap1.containsKey(uid)){ + if (videomap1.containsKey(uid)) { + System.out.println("videomap1含有uid=" + uid); + } else { + System.out.println("videomap1不含有uid=" + uid); + } + initotherviiodeo(uid, mOthervideoinfo); + + } else { + System.out.println("videomap1为空"); + } + + + } + + private boolean mDragViewvideoIsshow = false; + + private void initotherviiodeo(int uid, Othervideoinfo mOthervideoinfo) { + System.out.println("containerFram子控件数量" + containerFrame.getChildCount()); + + LinearLayout autoviewGroup = new LinearLayout(this); + int w = Stringtoint(mOthervideoinfo.getWidth()); + int h = Stringtoint(mOthervideoinfo.getHeight()); + w = getsizeh(w); + h = getsizeh(h); + RelativeLayout.LayoutParams lay = new RelativeLayout.LayoutParams(w, h); + + int left = Stringtoint(mOthervideoinfo.getLeft()); + int top = Stringtoint(mOthervideoinfo.getTop()); + left = getsizew(left); + top = getsizeh(top); + + System.out.println("---w=" + w + "h=" + h + "left=" + left + "top=" + top); + + lay.leftMargin = left; + + lay.topMargin = top; + autoviewGroup.setLayoutParams(lay); + + SurfaceView surfaceView = RtcEngine.CreateRendererView(getBaseContext()); + + surfaceView.setZOrderMediaOverlay(true); + LinearLayout.LayoutParams itempicparams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1); + + surfaceView.setLayoutParams(itempicparams); + + mRtcEngine.setupRemoteVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_HIDDEN, uid)); + + surfaceView.setTag(uid); + autoviewGroup.setTag(uid); + + //surfaceView.setClickable(false); + //autoviewGroup.setClickable(true); + autoviewGroup.addView(surfaceView); + surfaceView.setClickable(false); + autoviewGroup.setClickable(true); + + autoviewGroup.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + + // Toast.makeText(webviewActivity.this, containerFrame.getChildCount()+"点击", Toast.LENGTH_LONG).show(); + try { + int uid1 = (int) v.getTag(); + if (mDragViewvideoIsshow) { + updatevideo(uid1); + } + + } catch (Exception e) { + + } + + } + }); + +// //autoviewGroup.setBackgroundColor(Color.parseColor("#F5F5DC")); + + containerFrame.addView(autoviewGroup); + + int uindex = containerFrame.getChildCount() - 1; + + videomap1.put(uid, uindex); + // videomap.put(String.valueOf(uid),String.valueOf(uindex)); +// }else{ +// System.out.println("videomap1含有uid="+uid); +// } + } + + + private RtcEngine mRtcEngine;// Tutorial Step 1 + + // Tutorial Step 1 + private void initializeAgoraEngine() { + try { + + if (mRtcEngine == null) { + mRtcEngine = RtcEngine.create(getBaseContext(), getString(R.string.agora_app_id), mRtcEventHandler); + } + + } catch (Exception e) { + Log.e("", Log.getStackTraceString(e)); + + throw new RuntimeException("NEED TO check rtc sdk init fatal error\n" + Log.getStackTraceString(e)); + } + } + + // Tutorial Step 2 + private void setupVideoProfile() { + mRtcEngine.enableVideo(); + mRtcEngine.setVideoProfile(io.agora.rtc.Constants.VIDEO_PROFILE_360P, false); + } + + public static int getScreenWidth(Activity activity) { + return activity.getWindowManager().getDefaultDisplay().getWidth(); + } + + public static int getScreenHeight(Activity activity) { + return activity.getWindowManager().getDefaultDisplay().getHeight(); + } + + int pmw = 0; + int pmh = 0; + + public void getAndroiodScreenProperty() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + DisplayMetrics dm1 = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getRealMetrics(dm1); + + pmw = dm1.widthPixels; // 屏幕宽 + pmh = dm1.heightPixels; // 屏幕高 + + } else { + + Display display = getWindowManager().getDefaultDisplay(); + DisplayMetrics dm = new DisplayMetrics(); + @SuppressWarnings("rawtypes") + Class c; + try { + c = Class.forName("android.view.Display"); + @SuppressWarnings("unchecked") + Method method = c.getMethod("getRealMetrics", DisplayMetrics.class); + method.invoke(display, dm); + pmh = dm.heightPixels; + pmw = dm.widthPixels; + } catch (Exception e) { + e.printStackTrace(); + } + + } + + +//不含虚拟状态栏宽高 +// WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE); +// DisplayMetrics dm = new DisplayMetrics(); +// wm.getDefaultDisplay().getMetrics(dm); +// int width = dm.widthPixels; // 屏幕宽度(像素) +// +// int height = dm.heightPixels; // 屏幕高度(像素) +// +// float density = dm.density; // 屏幕密度(0.75 / 1.0 / 1.5) +// int densityDpi = dm.densityDpi; // 屏幕密度dpi(120 / 160 / 240) +// // 屏幕宽度算法:屏幕宽度(像素)/屏幕密度 +// int screenWidth = (int) (width / density); // 屏幕宽度(dp) +// int screenHeight = (int) (height / density);// 屏幕高度(dp) +// +// +// pmh=height; +// pmw=width; +// System.out.println("屏幕宽度(像素):" + width); +// System.out.println("屏幕高度(像素):" + height); +// System.out.println("屏幕密度(0.75 / 1.0 / 1.5):" + density); +// System.out.println("屏幕密度dpi(120 / 160 / 240):" + densityDpi); +// System.out.println("屏幕宽度(dp):" + screenWidth); +// System.out.println("屏幕高度(dp):" + screenHeight); +// +// Log.d("h_bl", "屏幕宽度(像素):" + width); +// Log.d("h_bl", "屏幕高度(像素):" + height); +// Log.d("h_bl", "屏幕密度(0.75 / 1.0 / 1.5):" + density); +// Log.d("h_bl", "屏幕密度dpi(120 / 160 / 240):" + densityDpi); +// Log.d("h_bl", "屏幕宽度(dp):" + screenWidth); +// Log.d("h_bl", "屏幕高度(dp):" + screenHeight); + } + + + /** + * @param length 长度 + * @return 返回根据比例缩放长度 + */ + public int getsizeh(int length) { + double scale = (double) pmh / 720; + System.out.println("scale==" + scale); + double size = scale * length; + System.out.println("size==" + size); + return (int) size; + } + + /** + * @param length 长度 + * @return 返回根据比例缩放长度 + */ + public int getsizew(int length) { + double scale = (double) pmw / 1280; + System.out.println("scale==" + scale); + double size = scale * length; + System.out.println("size==" + size); + return (int) size; + } + + + // Tutorial Step 3 + private void setupLocalVideo() { + + System.out.println("w=" + getScreenWidth(this) + "h=" + getScreenHeight(this)); + + System.out.println(mvideoinfobean.toString()); + + + LinearLayout autoviewGroup = new LinearLayout(this); + int w = Stringtoint(mvideoinfobean.getWidth()); + int h = Stringtoint(mvideoinfobean.getHeight()); + w = getsizeh(w); + h = getsizeh(h); + + RelativeLayout.LayoutParams lay = new RelativeLayout.LayoutParams(w, h); + int left = Stringtoint(mvideoinfobean.getLeft()); + int top = Stringtoint(mvideoinfobean.getTop()); + System.out.println("---w=" + w + "h=" + h + "left=" + left + "top=" + top); + + left = getsizew(left); + top = getsizeh(top); + lay.leftMargin = left; + lay.topMargin = top; + System.out.println("---w=" + w + "h=" + h + "left=" + left + "top=" + top); + + autoviewGroup.setLayoutParams(lay); + + SurfaceView surfaceView = RtcEngine.CreateRendererView(getBaseContext()); + surfaceView.setZOrderMediaOverlay(true); + LinearLayout.LayoutParams itempicparams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1); + + surfaceView.setLayoutParams(itempicparams); + + int uid = Integer.parseInt(mvideoinfobean.getPlayerid()); + + + autoviewGroup.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + + // Toast.makeText(webviewActivity.this, containerFrame.getChildCount()+"点击", Toast.LENGTH_LONG).show(); + try { + int uid1 = (int) v.getTag(); + + if (mDragViewvideoIsshow) { + updatevideo(uid1); + } + } catch (Exception e) { + + } + + } + }); + autoviewGroup.setTag(uid); + surfaceView.setTag(uid); +/** + * 当前用户视频移动悬浮框数据初始化 + */ + mymDragVideoinfoBean.setUid(uid); + mymDragVideoinfoBean.setVideoimg(true); + mymDragVideoinfoBean.setVoiceimg(true); + + autoviewGroup.addView(surfaceView); + containerFrame.addView(autoviewGroup); + System.out.println("显示本地视频"); + int uindex1 = containerFrame.getChildCount() - 1; + videomap1.put(uid, uindex1); + surfaceView.setClickable(false); + autoviewGroup.setClickable(true); + //autoviewGroup.setFocusable(true); + mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_HIDDEN, uid)); + } + + + public void updatevideo(int uid) { + if (mDragViewvideo.getTag() == null) { + mDragViewvideo.setTag(uid); + mvideoimg.setTag(uid); + mvoiceimg.setTag(uid); + + } else { + int vuid = (int) mDragViewvideo.getTag(); + mDragViewvideo.setTag(uid); + + mvideoimg.setTag(uid); + mvoiceimg.setTag(uid); + + if (vuid == uid) { + //mDragViewvideo显示和用户视频信息一致 + if (mDragViewvideo.getVisibility() == View.GONE) { + mDragViewvideo.setVisibility(View.VISIBLE); + + System.out.println("key444444" + videomap1.get(vuid)); + operatevideo(vuid); + } else { + mDragViewvideo.setVisibility(View.GONE); + operatevideo1(vuid); + } + + } else { + //mDragViewvideo显示和用户视频信息不一致 + if (mDragViewvideo.getVisibility() == View.GONE) { + //mDragViewvideo必须隐藏之后再显示其他用户视频信息 + mDragViewvideo.setVisibility(View.VISIBLE); + operatevideo(uid); + } else { + //mDragViewvideo + operatevideo1(vuid); + operatevideo(uid); + } + } + } + + } + + DragVideoinfoBean mymDragVideoinfoBean; + + + public void videoimgClicked(View view) { + if (view.getTag() != null) { + int uid = (int) view.getTag(); + if (mymDragVideoinfoBean.getUid() == uid) { + ImageView imageview = (ImageView) view; + int isok = -1; + SurfaceView surfaceView = (SurfaceView) mlinearvideo.getChildAt(0); + + if (mymDragVideoinfoBean.isVideoimg()) { + + isok = mRtcEngine.muteLocalVideoStream(true);//暂停本地视频 + + if (isok == 0) { + imageview.setImageResource(R.mipmap.a1); + if (surfaceView != null) { + surfaceView.setVisibility(View.INVISIBLE); + } + + mymDragVideoinfoBean.setVideoimg(false); + } + + + } else { + isok = mRtcEngine.muteLocalVideoStream(false);//开始本地视频 + if (isok == 0) { + if (surfaceView != null) { + surfaceView.setVisibility(View.VISIBLE); + } + + imageview.setImageResource(R.mipmap.a2); + mymDragVideoinfoBean.setVideoimg(true); + } + + + } + + + } + + } + + + } + + public void voiceimgClicked(View view) { + if (view.getTag() != null) { + int uid = (int) view.getTag(); + if (mymDragVideoinfoBean.getUid() == uid) { + ImageView imageview = (ImageView) view; + + if (mymDragVideoinfoBean.isVoiceimg()) { + int isok = -1; + isok = mRtcEngine.muteLocalAudioStream(true);//暂停本地音频 + + if (isok == 0) { + imageview.setImageResource(R.mipmap.a3); + + mymDragVideoinfoBean.setVoiceimg(false); + } + + + } else { + int isok = -1; + isok = mRtcEngine.muteLocalAudioStream(false);//开始本地音频 + if (isok == 0) { + imageview.setImageResource(R.mipmap.a4); + mymDragVideoinfoBean.setVoiceimg(true); + } + + } + + + } + + } + + } + + @PermissionSuccess(requestCode = 111) + public void videosuccess() { + Gson gson1 = new Gson(); + + + try { + mvideoinfobean = gson1.fromJson(videouserinfo, videoinfobean.class); + + if (!pmutil.isnullorEmpty(mvideoinfobean.getRoomid())) { + initAgoraEngineAndJoinChannel(); + } + + } catch (Exception e) { + // TODO: handle exception + } + } + + @PermissionFail(requestCode = 111) + public void videofail() { + List nopermission = new ArrayList(); + for (int i = 0; i < vidopermission.length; i++) { + if (ActivityCompat.shouldShowRequestPermissionRationale( + webviewActivity.this, vidopermission[i])) { + // 未勾选不再提示 + System.out.println("拒绝"); + nopermission.add(vidopermission[i]); + + + } else { + // 勾选不再提示 + if (ContextCompat.checkSelfPermission(this, vidopermission[i]) == PackageManager.PERMISSION_DENIED) { + showMissingPermissionDialog(); + break; + } + } + } + + + if (nopermission.size() > 0) { + + final String[] persions = new String[nopermission.size()]; + + for (int i = 0; i < nopermission.size(); i++) { + persions[i] = nopermission.get(i); + } + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("提示"); + builder.setMessage("亲,当前应用缺少必要权限。不打开将无法使用功能"); + + // 拒绝, 退出应用 + builder.setNegativeButton("退出", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + + } + }); + + builder.setPositiveButton("打开", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + PermissionGen.needPermission(webviewActivity.this, + 111, persions); + } + }); + builder.show(); + } + + } + + + public void operatevideo(int uid) { + + + initDragvideo(uid); + + if (videomap1 != null) { + System.out.println("key1111111111" + videomap1.get(uid)); + int uindex = videomap1.get(uid); + + + LinearLayout autoviewGroup = (LinearLayout) containerFrame.getChildAt(uindex); + + SurfaceView surfaceView = (SurfaceView) autoviewGroup.getChildAt(0); + autoviewGroup.removeAllViews(); + + if (mlinearvideo.getChildCount() > 0) { + mlinearvideo.removeAllViews(); + } + if (mymDragVideoinfoBean.getUid() == uid) { + mvideoimgGroup.setVisibility(View.VISIBLE); + } else { + mvideoimgGroup.setVisibility(View.GONE); + } + surfaceView.setClickable(false); + mlinearvideo.addView(surfaceView); + } + } + + /** + * @param uid 初始化视频悬浮按钮 + */ + public void initDragvideo(int uid) { + if (mymDragVideoinfoBean.getUid() == uid) { + if (mymDragVideoinfoBean.isVideoimg()) { + mvideoimg.setImageResource(R.mipmap.a2); + + } else { + mvideoimg.setImageResource(R.mipmap.a1); + } + + if (mymDragVideoinfoBean.isVoiceimg()) { + mvoiceimg.setImageResource(R.mipmap.a4); + } else { + mvoiceimg.setImageResource(R.mipmap.a3); + } + + } + + } + + public void operatevideo1(int uid) { + if (videomap1 != null) { + + if (mlinearvideo.getChildCount() > 0) { + + SurfaceView surfaceView = (SurfaceView) mlinearvideo.getChildAt(0); + mlinearvideo.removeAllViews(); + int uindex = videomap1.get(uid); + LinearLayout autoviewGroup = (LinearLayout) containerFrame.getChildAt(uindex); + + + if (autoviewGroup.getChildCount() > 0) { + autoviewGroup.removeAllViews(); + } + + if (mymDragVideoinfoBean.getUid() == uid) { + if (!mymDragVideoinfoBean.isVideoimg()) { + surfaceView.setVisibility(View.GONE); + } else { + surfaceView.setVisibility(View.VISIBLE); + } + + } + autoviewGroup.addView(surfaceView); + + } + } + } + + // Tutorial Step 4 + private void joinChannel() { + + String str = mvideoinfobean.getAgentid() + mvideoinfobean.getGameid() + mvideoinfobean.getRoomid(); + //String Channel=str.substring(str.length()-64); + String Channel = MD5(str); + + + int uid = Integer.parseInt(mvideoinfobean.getPlayerid()); + + mRtcEngine.joinChannel(null, Channel, "Extra Optional Data", uid); // if you do not specify the uid, we will generate the uid for you + } + + + private String MD5(String sourceStr) { + String result = ""; + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + md.update(sourceStr.getBytes()); + byte b[] = md.digest(); + int i; + StringBuffer buf = new StringBuffer(""); + for (int offset = 0; offset < b.length; offset++) { + i = b[offset]; + if (i < 0) + i += 256; + if (i < 16) + buf.append("0"); + buf.append(Integer.toHexString(i)); + } + result = buf.toString(); + System.out.println("MD5(" + sourceStr + ",32) = " + result); + + System.out.println("MD5(" + sourceStr + ",16) = " + buf.toString().substring(8, 24)); + } catch (NoSuchAlgorithmException e) { + System.out.println(e); + } + + return result; + } + + public int Stringtoint(String d) { + int a = (int) Double.parseDouble(d); + + return a; + + } + + @PermissionSuccess(requestCode = 19) + public void succeslocation() { + initlocation(); + } + + GamePayBean paybean; + String paydata; + + public void startpay(String data2) { + paydata = data2; + + Gson gson = new Gson(); + + System.out.println(data2); + + try { + + JSONObject json = new JSONObject(data2); + + String price = (String) json.get("price"); + System.out.println(price); + String body = json.getString("body"); + System.out.println(body); + int typeplay = json.getInt("typeplay"); + System.out.println(typeplay); + String type = json.getString("type"); + System.out.println(type); + int user = json.getInt("user"); + System.out.println(user); + paybean = new GamePayBean(); + paybean.setBody(body); + paybean.setPrice(price); + paybean.setType(type); + paybean.setTypeplay(typeplay + ""); + paybean.setUser(user + ""); + + WXPayEntryActivity pay = new WXPayEntryActivity(); + + pay.setHandler(payhandler); + Settingutil.iswxpay = true; + + GetPrepayIdTask getPrepayId = new GetPrepayIdTask(); + + getPrepayId.execute(); + + } catch (JSONException e) { + + e.printStackTrace(); + } + + } + + protected void pay(int type) { + JSONObject obj=new JSONObject(); + + try { + obj.put("user",paybean.getUser());//用户id + obj.put("state",type);//支付状态 + obj.put("typeplay",paybean.getTypeplay());//支付方式 + obj.put("type",paybean.getType());//支付游戏 + obj.put("data",paydata);//请求支付数据 + + x5webview.callHandler("PayuserPaytypePaystate", obj.toString(), new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + public String data = null; + + public void initgame(String webtype, String gamedirectory, + String gamedownloadurl, String data) { + //int orientation = 3; 横屏 + // int orientation = 2; 竖屏 + Settingutil.initgame = gamedirectory; + + Intent in = new Intent(); + in.putExtra("orientation", webtype); + in.putExtra("data", data); + in.putExtra("gamedirectory", gamedirectory); + in.putExtra("gamedownloadurl", gamedownloadurl); + in.setClass(webviewActivity.this, NewwebviewActivity.class); + startActivityForResult(in, 100); + + this.data = data; + + } + + // versionbean version1; + + // // 配置缺失提示 + // private void showMissingsettingDialog() { + // + // AlertDialog.Builder builder = new AlertDialog.Builder(this); + // builder.setTitle("提示"); + // builder.setMessage("您好,获取配置信息失败,请重新启动应用"); + // + // builder.setPositiveButton("退出", new DialogInterface.OnClickListener() { + // @Override + // public void onClick(DialogInterface dialog, int which) { + // finish(); + // } + // }); + // + // AlertDialog menuDialog= builder.create(); + // //menuDialog.setCanceledOnTouchOutside(false); + // menuDialog.setCancelable(false); + // menuDialog.show(); + // } + + // private versionbean pullxml1(String urlpath) { + // + // try { + // File file = new File(urlpath + File.separator + "version.xml"); + // + // if (file.exists()) { + // FileInputStream inputStream = new FileInputStream(file); + // // 得到解析器 + // XmlPullParser parser = Xml.newPullParser(); + // // 2.设置解析的文件流 + // parser.setInput(inputStream, "utf-8"); + // // 3.得到事件类型(START_DOCUMENT,END_DOCUMENT,START_TAG, END_TAG, + // // TEXT, etc.) + // int type = parser.getEventType(); + // // 一直读到文档结尾 + // version1 = new versionbean(); + // + // while (type != XmlPullParser.END_DOCUMENT) { + // + // switch (type) { + // case XmlPullParser.START_TAG: + // // 得到标签的名字 + // String tag_name = parser.getName(); + // if ("agent".equals(tag_name)) { + // + // String agentid = parser.getAttributeValue(null, + // "id"); + // System.out.println("agentid=" + agentid); + // version1.setAgentid(agentid); + // // String id = parser.getAttributeValue(0); + // // 得到属性值id + // } else if ("game".equals(tag_name)) { + // String gameid = parser + // .getAttributeValue(null, "id"); + // System.out.println("gameid=" + gameid); + // version1.setGameid(gameid); + // } else if ("version".equals(tag_name)) { + // + // String version = parser.getAttributeValue(null, + // "value"); + // System.out.println("version=" + version); + // version1.setVersion(version); + // + // } else if ("channel".equals(tag_name)) { + // + // String channelid = parser.getAttributeValue(null, + // "id"); + // version1.setChannelid(channelid); + // } + // + // break; + // default: + // break; + // + // } + // // 继续往下一个事件解析 + // type = parser.next(); + // } + // } + // } catch (IOException e) { + // e.printStackTrace(); + // } catch (XmlPullParserException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + // return version1; + // + // } + + // /** + // * 跳转 + // * + // * @param urlpath + // */ + // protected void handlerend1(String urlpath) { + // + // Intent in = new Intent(); + // String url = urlpath + File.separator + "index.html?Launchtype=1"; + // + // in.putExtra("urlpath", url); + // in.putExtra("data", data); + // + // in.setClass(webviewActivity.this, NewwebviewActivity.class); + // startActivityForResult(in, 100); + // + // } + + // protected void updatezip(String gamezip) { + // + // } + + // versionagentlist list1; + + private boolean isgamedirectory(String gamedirectory) { + + boolean isdirectory = false; + + /** + * 获得解压目录 + */ + String url = SpUtil.getStringSharedPerference(Shared, "urlpath"); + File rile = new File(url); + + if (rile.exists()) { + + String[] path = rile.list(); + + for (int i = 0; i < path.length; i++) { + System.out.println(path[i]); + if (gamedirectory.equals(path[i])) { + isdirectory = true; + break; + } + } + + } + + return isdirectory; + + } + + @PermissionFail(requestCode = 19) + public void errorlocation() { + List nopermission = new ArrayList(); + // String[] nopermission=null; + + for (int i = 0; i < locationpermission.length; i++) { + if (ActivityCompat.shouldShowRequestPermissionRationale(this, + locationpermission[i])) { + + nopermission.add(locationpermission[i]); + + // final String permission = carpermission[i]; + // 未勾选不再提示 + + System.out.println("拒绝"); + } else { + // 勾选不再提示 + if (ContextCompat.checkSelfPermission(this, + locationpermission[i]) == PackageManager.PERMISSION_DENIED) { + // showMissingPermissionDialog(); + + break; + } + } + } + + // if (nopermission.size() > 0) { + // + // final String[] persions = new String[nopermission.size()]; + // + // for (int i = 0; i < nopermission.size(); i++) { + // persions[i] = nopermission.get(i); + // } + // + // AlertDialog.Builder builder = new AlertDialog.Builder(this); + // builder.setTitle("提示"); + // builder.setMessage("亲,当前应用缺少必要权限。不打开将无法使用"); + // + // // 拒绝, 退出应用 + // builder.setNegativeButton("退出", + // new DialogInterface.OnClickListener() { + // @Override + // public void onClick(DialogInterface dialog, int which) { + // finish(); + // + // } + // }); + // + // builder.setPositiveButton("打开", + // new DialogInterface.OnClickListener() { + // @Override + // public void onClick(DialogInterface dialog, int which) { + // + // PermissionGen.needPermission(webviewActivity.this, + // 19, persions); + // } + // }); + // builder.show(); + // } + + } + + public void playautio(String audiourl, String user) { + Message msg = new Message(); + Bundle bundel = new Bundle(); + bundel.putString("audiourl", audiourl); + bundel.putString("user", user); + msg.setData(bundel); + playhandler.sendMessageDelayed(msg, 100); + + } + + public void initlocation() { + + // TODO Auto-generated method stub + // 初始化定位 + mLocationClient = new AMapLocationClient(getApplicationContext()); + + // 设置定位模式 + mLocationOption.setLocationMode(AMapLocationMode.Hight_Accuracy); + + if (!iscontinuouslocation) { + // 设置定位次数(在这里采用单次定位,true 单次定位false 连续定位) + mLocationOption.setOnceLocation(true); + // 设置为true,那么会返回最近3秒内定位精度最高的一次 + mLocationOption.setOnceLocationLatest(true); + } else { + mLocationOption.setOnceLocation(false); + mLocationOption.setInterval(3000); // 设置连续定位时间间隔 + } + + // 设置是否返回地理信息 + mLocationOption.setNeedAddress(true); + mLocationClient.setLocationOption(mLocationOption); + // 设置定位监听 + mLocationClient.setLocationListener(this); + mLocationClient.startLocation(); + } + + public void open() { + + startActivityForResult(new Intent(this, CaptureActivity.class), 100); + + } + + @PermissionSuccess(requestCode = 18) + public void succes() { + open(); + } + + @PermissionFail(requestCode = 18) + public void error() { + + if (ActivityCompat.shouldShowRequestPermissionRationale(this, + Manifest.permission.CAMERA)) { + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("提示"); + builder.setMessage("亲,扫一扫需要打开相机权限哦"); + + // 拒绝, 退出应用 + builder.setNegativeButton("不打开", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + } + }); + + builder.setPositiveButton("打开", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + PermissionGen.needPermission(webviewActivity.this, + 18, camerapermission); + } + }); + builder.show(); + + System.out.println("拒绝"); + } else { + // 勾选不再提示 + if (ContextCompat.checkSelfPermission(this, + Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED) { + showMissingPermissionDialog(); + } + } + + } + + public void saveBase64(String iconBase64) { + File file; + String bitmappath; + + if (Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED)) { + // sd卡存储(/mnt/sdcard/cache) + file = Environment.getExternalStorageDirectory();// 获取跟目录 + } else { + // 没有SD卡,缓存到系统存储 + file = Environment.getDataDirectory(); + } + file = Util.GetDirectory(); + bitmappath = file.getAbsolutePath() + File.separator + "photo.png"; + + // Bitmap sd=BitmapFactory.decodeResource(getResources(), + // R.drawable.ddd); + // Bitmap bit1=stringtoBitmap(bitmaptoString(sd)); + + Bitmap bit1 = stringtoBitmap(iconBase64); + + getScreenHot(bit1, bitmappath); + + } + + private void getScreenHot(Bitmap b1, String filePath) { + System.out.println(filePath); + if (b1 == null) { + System.out.println("-----"); + } + File file1 = new File(filePath); + try { + file1.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + + try { + try { + + FileOutputStream fos = new FileOutputStream(file1); + b1.compress(CompressFormat.PNG, 100, fos); + fos.flush(); + fos.close(); + } catch (FileNotFoundException e) { + throw new InvalidParameterException(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public Bitmap stringtoBitmap(String string) { + // 将字符串转换成Bitmap类型 + Bitmap bitmap = null; + try { + byte[] bitmapArray; + System.out.println(string); + bitmapArray = Base64.decode(string, Base64.DEFAULT); + bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0, + bitmapArray.length); + + } catch (Exception e) { + e.printStackTrace(); + } + return bitmap; + + } + + public String bitmaptoString(Bitmap bitmap) { + // 将Bitmap转换成字符串 + String string = null; + ByteArrayOutputStream bStream = new ByteArrayOutputStream(); + bitmap.compress(CompressFormat.PNG, 100, bStream); + byte[] bytes = bStream.toByteArray(); + string = Base64.encodeToString(bytes, Base64.DEFAULT); + return string; + } + + public void photo() { + jieping(); + } + + protected int dp2px(int dpval) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, + dpval, getResources().getDisplayMetrics()); + } + + protected int sp2px(int spval) { + + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, + spval, getResources().getDisplayMetrics()); + + } + + private void getScreenHot(View v1, String filePath) { + + View view1 = this.getWindow().getDecorView(); + view1.setDrawingCacheEnabled(true); + view1.buildDrawingCache(); + Bitmap b1 = view1.getDrawingCache(); + + File file1 = new File(filePath); + try { + file1.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + + try { + try { + FileOutputStream fos = new FileOutputStream(file1); + // bitmap.compress(CompressFormat.PNG, 100, fos); + // 压缩bitmap到输出流中 + b1.compress(CompressFormat.PNG, 100, fos); + fos.flush(); + fos.close(); + } catch (FileNotFoundException e) { + throw new InvalidParameterException(); + } + } catch (Exception e) { + e.printStackTrace(); + } + view1.setDrawingCacheEnabled(false); + } + + public static Bitmap changeColor(Bitmap bitmap) { + if (bitmap == null) { + return null; + } + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + int[] colorArray = new int[w * h]; + int n = 0; + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + int color = getMixtureWhite(bitmap.getPixel(j, i)); + colorArray[n++] = color; + } + } + return Bitmap.createBitmap(colorArray, w, h, Bitmap.Config.ARGB_8888); + } + + // 获取和白色混合颜色 + private static int getMixtureWhite(int color) { + int alpha = Color.alpha(color); + int red = Color.red(color); + int green = Color.green(color); + int blue = Color.blue(color); + return Color.rgb(getSingleMixtureWhite(red, alpha), + getSingleMixtureWhite(green, alpha), + getSingleMixtureWhite(blue, alpha)); + } + + // 获取单色的混合值 + private static int getSingleMixtureWhite(int color, int alpha) { + int newColor = color * alpha / 255 + 255 - alpha; + return newColor > 255 ? 255 : newColor; + } + + public Bitmap ratio(Bitmap image, float pixelW, float pixelH) { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + image.compress(Bitmap.CompressFormat.PNG, 100, os); + if (os.toByteArray().length / 1024 > 100) {// 判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出 + os.reset();// 重置baos即清空baos + image.compress(Bitmap.CompressFormat.PNG, 40, os);// 这里压缩50%,把压缩后的数据存放到baos中 + } + ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); + BitmapFactory.Options newOpts = new BitmapFactory.Options(); + // 开始读入图片,此时把options.inJustDecodeBounds 设回true了 + newOpts.inJustDecodeBounds = true; + newOpts.inPreferredConfig = Config.ARGB_8888; + Bitmap bitmap = BitmapFactory.decodeStream(is, null, newOpts); + newOpts.inJustDecodeBounds = false; + int w = newOpts.outWidth; + int h = newOpts.outHeight; + float hh = pixelH;// 设置高度为240f时,可以明显看到图片缩小了 + float ww = pixelW;// 设置宽度为120f,可以明显看到图片缩小了 + // 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可 + int be = 1;// be=1表示不缩放 + + if (w > h && w > ww) {// 如果宽度大的话根据宽度固定大小缩放 + be = (int) (newOpts.outWidth / ww); + } else if (w < h && h > hh) {// 如果高度高的话根据宽度固定大小缩放 + be = (int) (newOpts.outHeight / hh); + } + if (be <= 0) + be = 1; + newOpts.inSampleSize = be;// 设置缩放比例 + // 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了 + is = new ByteArrayInputStream(os.toByteArray()); + bitmap = BitmapFactory.decodeStream(is, null, newOpts); + // 压缩好比例大小后再进行质量压缩 + // return compress(bitmap, maxSize); // 这里再进行质量压缩的意义不大,反而耗资源,删除 + return bitmap; + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + switch (keyCode) { + + case KeyEvent.KEYCODE_BACK: + if (x5webview != null) { + if (x5webview.canGoBack()) { + x5webview.goBack(); + } else { + dialogexit.show(webviewActivity.this, "确定退出", + new onexitlistener() { + @Override + public void paylistener() { + + exitApp(); + } + + @Override + public void cancellistener() { + + } + }); + } + } else { + dialogexit.show(webviewActivity.this, "确定退出", + new onexitlistener() { + @Override + public void paylistener() { + exitApp(); + } + + @Override + public void cancellistener() { + + } + }); + } + + return true; + + default: + break; + } + + return super.onKeyDown(keyCode, event); + } + + public interface OnGetUserInfoListener { + void onGetUserInfo(String userInfo); // json字符串 + + void onNetError(); + } + + static class GetUserInfoTask extends AsyncTask { + + private OnGetUserInfoListener mListener; + private String mUrl; + + public GetUserInfoTask(OnGetUserInfoListener listener, + String getUserInfoUrl) { + mListener = listener; + mUrl = getUserInfoUrl; + } + + @Override + protected void onPreExecute() { + + super.onPreExecute(); + } + + @Override + protected String doInBackground(Object... params) { + HttpURLConnection conn = null; + BufferedReader in = null; + StringBuilder result = new StringBuilder(); + + try { + conn = (HttpURLConnection) new URL(mUrl).openConnection(); + in = new BufferedReader(new InputStreamReader( + conn.getInputStream(), "UTF-8")); + String buf; + while ((buf = in.readLine()) != null) + result.append(buf); + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (conn != null) + conn.disconnect(); + + // FileUtils.close(in); + } + return result.toString(); + } + + @Override + protected void onPostExecute(String s) { + Log.d("", "onPostExecute " + s); + mListener.onGetUserInfo(s); + } + } + + /** + * 获取通话状态 + */ + public int phonestate() { + TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); + int phonestate = 0; + /** + * 返回电话状态 + * + * CALL_STATE_IDLE 无任何状态时 CALL_STATE_OFFHOOK 接起电话时 CALL_STATE_RINGING + * 电话进来时 + * + * + */ + if (tm.getCallState() == TelephonyManager.CALL_STATE_IDLE) { + Log.d("test", "call state idle..."); + phonestate = 0; + + } else if (tm.getCallState() == TelephonyManager.CALL_STATE_OFFHOOK) { + Log.d("test", "call state offhook..."); + phonestate = 1; + } else if (tm.getCallState() == TelephonyManager.CALL_STATE_RINGING) { + Log.d("test", "call state ringing..."); + phonestate = 2; + + } + return phonestate; + } + + private void getUserInfo(String accessToken, String openId) { + String url = "https://api.weixin.qq.com/sns/userinfo?" + + "access_token=" + accessToken + "&openid=" + openId; + GetUserInfoTask mGetUserInfoTask = new GetUserInfoTask( + new OnGetUserInfoListener() { + + @Override + public void onNetError() { + + } + + @Override + public void onGetUserInfo(String userInfo) { + // text.setText(userInfo); + // Toast.makeText(webviewActivity.this, userInfo, 1) + // .show(); + JSONObject object; + try { + object = new JSONObject(userInfo); + String url = object.optString("headimgurl"); + + String unionid = object.optString("unionid"); + String openid = object.optString("openid"); + String nickname = object.optString("nickname"); + String sex = object.optString("sex"); + String city = object.optString("city"); + + String country = object.optString("country"); + SpUtil.setStringSharedPerference(Shared, "country", + country); + + String province = object.optString("province"); + SpUtil.setStringSharedPerference(Shared, + "province", province); + + SpUtil.setStringSharedPerference(Shared, "unionid", + unionid); + SpUtil.setStringSharedPerference(Shared, + "headimgurl", url); + + SpUtil.setStringSharedPerference(Shared, "openid", + openid); + SpUtil.setStringSharedPerference(Shared, + "nickname", nickname); + SpUtil.setStringSharedPerference(Shared, "sex", sex); + SpUtil.setStringSharedPerference(Shared, "city", + city); + + handler.sendEmptyMessage(1); + + } catch (JSONException e) { + e.printStackTrace(); + } + + } + }, url); + + mGetUserInfoTask.execute(); + } + + /** + * 退出程序 + */ + private void exitApp() { + deleteAllFiles(); + + Myapplication.getInstance().exit(); + + // finish(); + // System.exit(0); + } + + public String getAllFilename(String name) { + System.out.println("name=" + name); + + String channelname = ""; + + try { + String[] filename = Myapplication.application.getAssets() + .list(name); + System.out.println("------"); + + if (filename.length > 0) { + + System.out.println("目录长度" + filename.length); + + for (int i = 0; i < filename.length; i++) { + + System.out.println("=====" + filename[i]); + + if (filename[i].equals("BoolTest.java")) { + String[] filename1 = Myapplication.application + .getAssets().list( + name + File.separator + filename[i]); + System.out.println("0--" + filename1.length); + } else { + + String[] name1 = Myapplication.application.getAssets() + .list(name + File.separator + filename[i]); + System.out.println("name1--" + name1.length); + if(name1.length>=1){ + System.out.println("name1--" + name1[0]); + } + + if (name1.length >= 0) { + channelname = filename[i]; + } + + } + + } + + } else { + System.out.println("找不到目录"); + } + + } catch (IOException e) { + + e.printStackTrace(); + } + + return channelname; + + } + + public String getAllFilename1(String name) { + + String channelname = ""; + + try { + String[] filename = Myapplication.application.getAssets() + .list(name); + + if (filename.length > 0) { + + System.out.println("目录长度" + filename.length); + + for (int i = 0; i < filename.length; i++) { + + System.out.println("=====" + filename[i]); + + if (filename[i].equals("BoolTest.java")) { + String[] filename1 = Myapplication.application + .getAssets().list( + name + File.separator + filename[i]); + System.out.println("0--" + filename1.length); + } else { + + String[] name1 = Myapplication.application.getAssets() + .list(name + File.separator + filename[i]); + System.out.println("name1--" + name1.length); + System.out.println("name1--" + name1[0]); + if (name1.length > 0) { + channelname = filename[i]; + } + + } + + } + + } + + } catch (IOException e) { + + e.printStackTrace(); + } + + return channelname; + + } + + public void deleteAllFiles() { + /** + * 删除下载音频文件 + */ + if (destFileDir != null) { + File dir1 = new File(destFileDir); + + if (dir1.exists()) { + + File[] files = new File(destFileDir).listFiles(); + for (File file : files) { + file.delete(); + } + } + } + + /** + * 删除录音音频文件 + */ + if (dirs != null) { + File dir = new File(dirs); + if (dir.exists()) { + System.out.println("-----" + dir.getAbsolutePath()); + File[] audiofiles = new File(dirs).listFiles(); + for (File file1 : audiofiles) { + file1.delete(); + } + } + } + + /** + * 删除下载头像图片 + * + */ + + if (photofile1 != null) { + + if (photofile1.exists()) { + System.out.println("-----" + photofile1.getAbsolutePath()); + File[] audiofiles = photofile1.listFiles(); + for (File file1 : audiofiles) { + file1.delete(); + } + } + } + if (photofile1 != null) { + + if (photofile1.exists()) { + System.out.println("-----" + photofile1.getAbsolutePath()); + File[] audiofiles = photofile1.listFiles(); + System.out.println("头像数量=" + audiofiles.length); + } + } + } + + protected void changeState(int stateWantToCancel) { + + if (mCurrentState != stateWantToCancel) { + mCurrentState = stateWantToCancel; + switch (mCurrentState) { + case STATE_NORMAL: + + break; + case STATE_RECORDING: + + if (isRecording) { + mDialogManager.recording(); + } + break; + + case STATE_WANT_TO_CANCEL: + mDialogManager.wantToCancel(); + break; + } + } + } + + protected boolean wantToCancel(int x, int y, int x1, int y1) { + try { + int mx = Math.abs(x1 - x); + int my = Math.abs(y1 - y); + + if (mx > 100 || my > 100) { + return true; + } + } catch (Exception e) { + + } + + return false; + + } + + private String buildTransaction(final String type) { + + return (type == null) ? String.valueOf(System.currentTimeMillis()) + : type + System.currentTimeMillis(); + } + + // 获取音量大小的runnable + private Runnable mGetVoiceLevelRunnable = new Runnable() { + + @Override + public void run() { + + while (isRecording) { + try { + Thread.sleep(100); + mTime += 0.1f; + mhandler.sendEmptyMessage(MSG_VOICE_CHANGE); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + }; + + /** + * 回复标志位以及状态 + */ + private void reset() { + // TODO Auto-generated method stub + + if (isStopPlay) { + isPlayaudio = false;// 可以继续播放 + } + + isStopPlay = false; + + isRecording = false; + mTime = 0; + isautio = false; + changeState(STATE_NORMAL); + +// String getaudiourl = "javascript:getaudiourl(" + "'" + 0 + "'" + ",'" +// + 0 + "'" + ");"; +// +// webviewjh(getaudiourl); + + JSONObject json = new JSONObject(); + try { + json.put("audiourl", ""); + + json.put("time", 0); + x5webview.callHandler("getaudiourl", json.toString(), new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + + + }catch (Exception e){ + + } + } + + // 在onStart() 之后 + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + + super.onRestoreInstanceState(savedInstanceState); + } + + // 当activity 被销毁时 + // 在onStop()之前调用, 文档中说并不保证在onPause()的之前还是之后 + // 我的试验中一般是在onPause()之后 + @Override + protected void onSaveInstanceState(Bundle outState) { + // TODO Auto-generated method stub + super.onSaveInstanceState(outState); + System.out.println("调用onSaveInstanceState-----webviewactivity"); + //Myapplication.getInstance().exit();//退出应用 + + if (x5webview != null) { + + x5webview.saveState(outState); + } + } + + // 在这里面发送一个handler的消息 + @Override + public void wellPrepared() { + + System.out.println("wellPrepared"); + mhandler.sendEmptyMessage(MSG_AUDIO_PREPARED); + } + + @Override + public void onClick(View v) { + + } + + public MessageReceiver mMessageReceiver; + + public static String ACTION_INTENT_RECEIVER = "com.gc.broadcast.receiver"; + /** + * 动态注册广播 + */ + + public void registerMessageReceiver() { + mMessageReceiver = new MessageReceiver(); + IntentFilter filter = new IntentFilter(); + + filter.addAction(ACTION_INTENT_RECEIVER); + registerReceiver(mMessageReceiver, filter); + } + + public class MessageReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + // TODO Auto-generated method stub + if (intent.getAction().equals(ACTION_INTENT_RECEIVER)) { + int state = intent.getIntExtra("message", 0); + + // Toast.makeText(context, "---" + state, 1).show(); +// String user = "javascript:phonestate(" + "'" + state + "'" +// + ");"; + + // x5webview.loadUrl("javascript:phonestate(" + "'" + state + + // "'" + // + ");"); + + //webviewjh(user); + + + x5webview.callHandler("phonestate", ""+state, new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + + } + } + + } + + @PermissionSuccess(requestCode = 101) + public void success() { + if (isDown) { + try { + prepareAudio(); + } catch (Exception e) { + + } + } + } + + public void prepareAudio() { + + if (isPlayaudio) { + if (!pmutil.isnullorEmpty(uservoice)) { + isStopPlay = true; + + MediaManager.release(); +// String gameui_stop_voice = "javascript:gameui_stop_voice(" +// + "'" + uservoice + "'" + ");"; +// webviewjh(gameui_stop_voice); + x5webview.callHandler("gameui_stop_voice", ""+uservoice, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + + uservoice = ""; + + } + } + + long backPressed = System.currentTimeMillis(); + // + if (backPressed - lastBackPressed > QUIT_INTERVAL) { + lastBackPressed = backPressed; + System.out.println("准备录制"); + isautio = true; + mAudioManager.prepareAudio(); + } else { + lastBackPressed = backPressed; + } + } + + @PermissionFail(requestCode = 101) + public void fail() { + for (int i = 0; i < carpermission.length; i++) { + if (ActivityCompat.shouldShowRequestPermissionRationale( + webviewActivity.this, carpermission[i])) { + // 未勾选不再提示 + System.out.println("拒绝"); + + } else { + // 勾选不再提示 + if (ContextCompat.checkSelfPermission(this, carpermission[i]) == PackageManager.PERMISSION_DENIED) { + showMissingPermissionDialog(); + break; + } + } + } + } + + // 显示缺失权限提示 + private void showMissingPermissionDialog() { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("提示"); + builder.setMessage("当前应用缺少必要权限。请点击\"设置\"-\"权限\"-打开所需权限。"); + + // 拒绝, 退出应用 + builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + } + }); + + builder.setPositiveButton("设置", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + startAppSettings(); + } + }); + + builder.show(); + } + + // 启动应用的设置 + private void startAppSettings() { + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.parse(PACKAGE_URL_SCHEME + getPackageName())); + startActivity(intent); + } + + /** + * 为子类提供一个检查权限的方法 + * + * @param permissions + * @return + */ + public boolean hasPermission(String... permissions) { + for (String permission : permissions) { + if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { + return false; + + } + } + return true; + } + + @Override + public void onRequestPermissionsResult(int requestCode, + String[] permissions, int[] grantResults) { + + PermissionGen.onRequestPermissionsResult(this, requestCode, + permissions, grantResults); + } + + class BatteryReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + // 判断它是否是为电量变化的Broadcast Action + if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) { + // 获取当前电量 + int level = intent.getIntExtra("level", 0); + // 电量的总刻度 + int scale = intent.getIntExtra("scale", 100); + + // int Battery = ((level * 100) / scale); + // Toast.makeText(webviewActivity.this, Battery, 1).show(); + float batteryPct = (level / (float) scale); + // getBattery + // x5webview.loadUrl("javascript:getBattery(" + "'" + batteryPct + // + "'" + ");"); + + + x5webview.callHandler("getBattery", ""+batteryPct, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + //这里也是可以进行js回传的 + } + }); + + +// String getBattery = "javascript:getBattery(" + "'" + batteryPct +// + "'" + ");"; +// if (isfinsh) { +// webviewjh(getBattery); +// } + + } + } + + } + + class WifiChangeBroadcastReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + System.out.println("Wifi发生变化"); + getWifiInfo(); + + // x5webview.loadUrl("javascript:getwifiLevel(" + "'" + // + wifibean.getSsid() + "'" + ",'" + // + wifibean.getSignalLevel() + "'" + ");"); + + + + JSONObject json = new JSONObject(); + try { + json.put("ssidname", wifibean.getSsid()); + + json.put("signalLevel", wifibean.getSignalLevel()); + + System.out.println("---" + json.toString()); + x5webview.callHandler("getwifiLevel", json.toString(), new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + + } catch (JSONException e) { + e.printStackTrace(); + } + + + +// if (isfinsh) { +// String getwifiLevel = "javascript:getwifiLevel(" + "'" +// + wifibean.getSsid() + "'" + ",'" +// + wifibean.getSignalLevel() + "'" + ");"; +// webviewjh(getwifiLevel); +// } + + } + + } + + private class MyNetReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + + String action = intent.getAction(); + if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { + + mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + netInfo = mConnectivityManager.getActiveNetworkInfo(); + int type = 1; + + if (netInfo != null && netInfo.isAvailable()) { + + // ///////////网络连接 + String name = netInfo.getTypeName(); + + if (netInfo.getType() == ConnectivityManager.TYPE_WIFI) { + // ///WiFi网络 + type = 2; + } + // else + // if(netInfo.getType()==ConnectivityManager.TYPE_ETHERNET){ + // /////有线网络 + // + // } + else if (netInfo.getType() == ConnectivityManager.TYPE_MOBILE) { + // ///////3g网络 + type = 3; + } + } else { + // //////网络断开 + type = 1; + } + + // Toast.makeText(webviewActivity.this, "类型:"+type, 1).show(); + x5webview.callHandler("getnetwork", ""+type, new CallBackFunction() { + @Override + public void onCallBack(String data) { + //这里也是可以进行js回传的 + } + }); + + + + // x5webview.loadUrl("javascript:getnetwork(" + "'" + type + "'" + // + ");"); + } + + } + + } + + private void getWifiInfo() { + + WifiManager wifiManager = (WifiManager) this.getApplicationContext() + .getSystemService(WIFI_SERVICE); + WifiInfo wifiInfo = wifiManager.getConnectionInfo(); + if (wifiInfo.getBSSID() != null) { + // wifi名称 + String ssid = wifiInfo.getSSID(); + // wifi信号强度 0-4 弱到强 + + wifibean.setSsid(ssid); + + int signalLevel = WifiManager.calculateSignalLevel( + wifiInfo.getRssi(), 5); + + wifibean.setSignalLevel(signalLevel); + // Toast.makeText(this, "wifi 信号强度"+signalLevel , 1).show(); + + // wifi速度 + int speed = wifiInfo.getLinkSpeed(); + // wifi速度单位 + String units = WifiInfo.LINK_SPEED_UNITS; + System.out.println("ssid=" + ssid + ",signalLevel=" + signalLevel + + ",speed=" + speed + ",units=" + units); + } + } + + private ConnectivityManager mConnectivityManager; + private NetworkInfo netInfo; + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent date) { + super.onActivityResult(requestCode, resultCode, date); + if (requestCode == 100 && resultCode == RESULT_OK) { + Bundle bu = date.getExtras(); + String text = bu.getString("result"); + + // Toast.makeText(webviewActivity.this, text, 1).show(); + +// String webjh = "javascript:getsaomaData(" + "'" + text + "'" + ");"; +// webviewjh(webjh); + if(x5webview!=null){ + x5webview.callHandler("getsaomaData",text,new CallBackFunction(){ + @Override + public void onCallBack(String data) { + + } + }); + } + + } + + if (requestCode == CAMERA_WITH_DATA && resultCode == RESULT_OK) { + + String userSelectPath = PHOTO_DIR + "/" + picName; + // Toast.makeText(webviewActivity.this, userSelectPath, 1).show(); +// String webjh = "javascript:getcameraaAddress(" + "'" +// + userSelectPath + "'" + ");"; +// webviewjh(webjh); + x5webview.callHandler("getcameraaAddress", userSelectPath, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + + } + + if (resultCode == 101) { + Bundle bu = date.getExtras(); + String text = bu.getString("data"); +// System.out.println("网页回调给大厅=" + text); +// String getWebdata = "javascript:getWebdata(" + "'" + text + "'" +// + ");"; +// webviewjh(getWebdata); + + x5webview.callHandler("getWebdata", text, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + + + + } + } + + @Override + public void onLocationChanged(AMapLocation amapLocation) { + + getuserlocationinfo(amapLocation); + } + + MaplocationInfo location; + + private void getuserlocationinfo(AMapLocation amapLocation) { + location = new MaplocationInfo(); + + location.setLatitude(amapLocation.getLatitude());// 获取纬度 + + amapLocation.getLocationType();// 获取当前定位结果来源,如网络定位结果,详见定位类型表 + + location.setLongitude(amapLocation.getLongitude());// 获取经度 + + amapLocation.getAccuracy();// 获取精度信息 + location.setAddress(amapLocation.getAddress());// 地址,如果option中设置isNeedAddress为false,则没有此结果,网络定位结果中会有地址信息,GPS定位不返回地址信息。 + location.setCountry(amapLocation.getCountry());// 国家信息 + location.setProvince(amapLocation.getProvince());// 省信息 + location.setCity(amapLocation.getCity());// 城市信息 + location.setDistrict(amapLocation.getDistrict());// 城区信息 + location.setStreet(amapLocation.getStreet());// 街道信息 + location.setCityCode(amapLocation.getCityCode());// 城市编码 + + // amapLocation.getStreetNum();//街道门牌号信息 + + // amapLocation.getAdCode();//地区编码 + // location.setAltitude(amapLocation.getAltitude());// 海拔 + + amapLocation.getAoiName();// 获取当前定位点的AOI信息 + amapLocation.getBuildingId();// 获取当前室内定位的建筑物Id + amapLocation.getFloor();// 获取当前室内定位的楼层 + + handellocation.sendEmptyMessage(1); + } + + Handler handellocation = new Handler() { + @Override + public void dispatchMessage(Message msg) { + switch (msg.what) { + case 1: + Gson gson = new Gson(); + String json = gson.toJson(location); + System.out.println(json); + // x5webview.loadUrl("javascript:getlocationinfo(" + "'" + json + // + + // "'" + // + ");"); +// String getlocationinfo = "javascript:getlocationinfo(" + "'" +// + json + "'" + ");"; +// webviewjh(getlocationinfo); + + x5webview.callHandler("getlocationinfo", json, new CallBackFunction() { + @Override + public void onCallBack(String data) { + + } + }); + break; + case 2: + if (!hasPermission(locationpermission)) { + + PermissionGen.needPermission(webviewActivity.this, 19, + locationpermission); + } else { + initlocation(); + } + break; + default: + break; + } + + super.dispatchMessage(msg); + + } + }; + + @Override + public void resetPrepared() { + reset(); + + } +} diff --git a/app/src/main/java/com/tagmae/tsgame_erwang/weclomeactivity1.java b/app/src/main/java/com/tagmae/tsgame_erwang/weclomeactivity1.java new file mode 100644 index 0000000..d4995fd --- /dev/null +++ b/app/src/main/java/com/tagmae/tsgame_erwang/weclomeactivity1.java @@ -0,0 +1,2255 @@ +package com.tagmae.tsgame_erwang; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.ActivityManager; +import android.app.ActivityManager.RunningTaskInfo; +import android.app.AlertDialog; +import android.app.AlertDialog.Builder; +import android.app.ProgressDialog; +import android.content.ComponentName; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.Message; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; +import android.provider.Settings; +import android.support.annotation.Nullable; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AppCompatActivity; +import android.util.Log; +import android.util.Xml; +import android.view.KeyEvent; +import android.view.View; +import android.view.WindowManager; +import android.widget.ProgressBar; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.game.webgame.view.SpUtil; +import com.game.webgame.view.dialogexit; +import com.game.webgame.view.dialogexit.onexitlistener; +import com.game.webgame.view.pmutil; +import com.google.gson.Gson; + +import com.orhanobut.logger.AndroidLogAdapter; +import com.orhanobut.logger.CsvFormatStrategy; +import com.orhanobut.logger.DiskLogAdapter; +import com.orhanobut.logger.Logger; +import com.tencent.mm.opensdk.modelmsg.SendAuth; +import com.tencent.mm.opensdk.openapi.IWXAPI; +import com.tencent.mm.opensdk.openapi.WXAPIFactory; + + +import com.jx.jyhd.R; +import com.jx.jyhd.simcpux.Constants; +import com.jx.jyhd.simcpux.Util; +import com.jx.jyhd.simcpux.Wxistrue; +import com.jx.jyhd.wxapi.WXEntryActivity; +import com.tsgame.tsgame_niuniu.Bean.Gameversiontxt; +import com.tsgame.tsgame_niuniu.Bean.agentlistTxt; +import com.tsgame.tsgame_niuniu.Bean.channellistTxt; +import com.tsgame.tsgame_niuniu.Bean.filelistBean; +import com.tsgame.tsgame_niuniu.Bean.gamelistTxt; +import com.tsgame.tsgame_niuniu.Bean.marketlistTxt; +import com.tsgame.tsgame_niuniu.Bean.userbean; +import com.tsgame.tsgame_niuniu.Bean.versionagentlist; +import com.tsgame.tsgame_niuniu.Bean.versionbean; + +import com.tsgame.tsgame_niuniu.Bean1.Agentlist; +import com.tsgame.tsgame_niuniu.Bean1.ConfigData; +import com.tsgame.tsgame_niuniu.Bean1.Gamelist; +import com.tsgame.tsgame_niuniu.Bean1.JsonRootBean; +import com.tsgame.tsgame_niuniu.Bean1.gameversionUtil; +import com.tsgame.tsgame_niuniu.system.Gamesettingurl; +import com.tsgame.tsgame_niuniu.system.Myapplication; +import com.tsgame.tsgame_niuniu.util.Settingutil; +import com.tsgame.tsgame_niuniu.util.ZipUtils; +import com.tsgame.tsgame_niuniu.util.apputil; +import com.tsgame.tsgame_niuniu.util.initwebviewutil; +import com.umeng.analytics.MobclickAgent; +import com.umeng.analytics.MobclickAgent.EScenarioType; +import com.umeng.analytics.game.UMGameAgent; + +// Apache HttpClient已移除,改用OkHttp +// import org.apache.http.HttpEntity; +// import org.apache.http.HttpResponse; +// import org.apache.http.client.ClientProtocolException; +// import org.apache.http.client.HttpClient; +// import org.apache.http.client.methods.HttpGet; +// import org.apache.http.impl.client.DefaultHttpClient; +import org.json.JSONObject; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.zip.ZipException; + +import kr.co.namee.permissiongen.PermissionFail; +import kr.co.namee.permissiongen.PermissionGen; +import kr.co.namee.permissiongen.PermissionSuccess; +import okhttp3.CacheControl; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Headers; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +@SuppressLint("NewApi") +public class weclomeactivity1 extends AppCompatActivity{ + + ProgressBar progressBar; + String m_appNameStr = "tsgame_niuniu.apk"; // 下载到本地要给这个APP命的名字 + // 添加APK文件路径变量,用于安装 + private String apkFilePathForInstall = ""; + List testBean; + ProgressDialog m_progressDlg1; + + private SharedPreferences sp; + + + @SuppressLint("InlinedApi") + String[] permissons = new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.READ_PHONE_STATE }; + private static final String PACKAGE_URL_SCHEME = "package:"; // 方案 + + private String projectpath;// 解压路径 + TextView inittext; + TextView textView1; + private static final int disend = 1; + private static WakeLock m_wklk; + Handler m_mainHandler; + + public void setshowmessage(String Showmessage) { + System.out.println("----" + Showmessage); + if (!pmutil.isnullorEmpty(Showmessage)) { + apputil.Showmessage = Showmessage; + + } + } + + int i=0; + + @SuppressLint("HandlerLeak") + Handler hanlerq1 = new Handler() { + @Override + public void handleMessage(Message msg) { + Gson fson = new Gson(); + String s; + switch (msg.what){ + case 1: + s=msg.getData().getString("msg"); + //保存获取配置文件数据 + SpUtil.setStringSharedPerference(Shared,"gameconfig",s); + long time=System.currentTimeMillis(); + SpUtil.setLongSharedPerference(Shared,"gameconfigtime",time); + mJsonRootBean = fson.fromJson(s, JsonRootBean.class); + if(mJsonRootBean.getGamelist()!=null){ + //处理2。0配置 + chulisuoyin(); + }else{ + // 兼容1.0配置 + gameversiontxt = fson.fromJson(s, Gameversiontxt.class); + chuliversion_1(); + } + break; + case 2: + s=msg.getData().getString("msg"); + SpUtil.setStringSharedPerference(Shared,"magentlist",s); + Logger.t("hanlerq1").v(s); + magentlist=fson.fromJson(s, Agentlist.class); + chulipeizhiAgent(); + break; + case 3: + s=msg.getData().getString("msg"); + SpUtil.setStringSharedPerference(Shared,"mgamelist",s); + Logger.t("hanlerq1").v(s); + mgamelist=fson.fromJson(s, Gamelist.class); + chulipeizhiGame(); + break; + case 4: + i++;// + if(i==2){//两个配置文件读取完成 + if(!pmutil.isnullorEmpty(apputil.Showmessage)){ + showMissingsettingDialog(apputil.Showmessage); + }else{ + if(agentversionutil!=null&&gameversionutil!=null){ + chulipeizhi(); + } + } + } + break; + } + super.handleMessage(msg); + + } + }; + public void chuliversion_1(){ + apputil.Showmessage = ""; + + setshowmessage(gameversiontxt.getShowmessage()); + + List versionagentinfo = gameversiontxt.getAgentlist(); + + String urlpath = SpUtil.getStringSharedPerference(sp, "urlpath"); + String purl = urlpath + File.separator + Settingutil.initfile; + + System.out.println("purl=" + purl); + + versionbean versd = pullxml1(purl); + + String gameid = getAllFilename("gameid"); + if(!pmutil.isnullorEmpty(gameid)){ + versd.setGameid(gameid); + } + + System.out.println(versd.toString()); + String channel = getAllFilename("channel"); + String marketname = getAllFilename("market"); + System.out.println(getAllFilename("market")); + String agentid = getAllFilename("agent"); + System.out.println("agentid=" + agentid); + System.out.println("channel===" + channel); + int xmlgamecode = Integer.parseInt(versd.getVersion()); + + if (!pmutil.isnullorEmpty(channel)) { + versd.setChannelid(channel); + } + + boolean isgameutil = false; + + System.out.println("进入配置文件"); + + for (int k = 0; k < versionagentinfo.size(); k++) { + agentlistTxt agenttext = versionagentinfo.get(k); + System.out.println(agenttext.toString()); + System.out.println(""+agentid); + System.out.println("agenttext.getAgentid()="+agenttext.getAgentid()); + + if (agenttext.getAgentid().equals(agentid)) { + System.out.println("代理id匹配"+agentid); + System.out.println("代理id匹配"+agenttext.getAgentid()); + setshowmessage(versionagentinfo.get(k).getShowmessage()); + + List info = gameversiontxt.getAgentlist() + .get(k).getGamelist(); + + for (int i = 0; i < info.size(); i++) { + gamelistTxt gamelistfo = info.get(i); + + if (gamelistfo.getGameid().equals(versd.getGameid())) { + System.out.println("游戏id匹配"); + setshowmessage(gamelistfo.getShowmessage()); + + String newgame_zip = ""; + String newgame_version = ""; + if (!pmutil.isnullorEmpty(gamelistfo.getGame_zip())) { + newgame_zip = gamelistfo.getGame_zip(); + + } + + if (!pmutil.isnullorEmpty(gamelistfo + .getGame_version()) + && !gamelistfo.getGame_version() + .equals("0")) { + newgame_version = gamelistfo.getGame_version(); + } + + List info1 = gamelistfo + .getChannellist(); + for (int j = 0; j < info1.size(); j++) { + channellistTxt info2 = info1.get(j); + + String Channelid = info2.getChannelid(); + System.out.println("------" + Channelid); + if (Channelid.equals(versd.getChannelid())) { + + setshowmessage(info2.getShowmessage()); + + System.out.println("渠道id匹配"); + + if (!pmutil.isnullorEmpty(info2 + .getGame_zip())) { + newgame_zip = info2.getGame_zip(); + + } + + if (!pmutil.isnullorEmpty(info2 + .getGame_version()) + && !info2.getGame_version().equals( + "0")) { + newgame_version = info2 + .getGame_version(); + } + + List marketlist = info2 + .getMarketlist(); + + for (int f = 0; f < marketlist.size(); f++) { + marketlistTxt marketinfo = marketlist + .get(f); + if (marketinfo.getMarketid().equals( + marketname)) { + System.out.println("市场id 匹配"); + + setshowmessage(marketinfo + .getShowmessage()); + + if (!pmutil + .isnullorEmpty(apputil.Showmessage)) { + + showMissingsettingDialog(apputil.Showmessage); + + } else { + isgameutil = true; + String downloadurl = marketinfo + .getApp_download(); + + int versioncode = Integer + .parseInt(marketinfo + .getApp_version());// apk + + int gameversioncode = 0; + + try { + if (!pmutil + .isnullorEmpty(newgame_version)) { + gameversioncode = Integer + .parseInt(newgame_version); + + } + + } catch (Exception e) { + + } + + // 版本 + if (!pmutil + .isnullorEmpty(marketinfo + .getGame_version()) + && !marketinfo + .getGame_version() + .equals("0")) { + gameversioncode = Integer + .parseInt(marketinfo + .getGame_version());// 游戏 + } + + int AppVersioncode = 1; + + String apkversion = getAllFilename("appversion"); + // + if (pmutil + .isnullorEmpty(apkversion)) { + + } else { + AppVersioncode = Integer + .parseInt(apkversion); + } + + // 版本 + if (AppVersioncode > versioncode) { + apputil.code = 1; + } else { + apputil.code = 0; + } + + System.out + .println("AppVersioncode" + + AppVersioncode); + + System.out + .println("versioncode" + + versioncode); + + boolean isupdate = false; + + if (versioncode > AppVersioncode) { + progressBar.setVisibility(View.VISIBLE); + inittext.setText("下载apk安装包..."); + isupdate = true; + doNewVersionUpdate(downloadurl+"?a="+System.currentTimeMillis()); + + } + + System.out + .println("gameversioncode" + + gameversioncode + + "xmlgamecode" + + xmlgamecode); + if (!isupdate) { + if (gameversioncode > xmlgamecode) { + inittext.setText("正在升级版本..."); + progressBar.setVisibility(View.VISIBLE); + if (!pmutil + .isnullorEmpty(marketinfo + .getGame_zip())) { + System.out + .println("---" + + marketinfo + .getGame_zip()); + + updatezip(marketinfo + .getGame_zip()+"?a="+System.currentTimeMillis()); + } else { + if (!pmutil + .isnullorEmpty(newgame_zip)) { + updatezip(newgame_zip+"?a="+System.currentTimeMillis()); + } else { + showMissingsettingDialog(); + } + + } + + } else { + if (!isupdate) { + handlerend1(); + } + } + } + } + + } + } + + // + } + + } + } + + } + + } else { + + } + + } + if (!isgameutil) { + if (!pmutil.isnullorEmpty(apputil.Showmessage)) { + showMissingsettingDialog(apputil.Showmessage); + } else { + showMissingsettingDialog(); + } + + } + + } + + ConfigData mconfigData; + + public ConfigData getConfigData(){ + if(mconfigData==null){ + mconfigData=new ConfigData(); + mconfigData.setAgentid(getAllFilename("agent")); + + String urlpath = SpUtil.getStringSharedPerference(sp, "urlpath"); + String purl = urlpath + File.separator + Settingutil.initfile; + + versionbean versd = pullxml1(purl); + String gameid=getAllFilename("gameid"); + if(!pmutil.isnullorEmpty(gameid)){ + versd.setGameid(gameid); + } + + mconfigData.setGameid(versd.getGameid()); + mconfigData.setChannelid(getAllFilename("channel")); + String marketname = getAllFilename("market"); + mconfigData.setMarketid(marketname); + } + return mconfigData; + + + } + gameversionUtil agentversionutil; + gameversionUtil gameversionutil; + + GameupdateUtil gameupdateUtil; + + public void chulipeizhiAgent(){ + ConfigData mconfigData=getConfigData(); + if(gameupdateUtil==null){ + gameupdateUtil=new GameupdateUtil(); + } + + agentversionutil=gameupdateUtil.agentUtil(mconfigData,magentlist,null); + hanlerq1.sendEmptyMessage(4); + } + + public void chulipeizhiGame(){ + if(gameupdateUtil==null){ + gameupdateUtil=new GameupdateUtil(); + } + ConfigData mconfigData=getConfigData(); + gameversionutil=gameupdateUtil.agentUtil(mconfigData,null,mgamelist); + hanlerq1.sendEmptyMessage(4); + } + + public void chulisuoyin(){ + apputil.Showmessage = ""; + String agentid = getAllFilename("agent"); + + String urlpath = SpUtil.getStringSharedPerference(sp, "urlpath"); + String purl = urlpath + File.separator + Settingutil.initfile; + versionbean versd = pullxml1(purl); + String gameid1 = getAllFilename("gameid"); + if(!pmutil.isnullorEmpty(gameid1)){ + versd.setGameid(gameid1); + } + String gameid =versd.getGameid(); + setshowmessage(mJsonRootBean.getShowmessage()); + if(!pmutil.isnullorEmpty(gameid)&&!pmutil.isnullorEmpty(agentid)){ + for(int i=0;iappdownloadversion){ + appdownloadversion=Integer.parseInt(gameversionutil.getApp_version()); + appdownloadurl=gameversionutil.getApp_download(); + + }; + }catch (Exception e){ + + Logger.e("APP配置version格式版本问题",e); + } + + + + }else{ + try{ + if(!pmutil.isnullorEmpty(gameversionutil.getApp_download())){ + + appdownloadversion=Integer.parseInt(gameversionutil.getApp_version()); + appdownloadurl=gameversionutil.getApp_download(); + } + }catch (Exception e){ + Logger.e("gameversionutil配置APP version格式版本问题",e); + } + try{ + + if(!pmutil.isnullorEmpty(agentversionutil.getApp_download())){ + appdownloadversion=Integer.parseInt(agentversionutil.getApp_version()); + appdownloadurl=agentversionutil.getApp_download(); + } + }catch (Exception e){ + Logger.e("agentversionutil配置APP version格式版本问题",e); + } + } + + + + + //处理自游戏升级 + if(!pmutil.isnullorEmpty(gameversionutil.getGame_download())&&!pmutil.isnullorEmpty(agentversionutil.getGame_download())){ + //两个配置文件都配置了子游戏升级 取配置版本最高 + try{ + gamedownloadversion=Integer.parseInt(gameversionutil.getGame_version()); + gamedownloadurl=gameversionutil.getGame_download(); + if(Integer.parseInt(agentversionutil.getGame_version())>gamedownloadversion){ + gamedownloadversion=Integer.parseInt(agentversionutil.getGame_version()); + gamedownloadurl=agentversionutil.getGame_download(); + + }; + }catch (Exception e){ + + Logger.e("子游戏配置version格式版本问题",e); + } + + + + }else{ + try{ + if(!pmutil.isnullorEmpty(gameversionutil.getGame_download())){ + //两个配置文件都配置了app升级取配置版本最高都 + gamedownloadversion=Integer.parseInt(gameversionutil.getGame_version()); + gamedownloadurl=gameversionutil.getGame_download(); + } + }catch (Exception e){ + Logger.e("gameversionutil配置子游戏 version格式版本问题",e); + } + try{ + + if(!pmutil.isnullorEmpty(agentversionutil.getGame_download())){ + gamedownloadversion=Integer.parseInt(agentversionutil.getGame_version()); + gamedownloadurl=agentversionutil.getGame_download(); + } + }catch (Exception e){ + Logger.e("gameversionutil配置子游戏 version格式版本问题",e); + } + } + + + int AppVersioncode = 0; + + String apkversion = getAllFilename("appversion"); + // + if (pmutil + .isnullorEmpty(apkversion)) { + + } else { + AppVersioncode = Integer + .parseInt(apkversion); + } + + // 版本 + if (AppVersioncode > appdownloadversion) { + apputil.code = 1; + } else { + apputil.code = 0; + } + + boolean isupdate=false; + + if (appdownloadversion > AppVersioncode) { + progressBar.setVisibility(View.VISIBLE); + inittext.setText("下载apk安装包..."); + isupdate = true; + doNewVersionUpdate(appdownloadurl+"?a="+System.currentTimeMillis()); + + } + + if(!isupdate){ + + String urlpath = SpUtil.getStringSharedPerference(sp, "urlpath"); + String purl = urlpath + File.separator + Settingutil.initfile; + + System.out.println("purl=" + purl); + + versionbean versd = pullxml1(purl); + + String gameid=getAllFilename("gameid"); + if(!pmutil.isnullorEmpty(gameid)){ + versd.setGameid(gameid); + } + + int xmlgamecode = Integer.parseInt(versd.getVersion()); + + if (gamedownloadversion > xmlgamecode) { + inittext.setText("正在升级版本..."); + progressBar.setVisibility(View.VISIBLE); + + updatezip(gamedownloadurl+"?a="+System.currentTimeMillis()); + + + } else { + + handlerend1(); + + } + + + } + + } + public void inith5data(){ + String url = SpUtil.getStringSharedPerference(Shared, "urlpath"); + + url = url + File.separator + Settingutil.initfile+ File.separator+"app_data.js"; + System.out.println("初始化前数据"+ Fileutils.readFile(url)); + + StringBuffer buffer=new StringBuffer(); + + + String app_version="var app_version=1;";//初始化框架加载方式 + buffer.append(app_version); + + + + String app_gameconfig = getAllFilename("gameconfig"); + app_gameconfig="var app_gameconfig='"+app_gameconfig+"';"; + buffer.append(app_gameconfig); + + String app_gamedir = getAllFilename("gamedir"); + app_gamedir="var app_gamedir='"+app_gamedir+"';"; + buffer.append(app_gamedir); + + + String app_gamestart = getAllFilename("gamestart"); + app_gamestart="var app_gamestart='"+app_gamestart+"';"; + buffer.append(app_gamestart); + + + String app_agent = getAllFilename("agent"); + app_agent="var app_agent='"+app_agent+"';"; + buffer.append(app_agent); + + + String app_appversion = getAllFilename("appversion"); + app_appversion="var app_appversion='"+app_appversion+"';"; + buffer.append(app_appversion); + + + String app_market = getAllFilename("market"); + app_market="var app_market='"+app_market+"';"; + buffer.append(app_market); + + + String app_channel = getAllFilename("channel"); + app_channel="var app_channel='"+app_channel+"';"; + buffer.append(app_channel); + + String app_invitationcode = getAllFilename("tuiguang"); + if(!pmutil.isnullorEmpty(app_invitationcode)){ + app_invitationcode="var app_invitationcode='"+app_invitationcode+"';"; + + }else{ + app_invitationcode="var app_invitationcode='';"; + System.out.println("app_invitationcode"+app_invitationcode); + } + + buffer.append(app_invitationcode); + + String app_Launchtype = "0"; + app_Launchtype="var app_Launchtype='"+app_Launchtype+"';"; + buffer.append(app_Launchtype); + + + String app_gamename = getAllFilename("gamestart"); + app_gamename="var app_gamename='"+app_gamename+"';"; + buffer.append(app_gamename); + + String app_getwifisignalLevel="var app_getwifisignalLevel=1;"; + buffer.append(app_getwifisignalLevel); + + + //Fileutils.writeToFile(buffer.toString(),url); + + Fileutils.modifyFile(url,buffer.toString(),false); + + System.out.println("初始化后数据"+Fileutils.readFile(url)); + + + + + } + + @SuppressLint("HandlerLeak") + Handler hanler = new Handler() { + @Override + public void handleMessage(Message msg) { + int what = msg.what; + + switch (what) { + case 1: + + inith5data(); + + + apputil.activityname =""; + Intent in = new Intent(); + in.setClass(weclomeactivity1.this, webviewActivity.class); + startActivity(in); + finish(); + break; + case 2: + inittext.setText("正在升级版本..."); + textView1.setText(""); + hanler.sendEmptyMessageDelayed(disend, 1000); + break; + case 3: + if(!weclomeactivity1.this.isFinishing()){ + if (m_progressDlg1 != null) { + if (m_progressDlg1.isShowing()) { + m_progressDlg1.cancel(); + } + + } + } + + + inittext.setText("正在检测新版本..."); + download(); + + break; + + case 4: + inittext.setText("正在解压中..."); + break; + case 5: + + initdailog(); + break; + case 6: + showMissingsettingDialog(); + + break; + default: + break; + } + super.handleMessage(msg); + } + }; + + static SharedPreferences Shared; + private IWXAPI api; + + String packnameclass; + + @SuppressLint("HandlerLeak") + Handler handler = new Handler() { + @SuppressLint({ "ShowToast" }) + @Override + public void handleMessage(Message msg) { + int success = msg.what; + + Toast.makeText(weclomeactivity1.this, "--" + success, Toast.LENGTH_LONG).show(); + if (success != 1) { + + Wxistrue.isshare = true; + + Wxistrue.isphotoshare = true; + + } + + switch (msg.what) { + case 1: + + if (Shared == null) { + + } + userbean bean = new userbean(); + + String openid = SpUtil.getStringSharedPerference(Shared, + "openid"); + bean.setOpenid(openid); + + String headimgurl = SpUtil.getStringSharedPerference(Shared, + "headimgurl"); + bean.setHeadimgurl(headimgurl); + + String nickname = SpUtil.getStringSharedPerference(Shared, + "nickname"); + nickname = nickname.replaceAll("'", ""); + bean.setNickname(nickname); + + String sex = SpUtil.getStringSharedPerference(Shared, "sex"); + bean.setSex(sex); + + String city = SpUtil.getStringSharedPerference(Shared, "city"); + bean.setCity(city); + + String province = SpUtil.getStringSharedPerference(Shared, + "province"); + bean.setProvince(province); + + String unionid = SpUtil.getStringSharedPerference(Shared, + "unionid"); + bean.setUnionid(unionid); + + Wxistrue.islogin = true; + + // String sharelogin = "javascript:sharelogin(" + "'" + openid + // + "'" + ",'" + headimgurl + "'" + ",'" + nickname + "'" + // + ",'" + sex + "'" + ",'" + city + "'" + ",'" + // + province + "'" + ",'" + unionid + "'" + ");"; + // webviewjh(sharelogin); + + Gson gson = new Gson(); + String data = gson.toJson(bean); + + // Toast.makeText(weclomeactivity1.this, data, 1).show(); + + Intent result = new Intent(packnameclass, + Uri.parse("content://" + "")); + result.addCategory(Intent.CATEGORY_DEFAULT); + result.putExtra("data", data); + setResult(Activity.RESULT_OK, result); + finish(); + + // Intent result = new Intent(); + // + // // result.setComponent(new + // // ComponentName("com.example.ceshiintent", + // // packnameclass)); + // + // result.putExtra("data", data); + // setResult(Activity.RESULT_OK, result); + // finish(); + + // + // //in.setClassName(MainActivity.this, packnameclass); + // // Intent result = new Intent("com.example.appsend", + // // Uri.parse("content://result_uri")); + // + // in.putExtra("sharelogin", sharelogin); + // //startActivity(in); + // setResult(RESULT_OK, in); + // finish(); + + break; + default: + break; + } + super.handleMessage(msg); + } + }; + RelativeLayout relative1; + private Context mContext; + + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Util.verifyStoragePermissions(this); + if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) { + finish(); + return; + } + + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + /** + * 保持屏幕唤醒 不锁屏 + * + */ + // getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, + // WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + + setContentView(R.layout.welcome); + + CsvFormatStrategy formatStrategy=CsvFormatStrategy.newBuilder() + .tag("niuniu") + .build();//修改默认配置 + Logger.addLogAdapter(new DiskLogAdapter(formatStrategy));//保持日志文件 + Logger.addLogAdapter(new AndroidLogAdapter(){ + @Override + public boolean isLoggable(int priority, @Nullable String tag) { + //s是否开启打印功能 + return false; + } + }); + getclassname(); + + + mContext = this; + UMGameAgent.setDebugMode(true); + UMGameAgent.init(this); + // Deprecated UMGameAgent.setPlayerLevel("LV.01"); + UMGameAgent.setPlayerLevel(1); + // UMGameAgent.setSessionContinueMillis(1000); + // UMGameAgent.startWithConfigure( + // new UMAnalyticsConfig(mContext, "4f83c5d852701564c0000011", "Umeng", + // EScenarioType.E_UM_GAME)); + MobclickAgent.setScenarioType(mContext, EScenarioType.E_UM_NORMAL); + + relative1 = (RelativeLayout) findViewById(R.id.relative1); + Shared = SpUtil.getSharePerference(weclomeactivity1.this); + + api = WXAPIFactory.createWXAPI(this, Constants.APP_ID); + + init1(); + + } + private void getclassname() { + ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); + List runningTasks = manager.getRunningTasks(1); + RunningTaskInfo cinfo = runningTasks.get(0); + ComponentName component = cinfo.topActivity; + System.out.println("current activity is " + component.getClassName()); + apputil.activityname = component.getClassName(); + + } + + /** + * 登录微信 + */ + private void WXLogin() { + + if (!api.isWXAppInstalled()) { + Toast.makeText(weclomeactivity1.this, "您还未安装微信客户端", Toast.LENGTH_LONG).show(); + return; + } + + login(); + + } + + public void login() { + WXEntryActivity.setshareHandler(handler); + api = WXAPIFactory.createWXAPI(weclomeactivity1.this, Constants.APP_ID, + true); + api.registerApp(Constants.APP_ID); + SendAuth.Req req = new SendAuth.Req(); + req.scope = "snsapi_userinfo"; + req.state = "wechat_sdk_demo"; + api.sendReq(req); + + } + + @SuppressLint("InvalidWakeLockTag") + private void init1() { + + /* + * * + * 方法二 + */ + PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); + // m_wklk = pm.newWakeLock + // (PowerManager.ACQUIRE_CAUSES_WAKEUP | + // PowerManager.SCREEN_DIM_WAKE_LOCK, "Tag"); + // + + m_wklk = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "cn"); + + m_wklk.setReferenceCounted(false); + + m_wklk.acquire();// 设置保持唤醒 + + initwebviewutil.getInstance().sethandler(hanler); + + Settingutil.initfile = getAllFilename("gamestart");// 游戏解压之后目录 + + Settingutil.filestart = getAllFilename("gamedir");// 父级目录 + + System.out.println("Settingutil.initfile=" + Settingutil.initfile); + System.out.println("Settingutil.filestart=" + Settingutil.filestart); + + Intent in1 = getIntent(); + if (in1 != null) { + Bundle bundle = in1.getExtras(); + + if (bundle != null) { + packnameclass = bundle.getString("packname"); + System.out.println("packname=" + packnameclass); + + if (!pmutil.isnullorEmpty(packnameclass)) { + Wxistrue.islogin = false;// 暂停授权登陆 + apputil.wxtype = 2; + WXLogin(); + setIntent(null); + + } else { + if (!pmutil.isnullorEmpty(Settingutil.initfile) + && !pmutil.isnullorEmpty(Settingutil.filestart)) { + + init(); + } else { + showMissingsettingDialog(); + + } + + } + + } else { + + if (!pmutil.isnullorEmpty(Settingutil.initfile) + && !pmutil.isnullorEmpty(Settingutil.filestart)) { + + init(); + } else { + showMissingsettingDialog(); + + } + + } + } else { + System.out.println("Intent为空"); + if (!pmutil.isnullorEmpty(Settingutil.initfile) + && !pmutil.isnullorEmpty(Settingutil.filestart)) { + + init(); + } else { + System.out.println("Settingutil.initfile为空"); + showMissingsettingDialog(); + + } + } + + okclient = new OkHttpClient.Builder() + .connectTimeout(20, TimeUnit.SECONDS) + .readTimeout(20, TimeUnit.SECONDS).build(); + + } + + @Override + protected void onDestroy() { + if (m_wklk != null) { + try { + m_wklk.release(); // 解除保持唤醒 + } catch (Exception e) { + // TODO: handle exception + } + + } + super.onDestroy(); + + } + + @Override + protected void onResume() { + + super.onResume(); + if (m_wklk != null) { + m_wklk.acquire(); // 保持唤醒 + } + + MobclickAgent.onPageStart("welcomeactivity1"); + //统计页面(仅有Activity的应用中SDK自动调用,不 + + // 集成基本统计分析,初始化 Session + UMGameAgent.onResume(mContext); + } + + @Override + protected void onPause() { + // TODO Auto-generated method stub + super.onPause(); + if (m_wklk != null) { + try { + m_wklk.release(); // 解除保持唤醒 + } catch (Exception e) { + // TODO: handle exception + } + } + MobclickAgent.onPageEnd("welcomeactivity1"); + // //集成基本统计分析, 结束 Session + UMGameAgent.onPause(mContext); + + } + + private void init() { + relative1.setVisibility(View.VISIBLE); + System.out.println("Settingutil.initfile=" + Settingutil.initfile); + System.out.println("Settingutil.filestart=" + Settingutil.filestart); + String gameconfig = getAllFilename("gameconfig"); + gameconfig = gameconfig.replaceAll("-", "/"); + + if (!pmutil.isnullorEmpty(gameconfig)) { + Gamesettingurl.configofficialurl = "http://" + gameconfig + ".txt"; + System.out.println("Gamesettingurl.configofficialurl=" + + Gamesettingurl.configofficialurl); + } + + + progressBar = (ProgressBar) findViewById(R.id.progressBar1); + m_mainHandler = new Handler(); + inittext = (TextView) findViewById(R.id.inittext); + textView1 = (TextView) findViewById(R.id.textView1); + + if (!hasPermission(permissons)) { + + PermissionGen.needPermission(weclomeactivity1.this, 33, permissons); + } else { + + hanler.sendEmptyMessage(5); + sp = SpUtil.getSharePerference(Myapplication.application); + Boolean istrue = SpUtil.isFirst(sp); + + if (istrue) { + System.out.println("不是第一次"); + + String urlpath1 = SpUtil.getStringSharedPerference(sp, + "upurlpath") + File.separator + Settingutil.filestart; + File file = new File(urlpath1); + + if (file.exists()) { + + versionbean ver = null; + try { + + ver = pullassetxml(getAssets().open( + Settingutil.kfile + File.separator + + "version.xml")); + } catch (IOException e) { + + e.printStackTrace(); + + } + + SpUtil.setStringSharedPerference(sp, "urlpath", urlpath1); + + String urlpath = SpUtil.getStringSharedPerference(sp, + "urlpath"); + + String purl = urlpath + File.separator + + Settingutil.initfile; + + System.out.println("解压目录" + purl); + + File fie = new File(purl); + + if (fie.exists()) { + + System.out.println("----" + purl); + + versionbean versd = pullxml1(purl); + String gameid=getAllFilename("gameid"); + if(!pmutil.isnullorEmpty(gameid)){ + versd.setGameid(gameid); + } + + int assetversion = Integer.parseInt(ver.getVersion()); + + try{ + + if(versd!=null&&!pmutil.isnullorEmpty(versd.getVersion())){ + + int sdversion = Integer.parseInt(versd.getVersion()); + System.out.println("sdversion=" + sdversion); + + System.out.println("assetversion=" + assetversion); + + if (assetversion > sdversion) { + System.out.println("2"); + copyinit(); + + } else { + + copyasset(); + } + + + }else{ + copyinit(); + } + + }catch(Exception e){ + copyinit(); + } + } else { + copyinit(); + } + + } else { + copyinit(); + } + + } else { + copyasset(); + } + + } + + } + + public void copyinit() { + new Thread() { + public void run() { + + initwebviewutil.getInstance().init(); + }; + + }.start(); + } + + public void copyasset() { + new Thread() { + public void run() { + + initwebviewutil.getInstance().isfirst(); + }; + + }.start(); + } + + private void initdailog() { + if (m_progressDlg1 == null) { + m_progressDlg1 = new ProgressDialog(this); + } + m_progressDlg1.setProgressStyle(ProgressDialog.STYLE_SPINNER); + // 设置ProgressDialog 的进度条是否不明确 false 就是不设置为不明确 + m_progressDlg1.setIndeterminate(false); + m_progressDlg1.setCanceledOnTouchOutside(false); + + m_progressDlg1.setTitle("正在初始化…"); + m_progressDlg1.setMessage("请稍候..."); + + if (!weclomeactivity1.this.isFinishing()) { + + m_progressDlg1.show(); + } + + // SHA1: E1:11:0A:7C:D6:81:BC:31:FE:38:61:01:3C:C5:28:97:57:AD:94:FD + // 82:CB:24:28:2B:CB:97:F0:8F:23:78:C7:21:3D:74:D4:74:6B:9F:91 + } + + @PermissionSuccess(requestCode = 33) + public void filstsucces() { + System.out.println("允许"); + + hanler.sendEmptyMessage(5); + copyasset(); + } + + @PermissionFail(requestCode = 33) + public void filstfail() { + + + List nopermission = new ArrayList(); + // String[] nopermission=null; + for (int i = 0; i < permissons.length; i++) { + if (ActivityCompat.shouldShowRequestPermissionRationale(this, + permissons[i])) { + + nopermission.add(permissons[i]); + + // final String permission = carpermission[i]; + // 未勾选不再提示 + + System.out.println("拒绝"); + } else { + // 勾选不再提示 + if (ContextCompat.checkSelfPermission(this, + permissons[i]) == PackageManager.PERMISSION_DENIED) { + showMissingPermissionDialog(); + break; + } + } + } + if (nopermission.size() > 0) { + + final String[] persions = new String[nopermission.size()]; + + for (int i = 0; i < nopermission.size(); i++) { + persions[i] = nopermission.get(i); + } + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("提示"); + builder.setMessage("亲,当前应用缺少必要权限。不打开将无法使用"); + + // 拒绝, 退出应用 + builder.setNegativeButton("退出", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + + } + }); + + builder.setPositiveButton("打开", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + PermissionGen.needPermission(weclomeactivity1.this, + 33, persions); + } + }); + builder.show(); + } + + } + + // 配置缺失提示 + private void showMissingsettingDialog(String title) { + if (!weclomeactivity1.this.isFinishing()) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("提示"); + builder.setMessage(title); + + builder.setPositiveButton("退出", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + builder.setCancelable(false); + builder.show(); + } + + } + + // 配置缺失提示 + private void showMissingsettingDialog() { + runOnUiThread(new Runnable() { + @Override + public void run() { + if (!weclomeactivity1.this.isFinishing()&&hasWindowFocus()) { + System.out.println("有窗口焦点"); + AlertDialog.Builder builder = new AlertDialog.Builder(weclomeactivity1.this); + builder.setTitle("提示"); + builder.setMessage("您好,获取配置信息失败,检查是否连接网络,请重新启动应用"); + + builder.setPositiveButton("退出", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + builder.setCancelable(false); + builder.show(); + }else{ + System.out.println("无窗口焦点"); + + AlertDialog.Builder builder = new AlertDialog.Builder(weclomeactivity1.this); + builder.setTitle("提示"); + builder.setMessage("您好,获取配置信息失败,检查是否连接网络,请重新启动应用"); + + builder.setPositiveButton("退出", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + builder.setCancelable(false); + builder.show(); + } + } + }); + + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + switch (keyCode) { + + case KeyEvent.KEYCODE_BACK: + + dialogexit.show(weclomeactivity1.this, "确定退出", + new onexitlistener() { + @Override + public void paylistener() { + + exitApp(); + } + + @Override + public void cancellistener() { + + } + }); + + return true; + + default: + break; + } + + return super.onKeyDown(keyCode, event); + } + + /** + * 退出程序 + */ + private void exitApp() { + + finish(); + System.exit(0); + } + + // 显示缺失权限提示 + private void showMissingPermissionDialog() { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("提示"); + builder.setMessage("当前应用缺少必要权限。请点击\"设置\"-\"权限\"-打开所需权限。"); + + // 拒绝, 退出应用 + builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + } + }); + + builder.setPositiveButton("设置", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + startAppSettings(); + } + }); + + builder.show(); + } + + // 启动应用的设置 + private void startAppSettings() { + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.parse(PACKAGE_URL_SCHEME + getPackageName())); + startActivity(intent); + } + + private void download() { + + if (apputil.isNetworkConnected(this)) { + sp = SpUtil.getSharePerference(Myapplication.application); + projectpath = SpUtil.getStringSharedPerference(sp, "urlpath"); + + String urls = projectpath + File.separator + Settingutil.initfile + + File.separator + "version.xml"; + + File file = new File(urls); + + if (file.exists()) { + String purl = projectpath + File.separator + + Settingutil.initfile; + jsongame1(); + } else { + handlerend1(); + } + } else { + + AlertDialog.Builder builder = new Builder(this); + builder.setTitle("无法链接网络"); + builder.setMessage("网络错误,请设置网络"); + + builder.setPositiveButton("退出", + new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + // 获取系统版本号 + finish(); + + } + }); + builder.create().show(); + } + + } + + private void jsongame1() { + String url = ""; + url = Gamesettingurl.configofficialurl; + updateapk2(url,1); + } + + private void updateapk2(String url, final int what) { + + url = url + "?a=" + System.currentTimeMillis();//增加随机参数 + System.out.println("url==" + url); + CacheControl.Builder builder = new CacheControl.Builder(); + builder.noCache();// 不使用缓存,全部走网络 + CacheControl cacheControl = builder.build(); + + Request request1 = new Request.Builder().cacheControl(cacheControl) + .url(url).build(); + + Request request = new Request.Builder().url(url).build(); + + okclient.newCall(request1).enqueue(new Callback() { + + @Override + public void onResponse(Call arg0, Response response) + throws IOException { + + System.out.println(response.code() + "ss" + + response.body().toString()); + + if (response.code() == 200) { + + InputStream is = null; + byte[] buf = new byte[1024]; + is = response.body().byteStream(); + StringBuilder sb = new StringBuilder(""); + int lens = 0; + //读取文件内容,当文件内容长度大于0时, + while ((lens = is.read(buf)) > 0) { + //把字条串连接到尾部 + sb.append(new String(buf, 0, lens)); + } + is.close(); + final String s=sb.toString(); + System.out.println("长度="+s.length()); + if (s.length() < 30) { + runOnUiThread(new Runnable() { + @Override + public void run() { + AlertDialog.Builder builder = new AlertDialog.Builder( + weclomeactivity1.this); + builder.setTitle("提示"); + builder.setMessage(s); + builder.setPositiveButton("退出", + new DialogInterface.OnClickListener() { + @Override + public void onClick( + DialogInterface dialog, + int which) { + finish(); + } + }); + builder.show(); + } + }); + } else { + try { + JSONObject json = new JSONObject(s); + System.out.println("---" + json.toString()); + Message msg=new Message(); + msg.what=what; + Bundle bundle=new Bundle(); + bundle.putString("msg",s); + Logger.t("msg").v(s); + msg.setData(bundle); + hanlerq1.sendMessage(msg); + } catch (Exception e) { + e.printStackTrace(); + hanler.sendEmptyMessage(6); + } + } + } else { + hanler.sendEmptyMessage(6); + } + } + + @Override + public void onFailure(Call arg0, IOException arg1) { + System.out.println("获取数据失败"); + hanler.sendEmptyMessage(6); + } + }); + + } + + versionagentlist list1; + Gameversiontxt gameversiontxt; + JsonRootBean mJsonRootBean; + Agentlist magentlist; + Gamelist mgamelist; + + /** + * 提示更新新版本 + */ + private void doNewVersionUpdate(String url) { + System.out.println(url); + try { + downFile(url); // 开始下载 + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void downFile(final String url) { + + new Thread() { + public void run() { + // 替换为OkHttp客户端,修复Apache HttpClient兼容性问题 + if (okclient == null) { + okclient = new OkHttpClient(); + } + + Request request = new Request.Builder().url(url).build(); + + try { + Response response = okclient.newCall(request).execute(); + + if (!response.isSuccessful()) { + throw new IOException("下载失败,HTTP状态码: " + response.code()); + } + + long length = response.body().contentLength(); + if (progressBar != null) { + progressBar.setMax((int) length); + } + + final int sum = (int) length; + + InputStream is = response.body().byteStream(); + FileOutputStream fileOutputStream = null; + + // 在外层声明变量,避免作用域问题 + String apkFilePath = ""; + + if (is != null) { + // 修复:使用应用私有目录,兼容Android 10+的存储限制 + File downloadDir = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "apk"); + if (!downloadDir.exists()) { + downloadDir.mkdirs(); + } + File file = new File(downloadDir, m_appNameStr); + + // 记录文件路径供安装时使用 + apkFilePath = file.getAbsolutePath(); + + fileOutputStream = new FileOutputStream(file); + + byte[] buf = new byte[1024]; + int ch = 0; + int count = 0; + + NumberFormat nf = NumberFormat.getInstance(); + nf.setMaximumFractionDigits(2);// 保留一位小数 + double msum = (sum / 1024.0 / 1024.0); + final String msums = nf.format(msum) + " MB"; + + while ((ch = is.read(buf)) != -1) { + fileOutputStream.write(buf, 0, ch); + + count += ch; + + final int num = count; + + if (length > 0) { + if (progressBar != null) { + progressBar.setProgress(num); + } + + hanler.post(new Runnable() { + @SuppressLint("SetTextI18n") + @Override + public void run() { + NumberFormat nf = NumberFormat.getInstance(); + nf.setMaximumFractionDigits(2);// 保留一位小数 + double num1 = (num / 1024.0 / 1024.0); + final String nums = nf.format(num1) + " MB"; + textView1.setText("" + nums + "/" + msums); + } + }); + } + } + + // 将文件操作移到if块内,确保fileOutputStream不为null + fileOutputStream.flush(); + fileOutputStream.close(); + + // 保存APK文件路径供安装使用 + apkFilePathForInstall = apkFilePath; + + down(); // 告诉HANDER已经下载完成了,可以安装了 + } + + down(); // 告诉HANDER已经下载完成了,可以安装了 + } catch (IOException e) { + e.printStackTrace(); + } + } + }.start(); + } + + /** + * 告诉HANDER已经下载完成了,可以安装了 + */ + private void down() { + + m_mainHandler.post(new Runnable() { + public void run() { + update1(); + } + }); + } + + /** + * 安装程序 - 修复兼容Android 7.0+和10+ + */ + void update1() { + if (apkFilePathForInstall.isEmpty()) { + Toast.makeText(this, "APK文件路径错误", Toast.LENGTH_SHORT).show(); + return; + } + + File apkFile = new File(apkFilePathForInstall); + if (!apkFile.exists()) { + Toast.makeText(this, "APK文件不存在", Toast.LENGTH_SHORT).show(); + return; + } + + // Android 8.0+ 需要检查安装权限 + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + if (!getPackageManager().canRequestPackageInstalls()) { + // 跳转到设置页面开启安装权限 + Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES); + intent.setData(Uri.parse("package:" + getPackageName())); + startActivity(intent); + Toast.makeText(this, "请开启允许安装未知来源应用权限", Toast.LENGTH_LONG).show(); + return; + } + } + + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + // Android 7.0+ 需要使用FileProvider + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + Uri apkUri = android.support.v4.content.FileProvider.getUriForFile( + this, + getPackageName() + ".fileprovider", + apkFile); + intent.setDataAndType(apkUri, "application/vnd.android.package-archive"); + } else { + // Android 6.0及以下使用传统方式 + intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive"); + } + + try { + startActivity(intent); + } catch (Exception e) { + e.printStackTrace(); + Toast.makeText(this, "安装APK失败: " + e.getMessage(), Toast.LENGTH_LONG).show(); + } + //android.os.Process.killProcess(android.os.Process.myPid());// 安装后打开 + } + + public void handlerend1() { + if (progressBar != null) { + progressBar.setMax(100); + progressBar.setProgress(100); + } + + hanler.sendEmptyMessageDelayed(disend, 500); + } + + private void updatezip(String url) { + + try { + run(url); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private OkHttpClient okclient; + protected String destFileDir; + public void run(final String url) { + + Request request = new Request.Builder().url(url).build(); + okclient.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(Call arg0, IOException throwable) { + throwable.printStackTrace(); + + handlerend1(); + } + + @SuppressWarnings("resource") + @Override + public void onResponse(Call arg0, Response response) + throws IOException { + + long length = response.body().contentLength(); + progressBar.setMax((int) length); + + if (!response.isSuccessful()) + throw new IOException("Unexpected code " + response); + Headers responseHeaders = response.headers(); + for (int i = 0; i < responseHeaders.size(); i++) { + System.out.println(responseHeaders.name(i) + ": " + + responseHeaders.value(i)); + } + if (response.code() == 200) { + InputStream is = null; + byte[] buf = new byte[2048]; + int len = 0; + FileOutputStream fos = null; + is = response.body().byteStream(); + destFileDir = Objects.requireNonNull(Myapplication.application.getExternalFilesDir(null)) + .getAbsolutePath() + + File.separator + + "dowlod_zip"; + Log.i("path1", destFileDir); + + File dir = new File(destFileDir); + Log.i("dir",dir.getPath()); + if (!dir.exists()) { + + Boolean rTemp = dir.mkdirs(); + Log.i("mkdir",rTemp.toString()); + } + + final File file = new File(dir, System.currentTimeMillis()+"Projects.zip"); + System.out.println(file.getAbsolutePath()); + fos = new FileOutputStream(file); + int count = 0; + while ((len = is.read(buf)) != -1) { + fos.write(buf, 0, len); + count += len; + if (length > 0) { + progressBar.setProgress(count); + } + } + + fos.flush(); + fos.close(); + + hanler.sendEmptyMessage(4); + try { + new Thread() { + public void run() { + try { + Fileutils.deleteDir(projectpath + File.separator+Settingutil.initfile);//删除当前解压文件 + System.out.println("删除完成"); + }catch(Exception e){ + e.printStackTrace(); + } + + try { + System.out.println("解压"); + ZipUtils.upZipFile1(file, projectpath + File.separator); + + try { + System.out.println("删除destFileDir"); + Fileutils.deleteDir(destFileDir);//删除游戏zip包及文件 + }catch(Exception e){ + e.printStackTrace(); + } + handlerend1(); + } catch (ZipException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + showMissingsettingDialog(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + showMissingsettingDialog(); + } + } + + }.start(); + } catch (Exception e) { + showMissingsettingDialog(); + } + System.out.println(file.getAbsolutePath()); + } else { + showMissingsettingDialog(); + } + } + + }); + } + + private versionbean pullassetxml(InputStream inputStream) { + versionbean version2 = new versionbean(); + try { + XmlPullParser parser = Xml.newPullParser(); + // 2.设置解析的文件流 + parser.setInput(inputStream, "utf-8"); + // 3.得到事件类型(START_DOCUMENT,END_DOCUMENT,START_TAG, END_TAG, + // TEXT, etc.) + int type = parser.getEventType(); + // 一直读到文档结尾 + while (type != XmlPullParser.END_DOCUMENT) { + + switch (type) { + case XmlPullParser.START_TAG: + // 得到标签的名字 + String tag_name = parser.getName(); + if ("agent".equals(tag_name)) { + + String agentid = parser.getAttributeValue(null, "id"); + System.out.println("agentid=" + agentid); + version2.setAgentid(agentid); + + } else if ("game".equals(tag_name)) { + String gameid = parser.getAttributeValue(null, "id"); + System.out.println("gameid=" + gameid); + version2.setGameid(gameid); + } else if ("version".equals(tag_name)) { + + String version = parser + .getAttributeValue(null, "value"); + System.out.println("version=" + version); + version2.setVersion(version); + } + + break; + default: + break; + + } + // 继续往下一个事件解析 + type = parser.next(); + } + + } catch (XmlPullParserException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return version2; + } + + private versionbean pullxml1(String urlpath) { + versionbean version1 = new versionbean(); + try { + File file = new File(urlpath + File.separator + "version.xml"); + + if (file.exists()) { + FileInputStream inputStream = new FileInputStream(file); + // 得到解析器 + XmlPullParser parser = Xml.newPullParser(); + // 2.设置解析的文件流 + parser.setInput(inputStream, "utf-8"); + // 3.得到事件类型(START_DOCUMENT,END_DOCUMENT,START_TAG, END_TAG, + // TEXT, etc.) + int type = parser.getEventType(); + // 一直读到文档结尾 + + + while (type != XmlPullParser.END_DOCUMENT) { + + switch (type) { + case XmlPullParser.START_TAG: + // 得到标签的名字 + String tag_name = parser.getName(); + if ("agent".equals(tag_name)) { + + String agentid = parser.getAttributeValue(null, + "id"); + System.out.println("agentid=" + agentid); + version1.setAgentid(agentid); + // String id = parser.getAttributeValue(0); + // 得到属性值id + } else if ("game".equals(tag_name)) { + String gameid = parser + .getAttributeValue(null, "id"); + System.out.println("gameid=" + gameid); + version1.setGameid(gameid); + } else if ("version".equals(tag_name)) { + + String version = parser.getAttributeValue(null, + "value"); + System.out.println("version=" + version); + version1.setVersion(version); + + } else if ("channel".equals(tag_name)) { + + String channelid = parser.getAttributeValue(null, + "id"); + version1.setChannelid(channelid); + } + + break; + default: + break; + + } + // 继续往下一个事件解析 + type = parser.next(); + } + } + } catch (IOException e) { + e.printStackTrace(); + } catch (XmlPullParserException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return version1; + + } + + public boolean hasPermission(String... permissions) { + for (String permission : permissions) { + if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { + return false; + } + } + return true; + } + + @Override + public void onRequestPermissionsResult(int requestCode, + String[] permissions, int[] grantResults) { + + PermissionGen.onRequestPermissionsResult(this, requestCode, + permissions, grantResults); + } + + public String getFilenametg(String name) { + + String channelname = ""; + System.out.println("name=" + name); + try { + String[] filename = Myapplication.application.getAssets() + .list(name); + + if (filename.length > 0) { + + System.out.println("目录长度" + filename.length); + + for (int i = 0; i < filename.length; i++) { + + System.out.println("=====" + filename[i]); + + if (filename[i].equals("BoolTest.java")) { + String[] filename1 = Myapplication.application + .getAssets().list( + name + File.separator + filename[i]); + System.out.println("0--" + filename1.length); + } else { + + String[] name1 = Myapplication.application.getAssets() + .list(name + File.separator + filename[i]); + System.out.println("name1--" + name1.length); + if(name1.length>=1){ + System.out.println("name1--" + name1[0]); + } + + if (name1.length >= 0) { + channelname = filename[i]; + } + + } + + } + + } else { + System.out.println("找不到目录"); + } + + } catch (IOException e) { + + e.printStackTrace(); + } + + return channelname; + + } + + public String getAllFilename(String name) { + + String channelname = ""; + System.out.println("name=" + name); + try { + String[] filename = Myapplication.application.getAssets() + .list(name); + + if (filename.length > 0) { + + System.out.println("目录长度" + filename.length); + + for (int i = 0; i < filename.length; i++) { + + System.out.println("=====" + filename[i]); + + if (filename[i].equals("BoolTest.java")) { + String[] filename1 = Myapplication.application + .getAssets().list( + name + File.separator + filename[i]); + System.out.println("0--" + filename1.length); + } else { + + String[] name1 = Myapplication.application.getAssets() + .list(name + File.separator + filename[i]); + System.out.println("name1--" + name1.length); + if(name1.length>=1){ + System.out.println("name1--" + name1[0]); + } + + if (name1.length >= 0) { + channelname = filename[i]; + } + + } + + } + + } else { + System.out.println("找不到目录"); + } + + } catch (IOException e) { + + e.printStackTrace(); + } + + return channelname; + + } + + public String getchannelname(String name) { + String channelname = ""; + try { + String[] filename = Myapplication.application.getAssets() + .list(name); + if (filename.length > 0) { + + System.out.println("目录长度" + filename.length); + + for (int i = 0; i < filename.length; i++) { + + System.out.println("=====" + filename[i]); + + if (filename[i].equals("BoolTest.java")) { + + } else { + + if (filename[i].length() > 30) { + channelname = filename[i]; + } + + } + + } + + } + + } catch (IOException e) { + + e.printStackTrace(); + } + + return channelname; + + } + + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/DragVideoinfoBean.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/DragVideoinfoBean.java new file mode 100644 index 0000000..c4d7e6d --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/DragVideoinfoBean.java @@ -0,0 +1,50 @@ +package com.tsgame.tsgame_niuniu.Bean; + +/** + * 作者:YMI on 2017/11/16 15:51 + * 邮箱:18702631465@163.com + * QQ:1078561230 + */ + +public class DragVideoinfoBean { + /** + * uid 当前用户id + */ + private int uid; + + public int getUid() { + return uid; + } + + public void setUid(int uid) { + this.uid = uid; + } + + public boolean isVideoimg() { + return videoimg; + } + + public void setVideoimg(boolean videoimg) { + this.videoimg = videoimg; + } + + public boolean isVoiceimg() { + return voiceimg; + } + + public void setVoiceimg(boolean voiceimg) { + this.voiceimg = voiceimg; + } + + /** + * videoimg 当前用户视频流显示 + + */ + private boolean videoimg; + /** + * voiceimg 当前用户音频流显示 + */ + private boolean voiceimg; + + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/GamePayBean.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/GamePayBean.java new file mode 100644 index 0000000..6f39789 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/GamePayBean.java @@ -0,0 +1,51 @@ +package com.tsgame.tsgame_niuniu.Bean; + +public class GamePayBean { + private String user; + private String body; + private String typeplay; + private String type; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + private String price; + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public String getTypeplay() { + return typeplay; + } + + public void setTypeplay(String typeplay) { + this.typeplay = typeplay; + } + + public String getPrice() { + return price; + } + + public void setPrice(String price) { + this.price = price; + } + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/Gameversiontxt.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/Gameversiontxt.java new file mode 100644 index 0000000..e24672d --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/Gameversiontxt.java @@ -0,0 +1,28 @@ +package com.tsgame.tsgame_niuniu.Bean; + +import java.util.List; + + +public class Gameversiontxt { + private String showmessage; + private List agentlist; + public String getShowmessage() { + return showmessage; + } + public void setShowmessage(String showmessage) { + this.showmessage = showmessage; + } + public List getAgentlist() { + return agentlist; + } + public void setAgentlist(List agentlist) { + this.agentlist = agentlist; + } + @Override + public String toString() { + return "Gameversiontxt [showmessage=" + showmessage + ", agentlist=" + + agentlist + "]"; + } + + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/LianxirenBean.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/LianxirenBean.java new file mode 100644 index 0000000..c8de821 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/LianxirenBean.java @@ -0,0 +1,35 @@ +package com.tsgame.tsgame_niuniu.Bean; + +/** + * 作者:YMI on 2018/5/21 10:11 + * 邮箱:18702631465@163.com + * QQ:1078561230 + */ +public class LianxirenBean { + private String phoneNumber; + private String contactName; + + public String getPhoneNumber() { + return phoneNumber; + } + + public void setPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + } + + @Override + public String toString() { + return "LianxirenBean{" + + "phoneNumber='" + phoneNumber + '\'' + + ", contactName='" + contactName + '\'' + + '}'; + } + + public String getContactName() { + return contactName; + } + + public void setContactName(String contactName) { + this.contactName = contactName; + } +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/MaplocationInfo.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/MaplocationInfo.java new file mode 100644 index 0000000..7f47b3c --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/MaplocationInfo.java @@ -0,0 +1,117 @@ +package com.tsgame.tsgame_niuniu.Bean; + +public class MaplocationInfo { + @Override + public String toString() { + return "MaplocationInfo [latitude=" + latitude + ", longitude=" + + longitude + ", address=" + address + + ", country=" + country + ", province=" + province + ", city=" + + city + ", district=" + district + ", street=" + street + + ", cityCode=" + cityCode + "]"; + } + + private double latitude;//纬度 + + private double longitude;//纬度 + //private double altitude;//海拔 + + private String address;//地址描述 + + private String country;//国家 + private String province;//省份 + + + private String city;//城市 + + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + +// public double getAltitude() { +// return altitude; +// } +// +// public void setAltitude(double altitude) { +// this.altitude = altitude; +// } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getProvince() { + return province; + } + + public void setProvince(String province) { + this.province = province; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getDistrict() { + return district; + } + + public void setDistrict(String district) { + this.district = district; + } + + public String getStreet() { + return street; + } + + public void setStreet(String street) { + this.street = street; + } + + public String getCityCode() { + return cityCode; + } + + public void setCityCode(String cityCode) { + this.cityCode = cityCode; + } + + private String district;//城区 + + + private String street;//街道 + + private String cityCode;//城市编码 + + + + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/Othervideoinfo.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/Othervideoinfo.java new file mode 100644 index 0000000..a9acec4 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/Othervideoinfo.java @@ -0,0 +1,89 @@ +package com.tsgame.tsgame_niuniu.Bean; + +/** + * 作者:YMI on 2017/11/13 16:21 + * 邮箱:18702631465@163.com + * QQ:1078561230 + */ + +public class Othervideoinfo { + private String playerid; + private String left; + + private String top; + private String width; + private String height; + private String pmw; + private String pmh; + + @Override + public String toString() { + return "Othervideoinfo{" + + "playerid='" + playerid + '\'' + + ", left='" + left + '\'' + + ", top='" + top + '\'' + + ", width='" + width + '\'' + + ", height='" + height + '\'' + + ", pmw='" + pmw + '\'' + + ", pmh='" + pmh + '\'' + + '}'; + } + + public String getPmw() { + return pmw; + } + + public void setPmw(String pmw) { + this.pmw = pmw; + } + + public String getPmh() { + return pmh; + } + + public void setPmh(String pmh) { + this.pmh = pmh; + } + + public String getPlayerid() { + return playerid; + } + + public void setPlayerid(String playerid) { + this.playerid = playerid; + } + + public String getLeft() { + return left; + } + + public void setLeft(String left) { + this.left = left; + } + + public String getTop() { + return top; + } + + public void setTop(String top) { + this.top = top; + } + + public String getWidth() { + return width; + } + + public void setWidth(String width) { + this.width = width; + } + + + + public String getHeight() { + return height; + } + + public void setHeight(String height) { + this.height = height; + } +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/Wifinetworkbean.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/Wifinetworkbean.java new file mode 100644 index 0000000..0ba390f --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/Wifinetworkbean.java @@ -0,0 +1,18 @@ +package com.tsgame.tsgame_niuniu.Bean; + +public class Wifinetworkbean { + private int signalLevel; + private String ssid; + public int getSignalLevel() { + return signalLevel; + } + public void setSignalLevel(int signalLevel) { + this.signalLevel = signalLevel; + } + public String getSsid() { + return ssid; + } + public void setSsid(String ssid) { + this.ssid = ssid; + } +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/agentlistTxt.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/agentlistTxt.java new file mode 100644 index 0000000..d198fd9 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/agentlistTxt.java @@ -0,0 +1,40 @@ +package com.tsgame.tsgame_niuniu.Bean; + +import java.util.List; + +public class agentlistTxt { +@Override + public String toString() { + return "agentlistTxt [agentid=" + agentid + ", agentname=" + agentname + + ", showmessage=" + showmessage + ", gamelist=" + gamelist + + "]"; + } +private String agentid; +private String agentname; +private String showmessage; +private List gamelist; +public String getAgentid() { + return agentid; +} +public void setAgentid(String agentid) { + this.agentid = agentid; +} +public String getAgentname() { + return agentname; +} +public void setAgentname(String agentname) { + this.agentname = agentname; +} +public String getShowmessage() { + return showmessage; +} +public void setShowmessage(String showmessage) { + this.showmessage = showmessage; +} +public List getGamelist() { + return gamelist; +} +public void setGamelist(List gamelist) { + this.gamelist = gamelist; +} +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/channellistTxt.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/channellistTxt.java new file mode 100644 index 0000000..5034988 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/channellistTxt.java @@ -0,0 +1,84 @@ +package com.tsgame.tsgame_niuniu.Bean; + +import java.util.List; + +public class channellistTxt { + private String channelid; + private String channelname; + private String showmessage; + private String game_version; + private String game_size; + + public String getGame_zip() { + return game_zip; + } + + public void setGame_zip(String game_zip) { + this.game_zip = game_zip; + } + + private String game_zip; + + public String getGame_version() { + return game_version; + } + + public void setGame_version(String game_version) { + this.game_version = game_version; + } + + public String getGame_size() { + return game_size; + } + + public void setGame_size(String game_size) { + this.game_size = game_size; + } + + private List marketlist; + + public String getChannelid() { + return channelid; + } + + public void setChannelid(String channelid) { + this.channelid = channelid; + } + + public String getChannelname() { + return channelname; + } + + public void setChannelname(String channelname) { + this.channelname = channelname; + } + + public String getShowmessage() { + return showmessage; + } + + public void setShowmessage(String showmessage) { + this.showmessage = showmessage; + } + + public List getMarketlist() { + return marketlist; + } + + public void setMarketlist(List marketlist) { + this.marketlist = marketlist; + } + + @Override + public String toString() { + return "channellistTxt [channelid=" + channelid + ", channelname=" + + channelname + ", showmessage=" + showmessage + + ", game_version=" + game_version + ", game_size=" + game_size + + ", game_zip=" + game_zip + ", marketlist=" + marketlist + "]"; + } + + + + + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/filelistBean.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/filelistBean.java new file mode 100644 index 0000000..5c902df --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/filelistBean.java @@ -0,0 +1,55 @@ +package com.tsgame.tsgame_niuniu.Bean; + +public class filelistBean implements Comparable{ + + private int idx; + + public int getIdx() { + return idx; + } + + public void setIdx(int idx) { + this.idx = idx; + } + + private int type; + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + @Override + public String toString() { + return "filelistBean [idx=" + idx + ", type=" + type + ", download=" + + download + ", savepath=" + savepath + "]"; + } + + public String getDownload() { + return download; + } + + public void setDownload(String download) { + this.download = download; + } + + public String getSavepath() { + return savepath; + } + + public void setSavepath(String savepath) { + this.savepath = savepath; + } + + private String download; + + private String savepath; + + @Override + public int compareTo(filelistBean another) { + return this.getIdx() - another.getIdx(); + } + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/gameinfo.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/gameinfo.java new file mode 100644 index 0000000..72c7aad --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/gameinfo.java @@ -0,0 +1,63 @@ +package com.tsgame.tsgame_niuniu.Bean; + +public class gameinfo { +private String channelid; +private String channelname; +private String ios; +private String version_ios; +private String android; +private String version; + + +public String getChannelid() { + return channelid; +} +public void setChannelid(String channelid) { + this.channelid = channelid; +} +public String getChannelname() { + return channelname; +} +public void setChannelname(String channelname) { + this.channelname = channelname; +} +public String getIos() { + return ios; +} +public void setIos(String ios) { + this.ios = ios; +} +public String getVersion_ios() { + return version_ios; +} +public void setVersion_ios(String version_ios) { + this.version_ios = version_ios; +} +public String getAndroid() { + return android; +} +public void setAndroid(String android) { + this.android = android; +} +public String getVersion() { + return version; +} +public void setVersion(String version) { + this.version = version; +} +public String getGameversion() { + return gameversion; +} +public void setGameversion(String gameversion) { + this.gameversion = gameversion; +} +public String getGamezip() { + return gamezip; +} +public void setGamezip(String gamezip) { + this.gamezip = gamezip; +} +private String gameversion; +private String gamezip; + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/gamelist.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/gamelist.java new file mode 100644 index 0000000..7d8a7f5 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/gamelist.java @@ -0,0 +1,34 @@ +package com.tsgame.tsgame_niuniu.Bean; + +import java.util.List; + +public class gamelist { +public String getGameid() { + return gameid; + } + + public void setGameid(String gameid) { + this.gameid = gameid; + } + + public String getGamename() { + return gamename; + } + + public void setGamename(String gamename) { + this.gamename = gamename; + } + + public List getChannellist() { + return channellist; + } + + public void setChannellist(List channellist) { + this.channellist = channellist; + } + +private String gameid; +private String gamename; + +private List channellist; +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/gamelistTxt.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/gamelistTxt.java new file mode 100644 index 0000000..2fe1faa --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/gamelistTxt.java @@ -0,0 +1,98 @@ +package com.tsgame.tsgame_niuniu.Bean; + +import java.util.List; + +public class gamelistTxt { + private String gameid; + private String gamename; + private String showmessage; + private String game_zip; + private String game_version; + private String game_size; + private String game_image; + + public String getGameid() { + return gameid; + } + + public void setGameid(String gameid) { + this.gameid = gameid; + } + + public String getGamename() { + return gamename; + } + + public void setGamename(String gamename) { + this.gamename = gamename; + } + + public String getShowmessage() { + return showmessage; + } + + public void setShowmessage(String showmessage) { + this.showmessage = showmessage; + } + + public String getGame_zip() { + return game_zip; + } + + public void setGame_zip(String game_zip) { + this.game_zip = game_zip; + } + + public String getGame_version() { + return game_version; + } + + public void setGame_version(String game_version) { + this.game_version = game_version; + } + + public String getGame_size() { + return game_size; + } + + public void setGame_size(String game_size) { + this.game_size = game_size; + } + + public String getGame_image() { + return game_image; + } + + public void setGame_image(String game_image) { + this.game_image = game_image; + } + + public String getGame_description() { + return game_description; + } + + public void setGame_description(String game_description) { + this.game_description = game_description; + } + + public List getChannellist() { + return channellist; + } + + @Override + public String toString() { + return "gamelistTxt [gameid=" + gameid + ", gamename=" + gamename + + ", showmessage=" + showmessage + ", game_zip=" + game_zip + + ", game_version=" + game_version + ", game_size=" + game_size + + ", game_image=" + game_image + ", game_description=" + + game_description + ", channellist=" + channellist + "]"; + } + + public void setChannellist(List channellist) { + this.channellist = channellist; + } + + private String game_description; + private List channellist; + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/logbean.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/logbean.java new file mode 100644 index 0000000..04c959c --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/logbean.java @@ -0,0 +1,52 @@ +package com.tsgame.tsgame_niuniu.Bean; + +public class logbean { + private String agentid; + + private String playerid; + + private String gameid; + private String msg; + + public String getAgentid() { + return agentid; + } + + public void setAgentid(String agentid) { + this.agentid = agentid; + } + + public String getPlayerid() { + return playerid; + } + + public void setPlayerid(String playerid) { + this.playerid = playerid; + } + + public String getGameid() { + return gameid; + } + + public void setGameid(String gameid) { + this.gameid = gameid; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public String getPacket() { + return packet; + } + + public void setPacket(String packet) { + this.packet = packet; + } + + private String packet; +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/marketlistTxt.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/marketlistTxt.java new file mode 100644 index 0000000..c75a530 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/marketlistTxt.java @@ -0,0 +1,117 @@ +package com.tsgame.tsgame_niuniu.Bean; + +public class marketlistTxt { + private String marketid; + private String marketname; + private String showmessage; + + public String getMarketid() { + return marketid; + } + + public void setMarketid(String marketid) { + this.marketid = marketid; + } + + public String getMarketname() { + return marketname; + } + + public void setMarketname(String marketname) { + this.marketname = marketname; + } + + public String getShowmessage() { + return showmessage; + } + + public void setShowmessage(String showmessage) { + this.showmessage = showmessage; + } + + public String getApp_download() { + return app_download; + } + + public void setApp_download(String app_download) { + this.app_download = app_download; + } + + public String getApp_version() { + return app_version; + } + + public void setApp_version(String app_version) { + this.app_version = app_version; + } + + public String getApp_size() { + return app_size; + } + + public void setApp_size(String app_size) { + this.app_size = app_size; + } + + public String getGame_zip() { + return game_zip; + } + + public void setGame_zip(String game_zip) { + this.game_zip = game_zip; + } + + public String getGame_version() { + return game_version; + } + + public void setGame_version(String game_version) { + this.game_version = game_version; + } + + public String getGame_size() { + return game_size; + } + + public void setGame_size(String game_size) { + this.game_size = game_size; + } + + public String getGame_image() { + return game_image; + } + + public void setGame_image(String game_image) { + this.game_image = game_image; + } + + public String getGame_description() { + return game_description; + } + + public void setGame_description(String game_description) { + this.game_description = game_description; + } + + private String app_download; + private String app_version; + private String app_size; + private String game_zip; + + @Override + public String toString() { + return "marketlistTxt [marketid=" + marketid + ", marketname=" + + marketname + ", showmessage=" + showmessage + + ", app_download=" + app_download + ", app_version=" + + app_version + ", app_size=" + app_size + ", game_zip=" + + game_zip + ", game_version=" + game_version + ", game_size=" + + game_size + ", game_image=" + game_image + + ", game_description=" + game_description + "]"; + } + + private String game_version; + private String game_size; + private String game_image; + private String game_description; + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/phoneInfoBean.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/phoneInfoBean.java new file mode 100644 index 0000000..a19d465 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/phoneInfoBean.java @@ -0,0 +1,90 @@ +package com.tsgame.tsgame_niuniu.Bean; + +/** + * 作者:YMI on 2018/4/24 08:36 + * 邮箱:18702631465@163.com + * QQ:1078561230 + */ +public class phoneInfoBean { + private String PhoneVersion;//手机系统版本 + private String PhoneAdresseMAC;//mac 地址 + private String PhoneModel;//手机型号 + + private String PhoneDeviceBrand;//手机品牌 + + private String PhoneProvidersName;//手机服务商信息如 移动,联通 + + public String getPhoneVersion() { + return PhoneVersion; + } + + public void setPhoneVersion(String phoneVersion) { + PhoneVersion = phoneVersion; + } + + public String getPhoneAdresseMAC() { + return PhoneAdresseMAC; + } + + public void setPhoneAdresseMAC(String phoneAdresseMAC) { + PhoneAdresseMAC = phoneAdresseMAC; + } + + public String getPhoneModel() { + return PhoneModel; + } + + public void setPhoneModel(String phoneModel) { + PhoneModel = phoneModel; + } + + public String getPhoneDeviceBrand() { + return PhoneDeviceBrand; + } + + public void setPhoneDeviceBrand(String phoneDeviceBrand) { + PhoneDeviceBrand = phoneDeviceBrand; + } + + public String getPhoneProvidersName() { + return PhoneProvidersName; + } + + public void setPhoneProvidersName(String phoneProvidersName) { + PhoneProvidersName = phoneProvidersName; + } + + public String getPhoneIMEI() { + return PhoneIMEI; + } + + public void setPhoneIMEI(String phoneIMEI) { + PhoneIMEI = phoneIMEI; + } + + private String PhoneIMEI;//手机IMEI + + public String getPhoneIMSI() { + return PhoneIMSI; + } + + public void setPhoneIMSI(String phoneIMSI) { + PhoneIMSI = phoneIMSI; + } + + @Override + public String toString() { + return "phoneInfoBean{" + + "PhoneVersion='" + PhoneVersion + '\'' + + ", PhoneAdresseMAC='" + PhoneAdresseMAC + '\'' + + ", PhoneModel='" + PhoneModel + '\'' + + ", PhoneDeviceBrand='" + PhoneDeviceBrand + '\'' + + ", PhoneProvidersName='" + PhoneProvidersName + '\'' + + ", PhoneIMEI='" + PhoneIMEI + '\'' + + ", PhoneIMSI='" + PhoneIMSI + '\'' + + '}'; + } + + private String PhoneIMSI;//手机IMSI + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/photoBean.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/photoBean.java new file mode 100644 index 0000000..1d15450 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/photoBean.java @@ -0,0 +1,14 @@ +package com.tsgame.tsgame_niuniu.Bean; + +public class photoBean { +private String name; + +public String getName() { + return name; +} + +public void setName(String name) { + this.name = name; +} + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/savephotoURLBean.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/savephotoURLBean.java new file mode 100644 index 0000000..25083da --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/savephotoURLBean.java @@ -0,0 +1,38 @@ +package com.tsgame.tsgame_niuniu.Bean; + +import java.io.Serializable; + +public class savephotoURLBean implements Serializable{ + + + /** + * + */ + private static final long serialVersionUID = -2155795382070526238L; + + private String pid; + + private String photourl; + + public String getPid() { + return pid; + } + + public void setPid(String pid) { + this.pid = pid; + } + + public String getPhotourl() { + return photourl; + } + + @Override + public String toString() { + return "savephotoURLBean [pid=" + pid + ", photourl=" + photourl + "]"; + } + + public void setPhotourl(String photourl) { + this.photourl = photourl; + } + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/sittingversion.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/sittingversion.java new file mode 100644 index 0000000..3a02ce8 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/sittingversion.java @@ -0,0 +1,35 @@ +package com.tsgame.tsgame_niuniu.Bean; + +public class sittingversion { + private String app; + private String route; + private String rpc; + public String getApp() { + return app; + } + public void setApp(String app) { + this.app = app; + } + public String getRoute() { + return route; + } + public void setRoute(String route) { + this.route = route; + } + public String getRpc() { + return rpc; + } + + public logbean getData() { + return data; + } + public void setData(logbean data) { + this.data = data; + } + public void setRpc(String rpc) { + this.rpc = rpc; + } + + private logbean data; + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/userbean.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/userbean.java new file mode 100644 index 0000000..d31a2d8 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/userbean.java @@ -0,0 +1,61 @@ +package com.tsgame.tsgame_niuniu.Bean; + +public class userbean { +private String openid; +private String headimgurl; +private String nickname; + +private String sex; +private String city; +private String province; +private String unionid; +public String getOpenid() { + return openid; +} +public void setOpenid(String openid) { + this.openid = openid; +} +public String getHeadimgurl() { + return headimgurl; +} +public void setHeadimgurl(String headimgurl) { + this.headimgurl = headimgurl; +} +public String getNickname() { + return nickname; +} +public void setNickname(String nickname) { + this.nickname = nickname; +} +public String getSex() { + return sex; +} +public void setSex(String sex) { + this.sex = sex; +} +public String getCity() { + return city; +} +public void setCity(String city) { + this.city = city; +} +public String getProvince() { + return province; +} +public void setProvince(String province) { + this.province = province; +} +public String getUnionid() { + return unionid; +} +public void setUnionid(String unionid) { + this.unionid = unionid; +} +@Override +public String toString() { + return "userbean [openid=" + openid + ", headimgurl=" + headimgurl + + ", nickname=" + nickname + ", sex=" + sex + ", city=" + city + + ", province=" + province + ", unionid=" + unionid + "]"; +} + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/versionagentlist.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/versionagentlist.java new file mode 100644 index 0000000..1f94c04 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/versionagentlist.java @@ -0,0 +1,16 @@ +package com.tsgame.tsgame_niuniu.Bean; + +import java.util.List; + +public class versionagentlist { + private List agentlist; + + public List getAgentlist() { + return agentlist; + } + + public void setAgentlist(List agentlist) { + this.agentlist = agentlist; + } + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/versionagentlistinfo.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/versionagentlistinfo.java new file mode 100644 index 0000000..efd569a --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/versionagentlistinfo.java @@ -0,0 +1,34 @@ +package com.tsgame.tsgame_niuniu.Bean; + +import java.util.List; + +public class versionagentlistinfo { + private String agentid; + private String agentname; + private List gamelist; + + public String getAgentid() { + return agentid; + } + + public void setAgentid(String agentid) { + this.agentid = agentid; + } + + public String getAgentname() { + return agentname; + } + + public void setAgentname(String agentname) { + this.agentname = agentname; + } + + public List getGamelist() { + return gamelist; + } + + public void setGamelist(List gamelist) { + this.gamelist = gamelist; + } + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/versionbean.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/versionbean.java new file mode 100644 index 0000000..664a0f5 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/versionbean.java @@ -0,0 +1,53 @@ +package com.tsgame.tsgame_niuniu.Bean; + +public class versionbean { + private String gameid; + private String version; + private String channelid; + + public String getChannelid() { + return channelid; + } + + public void setChannelid(String channelid) { + this.channelid = channelid; + } + + + + @Override + public String toString() { + return "versionbean [gameid=" + gameid + ", version=" + version + + ", channelid=" + channelid + ", agentid=" + agentid + "]"; + } + + + + private String agentid; + + public String getGameid() { + return gameid; + } + + public void setGameid(String gameid) { + this.gameid = gameid; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getAgentid() { + return agentid; + } + + public void setAgentid(String agentid) { + this.agentid = agentid; + } + + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/videoinfobean.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/videoinfobean.java new file mode 100644 index 0000000..a1ecb07 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean/videoinfobean.java @@ -0,0 +1,108 @@ +package com.tsgame.tsgame_niuniu.Bean; + +public class videoinfobean { +private String playerid; +private String roomid; +private String agentid; +private String gameid; + + public String getGameid() { + return gameid; + } + + public void setGameid(String gameid) { + this.gameid = gameid; + } + + private String left; + private String top; + private String pmw; + private String pmh; + private String width; + private String height; + + public String getLeft() { + return left; + } + + public void setLeft(String left) { + this.left = left; + } + + public String getTop() { + return top; + } + + public void setTop(String top) { + this.top = top; + } + + public String getWidth() { + return width; + } + + public void setWidth(String width) { + this.width = width; + } + + public String getHeight() { + return height; + } + + public void setHeight(String height) { + this.height = height; + } + + @Override + public String toString() { + return "videoinfobean{" + + "playerid='" + playerid + '\'' + + ", roomid='" + roomid + '\'' + + ", agentid='" + agentid + '\'' + + ", gameid='" + gameid + '\'' + + ", left='" + left + '\'' + + ", top='" + top + '\'' + + ", pmw='" + pmw + '\'' + + ", pmh='" + pmh + '\'' + + ", width='" + width + '\'' + + ", height='" + height + '\'' + + '}'; + } + + public String getPmw() { + return pmw; + } + + public void setPmw(String pmw) { + this.pmw = pmw; + } + + public String getPmh() { + return pmh; + } + + public void setPmh(String pmh) { + this.pmh = pmh; + } + + public String getPlayerid() { + return playerid; +} +public void setPlayerid(String playerid) { + this.playerid = playerid; +} + +public String getRoomid() { + return roomid; +} +public void setRoomid(String roomid) { + this.roomid = roomid; +} +public String getAgentid() { + return agentid; +} +public void setAgentid(String agentid) { + this.agentid = agentid; +} + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/Agentlist.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/Agentlist.java new file mode 100644 index 0000000..ad5ed42 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/Agentlist.java @@ -0,0 +1,105 @@ +/** + * Copyright 2019 bejson.com + */ +package com.tsgame.tsgame_niuniu.Bean1; +import java.util.List; + +/** + * Auto-generated: 2019-02-19 15:23:20 + * + * @author bejson.com (i@bejson.com) + * @website http://www.bejson.com/java2pojo/ + */ +public class Agentlist { + + private String agentid; + private String agentname; + private String app_version; + private String app_download; + private String app_size; + private String game_version; + + private String showmessage; + public String getShowmessage() { + return showmessage; + } + + public void setShowmessage(String showmessage) { + this.showmessage = showmessage; + } + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + private String game_size; + private String url; + private List channellist; + public void setAgentid(String agentid) { + this.agentid = agentid; + } + public String getAgentid() { + return agentid; + } + + public void setAgentname(String agentname) { + this.agentname = agentname; + } + public String getAgentname() { + return agentname; + } + + public void setApp_version(String app_version) { + this.app_version = app_version; + } + public String getApp_version() { + return app_version; + } + + public void setApp_download(String app_download) { + this.app_download = app_download; + } + public String getApp_download() { + return app_download; + } + + public void setApp_size(String app_size) { + this.app_size = app_size; + } + public String getApp_size() { + return app_size; + } + + public void setGame_version(String game_version) { + this.game_version = game_version; + } + public String getGame_version() { + return game_version; + } + + private String game_download; + public void setGame_download(String game_download) { + this.game_download = game_download; + } + public String getGame_download() { + return game_download; + } + + public void setGame_size(String game_size) { + this.game_size = game_size; + } + public String getGame_size() { + return game_size; + } + + public void setChannellist(List channellist) { + this.channellist = channellist; + } + public List getChannellist() { + return channellist; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/Channellist.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/Channellist.java new file mode 100644 index 0000000..7d15e9b --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/Channellist.java @@ -0,0 +1,96 @@ +/** + * Copyright 2019 bejson.com + */ +package com.tsgame.tsgame_niuniu.Bean1; +import java.util.List; + +/** + * Auto-generated: 2019-02-19 15:23:20 + * + * @author bejson.com (i@bejson.com) + * @website http://www.bejson.com/java2pojo/ + */ +public class Channellist { + + private String channelid; + private String channelname; + private String app_version; + private String app_download; + private String app_size; + private String game_version; + + private String game_size; + private String showmessage; + public String getShowmessage() { + return showmessage; + } + + public void setShowmessage(String showmessage) { + this.showmessage = showmessage; + } + private List marketlist; + public void setChannelid(String channelid) { + this.channelid = channelid; + } + public String getChannelid() { + return channelid; + } + + public void setChannelname(String channelname) { + this.channelname = channelname; + } + public String getChannelname() { + return channelname; + } + + public void setApp_version(String app_version) { + this.app_version = app_version; + } + public String getApp_version() { + return app_version; + } + + public void setApp_download(String app_download) { + this.app_download = app_download; + } + public String getApp_download() { + return app_download; + } + + public void setApp_size(String app_size) { + this.app_size = app_size; + } + public String getApp_size() { + return app_size; + } + + public void setGame_version(String game_version) { + this.game_version = game_version; + } + public String getGame_version() { + return game_version; + } + + private String game_download; + public void setGame_download(String game_download) { + this.game_download = game_download; + } + public String getGame_download() { + return game_download; + } + + public void setGame_size(String game_size) { + this.game_size = game_size; + } + public String getGame_size() { + return game_size; + } + + public void setMarketlist(List marketlist) { + this.marketlist = marketlist; + } + public List getMarketlist() { + return marketlist; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/ConfigData.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/ConfigData.java new file mode 100644 index 0000000..c6318b9 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/ConfigData.java @@ -0,0 +1,40 @@ +package com.tsgame.tsgame_niuniu.Bean1; + +public class ConfigData { + private String agentid; + private String channelid; + private String marketid; + private String gameid; + + public String getAgentid() { + return agentid; + } + + public void setAgentid(String agentid) { + this.agentid = agentid; + } + + public String getChannelid() { + return channelid; + } + + public void setChannelid(String channelid) { + this.channelid = channelid; + } + + public String getMarketid() { + return marketid; + } + + public void setMarketid(String marketid) { + this.marketid = marketid; + } + + public String getGameid() { + return gameid; + } + + public void setGameid(String gameid) { + this.gameid = gameid; + } +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/Gamelist.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/Gamelist.java new file mode 100644 index 0000000..7778f15 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/Gamelist.java @@ -0,0 +1,105 @@ +/** + * Copyright 2019 bejson.com + */ +package com.tsgame.tsgame_niuniu.Bean1; +import java.util.List; + +/** + * Auto-generated: 2019-02-19 15:23:20 + * + * @author bejson.com (i@bejson.com) + * @website http://www.bejson.com/java2pojo/ + */ +public class Gamelist { + + private String gameid; + private String gamename; + private String url; + private String app_version; + private String app_download; + private String app_size; + private String game_version; + + private String game_size; + + private String showmessage; + public String getShowmessage() { + return showmessage; + } + + public void setShowmessage(String showmessage) { + this.showmessage = showmessage; + } + + private List agentlist; + public void setGameid(String gameid) { + this.gameid = gameid; + } + public String getGameid() { + return gameid; + } + + public void setGamename(String gamename) { + this.gamename = gamename; + } + public String getGamename() { + return gamename; + } + + public void setUrl(String url) { + this.url = url; + } + public String getUrl() { + return url; + } + + public void setApp_version(String app_version) { + this.app_version = app_version; + } + public String getApp_version() { + return app_version; + } + + public void setApp_download(String app_download) { + this.app_download = app_download; + } + public String getApp_download() { + return app_download; + } + + public void setApp_size(String app_size) { + this.app_size = app_size; + } + public String getApp_size() { + return app_size; + } + + public void setGame_version(String game_version) { + this.game_version = game_version; + } + public String getGame_version() { + return game_version; + } + + private String game_download; + public void setGame_download(String game_download) { + this.game_download = game_download; + } + public String getGame_download() { + return game_download; + } + public void setGame_size(String game_size) { + this.game_size = game_size; + } + public String getGame_size() { + return game_size; + } + + public void setAgentlist(List agentlist) { + this.agentlist = agentlist; + } + public List getAgentlist() { + return agentlist; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/JsonRootBean.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/JsonRootBean.java new file mode 100644 index 0000000..b1a9816 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/JsonRootBean.java @@ -0,0 +1,40 @@ +/** + * Copyright 2019 bejson.com + */ +package com.tsgame.tsgame_niuniu.Bean1; + +import java.util.List; + +/** + * Auto-generated: 2019-02-19 16:18:48 + * + * @author bejson.com (i@bejson.com) + * @website http://www.bejson.com/java2pojo/ + */ +public class JsonRootBean { + private String showmessage; + public String getShowmessage() { + return showmessage; + } + + public void setShowmessage(String showmessage) { + this.showmessage = showmessage; + } + + private List agentlist; + private List gamelist; + public void setAgentlist(List agentlist) { + this.agentlist = agentlist; + } + public List getAgentlist() { + return agentlist; + } + + public void setGamelist(List gamelist) { + this.gamelist = gamelist; + } + public List getGamelist() { + return gamelist; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/Marketlist.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/Marketlist.java new file mode 100644 index 0000000..6d41acc --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/Marketlist.java @@ -0,0 +1,98 @@ +/** + * Copyright 2019 bejson.com + */ +package com.tsgame.tsgame_niuniu.Bean1; +import java.util.List; + +/** + * Auto-generated: 2019-02-19 15:23:20 + * + * @author bejson.com (i@bejson.com) + * @website http://www.bejson.com/java2pojo/ + */ +public class Marketlist { + + private String marketid; + private String marketname; + private String app_version; + private String app_download; + private String app_size; + private String game_version; + + private String game_size; + private String showmessage; + + public List getGamelist() { + return gamelist; + } + + public void setGamelist(List gamelist) { + this.gamelist = gamelist; + } + + private List gamelist; + public String getShowmessage() { + return showmessage; + } + + public void setShowmessage(String showmessage) { + this.showmessage = showmessage; + } + + public void setMarketid(String marketid) { + this.marketid = marketid; + } + public String getMarketid() { + return marketid; + } + + public void setMarketname(String marketname) { + this.marketname = marketname; + } + public String getMarketname() { + return marketname; + } + + public void setApp_version(String app_version) { + this.app_version = app_version; + } + public String getApp_version() { + return app_version; + } + + public void setApp_download(String app_download) { + this.app_download = app_download; + } + public String getApp_download() { + return app_download; + } + + public void setApp_size(String app_size) { + this.app_size = app_size; + } + public String getApp_size() { + return app_size; + } + + public void setGame_version(String game_version) { + this.game_version = game_version; + } + public String getGame_version() { + return game_version; + } + private String game_download; + public void setGame_download(String game_download) { + this.game_download = game_download; + } + public String getGame_download() { + return game_download; + } + + public void setGame_size(String game_size) { + this.game_size = game_size; + } + public String getGame_size() { + return game_size; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/gameversionUtil.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/gameversionUtil.java new file mode 100644 index 0000000..26c5708 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Bean1/gameversionUtil.java @@ -0,0 +1,41 @@ +package com.tsgame.tsgame_niuniu.Bean1; + +public class gameversionUtil { + + private String app_version; + private String app_download; + private String game_version; + private String game_download; + + public String getApp_version() { + return app_version; + } + + public void setApp_version(String app_version) { + this.app_version = app_version; + } + + public String getApp_download() { + return app_download; + } + + public void setApp_download(String app_download) { + this.app_download = app_download; + } + + public String getGame_version() { + return game_version; + } + + public void setGame_version(String game_version) { + this.game_version = game_version; + } + + public String getGame_download() { + return game_download; + } + + public void setGame_download(String game_download) { + this.game_download = game_download; + } +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Volley/IamgeCache/DiskLruCache.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Volley/IamgeCache/DiskLruCache.java new file mode 100644 index 0000000..377ff3b --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Volley/IamgeCache/DiskLruCache.java @@ -0,0 +1,953 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.tsgame.tsgame_niuniu.Volley.IamgeCache; + +import java.io.BufferedInputStream; +import java.io.BufferedWriter; +import java.io.Closeable; +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.reflect.Array; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + ****************************************************************************** + * Taken from the JB source code, can be found in: + * libcore/luni/src/main/java/libcore/io/DiskLruCache.java + * or direct link: + * https://android.googlesource.com/platform/libcore/+/android-4.1.1_r1/luni/src/main/java/libcore/io/DiskLruCache.java + ****************************************************************************** + * + * A cache that uses a bounded amount of space on a filesystem. Each cache + * entry has a string key and a fixed number of values. Values are byte + * sequences, accessible as streams or files. Each value must be between {@code + * 0} and {@code Integer.MAX_VALUE} bytes in length. + * + *

The cache stores its data in a directory on the filesystem. This + * directory must be exclusive to the cache; the cache may delete or overwrite + * files from its directory. It is an error for multiple processes to use the + * same cache directory at the same time. + * + *

This cache limits the number of bytes that it will store on the + * filesystem. When the number of stored bytes exceeds the limit, the cache will + * remove entries in the background until the limit is satisfied. The limit is + * not strict: the cache may temporarily exceed it while waiting for files to be + * deleted. The limit does not include filesystem overhead or the cache + * journal so space-sensitive applications should set a conservative limit. + * + *

Clients call {@link #edit} to create or update the values of an entry. An + * entry may have only one editor at one time; if a value is not available to be + * edited then {@link #edit} will return null. + *

    + *
  • When an entry is being created it is necessary to + * supply a full set of values; the empty value should be used as a + * placeholder if necessary. + *
  • When an entry is being edited, it is not necessary + * to supply data for every value; values default to their previous + * value. + *
+ * Every {@link #edit} call must be matched by a call to {@link libcore.io.mywardrobe.data.DiskLruCache.Editor#commit} + * or {@link libcore.io.mywardrobe.data.DiskLruCache.Editor#abort}. Committing is atomic: a read observes the full set + * of values as they were before or after the commit, but never a mix of values. + * + *

Clients call {@link #get} to read a snapshot of an entry. The read will + * observe the value at the time that {@link #get} was called. Updates and + * removals after the call do not impact ongoing reads. + * + *

This class is tolerant of some I/O errors. If files are missing from the + * filesystem, the corresponding entries will be dropped from the cache. If + * an error occurs while writing a cache value, the edit will fail silently. + * Callers should handle other problems by catching {@code IOException} and + * responding appropriately. + */ +public final class DiskLruCache implements Closeable { + static final String JOURNAL_FILE = "journal"; + static final String JOURNAL_FILE_TMP = "journal.tmp"; + static final String MAGIC = "libcore.io.DiskLruCache"; + static final String VERSION_1 = "1"; + static final long ANY_SEQUENCE_NUMBER = -1; + private static final String CLEAN = "CLEAN"; + private static final String DIRTY = "DIRTY"; + private static final String REMOVE = "REMOVE"; + private static final String READ = "READ"; + + private static final Charset UTF_8 = Charset.forName("UTF-8"); + private static final int IO_BUFFER_SIZE = 8 * 1024; + + /* + * This cache uses a journal file named "journal". A typical journal file + * looks like this: + * libcore.io.DiskLruCache + * 1 + * 100 + * 2 + * + * CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054 + * DIRTY 335c4c6028171cfddfbaae1a9c313c52 + * CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342 + * REMOVE 335c4c6028171cfddfbaae1a9c313c52 + * DIRTY 1ab96a171faeeee38496d8b330771a7a + * CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234 + * READ 335c4c6028171cfddfbaae1a9c313c52 + * READ 3400330d1dfc7f3f7f4b8d4d803dfcf6 + * + * The first five lines of the journal form its header. They are the + * constant string "libcore.io.DiskLruCache", the disk cache's version, + * the application's version, the value count, and a blank line. + * + * Each of the subsequent lines in the file is a record of the state of a + * cache entry. Each line contains space-separated values: a state, a key, + * and optional state-specific values. + * o DIRTY lines track that an entry is actively being created or updated. + * Every successful DIRTY action should be followed by a CLEAN or REMOVE + * action. DIRTY lines without a matching CLEAN or REMOVE indicate that + * temporary files may need to be deleted. + * o CLEAN lines track a cache entry that has been successfully published + * and may be read. A publish line is followed by the lengths of each of + * its values. + * o READ lines track accesses for LRU. + * o REMOVE lines track entries that have been deleted. + * + * The journal file is appended to as cache operations occur. The journal may + * occasionally be compacted by dropping redundant lines. A temporary file named + * "journal.tmp" will be used during compaction; that file should be deleted if + * it exists when the cache is opened. + */ + + private final File directory; + private final File journalFile; + private final File journalFileTmp; + private final int appVersion; + private final long maxSize; + private final int valueCount; + private long size = 0; + private Writer journalWriter; + private final LinkedHashMap lruEntries + = new LinkedHashMap(0, 0.75f, true); + private int redundantOpCount; + + /** + * To differentiate between old and current snapshots, each entry is given + * a sequence number each time an edit is committed. A snapshot is stale if + * its sequence number is not equal to its entry's sequence number. + */ + private long nextSequenceNumber = 0; + + /* From java.util.Arrays */ + @SuppressWarnings("unchecked") + private static T[] copyOfRange(T[] original, int start, int end) { + final int originalLength = original.length; // For exception priority compatibility. + if (start > end) { + throw new IllegalArgumentException(); + } + if (start < 0 || start > originalLength) { + throw new ArrayIndexOutOfBoundsException(); + } + final int resultLength = end - start; + final int copyLength = Math.min(resultLength, originalLength - start); + final T[] result = (T[]) Array + .newInstance(original.getClass().getComponentType(), resultLength); + System.arraycopy(original, start, result, 0, copyLength); + return result; + } + + /** + * Returns the remainder of 'reader' as a string, closing it when done. + * 鐏忓敃eader濞翠礁澧挎担娆撳劥閸掑棔浜扴tring鏉╂柨娲栭敍灞肩瑬閸︺劌鐣幋鎰础鐏忓敃eader濞翠礁鍙ч梻顓滐拷 + */ + public static String readFully(Reader reader) throws IOException { + try { + StringWriter writer = new StringWriter(); + char[] buffer = new char[1024]; + int count; + while ((count = reader.read(buffer)) != -1) { + writer.write(buffer, 0, count); + } + return writer.toString(); + } finally { + reader.close(); + } + } + + /** + * Returns the ASCII characters up to but not including the next "\r\n", or + * "\n". + * + * @throws java.io.EOFException if the stream is exhausted before the next newline + * character. + */ + public static String readAsciiLine(InputStream in) throws IOException { + // TODO: support UTF-8 here instead + + StringBuilder result = new StringBuilder(80); + while (true) { + int c = in.read(); + if (c == -1) { + throw new EOFException(); + } else if (c == '\n') { + break; + } + + result.append((char) c); + } + int length = result.length(); + if (length > 0 && result.charAt(length - 1) == '\r') { + result.setLength(length - 1); + } + return result.toString(); + } + + /** + * Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null. + */ + public static void closeQuietly(Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (RuntimeException rethrown) { + throw rethrown; + } catch (Exception ignored) { + } + } + } + + /** + * Recursively delete everything in {@code dir}. + */ + // TODO: this should specify paths as Strings rather than as Files + public static void deleteContents(File dir) throws IOException { + File[] files = dir.listFiles(); + if (files == null) { + throw new IllegalArgumentException("not a directory: " + dir); + } + for (File file : files) { + if (file.isDirectory()) { + deleteContents(file); + } + if (!file.delete()) { + throw new IOException("failed to delete file: " + file); + } + } + } + + /** This cache uses a single background thread to evict entries. */ + private final ExecutorService executorService = new ThreadPoolExecutor(0, 1, + 60L, TimeUnit.SECONDS, new LinkedBlockingQueue()); + private final Callable cleanupCallable = new Callable() { + @Override public Void call() throws Exception { + synchronized (DiskLruCache.this) { + if (journalWriter == null) { + return null; // closed + } + trimToSize(); + if (journalRebuildRequired()) { + rebuildJournal(); + redundantOpCount = 0; + } + } + return null; + } + }; + + private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) { + this.directory = directory; + this.appVersion = appVersion; + this.journalFile = new File(directory, JOURNAL_FILE); + this.journalFileTmp = new File(directory, JOURNAL_FILE_TMP); + this.valueCount = valueCount; + this.maxSize = maxSize; + } + + /** + * Opens the cache in {@code directory}, creating a cache if none exists + * there. + * + * @param directory a writable directory + * @param appVersion + * @param valueCount the number of values per cache entry. Must be positive. + * @param maxSize the maximum number of bytes this cache should use to store + * @throws java.io.IOException if reading or writing the cache directory fails + */ + public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize) + throws IOException { + if (maxSize <= 0) { + throw new IllegalArgumentException("maxSize <= 0"); + } + if (valueCount <= 0) { + throw new IllegalArgumentException("valueCount <= 0"); + } + + // prefer to pick up where we left off + DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); + if (cache.journalFile.exists()) { + try { + cache.readJournal(); + cache.processJournal(); + cache.journalWriter = new BufferedWriter(new FileWriter(cache.journalFile, true), + IO_BUFFER_SIZE); + return cache; + } catch (IOException journalIsCorrupt) { +// System.logW("DiskLruCache " + directory + " is corrupt: " +// + journalIsCorrupt.getMessage() + ", removing"); + cache.delete(); + } + } + + // create a new empty cache + directory.mkdirs(); + cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); + cache.rebuildJournal(); + return cache; + } + + private void readJournal() throws IOException { + InputStream in = new BufferedInputStream(new FileInputStream(journalFile), IO_BUFFER_SIZE); + try { + String magic = readAsciiLine(in); + String version = readAsciiLine(in); + String appVersionString = readAsciiLine(in); + String valueCountString = readAsciiLine(in); + String blank = readAsciiLine(in); + if (!MAGIC.equals(magic) + || !VERSION_1.equals(version) + || !Integer.toString(appVersion).equals(appVersionString) + || !Integer.toString(valueCount).equals(valueCountString) + || !"".equals(blank)) { + throw new IOException("unexpected journal header: [" + + magic + ", " + version + ", " + valueCountString + ", " + blank + "]"); + } + + while (true) { + try { + readJournalLine(readAsciiLine(in)); + } catch (EOFException endOfJournal) { + break; + } + } + } finally { + closeQuietly(in); + } + } + + private void readJournalLine(String line) throws IOException { + String[] parts = line.split(" "); + if (parts.length < 2) { + throw new IOException("unexpected journal line: " + line); + } + + String key = parts[1]; + if (parts[0].equals(REMOVE) && parts.length == 2) { + lruEntries.remove(key); + return; + } + + Entry entry = lruEntries.get(key); + if (entry == null) { + entry = new Entry(key); + lruEntries.put(key, entry); + } + + if (parts[0].equals(CLEAN) && parts.length == 2 + valueCount) { + entry.readable = true; + entry.currentEditor = null; + entry.setLengths(copyOfRange(parts, 2, parts.length)); + } else if (parts[0].equals(DIRTY) && parts.length == 2) { + entry.currentEditor = new Editor(entry); + } else if (parts[0].equals(READ) && parts.length == 2) { + // this work was already done by calling lruEntries.get() + } else { + throw new IOException("unexpected journal line: " + line); + } + } + + /** + * 鐠囥儲鏌熷▔鏇犳暏娴滃骸鍨垫慨瀣吀缁犳ⅴize閻ㄥ嫬銇囩亸蹇ョ礉楠炶泛鍨归梽銈嗘¥閺佸牊鏋冩禒锟? */ + private void processJournal() throws IOException { + deleteIfExists(journalFileTmp); + for (Iterator i = lruEntries.values().iterator(); i.hasNext(); ) { + Entry entry = i.next(); + if (entry.currentEditor == null) { + for (int t = 0; t < valueCount; t++) { + size += entry.lengths[t]; + } + } else { + entry.currentEditor = null; + for (int t = 0; t < valueCount; t++) { + deleteIfExists(entry.getCleanFile(t)); + deleteIfExists(entry.getDirtyFile(t)); + } + i.remove(); + } + } + } + + /** + * Creates a new journal that omits redundant information. This replaces the + * current journal if it exists. + * + */ + private synchronized void rebuildJournal() throws IOException { + if (journalWriter != null) { + journalWriter.close(); + } + + Writer writer = new BufferedWriter(new FileWriter(journalFileTmp), IO_BUFFER_SIZE); + writer.write(MAGIC); + writer.write("\n"); + writer.write(VERSION_1); + writer.write("\n"); + writer.write(Integer.toString(appVersion)); + writer.write("\n"); + writer.write(Integer.toString(valueCount)); + writer.write("\n"); + writer.write("\n"); + + for (Entry entry : lruEntries.values()) { + if (entry.currentEditor != null) { + writer.write(DIRTY + ' ' + entry.key + '\n'); + } else { + writer.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); + } + } + + writer.close(); + journalFileTmp.renameTo(journalFile); + journalWriter = new BufferedWriter(new FileWriter(journalFile, true), IO_BUFFER_SIZE); + } + + private static void deleteIfExists(File file) throws IOException { +// try { +// Libcore.os.remove(file.getPath()); +// } catch (ErrnoException errnoException) { +// if (errnoException.errno != OsConstants.ENOENT) { +// throw errnoException.rethrowAsIOException(); +// } +// } + if (file.exists() && !file.delete()) { + throw new IOException(); + } + } + + /** + * Returns a snapshot of the entry named {@code key}, or null if it doesn't + * exist is not currently readable. If a value is returned, it is moved to + * the head of the LRU queue. + */ + public synchronized Snapshot get(String key) throws IOException { + checkNotClosed(); + validateKey(key); + Entry entry = lruEntries.get(key); + if (entry == null) { + return null; + } + + if (!entry.readable) { + return null; + } + + /* + * Open all streams eagerly to guarantee that we see a single published + * snapshot. If we opened streams lazily then the streams could come + * from different edits. + */ + InputStream[] ins = new InputStream[valueCount]; + try { + for (int i = 0; i < valueCount; i++) { + ins[i] = new FileInputStream(entry.getCleanFile(i)); + } + } catch (FileNotFoundException e) { + // a file must have been deleted manually! + return null; + } + + redundantOpCount++; + journalWriter.append(READ + ' ' + key + '\n'); + if (journalRebuildRequired()) { + executorService.submit(cleanupCallable); + } + + return new Snapshot(key, entry.sequenceNumber, ins); + } + + /** + * Returns an editor for the entry named {@code key}, or null if another + * edit is in progress. + */ + public Editor edit(String key) throws IOException { + return edit(key, ANY_SEQUENCE_NUMBER); + } + + private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException { + checkNotClosed(); + validateKey(key); + Entry entry = lruEntries.get(key); + if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER + && (entry == null || entry.sequenceNumber != expectedSequenceNumber)) { + return null; // snapshot is stale + } + if (entry == null) { + entry = new Entry(key); + lruEntries.put(key, entry); + } else if (entry.currentEditor != null) { + return null; // another edit is in progress + } + + Editor editor = new Editor(entry); + entry.currentEditor = editor; + + // flush the journal before creating files to prevent file leaks + journalWriter.write(DIRTY + ' ' + key + '\n'); + journalWriter.flush(); + return editor; + } + + /** + * Returns the directory where this cache stores its data. + */ + public File getDirectory() { + return directory; + } + + /** + * Returns the maximum number of bytes that this cache should use to store + * its data. + */ + public long maxSize() { + return maxSize; + } + + /** + * Returns the number of bytes currently being used to store the values in + * this cache. This may be greater than the max size if a background + * deletion is pending. + */ + public synchronized long size() { + return size; + } + + private synchronized void completeEdit(Editor editor, boolean success) throws IOException { + Entry entry = editor.entry; + if (entry.currentEditor != editor) { + throw new IllegalStateException(); + } + + // if this edit is creating the entry for the first time, every index must have a value + if (success && !entry.readable) { + for (int i = 0; i < valueCount; i++) { + if (!entry.getDirtyFile(i).exists()) { + editor.abort(); + throw new IllegalStateException("edit didn't create file " + i); + } + } + } + + for (int i = 0; i < valueCount; i++) { + File dirty = entry.getDirtyFile(i); + if (success) { + if (dirty.exists()) { + File clean = entry.getCleanFile(i); + dirty.renameTo(clean); + long oldLength = entry.lengths[i]; + long newLength = clean.length(); + entry.lengths[i] = newLength; + size = size - oldLength + newLength; + } + } else { + deleteIfExists(dirty); + } + } + + redundantOpCount++; + entry.currentEditor = null; + if (entry.readable | success) { + entry.readable = true; + journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); + if (success) { + entry.sequenceNumber = nextSequenceNumber++; + } + } else { + lruEntries.remove(entry.key); + journalWriter.write(REMOVE + ' ' + entry.key + '\n'); + } + + if (size > maxSize || journalRebuildRequired()) { + executorService.submit(cleanupCallable); + } + } + + /** + * We only rebuild the journal when it will halve the size of the journal + * and eliminate at least 2000 ops. + */ + private boolean journalRebuildRequired() { + final int REDUNDANT_OP_COMPACT_THRESHOLD = 2000; + return redundantOpCount >= REDUNDANT_OP_COMPACT_THRESHOLD + && redundantOpCount >= lruEntries.size(); + } + + /** + * Drops the entry for {@code key} if it exists and can be removed. Entries + * actively being edited cannot be removed. + * + * @return true if an entry was removed. + */ + public synchronized boolean remove(String key) throws IOException { + checkNotClosed(); + validateKey(key); + Entry entry = lruEntries.get(key); + if (entry == null || entry.currentEditor != null) { + return false; + } + + for (int i = 0; i < valueCount; i++) { + File file = entry.getCleanFile(i); + if (!file.delete()) { + throw new IOException("failed to delete " + file); + } + size -= entry.lengths[i]; + entry.lengths[i] = 0; + } + + redundantOpCount++; + journalWriter.append(REMOVE + ' ' + key + '\n'); + lruEntries.remove(key); + + if (journalRebuildRequired()) { + executorService.submit(cleanupCallable); + } + + return true; + } + + /** + * Returns true if this cache has been closed. + */ + public boolean isClosed() { + return journalWriter == null; + } + + private void checkNotClosed() { + if (journalWriter == null) { + throw new IllegalStateException("cache is closed"); + } + } + + /** + * Force buffered operations to the filesystem. + */ + public synchronized void flush() throws IOException { + checkNotClosed(); + trimToSize(); + journalWriter.flush(); + } + + /** + * Closes this cache. Stored values will remain on the filesystem. + */ + public synchronized void close() throws IOException { + if (journalWriter == null) { + return; // already closed + } + for (Entry entry : new ArrayList(lruEntries.values())) { + if (entry.currentEditor != null) { + entry.currentEditor.abort(); + } + } + trimToSize(); + journalWriter.close(); + journalWriter = null; + } + + private void trimToSize() throws IOException { + while (size > maxSize) { +// Map.Entry toEvict = lruEntries.eldest(); + final Map.Entry toEvict = lruEntries.entrySet().iterator().next(); + remove(toEvict.getKey()); + } + } + + /** + * Closes the cache and deletes all of its stored values. This will delete + * all files in the cache directory including files that weren't created by + * the cache. + */ + public void delete() throws IOException { + close(); + deleteContents(directory); + } + + private void validateKey(String key) { + if (key.contains(" ") || key.contains("\n") || key.contains("\r")) { + throw new IllegalArgumentException( + "keys must not contain spaces or newlines: \"" + key + "\""); + } + } + + private static String inputStreamToString(InputStream in) throws IOException { + return readFully(new InputStreamReader(in, UTF_8)); + } + + /** + * A snapshot of the values for an entry. + */ + public final class Snapshot implements Closeable { + private final String key; + private final long sequenceNumber; + private final InputStream[] ins; + + private Snapshot(String key, long sequenceNumber, InputStream[] ins) { + this.key = key; + this.sequenceNumber = sequenceNumber; + this.ins = ins; + } + + /** + * Returns an editor for this snapshot's entry, or null if either the + * entry has changed since this snapshot was created or if another edit + * is in progress. + */ + public Editor edit() throws IOException { + return DiskLruCache.this.edit(key, sequenceNumber); + } + + /** + * Returns the unbuffered stream with the value for {@code index}. + */ + public InputStream getInputStream(int index) { + return ins[index]; + } + + /** + * Returns the string value for {@code index}. + */ + public String getString(int index) throws IOException { + return inputStreamToString(getInputStream(index)); + } + + @Override public void close() { + for (InputStream in : ins) { + closeQuietly(in); + } + } + } + + /** + * Edits the values for an entry. + */ + public final class Editor { + private final Entry entry; + private boolean hasErrors; + + private Editor(Entry entry) { + this.entry = entry; + } + + /** + * Returns an unbuffered input stream to read the last committed value, + * or null if no value has been committed. + */ + public InputStream newInputStream(int index) throws IOException { + synchronized (DiskLruCache.this) { + if (entry.currentEditor != this) { + throw new IllegalStateException(); + } + if (!entry.readable) { + return null; + } + return new FileInputStream(entry.getCleanFile(index)); + } + } + + /** + * Returns the last committed value as a string, or null if no value + * has been committed. + */ + public String getString(int index) throws IOException { + InputStream in = newInputStream(index); + return in != null ? inputStreamToString(in) : null; + } + + /** + * Returns a new unbuffered output stream to write the value at + * {@code index}. If the underlying output stream encounters errors + * when writing to the filesystem, this edit will be aborted when + * {@link #commit} is called. The returned output stream does not throw + * IOExceptions. + */ + public OutputStream newOutputStream(int index) throws IOException { + synchronized (DiskLruCache.this) { + if (entry.currentEditor != this) { + throw new IllegalStateException(); + } + return new FaultHidingOutputStream(new FileOutputStream(entry.getDirtyFile(index))); + } + } + + /** + * Sets the value at {@code index} to {@code value}. + */ + public void set(int index, String value) throws IOException { + Writer writer = null; + try { + writer = new OutputStreamWriter(newOutputStream(index), UTF_8); + writer.write(value); + } finally { + closeQuietly(writer); + } + } + + /** + * Commits this edit so it is visible to readers. This releases the + * edit lock so another edit may be started on the same key. + */ + public void commit() throws IOException { + if (hasErrors) { + completeEdit(this, false); + remove(entry.key); // the previous entry is stale + } else { + completeEdit(this, true); + } + } + + /** + * Aborts this edit. This releases the edit lock so another edit may be + * started on the same key. + */ + public void abort() throws IOException { + completeEdit(this, false); + } + + private class FaultHidingOutputStream extends FilterOutputStream { + private FaultHidingOutputStream(OutputStream out) { + super(out); + } + + @Override public void write(int oneByte) { + try { + out.write(oneByte); + } catch (IOException e) { + hasErrors = true; + } + } + + @Override public void write(byte[] buffer, int offset, int length) { + try { + out.write(buffer, offset, length); + } catch (IOException e) { + hasErrors = true; + } + } + + @Override public void close() { + try { + out.close(); + } catch (IOException e) { + hasErrors = true; + } + } + + @Override public void flush() { + try { + out.flush(); + } catch (IOException e) { + hasErrors = true; + } + } + } + } + + private final class Entry { + private final String key; + + /** Lengths of this entry's files. */ + private final long[] lengths; + + /** True if this entry has ever been published */ + private boolean readable; + + /** The ongoing edit or null if this entry is not being edited. */ + private Editor currentEditor; + + /** The sequence number of the most recently committed edit to this entry. */ + private long sequenceNumber; + + private Entry(String key) { + this.key = key; + this.lengths = new long[valueCount]; + } + + public String getLengths() throws IOException { + StringBuilder result = new StringBuilder(); + for (long size : lengths) { + result.append(' ').append(size); + } + return result.toString(); + } + + /** + * Set lengths using decimal numbers like "10123". + */ + private void setLengths(String[] strings) throws IOException { + if (strings.length != valueCount) { + throw invalidLengths(strings); + } + + try { + for (int i = 0; i < strings.length; i++) { + lengths[i] = Long.parseLong(strings[i]); + } + } catch (NumberFormatException e) { + throw invalidLengths(strings); + } + } + + private IOException invalidLengths(String[] strings) throws IOException { + throw new IOException("unexpected journal line: " + Arrays.toString(strings)); + } + + public File getCleanFile(int i) { + return new File(directory, key + "." + i); + } + + public File getDirtyFile(int i) { + return new File(directory, key + "." + i + ".tmp"); + } + } +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Volley/IamgeCache/ImageCacheManager.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Volley/IamgeCache/ImageCacheManager.java new file mode 100644 index 0000000..55075fd --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Volley/IamgeCache/ImageCacheManager.java @@ -0,0 +1,38 @@ +package com.tsgame.tsgame_niuniu.Volley.IamgeCache; + + +import android.app.ActivityManager; +import android.content.Context; +import android.graphics.Bitmap; +import android.support.v4.util.LruCache; + +import com.android.volley.toolbox.ImageLoader; +import com.android.volley.toolbox.ImageLoader.ImageContainer; +import com.android.volley.toolbox.ImageLoader.ImageListener; +import com.game.webgame.network.volleymanager; +import com.jx.jyhd.R; +import com.tsgame.tsgame_niuniu.system.Myapplication; + + +public class ImageCacheManager{ + + + + //getRunTime.maxMemory/8 + private static final int MEMORY_CACHE_MAX_SIZE = 1024*1024*((ActivityManager)Myapplication.application.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass()/8; + private static LruImageCache imageCache = new LruImageCache( + "imagecache", + 1024*1024*30,//外置存储缓存最大值 + MEMORY_CACHE_MAX_SIZE);//内存缓存最大值 + + public static ImageLoader mImagerLoader = new ImageLoader( + volleymanager.getInstance().getmRequestQueue(), + imageCache); + + public static ImageContainer loadImage(String url,ImageLoader.ImageListener listener){ + ImageListener listener1=ImageLoader.getImageListener(null, R.drawable.ic_launcher, R.drawable.ic_launcher); + + return mImagerLoader.get(url, listener); + } + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Volley/IamgeCache/LruImageCache.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Volley/IamgeCache/LruImageCache.java new file mode 100644 index 0000000..ed51543 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Volley/IamgeCache/LruImageCache.java @@ -0,0 +1,188 @@ +package com.tsgame.tsgame_niuniu.Volley.IamgeCache; + + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.graphics.Bitmap; +import android.graphics.Bitmap.CompressFormat; +import android.graphics.BitmapFactory; +import android.os.Build; +import android.os.Environment; +import android.support.v4.util.LruCache; + +import com.android.volley.toolbox.ImageLoader.ImageCache; +import com.tsgame.tsgame_niuniu.Volley.IamgeCache.DiskLruCache.Editor; +import com.tsgame.tsgame_niuniu.system.Myapplication; + +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.MessageDigest; + + +@SuppressLint("NewApi") +public class LruImageCache extends LruCache implements ImageCache { + + + private static String CACHE_DIR_NAME; + private static DiskLruCache mDiskLruCache; + // 重写此方法来衡量每张图片的大小,默认返回图片数量。 + @Override + protected int sizeOf(String key, Bitmap bitmap) { + if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB_MR1){//SDK>=3.1使用的方法不一样 + /** + * SDK的兼容性开发: + * 我们经常碰到高版本使用的方法和低版本使用的方法不一样。 + * 比如:bitmap.getByteCount()在12的api才能调用得到 + * 就应该判断版本号选用不同的方法 + * 如果检测编译都不能通过,则: + * @SuppressLint("NewApi") + * @disable + */ + System.out.println("bitmap.getByteCount()=="+bitmap.getByteCount()/1024/1024); + return bitmap.getByteCount(); + }else{ + System.out.println("bitmap.getRowBytes()*bitmap.getHeight()"+bitmap.getRowBytes()*bitmap.getHeight()); + return bitmap.getRowBytes()*bitmap.getHeight(); + } + } + + public LruImageCache(String cache_dir_name, int discMaxSize,int memoryMaxSize) { + super(memoryMaxSize); + + try { + CACHE_DIR_NAME = cache_dir_name; + //打开缓存目录 + mDiskLruCache = DiskLruCache.open( + getDiskCacheDir(Myapplication.application,CACHE_DIR_NAME), + getAppVersion(Myapplication.application), //版本号,跟app的版本号一直 + 1, //缓存一个文件是否允许同一个文件缓存两个 + discMaxSize);//缓存的最大限制、 + + } catch (Exception e) { + e.printStackTrace(); + } + } + + private int getAppVersion(Context context) { + PackageInfo packageInfo; + try { + packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); + return packageInfo.versionCode; + } catch (NameNotFoundException e) { + e.printStackTrace(); + } + return 1; + } + + private File getDiskCacheDir(Context context, String appLabel) { + + String path;///mnt/sdcard/cache/appLabel + if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ + //sd卡存储(/mnt/sdcard/cache) + path = context.getExternalCacheDir().getPath(); + }else{ + //没有SD卡,缓存到系统存储 + path = context.getCacheDir().getPath(); + } + System.out.println("path=="+path); + + return new File(path+File.separator+appLabel); + } + + @Override + public Bitmap getBitmap(String str) {//str--url + System.out.println("getBitmap--str:"+str); + Bitmap bitmap = null; + bitmap = get(str); + String key = generateKey(str); + //从lrucache内存里面拿图片 + try { + if(bitmap!=null){ + System.out.println("拿到内存缓存"); + //内存里面有图片 + return bitmap; + } + System.out.println("没有内存缓存"); + // 当请求网络图片之前volley会回调该方法判断是否有缓存,有就直接返回,没有就调用网络 + //1.去内存里面拿图片 + //2.磁盘拿图片 + DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key); + + if(snapshot!=null){ + InputStream is = snapshot.getInputStream(0); + bitmap = BitmapFactory.decodeStream(is); + + if(bitmap!=null){ + put(str, bitmap);//缓存到内存里面 + System.out.println("拿到外部缓存"+bitmap); + } + } + return bitmap; + } catch (Exception e) { + e.printStackTrace(); + } + return bitmap; + } + + @Override + public void putBitmap(String str, Bitmap bitmap) { + System.out.println("putBitmap--str:"+str); + + put(str, bitmap); + + String key = generateKey(str); + try { + //缓存到lruCache内部缓存 + System.out.println("保存到内存缓存"); + //当本地没有缓存,请求完网络后,将图片缓存起来 + System.out.println("保存到外部缓存"); + if(mDiskLruCache.get(key)==null){ + Editor edit = mDiskLruCache.edit(key); + + OutputStream os = edit.newOutputStream(0); + boolean compress = bitmap.compress(CompressFormat.PNG, 100, os); + + if(compress){ + edit.commit(); + }else{ + edit.abort(); + } + mDiskLruCache.flush(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static String generateKey(String url){ + String cacheKey = null; + try { + MessageDigest mDigest = MessageDigest.getInstance("MD5"); + mDigest.update(url.getBytes()); + byte[] digest = mDigest.digest(); + //byte转成16进制的字符串(效果:根据url,加密,后生成一串固定长度的字符串) + cacheKey = bytesToHexString(digest); + } catch (Exception e) { + e.printStackTrace(); + } + return cacheKey; + + } + + //byte转成16进制的字符串 + private static String bytesToHexString(byte[] bytes) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < bytes.length; i++) { + String hexString = Integer.toHexString(0xFF & bytes[i]); + if(hexString.length()==1){ + sb.append('0'); + } + sb.append(hexString); + } + return sb.toString(); + } + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/Volley/IamgeCache/LruImagefileCache.java b/app/src/main/java/com/tsgame/tsgame_niuniu/Volley/IamgeCache/LruImagefileCache.java new file mode 100644 index 0000000..e7e26d5 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/Volley/IamgeCache/LruImagefileCache.java @@ -0,0 +1,27 @@ +package com.tsgame.tsgame_niuniu.Volley.IamgeCache; + +import com.android.volley.toolbox.ImageLoader.ImageCache; + +import android.graphics.Bitmap; +import android.support.v4.util.LruCache; + +public class LruImagefileCache extends LruCache implements ImageCache{ + + public LruImagefileCache(int maxSize) { + super(maxSize); + // TODO Auto-generated constructor stub + } + + @Override + public Bitmap getBitmap(String arg0) { + // TODO Auto-generated method stub + return null; + } + + @Override + public void putBitmap(String arg0, Bitmap arg1) { + // TODO Auto-generated method stub + + } + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/buglyutil/BuglyUtil.java b/app/src/main/java/com/tsgame/tsgame_niuniu/buglyutil/BuglyUtil.java new file mode 100644 index 0000000..7114d46 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/buglyutil/BuglyUtil.java @@ -0,0 +1,7 @@ +package com.tsgame.tsgame_niuniu.buglyutil; + +public class BuglyUtil { + public static String appid="4e3658499c";//951614c5cc//e076612c8c + // + public static String appkey="2c6ccff4-63ce-4a99-accc-ee754f621cb8";//866da9fb-cf8d-4f0b-aca1-e106ed46cbee//e16e8705-45b5-433d-9c1e-3f0809d8bb6c +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/permithttps/PermitHttpsUtils.java b/app/src/main/java/com/tsgame/tsgame_niuniu/permithttps/PermitHttpsUtils.java new file mode 100644 index 0000000..15e8f24 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/permithttps/PermitHttpsUtils.java @@ -0,0 +1,210 @@ +package com.tsgame.tsgame_niuniu.permithttps; + + +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +import okhttp3.OkHttpClient; + +/** + * Created by XG on 2017/7/24. + */ + +public class PermitHttpsUtils { + public static class SSLParams { + public javax.net.ssl.SSLSocketFactory sSLSocketFactory; + public X509TrustManager trustManager; + } + + public static SSLParams getSslSocketFactory(InputStream[] certificates, InputStream bksFile, String password) { + SSLParams sslParams = new SSLParams(); + try { + TrustManager[] trustManagers = prepareTrustManager(certificates); + KeyManager[] keyManagers = prepareKeyManager(bksFile, password); + SSLContext sslContext = SSLContext.getInstance("TLS"); + X509TrustManager trustManager; + if (trustManagers != null) { + trustManager = new MyTrustManager(chooseTrustManager(trustManagers)); + } else { + trustManager = new UnSafeTrustManager(); + } + sslContext.init(keyManagers, new TrustManager[]{trustManager}, null); + sslParams.sSLSocketFactory = sslContext.getSocketFactory(); + sslParams.trustManager = trustManager; + return sslParams; + } catch (NoSuchAlgorithmException e) { + throw new AssertionError(e); + } catch (KeyManagementException e) { + throw new AssertionError(e); + } catch (KeyStoreException e) { + throw new AssertionError(e); + } + } + + + public static class UnSafeTrustManager implements X509TrustManager { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new java.security.cert.X509Certificate[]{}; + } + } + + private static TrustManager[] prepareTrustManager(InputStream... certificates) { + if (certificates == null || certificates.length <= 0) return null; + try { + + CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(null); + int index = 0; + for (InputStream certificate : certificates) { + String certificateAlias = Integer.toString(index++); + keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate)); + try { + if (certificate != null) + certificate.close(); + } catch (IOException e) + + { + } + } + TrustManagerFactory trustManagerFactory = null; + + trustManagerFactory = TrustManagerFactory. + getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(keyStore); + + TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); + + return trustManagers; + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (CertificateException e) { + e.printStackTrace(); + } catch (KeyStoreException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + + } + + private static KeyManager[] prepareKeyManager(InputStream bksFile, String password) { + try { + if (bksFile == null || password == null) return null; + + KeyStore clientKeyStore = KeyStore.getInstance("BKS"); + clientKeyStore.load(bksFile, password.toCharArray()); + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(clientKeyStore, password.toCharArray()); + return keyManagerFactory.getKeyManagers(); + + } catch (KeyStoreException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (UnrecoverableKeyException e) { + e.printStackTrace(); + } catch (CertificateException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + private static X509TrustManager chooseTrustManager(TrustManager[] trustManagers) { + for (TrustManager trustManager : trustManagers) { + if (trustManager instanceof X509TrustManager) { + return (X509TrustManager) trustManager; + } + } + return null; + } + + + private static class MyTrustManager implements X509TrustManager { + private X509TrustManager defaultTrustManager; + private X509TrustManager localTrustManager; + + public MyTrustManager(X509TrustManager localTrustManager) throws NoSuchAlgorithmException, KeyStoreException { + TrustManagerFactory var4 = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + var4.init((KeyStore) null); + defaultTrustManager = chooseTrustManager(var4.getTrustManagers()); + this.localTrustManager = localTrustManager; + } + + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + try { + defaultTrustManager.checkServerTrusted(chain, authType); + } catch (CertificateException ce) { + localTrustManager.checkServerTrusted(chain, authType); + } + } + + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + } + + public static void setPermitHttps(OkHttpClient.Builder builder, boolean isBypassAuthen) { + if (isBypassAuthen) { + PermitHttpsUtils.SSLParams sslParams = PermitHttpsUtils.getSslSocketFactory(null, null, null); + builder.sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager); + } else { + SSLContext sslContext = null; + try { + sslContext = SSLContext.getInstance("TLS"); + try { + sslContext.init(null, null, null); + } catch (KeyManagementException e) { + e.printStackTrace(); + } + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + + SSLSocketFactory socketFactory = new Tls12SocketFactory(sslContext.getSocketFactory()); + builder.sslSocketFactory(socketFactory, new PermitHttpsUtils.UnSafeTrustManager()); + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/permithttps/Tls12SocketFactory.java b/app/src/main/java/com/tsgame/tsgame_niuniu/permithttps/Tls12SocketFactory.java new file mode 100644 index 0000000..ed6ba03 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/permithttps/Tls12SocketFactory.java @@ -0,0 +1,67 @@ +package com.tsgame.tsgame_niuniu.permithttps; + + + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; + +/** + * Created by XG on 2017/7/24. + */ + +class Tls12SocketFactory extends SSLSocketFactory { + private static final String[] TLS_SUPPORT_VERSION = {"TLSv1.1", "TLSv1.2"}; + + final SSLSocketFactory delegate; + + public Tls12SocketFactory(SSLSocketFactory base) { + this.delegate = base; + } + + @Override + public String[] getDefaultCipherSuites() { + return delegate.getDefaultCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() { + return delegate.getSupportedCipherSuites(); + } + + @Override + public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { + return patch(delegate.createSocket(s, host, port, autoClose)); + } + + @Override + public Socket createSocket(String host, int port) throws IOException { + return patch(delegate.createSocket(host, port)); + } + + @Override + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { + return patch(delegate.createSocket(host, port, localHost, localPort)); + } + + @Override + public Socket createSocket(InetAddress host, int port) throws IOException { + return patch(delegate.createSocket(host, port)); + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { + return patch(delegate.createSocket(address, port, localAddress, localPort)); + } + + private Socket patch(Socket s) { + if (s instanceof SSLSocket) { + ((SSLSocket) s).setEnabledProtocols(TLS_SUPPORT_VERSION); + } + return s; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/permithttps/UnSafeHostnameVerifier.java b/app/src/main/java/com/tsgame/tsgame_niuniu/permithttps/UnSafeHostnameVerifier.java new file mode 100644 index 0000000..5f00356 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/permithttps/UnSafeHostnameVerifier.java @@ -0,0 +1,16 @@ +package com.tsgame.tsgame_niuniu.permithttps; + + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLSession; + +/** + * Created by XG on 2017/7/24. + */ + +public class UnSafeHostnameVerifier implements HostnameVerifier { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/receiver/PhoneStateBroadCastReceiver.java b/app/src/main/java/com/tsgame/tsgame_niuniu/receiver/PhoneStateBroadCastReceiver.java new file mode 100644 index 0000000..7106a37 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/receiver/PhoneStateBroadCastReceiver.java @@ -0,0 +1,91 @@ +package com.tsgame.tsgame_niuniu.receiver; + + +import android.app.Service; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.telephony.TelephonyManager; +import android.util.Log; + +import com.tagmae.tsgame_erwang.webviewActivity; + +public class PhoneStateBroadCastReceiver extends BroadcastReceiver { + + private static String TAG = "PhoneStateBroadCastReceiver"; + private static boolean mIncomingFlag = false;// + private static String mIncomingNumber = null;//手机号码 + + + + + + private static final int CALL_STATE_IDLE=0;//无任何状态时 + private static final int CALL_STATE_OFFHOOK=1;//接起电话时 + private static final int CALL_STATE_RINGING=2;//电话进来时 + private static final int ACTION_NEW_OUTGOING_CALL=3;//去电 + + /** + * 返回电话状态 + * + * CALL_STATE_IDLE 无任何状态时 + * CALL_STATE_OFFHOOK 接起电话时 + * CALL_STATE_RINGING 电话进来时 + * + */ + + @Override + public void onReceive(Context context, Intent intent) { + int state=0; + + // 如果是拨打电话 + if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) { + + state=ACTION_NEW_OUTGOING_CALL; + + mIncomingFlag = false; + String phoneNumber = intent + .getStringExtra(Intent.EXTRA_PHONE_NUMBER); + Log.i(TAG, "call OUT:" + phoneNumber); + + } else { + // 如果是来电 + TelephonyManager tManager = (TelephonyManager) context + .getSystemService(Service.TELEPHONY_SERVICE); + switch (tManager.getCallState()) { + case TelephonyManager.CALL_STATE_RINGING: + + state=CALL_STATE_RINGING;//响铃 + + mIncomingNumber = intent.getStringExtra("incoming_number"); + + Log.i(TAG, "RINGING :" + mIncomingNumber); + break; + case TelephonyManager.CALL_STATE_OFFHOOK://接电话 + + state=CALL_STATE_OFFHOOK;// + + if (mIncomingFlag) { + Log.i(TAG, "incoming ACCEPT :" + mIncomingNumber); + } + break; + case TelephonyManager.CALL_STATE_IDLE: + state=CALL_STATE_IDLE;//挂断 + + if (mIncomingFlag) { + Log.i(TAG, "incoming IDLE"); + } + break; + } + + } + + Intent mIntent=new Intent(webviewActivity.ACTION_INTENT_RECEIVER); + mIntent.putExtra("message", state); + + context.sendBroadcast(mIntent); + + } + + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/receiver/ScreenListener.java b/app/src/main/java/com/tsgame/tsgame_niuniu/receiver/ScreenListener.java new file mode 100644 index 0000000..7753793 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/receiver/ScreenListener.java @@ -0,0 +1,92 @@ +package com.tsgame.tsgame_niuniu.receiver; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.PowerManager; + +public class ScreenListener { + private Context mContext; + private ScreenBroadcastReceiver mScreenReceiver; + private ScreenStateListener mScreenStateListener; + + public ScreenListener(Context context) { + mContext = context; + mScreenReceiver = new ScreenBroadcastReceiver(); + } + + /** + * screen状态广播接收者 + */ + private class ScreenBroadcastReceiver extends BroadcastReceiver { + private String action = null; + + @Override + public void onReceive(Context context, Intent intent) { + action = intent.getAction(); + if (Intent.ACTION_SCREEN_ON.equals(action)) { // 开屏 + mScreenStateListener.onScreenOn(); + } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { // 锁屏 + mScreenStateListener.onScreenOff(); + } else if (Intent.ACTION_USER_PRESENT.equals(action)) { // 解锁 + mScreenStateListener.onUserPresent(); + } + } + } + + /** + * 开始监听screen状态 + * + * @param listener + */ + public void begin(ScreenStateListener listener) { + mScreenStateListener = listener; + registerListener(); + getScreenState(); + } + + /** + * 获取screen状态 + */ + @SuppressWarnings("deprecation") + private void getScreenState() { + PowerManager manager = (PowerManager) mContext + .getSystemService(Context.POWER_SERVICE); + if (manager.isScreenOn()) { + if (mScreenStateListener != null) { + mScreenStateListener.onScreenOn(); + } + } else { + if (mScreenStateListener != null) { + mScreenStateListener.onScreenOff(); + } + } + } + + /** + * 停止screen状态监听 + */ + public void unregisterListener() { + mContext.unregisterReceiver(mScreenReceiver); + } + + /** + * 启动screen状态广播接收器 + */ + private void registerListener() { + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_SCREEN_ON); + filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(Intent.ACTION_USER_PRESENT); + mContext.registerReceiver(mScreenReceiver, filter); + } + + public interface ScreenStateListener {// 返回给调用者屏幕状态信息 + public void onScreenOn(); + + public void onScreenOff(); + + public void onUserPresent(); + } +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/simcpux/bean/sharetypeBean.java b/app/src/main/java/com/tsgame/tsgame_niuniu/simcpux/bean/sharetypeBean.java new file mode 100644 index 0000000..c88f947 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/simcpux/bean/sharetypeBean.java @@ -0,0 +1,76 @@ +package com.tsgame.tsgame_niuniu.simcpux.bean; + +public class sharetypeBean { + private String sharefriend; + + public String getSharefriend() { + return sharefriend; + } + + + public void setSharefriend(String sharefriend) { + this.sharefriend = sharefriend; + } + + private String type; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + private String webpageUrl; + private String sharetype; + + public String getSharetype() { + return sharetype; + } + + public void setSharetype(String sharetype) { + this.sharetype = sharetype; + } + + private String title; + private String description; + + @Override + public String toString() { + return "sharetypeBean{" + + "sharefriend='" + sharefriend + '\'' + + ", type='" + type + '\'' + + ", webpageUrl='" + webpageUrl + '\'' + + ", sharetype='" + sharetype + '\'' + + ", title='" + title + '\'' + + ", description='" + description + '\'' + + '}'; + } + + public String getWebpageUrl() { + return webpageUrl; + } + + public void setWebpageUrl(String webpageUrl) { + this.webpageUrl = webpageUrl; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + +} + diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/system/CrashHandler.java b/app/src/main/java/com/tsgame/tsgame_niuniu/system/CrashHandler.java new file mode 100644 index 0000000..4858c6c --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/system/CrashHandler.java @@ -0,0 +1,154 @@ +package com.tsgame.tsgame_niuniu.system; + + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.lang.Thread.UncaughtExceptionHandler; +import java.text.SimpleDateFormat; +import java.util.Date; + +import com.game.webgame.view.SpUtil; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Build; +import android.os.Environment; +import android.os.Looper; +import android.util.Log; + +public class CrashHandler implements UncaughtExceptionHandler{ + private static final String TAG = "CrashHandler"; + private static final boolean DEBUG = true; + + private static String PATH = Environment.getExternalStorageDirectory().getPath() + "/CrashTest/log/";//Environment.getExternalStorageDirectory().getPath() + private static final String FILE_NAME = "crash"; + private static final String FILE_NAME_SUFFIX = ".txt"; + + private static CrashHandler sInstance = new CrashHandler(); + private static UncaughtExceptionHandler mDefaultCrashHandler; + private Context mContext; + SharedPreferences share; + + public CrashHandler() { + // TODO Auto-generated constructor stub + } + + public static CrashHandler getInstance(){ + return sInstance; + } + + public void init(Context context){ + mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler(); + Thread.setDefaultUncaughtExceptionHandler(this); + mContext = context.getApplicationContext(); + share=SpUtil.getSharePerference(context); + + } + + //有未被捕获的异常的时候,系统就自动调用这个方法 + @Override + public void uncaughtException(Thread thread, final Throwable ex) { + + + +// new Thread() { +// public void run() { +// Looper.prepare(); +// new AlertDialog.Builder(mContext).setTitle("提示") +// .setCancelable(false).setMessage("抱歉,程序无响应,请重新打开") +// .setNeutralButton("确定",new DialogInterface.OnClickListener() { +// @Override +// public void onClick(DialogInterface dialog, int which) { +// // TODO Auto-generated method stub +// ex.printStackTrace(); +// System.exit(0); +// } +// }).create().show(); +// Looper.loop(); +// }; +// +// }.start(); + + Log.w(TAG, "uncaughtException:"+ex.getMessage()+","+PATH); + + try { + dumpExceptionToSDCard(ex); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + ex.printStackTrace(); + if(mDefaultCrashHandler != null){ + mDefaultCrashHandler.uncaughtException(thread, ex); + }else{ + android.os.Process.killProcess(android.os.Process.myPid()); + } + } + + private void dumpExceptionToSDCard(Throwable ex) throws IOException{ + if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ + if(DEBUG){ + Log.w(TAG, "sdcard unmounted, skip dump exception"); + return; + } + } + File dir= new File(PATH); + if(!dir.exists()){ + dir.mkdirs(); + } + long current = System.currentTimeMillis(); + String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(current)); + String filename="love"+PATH+FILE_NAME + time + FILE_NAME_SUFFIX; + + + + + File file = new File(filename); + SpUtil.setStringSharedPerference(share, "bugfilename",filename); + try { + PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file))); + pw.println(time); + dumpPhoneInfo(pw); + pw.println(); + ex.printStackTrace(pw); + pw.close(); + } catch (NameNotFoundException e) { + Log.e(TAG, "dump crash info failed"); + } + + + } + + private void dumpPhoneInfo(PrintWriter pw) throws NameNotFoundException{ + PackageManager pm = mContext.getPackageManager(); + PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES); + pw.print("App Version: "); + pw.print(pi.versionName); + pw.print('_'); + pw.println(pi.versionCode); + + //Android版本号 + pw.print("OS Version"); + pw.print(Build.VERSION.RELEASE); + pw.print("_"); + pw.println(Build.VERSION.SDK_INT); + + //手机制造商 + pw.print("Vendor: "); + pw.println(Build.MODEL); + + //CPU架构 + pw.print("CPU ABI: "); + pw.println(Build.CPU_ABI); + } + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/system/Gamesettingurl.java b/app/src/main/java/com/tsgame/tsgame_niuniu/system/Gamesettingurl.java new file mode 100644 index 0000000..42c1605 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/system/Gamesettingurl.java @@ -0,0 +1,26 @@ +package com.tsgame.tsgame_niuniu.system; + +public class Gamesettingurl { + /** + * 配置文件测试地址 + */ + public static String configtexturl = ""; + + /** + * 配置文件正式地址 + */ + public static String configofficialurl = ""; + + + /** + * 配置文件测试地址 + */ + public static String configtexturls = ""; + + /** + * 配置文件正式地址 + */ + public static String configofficialurls = ""; + + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/system/Myapplication.java b/app/src/main/java/com/tsgame/tsgame_niuniu/system/Myapplication.java new file mode 100644 index 0000000..3254196 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/system/Myapplication.java @@ -0,0 +1,179 @@ +package com.tsgame.tsgame_niuniu.system; + +import android.app.Activity; +import android.app.Application; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.RequiresApi; +import android.util.Log; + +import com.game.webgame.network.volleymanager; +import com.tencent.bugly.crashreport.CrashReport; +import com.tencent.mm.opensdk.constants.ConstantsAPI; +import com.tencent.mm.opensdk.openapi.IWXAPI; +import com.tencent.mm.opensdk.openapi.WXAPIFactory; +import com.tencent.smtt.sdk.QbSdk; +import com.jx.jyhd.simcpux.Constants; +import com.tsgame.tsgame_niuniu.buglyutil.BuglyUtil; + +import java.lang.ref.WeakReference; +import java.util.LinkedList; +import java.util.List; + +public class Myapplication extends Application { + + public static Myapplication application; + private static Myapplication instance; + public static IWXAPI api; + public static WeakReference mCurrentActivity; + private final List activityList = new LinkedList<>(); + + @RequiresApi(api = Build.VERSION_CODES.ICE_CREAM_SANDWICH) + @Override + public void onCreate() { + super.onCreate(); + + registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { + @Override + public void onActivityCreated (@NonNull Activity activity, Bundle bundle) { + } + + @Override + public void onActivityStarted (@NonNull Activity activity) { + } + + @Override + public void onActivityResumed (@NonNull Activity activity) { + mCurrentActivity = new WeakReference<>(activity); + } + + @Override + public void onActivityPaused (@NonNull Activity activity) { + } + + @Override + public void onActivityStopped (@NonNull Activity activity) { + } + + @Override + public void onActivitySaveInstanceState (@NonNull Activity activity, @NonNull Bundle bundle) { + } + + @Override + public void onActivityDestroyed (@NonNull Activity activity) { + } + }); + + initx5webview(); + wxinit(); + application = this; + // 在这里为应用设置异常处理,然后程序才能获取未处理的异常 + CrashHandler crashHandler = CrashHandler.getInstance(); + crashHandler.init(this); + CrashReport.initCrashReport(getApplicationContext(), BuglyUtil.appid, true); + + volleymanager.getInstance(); + + } + + public static Myapplication getInstance() { + if (null == instance) { + instance = new Myapplication(); + } + return instance; + } + private void initx5webview() { + try { + //搜集本地tbs内核信息并上报服务器,服务器返回结果决定使用哪个内核。 + QbSdk.PreInitCallback cb = new QbSdk.PreInitCallback() { + @Override + public void onViewInitFinished(boolean arg0) { + //x5內核初始化完成的回调,为true表示x5内核加载成功,否则表示x5内核加载失败,会自动切换到系统内核。 + Log.d("initx5webview", " onViewInitFinished is " + arg0); + Log.e("initx5webview","加载内核是否成功:"+arg0); + } + + @Override + public void onCoreInitFinished() { + } + }; // 设置允许移动网络下载内核,确保44286版本能正常下载 + QbSdk.setDownloadWithoutWifi(true); + //x5内核初始化接口 + QbSdk.initX5Environment(getApplicationContext(), cb); + }catch(Exception e){ + Log.d("appx5", String.valueOf(e)); + } + } + + private void wxinit(){ + api = WXAPIFactory.createWXAPI(this, Constants.APP_ID, true); + api.registerApp(Constants.APP_ID); + registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + api.registerApp(Constants.APP_ID); + } + }, new IntentFilter(ConstantsAPI.ACTION_REFRESH_WXAPP)); + } + + //08:CA:91:93:45:D3:C0:B4:76:73:E1:E6:7A:3D:74:C9:3E:B7:A7:11 + public void addActivity(Activity activity) { + activityList.add(activity); + } + + public void exit() { + try { + for (Activity activity : activityList) { + if (activity != null) + activity.finish(); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + activityList.clear(); + android.os.Process.killProcess(android.os.Process.myPid()); + } + } + + @Override + public void onTrimMemory(int level) { + super.onTrimMemory(level); + switch (level) { + //TRIM_MEMORY_UI_HIDDEN 表示应用程序的所有UI界面被隐藏了,即用户点击了Home键或者Back键导致应用的UI界面不可见.这时候应该释放一些资源 + case Activity.TRIM_MEMORY_UI_HIDDEN: + Log.i("TRIM", "onTrimMemory() level=TRIM_MEMORY_UI_HIDDEN"); + break; + //TRIM_MEMORY_RUNNING_MODERATE 表示应用程序正常运行,并且不会被杀掉。但是目前手机的内存已经有点低了,系统可能会开始根据LRU缓存规则来去杀死进程了。 + case Activity.TRIM_MEMORY_RUNNING_MODERATE: + Log.i("TRIM", "onTrimMemory() level=TRIM_MEMORY_RUNNING_MODERATE"); + break; + //TRIM_MEMORY_RUNNING_LOW 表示应用程序正常运行,并且不会被杀掉。但是目前手机的内存已经非常低了,我们应该去释放掉一些不必要的资源以提升系统的性能,同时这也会直接影响到我们应用程序的性能。 + case Activity.TRIM_MEMORY_RUNNING_LOW: + Log.i("TRIM", "onTrimMemory() level=TRIM_MEMORY_RUNNING_LOW"); + break; + //TRIM_MEMORY_RUNNING_CRITICAL 表示应用程序仍然正常运行,但是系统已经根据LRU缓存规则杀掉了大部分缓存的进程了。这个时候我们应当尽可能地去释放任何不必要的资源,不然的话系统可能会继续杀掉所有缓存中的进程,并且开始杀掉一些本来应当保持运行的进程,比如说后台运行的服务。 + case Activity.TRIM_MEMORY_RUNNING_CRITICAL: + Log.i("TRIM", "onTrimMemory() level=TRIM_MEMORY_RUNNING_CRITICAL"); + break; + //当应用程序是缓存的,则会收到以下几种类型的回调: + //TRIM_MEMORY_BACKGROUND 表示手机目前内存已经很低了,系统准备开始根据LRU缓存来清理进程。这个时候我们的程序在LRU缓存列表的最近位置,是不太可能被清理掉的,但这时去释放掉一些比较容易恢复的资源能够让手机的内存变得比较充足,从而让我们的程序更长时间地保留在缓存当中,这样当用户返回我们的程序时会感觉非常顺畅,而不是经历了一次重新启动的过程。 + case Activity.TRIM_MEMORY_BACKGROUND: + Log.i("TRIM", "onTrimMemory() level=TRIM_MEMORY_BACKGROUND"); + break; + //TRIM_MEMORY_MODERATE 表示手机目前内存已经很低了,并且我们的程序处于LRU缓存列表的中间位置,如果手机内存还得不到进一步释放的话,那么我们的程序就有被系统杀掉的风险了。 + case Activity.TRIM_MEMORY_MODERATE: + Log.i("TRIM", "onTrimMemory() level=TRIM_MEMORY_MODERATE"); + break; + //TRIM_MEMORY_COMPLETE 表示手机目前内存已经很低了,并且我们的程序处于LRU缓存列表的最边缘位置,系统会最优先考虑杀掉我们的应用程序,在这个时候应当尽可能地把一切可以释放的东西都进行释放。 + case Activity.TRIM_MEMORY_COMPLETE: + Log.i("TRIM", "onTrimMemory() level=TRIM_MEMORY_COMPLETE"); + break; + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/system/WX_Myurl.java b/app/src/main/java/com/tsgame/tsgame_niuniu/system/WX_Myurl.java new file mode 100644 index 0000000..9742aba --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/system/WX_Myurl.java @@ -0,0 +1,22 @@ +package com.tsgame.tsgame_niuniu.system; + +public class WX_Myurl { + /** + * 获取 access_token + */ + public static String getwxaccess_token = "https://api.weixin.qq.com/sns/oauth2/access_token"; + + /** + * 获取 userinfo + */ + public static String getwxuserinfo = "https://api.weixin.qq.com/sns/userinfo"; + /** + * 刷新 refresh_token + */ + public static String refresh_token = "https://api.weixin.qq.com/sns/oauth2/refresh_token"; + /** + * 锟斤拷锟斤拷锟斤拷权凭证锟斤拷access_token锟斤拷锟角凤拷锟斤拷效 + * + */ + public static String isaccess_token = "https://api.weixin.qq.com/sns/auth"; +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/util/CountDownTimerUtils.java b/app/src/main/java/com/tsgame/tsgame_niuniu/util/CountDownTimerUtils.java new file mode 100644 index 0000000..c3e4b3d --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/util/CountDownTimerUtils.java @@ -0,0 +1,57 @@ +package com.tsgame.tsgame_niuniu.util; + +import android.graphics.Color; +import android.os.CountDownTimer; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.style.ForegroundColorSpan; +import android.widget.TextView; + +/** + * Created by Administrator on 2017/4/24. + */ + +public class CountDownTimerUtils extends CountDownTimer { + private TextView mTextView; + + public CountDownTimerUtils(TextView textView, long millisInFuture, + long countDownInterval) { + super(millisInFuture, countDownInterval); + this.mTextView = textView; + } + + @Override + public void onTick(long millisUntilFinished) { + mTextView.setClickable(false); // 设置不可点击 + mTextView.setText(millisUntilFinished / 1000 + "秒后可重新发送"); // 设置倒计时时间 + // mTextView.setBackgroundResource(R.drawable.bg_identify_code_press); + // //设置按钮为灰色,这时是不能点击的 + + /** + * 超链接 URLSpan 文字背景颜色 BackgroundColorSpan 文字颜色 ForegroundColorSpan 字体大小 + * AbsoluteSizeSpan 粗体、斜体 StyleSpan 删除线 StrikethroughSpan 下划线 + * UnderlineSpan 图片 ImageSpan + * http://blog.csdn.net/ah200614435/article/details/7914459 + */ + SpannableString spannableString = new SpannableString(mTextView + .getText().toString()); // 获取按钮上的文字 + ForegroundColorSpan span = new ForegroundColorSpan(Color.RED); + /** + * public void setSpan(Object what, int start, int end, int flags) { + * 主要是start跟end,start是起始位置,无论中英文,都算一个。 + * 从0开始计算起。end是结束位置,所以处理的文字,包含开始位置,但不包含结束位置。 + */ + spannableString.setSpan(span, 0, 2, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);// 将倒计时的时间设置为红色 + mTextView.setText(spannableString); + + } + + @Override + public void onFinish() { + mTextView.setText("重新获取验证码"); + mTextView.setClickable(true);// 重新获得点击 + // mTextView.setBackgroundResource(R.drawable.bg_identify_code_normal); + // //还原背景色 + + } +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/util/DirTraversal.java b/app/src/main/java/com/tsgame/tsgame_niuniu/util/DirTraversal.java new file mode 100644 index 0000000..f498fc0 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/util/DirTraversal.java @@ -0,0 +1,62 @@ +package com.tsgame.tsgame_niuniu.util; + +import java.io.File; +import java.util.ArrayList; +import java.util.LinkedList; + +public class DirTraversal { + //no recursion 输入所以文件路径 + public static LinkedList listLinkedFiles(String strPath) { + LinkedList list = new LinkedList(); + File dir = new File(strPath); + File file[] = dir.listFiles(); + for (int i = 0; i < file.length; i++) { + if (file[i].isDirectory()) + list.add(file[i]); + else + System.out.println(file[i].getAbsolutePath()); + } + File tmp; + while (!list.isEmpty()) { + tmp = (File) list.removeFirst(); + if (tmp.isDirectory()) { + file = tmp.listFiles(); + if (file == null) + continue; + for (int i = 0; i < file.length; i++) { + if (file[i].isDirectory()) + list.add(file[i]); + else + System.out.println(file[i].getAbsolutePath()); + } + } else { + System.out.println(tmp.getAbsolutePath()); + } + } + return list; + } + + + //recursion + public static ArrayList listFiles(String strPath) { + return refreshFileList(strPath); + } + + public static ArrayList refreshFileList(String strPath) { + ArrayList filelist = new ArrayList(); + File dir = new File(strPath); + File[] files = dir.listFiles(); + + if (files == null) + return null; + for (int i = 0; i < files.length; i++) { + if (files[i].isDirectory()) { + refreshFileList(files[i].getAbsolutePath()); + } else { + if(files[i].getName().toLowerCase().endsWith("zip")) + filelist.add(files[i]); + } + } + return filelist; + } +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/util/DouYinIntentShareUtil.java b/app/src/main/java/com/tsgame/tsgame_niuniu/util/DouYinIntentShareUtil.java new file mode 100644 index 0000000..91ab791 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/util/DouYinIntentShareUtil.java @@ -0,0 +1,1199 @@ +package com.tsgame.tsgame_niuniu.util; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import android.text.TextUtils; +import android.util.Log; +import android.widget.Toast; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +/** + * 抖音分享工具类 - 无需SDK,使用Intent实现 + */ +public class DouYinIntentShareUtil { + + private static final String TAG = "DouYinIntentShareUtil"; + + // 抖音可能的包名列表,不同版本或地区的抖音可能使用不同的包名 + private static final String DOUYIN_PACKAGE_NAME = "com.ss.android.ugc.aweme"; + private static final String DOUYIN_LITE_PACKAGE_NAME = "com.ss.android.ugc.aweme.lite"; + private static final String DOUYIN_GLOBAL_PACKAGE_NAME = "com.zhiliaoapp.musically"; + + // 可能的抖音包名列表 + private static final List DOUYIN_PACKAGES = Arrays.asList( + DOUYIN_PACKAGE_NAME, // 主要抖音包名 + DOUYIN_LITE_PACKAGE_NAME, // 抖音极速版 + DOUYIN_GLOBAL_PACKAGE_NAME // TikTok国际版 + ); + + private static DouYinIntentShareUtil instance; + private final Context mContext; + private DouYinShareCallback mCallback; + + // 缓存已安装的抖音包名 + private String installedDouYinPackage = null; + + private DouYinIntentShareUtil(Context context) { + this.mContext = context.getApplicationContext(); + } + + public static DouYinIntentShareUtil getInstance(Context context) { + if (instance == null && context != null) { + instance = new DouYinIntentShareUtil(context); + } + return instance; + } + + /** + * 设置分享回调 + * @param callback 分享回调 + */ + public void setShareCallback(DouYinShareCallback callback) { + this.mCallback = callback; + } + + /** + * 检查抖音是否已安装 + * @return 是否安装 + */ + public boolean isDouyinInstalled() { + // 如果之前已找到包名,直接返回true + if (installedDouYinPackage != null) { + return true; + } + + // 检查所有可能的抖音包名 + PackageManager pm = mContext.getPackageManager(); + for (String packageName : DOUYIN_PACKAGES) { + boolean installed = false; + try { + // 1. 尝试获取包信息 + pm.getPackageInfo(packageName, 0); + installed = true; + } catch (PackageManager.NameNotFoundException e) { + // 忽略 + } + + // 2. 如果getPackageInfo失败,尝试获取启动Intent + if (!installed) { + try { + if (pm.getLaunchIntentForPackage(packageName) != null) { + installed = true; + } + } catch (Exception e) { + // 忽略 + } + } + + // 3. 尝试查询是否支持分享Intent + if (!installed) { + try { + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); // 抖音通常支持图片和视频,但也可能支持纯文本Intent filter + intent.setPackage(packageName); + List list = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); + if (list != null && list.size() > 0) { + installed = true; + } else { + // 尝试查询视频分享支持 + intent.setType("video/*"); + list = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); + if (list != null && list.size() > 0) { + installed = true; + } + } + } catch (Exception e) { + // 忽略 + } + } + + if (installed) { + // 找到已安装的抖音,缓存包名 + installedDouYinPackage = packageName; + Log.d(TAG, "找到已安装的抖音: " + packageName); + return true; + } + } + + Log.d(TAG, "未找到已安装的抖音应用"); + return false; + } + + /** + * 获取已安装的抖音包名 + * @return 抖音包名,如果未安装则返回默认包名 + */ + private String getInstalledDouYinPackage() { + if (installedDouYinPackage != null) { + return installedDouYinPackage; + } + + // 如果没有缓存,重新检测 + isDouyinInstalled(); + return installedDouYinPackage != null ? installedDouYinPackage : DOUYIN_PACKAGE_NAME; + } + + /** + * 与isDouyinInstalled方法功能相同,保持兼容性 + * @return 是否安装抖音 + */ + public boolean isDouYinInstalled() { + // 在鸿蒙卓易通环境下,不建议过于依赖此检测,分享时建议尝试直接拉起 + return isDouyinInstalled(); + } + + /** + * 通过各种方法尝试启动抖音应用 + * @param activity 活动上下文 + * @return 是否成功启动 + */ + private boolean tryLaunchDouyin(Activity activity) { + try { + String packageName = getInstalledDouYinPackage(); + Log.d(TAG, "尝试启动抖音,包名: " + packageName); + + // 方法0:最稳妥的Intent Chooser方式(适配鸿蒙卓易通) + try { + // 如果是单纯想打开抖音,我们可以构造一个简单的VIEW Intent或者MAIN Intent + // 但如果是为了分享,建议直接调用shareToPrivateMessage等方法 + // 这里仅作为启动应用的逻辑 + Intent intent = activity.getPackageManager().getLaunchIntentForPackage(packageName); + if (intent == null) { + // 如果获取不到LaunchIntent,构建通用启动Intent + intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_LAUNCHER); + intent.setPackage(packageName); + } + + if (intent != null) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); // 卓易通关键flag + activity.startActivity(intent); + return true; + } + } catch (Exception e) { + Log.e(TAG, "启动抖音失败: " + e.getMessage()); + final String msg = "启动抖音失败: " + e.getMessage(); + activity.runOnUiThread(() -> Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show()); + } + + // 方法1:使用标准启动方式 (旧逻辑保留) + Intent launchIntent = activity.getPackageManager().getLaunchIntentForPackage(packageName); + if (launchIntent != null) { + launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + activity.startActivity(launchIntent); + Log.d(TAG, "成功使用标准方式启动抖音"); + activity.runOnUiThread(() -> Toast.makeText(activity, "标准方式启动成功", Toast.LENGTH_SHORT).show()); + return true; + } + + // 方法2:使用ACTION_MAIN + CATEGORY_LAUNCHER + try { + Intent mainIntent = new Intent(Intent.ACTION_MAIN); + mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); + mainIntent.setPackage(packageName); + + List resolveInfoList = + activity.getPackageManager().queryIntentActivities(mainIntent, 0); + if (resolveInfoList != null && !resolveInfoList.isEmpty()) { + android.content.pm.ResolveInfo resolveInfo = resolveInfoList.get(0); + String className = resolveInfo.activityInfo.name; + + Intent componentIntent = new Intent(Intent.ACTION_MAIN); + componentIntent.addCategory(Intent.CATEGORY_LAUNCHER); + componentIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + componentIntent.setComponent(new ComponentName(packageName, className)); + + activity.startActivity(componentIntent); + Log.d(TAG, "成功使用组件方式启动抖音"); + return true; + } + } catch (Exception e) { + Log.e(TAG, "方法2失败: " + e.getMessage()); + } + + // 尝试所有可能的抖音URI schemes + String[] schemes = { + "snssdk1128://", // 原有scheme + "aweme://", // 原有scheme + "douyin://", // 新增scheme + "douyinlite://", // 抖音极速版scheme + "snssdk1128://feed", // 带路径的scheme + "aweme://feed", // 带路径的scheme + "douyin://feed", // 带路径的scheme + "snssdk1128://home/trending", // 热门页 + "douyin://home/trending", // 热门页 + "snssdk1128://post", // 发布页 + "douyin://post" // 发布页 + }; + + for (String scheme : schemes) { + try { + Intent schemeIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(scheme)); + schemeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + // 如果设置包名,可以确保只打开抖音应用 + schemeIntent.setPackage(packageName); + activity.startActivity(schemeIntent); + Log.d(TAG, "成功使用scheme方式启动抖音: " + scheme); + return true; + } catch (Exception e) { + Log.e(TAG, "scheme方式失败 " + scheme + ": " + e.getMessage()); + // 继续尝试下一个scheme + } + } + + // 方法4:尝试使用系统VIEW处理 + try { + Intent viewIntent = new Intent(Intent.ACTION_VIEW); + viewIntent.setData(Uri.parse("https://www.douyin.com")); + viewIntent.setPackage(packageName); + viewIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + activity.startActivity(viewIntent); + Log.d(TAG, "成功使用Web链接方式启动抖音"); + return true; + } catch (Exception e) { + Log.e(TAG, "Web链接方式失败: " + e.getMessage()); + } + + Log.e(TAG, "所有启动抖音的方法均失败"); + return false; + } catch (Exception e) { + Log.e(TAG, "启动抖音过程中发生异常: " + e.getMessage(), e); + return false; + } + } + + /** + * 分享纯文本到抖音 + * @param activity 活动 + * @param text 要分享的文本 + */ + public void shareTextToDouyin(Activity activity, String text) { + // 在鸿蒙卓易通环境下,避免过早报错,尝试强制分享 + boolean isPackageDetected = isDouyinInstalled(); + + try { + // 使用兼容方式复制到剪贴板,作为兜底 + try { + copyToClipboard(activity, text); + } catch (Exception e) { + // 忽略 + } + + String packageName = getInstalledDouYinPackage(); + boolean launched = false; + + // 方法1:优先尝试系统Intent Chooser,这是最可靠的方式 + try { + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_TEXT, text); + + // 鸿蒙/卓易通关键适配Flags + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + + if (isPackageDetected) { + intent.setPackage(packageName); + activity.startActivity(intent); + launched = true; + } else { + // 没检测到包名,更可以尝试Chooser + Intent chooser = Intent.createChooser(intent, "分享到抖音"); + chooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + activity.startActivity(chooser); + launched = true; + } + Log.d(TAG, "成功启动文本分享"); + activity.runOnUiThread(() -> Toast.makeText(activity, "成功启动文本分享", Toast.LENGTH_SHORT).show()); + } catch (Exception e) { + Log.e(TAG, "启动文本分享失败: " + e.getMessage()); + final String msg = "启动文本分享失败: " + e.getMessage(); + activity.runOnUiThread(() -> Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show()); + } + + // 方法2:如果分享Intent失败,尝试仅启动应用 + if (!launched) { + launched = tryLaunchDouyin(activity); + } + + if (launched) { + Toast.makeText(activity, "已将内容复制到剪贴板,请在抖音中粘贴并分享", Toast.LENGTH_LONG).show(); + + // 假设分享成功 + if (mCallback != null) { + new Handler(Looper.getMainLooper()).postDelayed(() -> { + mCallback.onSuccess(); + }, 1000); + } + return; + } + + // 如果所有方法都失败了,尝试使用系统分享菜单 + Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setType("text/plain"); + shareIntent.putExtra(Intent.EXTRA_TEXT, text); + + Intent chooser = Intent.createChooser(shareIntent, "分享到"); + activity.startActivity(chooser); + Toast.makeText(activity, "请从分享列表中选择抖音", Toast.LENGTH_SHORT).show(); + + if (mCallback != null) { + new Handler(Looper.getMainLooper()).postDelayed(() -> { + mCallback.onSuccess(); + }, 1000); + } + } catch (Exception e) { + Log.e(TAG, "分享过程中出现异常: " + e.getMessage(), e); + handleShareException(activity, e); + } + } + + /** + * 分享图片到抖音 + * @param activity 活动 + * @param localImagePath 本地图片路径 + */ + public void shareImageToDouyin(Activity activity, String localImagePath) { + // 在鸿蒙卓易通环境下,避免过早报错,尝试强制分享 + boolean isPackageDetected = isDouyinInstalled(); + + File imageFile = new File(localImagePath); + if (!imageFile.exists()) { + Toast.makeText(activity, "分享图片不存在", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-2, "图片文件不存在"); + } + return; + } + + try { + String packageName = getInstalledDouYinPackage(); + + // 创建分享Intent + Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setType("image/*"); + + // 根据Android版本使用不同的Uri方式 + Uri imageUri; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + // Android 7.0及以上使用FileProvider + imageUri = FileProviderUtil.getUriForFile(activity, imageFile); + shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } else { + // Android 7.0以下直接使用文件Uri + imageUri = Uri.fromFile(imageFile); + } + + shareIntent.putExtra(Intent.EXTRA_STREAM, imageUri); + + // 鸿蒙/卓易通关键适配Flags + shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + shareIntent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // 确保Flags也被设置在Intent上 + + + boolean launched = false; + + if (isPackageDetected) { + try { + Intent directIntent = new Intent(shareIntent); + directIntent.setPackage(packageName); + activity.startActivity(directIntent); + launched = true; + Log.d(TAG, "已发送分享图片Intent到抖音"); + final String successMsg = "已发送分享图片Intent到抖音"; + activity.runOnUiThread(() -> Toast.makeText(activity, successMsg, Toast.LENGTH_SHORT).show()); + } catch (Exception e) { + Log.e(TAG, "直接分享到抖音失败: " + e.getMessage()); + final String failMsg = "直接分享失败: " + e.getMessage(); + activity.runOnUiThread(() -> Toast.makeText(activity, failMsg, Toast.LENGTH_SHORT).show()); + } + } + + if (!launched) { + try { + Intent cleanIntent = new Intent(Intent.ACTION_SEND); + cleanIntent.setType("image/*"); + cleanIntent.putExtra(Intent.EXTRA_STREAM, imageUri); + cleanIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + + // 使用系统Chooser + Intent chooserIntent = Intent.createChooser(cleanIntent, "分享到抖音"); + chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + chooserIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + activity.startActivity(chooserIntent); + launched = true; + Log.d(TAG, "使用System Chooser分享图片"); + activity.runOnUiThread(() -> Toast.makeText(activity, "尝试使用System Chooser", Toast.LENGTH_SHORT).show()); + } catch (Exception e) { + Log.e(TAG, "Chooser分享失败: " + e.getMessage()); + final String failMsg2 = "Chooser失败: " + e.getMessage(); + activity.runOnUiThread(() -> Toast.makeText(activity, failMsg2, Toast.LENGTH_SHORT).show()); + } + } + + if (launched) { + // 延迟回调成功 + if (mCallback != null) { + new Handler(Looper.getMainLooper()).postDelayed(() -> { + mCallback.onSuccess(); + }, 1000); + } + } + // 如果launched为false,前面已经弹出了Toast,这里不再重复提示"请检查抖音是否安装" + // else { ... } + + } catch (Exception e) { + Log.e(TAG, "分享图片到抖音失败: " + e.getMessage(), e); + handleShareException(activity, e); + } + } + + /** + * 分享多张图片到抖音 + * @param activity 活动 + * @param imagePaths 图片路径列表 + */ + public void shareImagesToDouyin(Activity activity, ArrayList imagePaths) { + // boolean isDouyinInstalled = isDouyinInstalled(); // Relaxed check + + if (imagePaths == null || imagePaths.isEmpty()) { + Toast.makeText(activity, "分享图片为空", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-1, "分享图片为空"); + } + return; + } + + try { + ArrayList imageUris = new ArrayList<>(); + for (String path : imagePaths) { + File file = new File(path); + if (file.exists()) { + // 根据Android版本使用不同的Uri方式 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + // Android 7.0及以上使用FileProvider + Uri fileUri = FileProviderUtil.getUriForFile(activity, file); + imageUris.add(fileUri); + } else { + // Android 7.0以下直接使用文件Uri + imageUris.add(Uri.fromFile(file)); + } + } + } + + if (imageUris.isEmpty()) { + Toast.makeText(activity, "没有有效图片可分享", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-1, "没有有效图片可分享"); + } + return; + } + + Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE); + intent.setType("image/*"); + intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris); + + // 鸿蒙/卓易通关键适配Flags + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } + + boolean launched = false; + String packageName = getInstalledDouYinPackage(); + + // 1. 尝试直接定向分享 + try { + Intent directIntent = new Intent(intent); + directIntent.setPackage(packageName); + activity.startActivity(directIntent); + launched = true; + activity.runOnUiThread(() -> Toast.makeText(activity, "多图直接分享成功", Toast.LENGTH_SHORT).show()); + } catch (Exception e) { + Log.d(TAG, "直接分享多图失败,转为系统分享: " + e.getMessage()); + final String msg = "直接分享多图失败: " + e.getMessage(); + activity.runOnUiThread(() -> Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show()); + } + + // 2. 失败则使用Chooser (无包名限制) + if (!launched) { + try { + startShareActivity(activity, intent); + activity.runOnUiThread(() -> Toast.makeText(activity, "尝试System Share多图", Toast.LENGTH_SHORT).show()); + } catch (Exception e) { + Log.e(TAG, "多图System Share失败: " + e.getMessage()); + final String msg2 = "多图System Share失败: " + e.getMessage(); + activity.runOnUiThread(() -> Toast.makeText(activity, msg2, Toast.LENGTH_SHORT).show()); + + Intent chooser = Intent.createChooser(intent, "分享到抖音"); + chooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + activity.startActivity(chooser); + } + } + } catch (Exception e) { + handleShareException(activity, e); + } + } + + /** + * 分享Bitmap到抖音 + * @param activity 活动 + * @param bitmap 位图 + */ + public void shareBitmapToDouyin(Activity activity, Bitmap bitmap) { + if (bitmap == null) { + Toast.makeText(activity, "分享图片为空", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-1, "分享图片为空"); + } + return; + } + + // 直接在此类中实现保存Bitmap到临时文件的功能,避免依赖外部工具类 + try { + File cacheDir = activity.getExternalCacheDir(); + if (cacheDir == null) { + cacheDir = activity.getCacheDir(); + } + + File imageFile = new File(cacheDir, "douyin_share_" + UUID.randomUUID().toString() + ".jpg"); + FileOutputStream fos = new FileOutputStream(imageFile); + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos); + fos.flush(); + fos.close(); + + // 保存成功,分享图片 + shareImageToDouyin(activity, imageFile.getAbsolutePath()); + } catch (Exception e) { + Toast.makeText(activity, "保存图片失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-2, "保存图片失败: " + e.getMessage()); + } + } + } + + /** + * 分享视频到抖音 + * @param activity 活动 + * @param videoPath 视频路径 + */ + public void shareVideoToDouyin(Activity activity, String videoPath) { + // 在鸿蒙卓易通环境下,避免过早报错,尝试强制分享 + boolean isPackageDetected = isDouyinInstalled(); + + File videoFile = new File(videoPath); + if (!videoFile.exists()) { + Toast.makeText(activity, "视频文件不存在", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-2, "视频文件不存在"); + } + return; + } + + try { + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("video/*"); + + // 鸿蒙/卓易通关键适配Flags + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + + // 根据Android版本使用不同的Uri方式 + Uri videoUri; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + // Android 7.0及以上使用FileProvider + videoUri = FileProviderUtil.getUriForFile(activity, videoFile); + intent.putExtra(Intent.EXTRA_STREAM, videoUri); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } else { + // Android 7.0以下直接使用文件Uri + videoUri = Uri.fromFile(videoFile); + intent.putExtra(Intent.EXTRA_STREAM, videoUri); + } + + boolean launched = false; + + if (isPackageDetected) { + try { + Intent directIntent = new Intent(intent); + String packageName = getInstalledDouYinPackage(); + directIntent.setPackage(packageName); + startShareActivity(activity, directIntent); + launched = true; + Log.d(TAG, "已发送分享视频Intent到抖音"); + activity.runOnUiThread(() -> Toast.makeText(activity, "已发送分享视频Intent到抖音", Toast.LENGTH_SHORT).show()); + } catch (Exception e) { + Log.e(TAG, "直接分享视频到抖音失败: " + e.getMessage()); + final String failMsg = "直接分享视频失败: " + e.getMessage(); + activity.runOnUiThread(() -> Toast.makeText(activity, failMsg, Toast.LENGTH_SHORT).show()); + } + } + + if (!launched) { + try { + Intent cleanIntent = new Intent(Intent.ACTION_SEND); + cleanIntent.setType("video/*"); + cleanIntent.putExtra(Intent.EXTRA_STREAM, videoUri); + cleanIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + + // 使用系统Chooser + Intent chooserIntent = Intent.createChooser(cleanIntent, "分享视频到抖音"); + chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + chooserIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + activity.startActivity(chooserIntent); + launched = true; + Log.d(TAG, "使用System Chooser分享视频"); + activity.runOnUiThread(() -> Toast.makeText(activity, "尝试使用System Chooser分享视频", Toast.LENGTH_SHORT).show()); + } catch (Exception e) { + Log.e(TAG, "Chooser分享视频失败: " + e.getMessage()); + final String failMsg2 = "Chooser视频失败: " + e.getMessage(); + activity.runOnUiThread(() -> Toast.makeText(activity, failMsg2, Toast.LENGTH_SHORT).show()); + } + } + + if (launched) { + // 延迟回调成功 + if (mCallback != null) { + new Handler(Looper.getMainLooper()).postDelayed(() -> { + mCallback.onSuccess(); + }, 1000); + } + } + // 失败时已由Catch块提示,不再重复显示通用错误 + // else { ... } + + } catch (Exception e) { + handleShareException(activity, e); + } + } + + /** + * 分享网页链接到抖音 + * 抖音不支持直接分享网页,只能通过文本方式 + * @param activity 活动 + * @param title 标题 + * @param description 描述 + * @param webUrl 网页链接 + */ + public void shareWebPageToDouyin(Activity activity, String title, String description, String webUrl) { + // Strict check removed + + // 抖音只能通过文本方式分享网页链接 + StringBuilder sb = new StringBuilder(); + if (!TextUtils.isEmpty(title)) { + sb.append(title).append("\n\n"); + } + if (!TextUtils.isEmpty(description)) { + sb.append(description).append("\n\n"); + } + if (!TextUtils.isEmpty(webUrl)) { + sb.append(webUrl); + } + + shareTextToDouyin(activity, sb.toString()); + } + + /** + * 分享网页链接到抖音 + * @param activity 活动 + * @param url 要分享的网页链接 + * @param title 分享标题,可选 + * @param description 分享描述,可选 + */ + public void shareWebpageToDouyin(Activity activity, String url, String title, String description) { + // Strict check removed + + if (TextUtils.isEmpty(url)) { + Toast.makeText(activity, "分享链接不能为空", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-1, "分享链接不能为空"); + } + return; + } + + try { + String packageName = getInstalledDouYinPackage(); + + // 构建完整分享内容 + StringBuilder shareContent = new StringBuilder(); + if (!TextUtils.isEmpty(title)) { + shareContent.append(title).append("\n"); + } + if (!TextUtils.isEmpty(description)) { + shareContent.append(description).append("\n"); + } + shareContent.append(url); + + // 复制到剪贴板,便于用户在抖音中粘贴 + copyToClipboard(activity, shareContent.toString()); + + // 方法1: 尝试使用系统分享直接发送到抖音 + Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setPackage(packageName); // 指定只分享到抖音 + shareIntent.setType("text/plain"); + shareIntent.putExtra(Intent.EXTRA_TEXT, shareContent.toString()); + + try { + activity.startActivity(shareIntent); + Log.d(TAG, "已发送网页分享Intent到抖音"); + + // 延迟回调成功 + if (mCallback != null) { + new Handler(Looper.getMainLooper()).postDelayed(() -> { + mCallback.onSuccess(); + }, 1000); + } + return; + } catch (android.content.ActivityNotFoundException e) { + Log.e(TAG, "直接分享网页到抖音失败,尝试替代方法: " + e.getMessage()); + } + + // 方法2: 如果直接分享失败,尝试使用VIEW操作打开抖音分享页面 + try { + // 抖音支持的分享scheme,尝试不同的形式 + String[] shareSchemes = { + "snssdk1128://share?content=" + Uri.encode(shareContent.toString()), + "douyin://share?content=" + Uri.encode(shareContent.toString()), + "aweme://share?content=" + Uri.encode(shareContent.toString()) + }; + + for (String scheme : shareSchemes) { + try { + Intent schemeIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(scheme)); + schemeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + schemeIntent.setPackage(packageName); + activity.startActivity(schemeIntent); + Log.d(TAG, "成功使用scheme方式分享网页到抖音: " + scheme); + + // 延迟回调成功 + if (mCallback != null) { + new Handler(Looper.getMainLooper()).postDelayed(() -> { + mCallback.onSuccess(); + }, 1000); + } + return; + } catch (Exception schemeEx) { + Log.e(TAG, "scheme方式分享失败 " + scheme + ": " + schemeEx.getMessage()); + // 继续尝试下一个scheme + } + } + } catch (Exception e) { + Log.e(TAG, "scheme分享过程中出现异常: " + e.getMessage()); + } + + // 方法3: 如果前两种方法都失败,启动抖音并提示用户手动粘贴分享 + boolean launched = tryLaunchDouyin(activity); + if (launched) { + Toast.makeText(activity, "已将链接复制到剪贴板,请在抖音中粘贴并分享", Toast.LENGTH_LONG).show(); + + // 假设分享成功 + if (mCallback != null) { + new Handler(Looper.getMainLooper()).postDelayed(() -> { + mCallback.onSuccess(); + }, 1000); + } + return; + } + + // 方法4: 如果启动抖音也失败,尝试使用系统分享选择器 + Intent chooserIntent = Intent.createChooser(shareIntent.setPackage(null), "分享到"); + activity.startActivity(chooserIntent); + Toast.makeText(activity, "请从分享列表中选择抖音", Toast.LENGTH_SHORT).show(); + + // 假设分享成功 + if (mCallback != null) { + new Handler(Looper.getMainLooper()).postDelayed(() -> { + mCallback.onSuccess(); + }, 1000); + } + + } catch (Exception e) { + Log.e(TAG, "分享网页过程中出现异常: " + e.getMessage(), e); + handleShareException(activity, e); + } + } + + + + /** + * 启动分享Activity - 不再直接调用,使用系统分享菜单代替 + */ + private void startShareActivity(Activity activity, Intent intent) { + try { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + // 创建选择器并提示用户选择抖音 + Intent chooser = Intent.createChooser(intent, "分享到抖音"); + activity.startActivity(chooser); + Toast.makeText(activity, "请从列表中选择抖音", Toast.LENGTH_SHORT).show(); + + // 假设分享成功 + if (mCallback != null) { + new Handler(Looper.getMainLooper()).postDelayed(() -> { + mCallback.onSuccess(); + }, 1000); + } + } catch (Exception e) { + handleShareException(activity, e); + } + } + + /** + * 处理未安装抖音的情况 + */ + private void handleNotInstalled(Activity activity) { + Toast.makeText(activity, "请先安装抖音客户端", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-1, "未安装抖音客户端"); + } + } + + /** + * 处理分享异常 + */ + private void handleShareException(Activity activity, Exception e) { + Toast.makeText(activity, "分享失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-3, "分享失败: " + e.getMessage()); + } + } + + /** + * 处理抖音分享结果回调 + * @param req 请求对象 + * @param resp 响应对象 + */ + public void handleShareResult(Object req, Object resp) { + if (resp == null) { + return; + } + + try { + // 尝试通过反射获取状态码 + int errorCode = -1; + String errorMsg = "未知错误"; + + try { + // 尝试从响应对象获取状态码和错误信息 + Class respClass = resp.getClass(); + java.lang.reflect.Field errCodeField = respClass.getDeclaredField("errCode"); + java.lang.reflect.Field errStrField = respClass.getDeclaredField("errStr"); + + errCodeField.setAccessible(true); + errStrField.setAccessible(true); + + errorCode = (int) errCodeField.get(resp); + errorMsg = (String) errStrField.get(resp); + } catch (Exception e) { + // 反射失败,尝试通过toString()方法解析响应信息 + String respStr = resp.toString(); + if (respStr.contains("errCode=")) { + try { + int startIndex = respStr.indexOf("errCode=") + 8; + int endIndex = respStr.indexOf(",", startIndex); + if (endIndex < 0) { + endIndex = respStr.indexOf("}", startIndex); + } + if (endIndex > startIndex) { + errorCode = Integer.parseInt(respStr.substring(startIndex, endIndex).trim()); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + + // 根据错误码处理不同的结果 + if (errorCode == 0) { + // 分享成功 + if (mCallback != null) { + mCallback.onSuccess(); + } + } else if (errorCode == -2) { + // 用户取消 + if (mCallback != null) { + mCallback.onCancel(); + } + } else { + // 分享失败 + if (mCallback != null) { + mCallback.onError(errorCode, errorMsg); + } + } + } catch (Exception e) { + e.printStackTrace(); + if (mCallback != null) { + mCallback.onError(-1, "处理分享结果异常: " + e.getMessage()); + } + } + } + + /** + * 分享内容到抖音私信 + * @param activity 活动上下文 + * @param content 要分享的内容 + * @param mediaUri 要分享的媒体Uri (可为null) + * @param mediaType 媒体类型 ("image"或"video",仅在mediaUri不为null时有效) + * @return 是否成功启动分享 + */ + public boolean shareToPrivateMessage(Activity activity, String content, Uri mediaUri, String mediaType) { + // Strict check removed for HarmonyOS compatibility + // if (!isDouyinInstalled()) { + // handleNotInstalled(activity); + // return false; + // } + + try { + // 简化处理:将文本复制到剪贴板 + if (content != null && !content.isEmpty()) { + copyToClipboard(activity, content); + Toast.makeText(activity, "内容已复制到剪贴板,请在抖音中粘贴发送", Toast.LENGTH_LONG).show(); + } + + // 直接启动抖音主应用 + boolean launched = tryLaunchDouyin(activity); + if (launched) { + // 成功启动,提示用户操作步骤 + Toast.makeText(activity, "请点击抖音底部\"消息\"按钮,选择联系人并粘贴内容", Toast.LENGTH_LONG).show(); + + // 假设操作成功 + if (mCallback != null) { + new Handler(Looper.getMainLooper()).postDelayed(() -> { + mCallback.onSuccess(); + }, 1000); + } + return true; + } else { + // 启动失败 + Toast.makeText(activity, "无法启动抖音,请手动打开抖音进行分享", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-1, "无法启动抖音"); + } + return false; + } + } catch (Exception e) { + Log.e(TAG, "分享到抖音私信过程中发生异常: " + e.getMessage(), e); + if (mCallback != null) { + mCallback.onError(-1, "分享失败: " + e.getMessage()); + } + return false; + } + } + + /** + * 分享内容到抖音群聊 + * @param activity 活动上下文 + * @param content 要分享的内容 + * @param mediaUri 要分享的媒体Uri (可为null) + * @param mediaType 媒体类型 ("image"或"video",仅在mediaUri不为null时有效) + * @return 是否成功启动分享 + */ + public boolean shareToGroupChat(Activity activity, String content, Uri mediaUri, String mediaType) { + // Strict check removed for HarmonyOS compatibility + // if (!isDouyinInstalled()) { + // handleNotInstalled(activity); + // return false; + // } + + try { + String packageName = getInstalledDouYinPackage(); + + // 尝试各种可能的群聊URI scheme + String[] groupChatSchemes = { + "snssdk1128://chat_group", // 可能的群聊scheme + "douyin://chat_group", // 可能的群聊scheme + "aweme://chat_group", // 可能的群聊scheme + "snssdk1128://im/group", // 可能的群聊scheme + "douyin://im/group", // 可能的群聊scheme + }; + + boolean groupPageOpened = false; + + for (String scheme : groupChatSchemes) { + try { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(scheme)); + intent.setPackage(packageName); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + activity.startActivity(intent); + Log.d(TAG, "成功使用scheme打开抖音群聊页面: " + scheme); + groupPageOpened = true; + break; + } catch (Exception e) { + Log.e(TAG, "scheme方式失败 " + scheme + ": " + e.getMessage()); + // 继续尝试下一个scheme + } + } + + if (!groupPageOpened) { + // 如果无法直接打开群聊页面,尝试打开普通消息页面 + boolean messagePageOpened = openDouYinMessagePage(activity); + + if (!messagePageOpened) { + // 如果消息页面也打不开,就直接启动抖音 + boolean launched = tryLaunchDouyin(activity); + if (launched) { + Toast.makeText(activity, "抖音已启动,请点击底部消息按钮进入并选择群聊", Toast.LENGTH_LONG).show(); + } else { + Toast.makeText(activity, "无法启动抖音,请手动操作", Toast.LENGTH_SHORT).show(); + return false; + } + } else { + Toast.makeText(activity, "请在消息页面选择或创建群聊进行分享", Toast.LENGTH_LONG).show(); + } + } else { + Toast.makeText(activity, "请选择群聊进行分享", Toast.LENGTH_LONG).show(); + } + + // 将内容复制到剪贴板以便用户粘贴 + if (content != null && !content.isEmpty()) { + copyToClipboard(activity, content); + Toast.makeText(activity, "内容已复制到剪贴板,可在群聊中粘贴", Toast.LENGTH_SHORT).show(); + } + + // 如果有媒体文件,通过临时文件存储,以便用户手动分享 + if (mediaUri != null) { + try { + Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setPackage(packageName); + + if ("image".equals(mediaType)) { + shareIntent.setType("image/*"); + } else if ("video".equals(mediaType)) { + shareIntent.setType("video/*"); + } else { + shareIntent.setType("*/*"); + } + + shareIntent.putExtra(Intent.EXTRA_STREAM, mediaUri); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } + + // 创建临时分享弹窗,辅助用户操作 + Intent chooser = Intent.createChooser(shareIntent, "请选择'抖音'"); + activity.startActivity(chooser); + + Toast.makeText(activity, "请在弹出窗口中选择抖音,进入群聊后再选择群组", Toast.LENGTH_LONG).show(); + } catch (Exception e) { + Log.e(TAG, "准备媒体分享失败: " + e.getMessage()); + // 如果媒体分享失败,至少已经将文本内容复制到剪贴板 + } + } + + // 假设分享过程启动成功 + if (mCallback != null) { + new Handler(Looper.getMainLooper()).postDelayed(() -> { + mCallback.onSuccess(); + }, 1000); + } + + return true; + } catch (Exception e) { + Log.e(TAG, "分享到群聊过程中发生异常: " + e.getMessage(), e); + if (mCallback != null) { + mCallback.onError(-1, "分享到群聊失败: " + e.getMessage()); + } + return false; + } + } + + /** + * 兼容性复制文本到剪贴板 + * 支持API 9及以上版本 + * @param context 上下文 + * @param text 要复制的文本 + */ + private void copyToClipboard(Context context, String text) { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + // API 11及以上使用ClipboardManager + android.content.ClipboardManager clipboardManager = + (android.content.ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clipData = + android.content.ClipData.newPlainText("分享内容", text); + clipboardManager.setPrimaryClip(clipData); + } else { + // API 11以下使用旧版的android.text.ClipboardManager + android.text.ClipboardManager clipboardManager = + (android.text.ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + clipboardManager.setText(text); + } + Log.d(TAG, "成功复制文本到剪贴板"); + } catch (Exception e) { + Log.e(TAG, "复制到剪贴板失败: " + e.getMessage(), e); + } + } + + /** + * 打开抖音消息页面 + * @param activity 活动 + * @return 是否成功打开 + */ + private boolean openDouYinMessagePage(Activity activity) { + String packageName = getInstalledDouYinPackage(); + + // 抖音消息页面的可能URI schemas + String[] messageSchemas = { + "snssdk1128://chat?type=im_friend", // 标准抖音 + "douyin://chat?type=im_friend", // 新版抖音 + "aweme://chat?type=im_friend", // 旧版抖音 + "snssdk1128://im/friend", // 其他可能的schema + "douyin://im/friend", // 其他可能的schema + }; + + // 尝试打开抖音消息选择页面 + for (String schema : messageSchemas) { + try { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(schema)); + intent.setPackage(packageName); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + activity.startActivity(intent); + Log.d(TAG, "成功使用Schema打开抖音消息页面: " + schema); + return true; + } catch (Exception e) { + Log.e(TAG, "使用Schema " + schema + " 打开抖音消息页面失败: " + e.getMessage()); + // 继续尝试下一个schema + } + } + + // 如果所有Schema都失败了,尝试直接打开具体的消息Activity + try { + Intent intent = new Intent(); + intent.setComponent(new ComponentName(packageName, packageName + ".module.message.ui.MessageListActivity")); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + activity.startActivity(intent); + Log.d(TAG, "成功使用组件名称打开抖音消息页面"); + return true; + } catch (Exception e) { + Log.e(TAG, "使用组件名称打开抖音消息页面失败: " + e.getMessage()); + } + + return false; + } + /** + * 抖音分享回调接口 + */ + public interface DouYinShareCallback { + void onSuccess(); + void onError(int code, String message); + void onCancel(); + } +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/util/FileProviderUtil.java b/app/src/main/java/com/tsgame/tsgame_niuniu/util/FileProviderUtil.java new file mode 100644 index 0000000..7aa7fff --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/util/FileProviderUtil.java @@ -0,0 +1,36 @@ +package com.tsgame.tsgame_niuniu.util; + +import android.content.Context; +import android.net.Uri; +import android.os.Build; +import android.support.v4.content.FileProvider; +import java.io.File; + +/** + * 文件Uri处理工具类 + * 主要用于适配Android 7.0及以上版本的文件访问安全策略 + */ +public class FileProviderUtil { + + /** + * 获取文件的Uri,适配不同Android版本 + * @param context 上下文 + * @param file 文件 + * @return Uri对象 + */ + public static Uri getUriForFile(Context context, File file) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + // Android 7.0及以上版本使用FileProvider + try { + return FileProvider.getUriForFile(context, + context.getPackageName() + ".fileprovider", file); + } catch (IllegalArgumentException e) { + // 如果获取失败,尝试使用传统方式 + return Uri.fromFile(file); + } + } else { + // Android 7.0以下直接使用文件Uri + return Uri.fromFile(file); + } + } +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/util/MediaFile.java b/app/src/main/java/com/tsgame/tsgame_niuniu/util/MediaFile.java new file mode 100644 index 0000000..35b8b24 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/util/MediaFile.java @@ -0,0 +1,141 @@ +package com.tsgame.tsgame_niuniu.util; + +import java.util.HashMap; +import java.util.Iterator; + +public class MediaFile { + public static String sFileExtensions; + public static final int FILE_TYPE_MP3 = 1; + public static final int FILE_TYPE_M4A = 2; + public static final int FILE_TYPE_WAV = 3; + public static final int FILE_TYPE_AMR = 4; + public static final int FILE_TYPE_AWB = 5; + public static final int FILE_TYPE_WMA = 6; + public static final int FILE_TYPE_OGG = 7; + private static final int FIRST_AUDIO_FILE_TYPE = FILE_TYPE_MP3; + private static final int LAST_AUDIO_FILE_TYPE = FILE_TYPE_OGG; + // MIDI file types + public static final int FILE_TYPE_MID = 11; + public static final int FILE_TYPE_SMF = 12; + public static final int FILE_TYPE_IMY = 13; + private static final int FIRST_MIDI_FILE_TYPE = FILE_TYPE_MID; + private static final int LAST_MIDI_FILE_TYPE = FILE_TYPE_IMY; + // Video file types + public static final int FILE_TYPE_MP4 = 21; + public static final int FILE_TYPE_M4V = 22; + public static final int FILE_TYPE_3GPP = 23; + public static final int FILE_TYPE_3GPP2 = 24; + public static final int FILE_TYPE_WMV = 25; + private static final int FIRST_VIDEO_FILE_TYPE = FILE_TYPE_MP4; + private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_WMV; + // Image file types + public static final int FILE_TYPE_JPEG = 31; + public static final int FILE_TYPE_GIF = 32; + public static final int FILE_TYPE_PNG = 33; + public static final int FILE_TYPE_BMP = 34; + public static final int FILE_TYPE_WBMP = 35; + private static final int FIRST_IMAGE_FILE_TYPE = FILE_TYPE_JPEG; + private static final int LAST_IMAGE_FILE_TYPE = FILE_TYPE_WBMP; + // Playlist file types + public static final int FILE_TYPE_M3U = 41; + public static final int FILE_TYPE_PLS = 42; + public static final int FILE_TYPE_WPL = 43; + private static final int FIRST_PLAYLIST_FILE_TYPE = FILE_TYPE_M3U; + private static final int LAST_PLAYLIST_FILE_TYPE = FILE_TYPE_WPL; + + static class MediaFileType { + int fileType; + String mimeType; + + MediaFileType(int fileType, String mimeType) { + this.fileType = fileType; + this.mimeType = mimeType; + + } + } + + private static HashMap sFileTypeMap = new HashMap(); + private static HashMap sMimeTypeMap = new HashMap(); + + static void addFileType(String extension, int fileType, String mimeType) { + sFileTypeMap.put(extension, new MediaFileType(fileType, mimeType)); + sMimeTypeMap.put(mimeType, new Integer(fileType)); + } + static { + addFileType("MP3",FILE_TYPE_MP3,"audio/mpeg"); + addFileType("M4A",FILE_TYPE_M4A,"audio/mp4"); + addFileType("WAV",FILE_TYPE_WAV,"audio/x-wav"); + addFileType("AMR",FILE_TYPE_AMR,"audio/amr"); + addFileType("AWB",FILE_TYPE_AWB,"audio/amr-wb"); + addFileType("WMA",FILE_TYPE_WMA,"audio/x-ms-wma"); + addFileType("OGG",FILE_TYPE_OGG,"application/ogg"); + addFileType("MID",FILE_TYPE_MID,"audio/midi"); + addFileType("XMF",FILE_TYPE_MID,"audio/midi"); + addFileType("RTTTL",FILE_TYPE_MID,"audio/midi"); + addFileType("SMF",FILE_TYPE_SMF,"audio/sp-midi"); + addFileType("IMY",FILE_TYPE_IMY,"audio/imelody"); + addFileType("MP4",FILE_TYPE_MP4,"video/mp4"); + addFileType("M4V",FILE_TYPE_M4V,"video/mp4"); + addFileType("3GP",FILE_TYPE_3GPP,"video/3gpp"); + addFileType("3GPP",FILE_TYPE_3GPP,"video/3gpp"); + addFileType("3G2",FILE_TYPE_3GPP2,"video/3gpp2"); + addFileType("3GPP2",FILE_TYPE_3GPP2,"video/3gpp2"); + addFileType("WMV",FILE_TYPE_WMV,"video/x-ms-wmv"); + addFileType("JPG",FILE_TYPE_JPEG,"image/jpeg"); + addFileType("JPEG",FILE_TYPE_JPEG,"image/jpeg"); + addFileType("GIF",FILE_TYPE_GIF,"image/gif"); + addFileType("PNG",FILE_TYPE_PNG,"image/png"); + addFileType("BMP",FILE_TYPE_BMP,"image/x-ms-bmp"); + addFileType("WBMP",FILE_TYPE_WBMP,"image/vnd.wap.wbmp"); + addFileType("M3U",FILE_TYPE_M3U,"audio/x-mpegurl"); + addFileType("PLS",FILE_TYPE_PLS,"audio/x-scpls"); + addFileType("WPL",FILE_TYPE_WPL,"application/vnd.ms-wpl"); + // compute file extensions list for native Media Scanner + StringBuilder builder = new StringBuilder(); + Iterator iterator = sFileTypeMap.keySet().iterator(); + while (iterator.hasNext()) { + if (builder.length() > 0) { + builder.append(','); + } + builder.append(iterator.next()); + } + sFileExtensions = builder.toString(); + } + public static final String UNKNOWN_STRING = ""; + public static boolean isAudioFileType(int fileType) { + return ((fileType >= FIRST_AUDIO_FILE_TYPE && + fileType <= LAST_AUDIO_FILE_TYPE) || + (fileType >= FIRST_MIDI_FILE_TYPE && + fileType <= LAST_MIDI_FILE_TYPE)); + } + public static boolean isVideoFileType(int fileType) { + return (fileType >= FIRST_VIDEO_FILE_TYPE && + fileType <= LAST_VIDEO_FILE_TYPE); + } + public static boolean isImageFileType(int fileType) { + return (fileType >= FIRST_IMAGE_FILE_TYPE && + fileType <= LAST_IMAGE_FILE_TYPE); + } + public static boolean isPlayListFileType(int fileType) { + return (fileType >= FIRST_PLAYLIST_FILE_TYPE && + fileType <= LAST_PLAYLIST_FILE_TYPE); + } + public static MediaFileType getFileType(String path) { + int lastDot = path.lastIndexOf("."); + if (lastDot < 0) + return null; + return sFileTypeMap.get(path.substring(lastDot + 1).toUpperCase()); + } + //重载方法,根据文件路径识别音频文件 + public static boolean isAudioFileType(String path) { + MediaFileType type = getFileType(path); + if(null != type) { + return isAudioFileType(type.fileType); + } + return false; + } + public static int getFileTypeForMimeType(String mimeType) { + Integer value = sMimeTypeMap.get(mimeType); + return (value == null ? 0 : value.intValue()); + } +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/util/QQIntentShareUtil.java b/app/src/main/java/com/tsgame/tsgame_niuniu/util/QQIntentShareUtil.java new file mode 100644 index 0000000..d07a262 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/util/QQIntentShareUtil.java @@ -0,0 +1,748 @@ +package com.tsgame.tsgame_niuniu.util; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import android.text.TextUtils; +import android.util.Log; +import android.widget.Toast; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +/** + * QQ分享工具类 - 无需SDK,使用Intent实现 + */ +public class QQIntentShareUtil { + + private static final String TAG = "QQIntentShareUtil"; + + // QQ可能的包名列表 + private static final String QQ_PACKAGE_NAME = "com.tencent.mobileqq"; + private static final String TIM_PACKAGE_NAME = "com.tencent.tim"; + private static final String QQ_LITE_PACKAGE_NAME = "com.tencent.qqlite"; + private static final String QQ_INTERNATIONAL_PACKAGE_NAME = "com.tencent.mobileqqi"; + + // 可能的QQ包名列表 + private static final List QQ_PACKAGES = Arrays.asList( + QQ_PACKAGE_NAME, // 标准QQ + TIM_PACKAGE_NAME, // TIM + QQ_LITE_PACKAGE_NAME, // QQ轻聊版 + QQ_INTERNATIONAL_PACKAGE_NAME // 国际版QQ + ); + + // QQ分享的Activity组件名称 + private static final String QQ_SHARE_COMPONENT = "com.tencent.mobileqq.activity.JumpActivity"; + private static final String QQ_TIM_SHARE_COMPONENT = "com.tencent.tim.activity.JumpActivity"; + + // QQ聊天的Activity组件名称 + private static final String QQ_CHAT_COMPONENT = "com.tencent.mobileqq.activity.ChatActivity"; + private static final String TIM_CHAT_COMPONENT = "com.tencent.tim.activity.ChatActivity"; + + // QQ临时会话的Activity组件名称 + private static final String QQ_TEMP_CHAT_COMPONENT = "com.tencent.mobileqq.activity.TempSessionActivity"; + private static final String TIM_TEMP_CHAT_COMPONENT = "com.tencent.tim.activity.TempSessionActivity"; + + // QQ空间分享的Activity组件名称 + private static final String QZONE_COMPONENT = "com.tencent.mobileqq.activity.QzonePublishMoodActivity"; + private static final String TIM_QZONE_COMPONENT = "com.tencent.tim.activity.QzonePublishMoodActivity"; + + private static QQIntentShareUtil instance; + private final Context mContext; + private QQShareCallback mCallback; + + // 缓存已安装的QQ包名 + private String installedQQPackage = null; + + private QQIntentShareUtil(Context context) { + this.mContext = context.getApplicationContext(); + } + + public static QQIntentShareUtil getInstance(Context context) { + if (instance == null && context != null) { + instance = new QQIntentShareUtil(context); + } + return instance; + } + + /** + * 设置分享回调 + * @param callback 分享回调 + */ + public void setShareCallback(QQShareCallback callback) { + this.mCallback = callback; + } + + /** + * 检查QQ是否已安装 + * @return 是否安装 + */ + public boolean isQQInstalled() { + // 如果之前已找到包名,直接返回true + if (installedQQPackage != null) { + return true; + } + + // 检查所有可能的QQ包名 + PackageManager pm = mContext.getPackageManager(); + for (String packageName : QQ_PACKAGES) { + boolean installed = false; + try { + // 1. 尝试获取包信息 + pm.getPackageInfo(packageName, 0); + installed = true; + } catch (PackageManager.NameNotFoundException e) { + // 忽略 + } + + // 2. 如果getPackageInfo失败,尝试获取启动Intent + if (!installed) { + try { + if (pm.getLaunchIntentForPackage(packageName) != null) { + installed = true; + } + } catch (Exception e) { + // 忽略 + } + } + + // 3. 尝试查询是否支持分享Intent (针对部分机型/系统的兜底策略) + if (!installed) { + try { + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); + intent.setPackage(packageName); + List list = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); + if (list != null && list.size() > 0) { + installed = true; + } + } catch (Exception e) { + // 忽略 + } + } + + if (installed) { + // 找到已安装的QQ,缓存包名 + installedQQPackage = packageName; + Log.d(TAG, "找到已安装的QQ: " + packageName); + return true; + } + } + + Log.d(TAG, "未找到已安装的QQ应用"); + return false; + } + + /** + * 获取已安装的QQ包名 + * @return QQ包名,如果未安装则返回默认包名 + */ + private String getInstalledQQPackage() { + if (installedQQPackage != null) { + return installedQQPackage; + } + + // 如果没有缓存,重新检测 + isQQInstalled(); + return installedQQPackage != null ? installedQQPackage : QQ_PACKAGE_NAME; + } + + /** + * 获取QQ分享的组件名称 + */ + private String getQQShareComponent() { + String packageName = getInstalledQQPackage(); + if (TIM_PACKAGE_NAME.equals(packageName)) { + return QQ_TIM_SHARE_COMPONENT; + } + return QQ_SHARE_COMPONENT; + } + + /** + * 获取QQ聊天的组件名称 + */ + private String getQQChatComponent() { + String packageName = getInstalledQQPackage(); + if (TIM_PACKAGE_NAME.equals(packageName)) { + return TIM_CHAT_COMPONENT; + } + return QQ_CHAT_COMPONENT; + } + + /** + * 获取QQ临时会话的组件名称 + */ + private String getQQTempChatComponent() { + String packageName = getInstalledQQPackage(); + if (TIM_PACKAGE_NAME.equals(packageName)) { + return TIM_TEMP_CHAT_COMPONENT; + } + return QQ_TEMP_CHAT_COMPONENT; + } + + /** + * 获取QQ空间分享的组件名称 + */ + private String getQZoneShareComponent() { + String packageName = getInstalledQQPackage(); + if (TIM_PACKAGE_NAME.equals(packageName)) { + return TIM_QZONE_COMPONENT; + } + return QZONE_COMPONENT; + } + + /** + * 分享纯文本到QQ好友 + * @param activity 活动 + * @param text 要分享的文本 + */ + public void shareTextToQQ(Activity activity, String text) { + // 在鸿蒙卓易通环境下,不完全依赖isQQInstalled,尝试强制拉起 + boolean isPackageDetected = isQQInstalled(); + + try { + // 尝试复制文本到剪贴板,作为兜底 + try { + copyToClipboard(activity, text); + } catch (Exception e) { + // 忽略剪贴板异常 + } + + String packageName = getInstalledQQPackage(); + boolean launched = false; + + // 方法1: 尝试使用系统Chooser,这是最兼容的方式,特别适合鸿蒙环境 + try { + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_TEXT, text); + + // 鸿蒙/卓易通关键适配Flags + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + + // 如果检测到了包名,优先尝试指定包名,但不是必须的 + if (isPackageDetected) { + intent.setPackage(packageName); + activity.startActivity(intent); + launched = true; + } else { + // 没有检测到包名,更需要使用Chooser,并提示用户选择QQ + Intent chooser = Intent.createChooser(intent, "请选择QQ进行分享"); + chooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + activity.startActivity(chooser); + launched = true; + } + + Log.d(TAG, "成功启动分享"); + activity.runOnUiThread(() -> Toast.makeText(activity, "成功启动QQ分享", Toast.LENGTH_SHORT).show()); + } catch (Exception e) { + Log.e(TAG, "启动分享失败: " + e.getMessage()); + final String msg = "启动分享失败: " + e.getMessage(); + activity.runOnUiThread(() -> Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show()); + } + + // 方法2: 如果上面的方法失败,回退到原有的特定Intent启动逻辑 + if (!launched) { + // 原有的逻辑保留作为备选... + + // ... (原有代码可以保留在if (!launched)块中,或简化) + } + + // 假设分享过程启动成功 + if (mCallback != null) { + new Handler(Looper.getMainLooper()).postDelayed(() -> { + mCallback.onSuccess(); + }, 1000); + } + } catch (Exception e) { + Log.e(TAG, "分享文本到QQ失败: " + e.getMessage(), e); + + // 最终兜底:提示手动分享 + Toast.makeText(activity, "暂无法直接拉起QQ,已复制内容,请手动打开QQ粘贴分享", Toast.LENGTH_LONG).show(); + handleShareException(activity, e); + } + } + + /** + * 分享纯文本到QQ空间 + * @param activity 活动 + * @param text 要分享的文本 + */ + public void shareTextToQZone(Activity activity, String text) { + if (!isQQInstalled()) { + handleNotInstalled(activity); + return; + } + + try { + String packageName = getInstalledQQPackage(); + + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_TEXT, text); + + // 使用组件名称直接跳转到QQ空间分享界面 + ComponentName comp = new ComponentName(packageName, getQZoneShareComponent()); + intent.setComponent(comp); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + activity.startActivity(intent); + Toast.makeText(activity, "正在分享到QQ空间", Toast.LENGTH_SHORT).show(); + + // 假设分享成功 + if (mCallback != null) { + new Handler(Looper.getMainLooper()).postDelayed(() -> { + mCallback.onSuccess(); + }, 1000); + } + } catch (Exception e) { + Log.e(TAG, "分享文本到QQ空间失败: " + e.getMessage(), e); + + // 尝试使用通用分享 + try { + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_TEXT, text); + + Intent chooser = Intent.createChooser(intent, "分享到QQ空间"); + activity.startActivity(chooser); + Toast.makeText(activity, "请从列表中选择QQ", Toast.LENGTH_SHORT).show(); + + if (mCallback != null) { + new Handler(Looper.getMainLooper()).postDelayed(() -> { + mCallback.onSuccess(); + }, 1000); + } + } catch (Exception ex) { + handleShareException(activity, ex); + } + } + } + + /** + * 分享图片到QQ + * @param activity 活动 + * @param localImagePath 本地图片路径 + */ + public void shareImageToQQ(Activity activity, String localImagePath) { + // 在鸿蒙卓易通环境下,避免过早报错,尝试强制分享 + boolean isPackageDetected = isQQInstalled(); + + File imageFile = new File(localImagePath); + if (!imageFile.exists()) { + Toast.makeText(activity, "分享图片不存在", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-2, "图片文件不存在"); + } + return; + } + + try { + String packageName = getInstalledQQPackage(); + + // 创建分享Intent + Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setType("image/*"); + + // 根据Android版本使用不同的Uri方式 + Uri imageUri; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + // Android 7.0及以上使用FileProvider + imageUri = FileProviderUtil.getUriForFile(activity, imageFile); + shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } else { + // Android 7.0以下直接使用文件Uri + imageUri = Uri.fromFile(imageFile); + } + + shareIntent.putExtra(Intent.EXTRA_STREAM, imageUri); + + // 鸿蒙/卓易通关键适配Flags + shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + shareIntent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // 确保Flags也被设置在Intent上 + + // 尝试直接拉起 + boolean launched = false; + + if (isPackageDetected) { + try { + // 复制一份Intent用于尝试 + Intent directIntent = new Intent(shareIntent); + ComponentName comp = new ComponentName(packageName, getQQShareComponent()); + directIntent.setComponent(comp); + activity.startActivity(directIntent); + launched = true; + Log.d(TAG, "已发送分享图片Intent到QQ"); + activity.runOnUiThread(() -> Toast.makeText(activity, "已发送分享图片Intent到QQ", Toast.LENGTH_SHORT).show()); + } catch (Exception e) { + Log.e(TAG, "直接分享到QQ失败: " + e.getMessage()); + final String failMsg = "直接分享失败: " + e.getMessage(); + activity.runOnUiThread(() -> Toast.makeText(activity, failMsg, Toast.LENGTH_SHORT).show()); + } + } + + // 如果直接拉起失败,或者未检测到包名,使用Chooser + if (!launched) { + try { + Intent chooserIntent = Intent.createChooser(shareIntent, "分享到QQ"); + chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + chooserIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // 确保Chooser也有权限 + activity.startActivity(chooserIntent); + launched = true; + Log.d(TAG, "使用System Chooser分享图片"); + activity.runOnUiThread(() -> Toast.makeText(activity, "尝试使用System Chooser分享图片", Toast.LENGTH_SHORT).show()); + } catch (Exception e) { + Log.e(TAG, "Chooser分享失败: " + e.getMessage()); + } + } + + if (launched) { + if (mCallback != null) { + new Handler(Looper.getMainLooper()).postDelayed(() -> { + mCallback.onSuccess(); + }, 1000); + } + } else { + Toast.makeText(activity, "分享图片失败,请手动打开QQ分享", Toast.LENGTH_SHORT).show(); + } + + } catch (Exception e) { + Log.e(TAG, "分享图片到QQ失败: " + e.getMessage(), e); + handleShareException(activity, e); + } + } + + /** + * 分享图片到QQ空间 + * @param activity 活动 + * @param localImagePath 本地图片路径 + */ + public void shareImageToQZone(Activity activity, String localImagePath) { + if (!isQQInstalled()) { + handleNotInstalled(activity); + return; + } + + File imageFile = new File(localImagePath); + if (!imageFile.exists()) { + Toast.makeText(activity, "分享图片不存在", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-2, "图片文件不存在"); + } + return; + } + + try { + String packageName = getInstalledQQPackage(); + + // 创建分享Intent + Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setType("image/*"); + + // 设置组件名称 + ComponentName comp = new ComponentName(packageName, getQZoneShareComponent()); + shareIntent.setComponent(comp); + + // 根据Android版本使用不同的Uri方式 + Uri imageUri; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + // Android 7.0及以上使用FileProvider + imageUri = FileProviderUtil.getUriForFile(activity, imageFile); + shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } else { + // Android 7.0以下直接使用文件Uri + imageUri = Uri.fromFile(imageFile); + } + + shareIntent.putExtra(Intent.EXTRA_STREAM, imageUri); + shareIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + try { + activity.startActivity(shareIntent); + Log.d(TAG, "已发送分享图片Intent到QQ空间"); + + // 延迟回调成功 + if (mCallback != null) { + new Handler(Looper.getMainLooper()).postDelayed(() -> { + mCallback.onSuccess(); + }, 1000); + } + } catch (android.content.ActivityNotFoundException e) { + Log.e(TAG, "直接分享到QQ空间失败,尝试使用选择器: " + e.getMessage()); + + // 如果直接分享失败,使用选择器 + Intent chooserIntent = Intent.createChooser(shareIntent.setComponent(null), "分享到QQ空间"); + activity.startActivity(chooserIntent); + Toast.makeText(activity, "请从列表中选择QQ", Toast.LENGTH_SHORT).show(); + + // 假设分享成功 + if (mCallback != null) { + new Handler(Looper.getMainLooper()).postDelayed(() -> { + mCallback.onSuccess(); + }, 1000); + } + } + } catch (Exception e) { + Log.e(TAG, "分享图片到QQ空间失败: " + e.getMessage(), e); + handleShareException(activity, e); + } + } + + /** + * 分享BitMap到QQ + * @param activity 活动 + * @param bitmap 位图 + * @param isQzone 是否分享到QQ空间 + */ + public void shareBitmapToQQ(Activity activity, Bitmap bitmap, boolean isQzone) { + if (bitmap == null) { + Toast.makeText(activity, "分享图片为空", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-1, "分享图片为空"); + } + return; + } + + try { + File cacheDir = activity.getExternalCacheDir(); + if (cacheDir == null) { + cacheDir = activity.getCacheDir(); + } + + File imageFile = new File(cacheDir, "qq_share_" + UUID.randomUUID().toString() + ".jpg"); + FileOutputStream fos = new FileOutputStream(imageFile); + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos); + fos.flush(); + fos.close(); + + // 保存成功,分享图片 + if (isQzone) { + shareImageToQZone(activity, imageFile.getAbsolutePath()); + } else { + shareImageToQQ(activity, imageFile.getAbsolutePath()); + } + } catch (Exception e) { + Toast.makeText(activity, "保存图片失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-2, "保存图片失败: " + e.getMessage()); + } + } + } + + /** + * 分享多张图片到QQ(群发) + * @param activity 活动 + * @param imagePaths 图片路径列表 + * @param isQzone 是否分享到QQ空间 + */ + public void shareImagesToQQ(Activity activity, ArrayList imagePaths, boolean isQzone) { + if (imagePaths == null || imagePaths.isEmpty()) { + Toast.makeText(activity, "分享图片为空", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-1, "分享图片为空"); + } + return; + } + + try { + ArrayList imageUris = new ArrayList<>(); + for (String path : imagePaths) { + File file = new File(path); + if (file.exists()) { + // 根据Android版本使用不同的Uri方式 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + // Android 7.0及以上使用FileProvider + Uri fileUri = FileProviderUtil.getUriForFile(activity, file); + imageUris.add(fileUri); + } else { + // Android 7.0以下直接使用文件Uri + imageUris.add(Uri.fromFile(file)); + } + } + } + + if (imageUris.isEmpty()) { + Toast.makeText(activity, "没有有效图片可分享", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-1, "没有有效图片可分享"); + } + return; + } + + Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE); + // 获取已安装的QQ包名 + String packageName = getInstalledQQPackage(); + //intent.setPackage(packageName); // 不再强制依赖包名 + intent.setType("image/*"); + intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); // 鸿蒙卓易通适配 + + boolean launched = false; + boolean isPackageDetected = isQQInstalled(); + + if (isPackageDetected) { + try { + Intent directIntent = new Intent(intent); + // 设置组件名称 + if (isQzone) { + ComponentName comp = new ComponentName(packageName, getQZoneShareComponent()); + directIntent.setComponent(comp); + } else { + ComponentName comp = new ComponentName(packageName, getQQShareComponent()); + directIntent.setComponent(comp); + } + activity.startActivity(directIntent); + launched = true; + Log.d(TAG, "已发送多图分享Intent到QQ"); + } catch (Exception e) { + Log.e(TAG, "直接分享多图到QQ失败: " + e.getMessage()); + } + } + + if (!launched) { + Intent chooser = Intent.createChooser(intent, isQzone ? "分享到QQ空间" : "分享到QQ"); + chooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + chooser.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + activity.startActivity(chooser); + Log.d(TAG, "使用System Chooser分享多图"); + launched = true; + } + + if (launched) { + // 延迟回调成功 + if (mCallback != null) { + new Handler(Looper.getMainLooper()).postDelayed(() -> { + mCallback.onSuccess(); + }, 1000); + } + } + + } catch (Exception e) { + handleShareException(activity, e); + } + } + + /** + * 分享网页链接到QQ + * @param activity 活动 + * @param title 标题 + * @param description 描述 + * @param webUrl 网页链接 + * @param imageUrl 图片链接(可选) + * @param isQzone 是否分享到QQ空间 + */ + public void shareWebPageToQQ(Activity activity, String title, String description, String webUrl, String imageUrl, boolean isQzone) { + if (!isQQInstalled()) { + handleNotInstalled(activity); + return; + } + + try { + // QQ支持直接分享网页链接,但实际上QQ会解析文本内容来查找URL + StringBuilder sb = new StringBuilder(); + if (!TextUtils.isEmpty(title)) { + sb.append(title).append("\n\n"); + } + if (!TextUtils.isEmpty(description)) { + sb.append(description).append("\n\n"); + } + + + String text = sb.toString().trim(); + + if (isQzone) { + shareTextToQZone(activity, text); + } else { + shareTextToQQ(activity, text); + } + } catch (Exception e) { + handleShareException(activity, e); + } + } + + /** + * 处理未安装QQ的情况 + */ + private void handleNotInstalled(Activity activity) { + Toast.makeText(activity, "请先安装QQ客户端", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-1, "未安装QQ客户端"); + } + } + + /** + * 处理分享异常 + */ + private void handleShareException(Activity activity, Exception e) { + Toast.makeText(activity, "分享失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-3, "分享失败: " + e.getMessage()); + } + } + + /** + * 兼容性复制文本到剪贴板 + * 支持API 9及以上版本 + * @param context 上下文 + * @param text 要复制的文本 + */ + private void copyToClipboard(Context context, String text) { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + // API 11及以上使用ClipboardManager + android.content.ClipboardManager clipboardManager = + (android.content.ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clipData = + android.content.ClipData.newPlainText("分享内容", text); + clipboardManager.setPrimaryClip(clipData); + } else { + // API 11以下使用旧版的android.text.ClipboardManager + android.text.ClipboardManager clipboardManager = + (android.text.ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + clipboardManager.setText(text); + } + } catch (Exception e) { + Log.e(TAG, "复制到剪贴板失败: " + e.getMessage(), e); + } + } + + /** + * QQ分享回调接口 + */ + public interface QQShareCallback { + /** + * 分享成功 + */ + void onSuccess(); + + /** + * 分享失败 + * @param code 错误码 + * @param msg 错误信息 + */ + void onError(int code, String msg); + + /** + * 分享取消 + */ + void onCancel(); + } +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/util/Settingutil.java b/app/src/main/java/com/tsgame/tsgame_niuniu/util/Settingutil.java new file mode 100644 index 0000000..6d0b766 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/util/Settingutil.java @@ -0,0 +1,32 @@ +package com.tsgame.tsgame_niuniu.util; + +public class Settingutil { + + /** + * 项目assrts 下目录名 + */ + public static String kfile = "gamehall"; + + + /** + * 启动父目录名 + */ + public static String filestart = ""; + + /** + * 初始化游戏的压缩包名 + */ + public static String initfile = ""; + /* + * 初始化游戏的压缩包名 + */ + + public static String initgame=""; + + public static boolean iswxpay=false; + + /** + * 语音开关 + */ + public static boolean voicePlaying=true; +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/util/VibratorUtil.java b/app/src/main/java/com/tsgame/tsgame_niuniu/util/VibratorUtil.java new file mode 100644 index 0000000..e3943b2 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/util/VibratorUtil.java @@ -0,0 +1,88 @@ +package com.tsgame.tsgame_niuniu.util; + +import android.app.Activity; +import android.app.Service; +import android.content.Context; +import android.os.Vibrator; + +public class VibratorUtil { + + Vibrator mVibrator; + Context mContext; + private static VibratorUtil mKqwVibrator; + + public VibratorUtil(Context context) { + mContext = context; + // 初始化振动器对象 + + mVibrator = (Vibrator) context + .getSystemService(Context.VIBRATOR_SERVICE); + } + + public static VibratorUtil getInstance(Context context) { + + if (mKqwVibrator == null) { + + mKqwVibrator = new VibratorUtil(context); + + } + return mKqwVibrator; + + } + + /** + * 开始震动 + * + * @param time + * 震动时间 毫秒 + */ + public void vibrate(long time) { + mVibrator.vibrate(time); + } + + /** + * 取消震动 + * + * @param time + * 震动时间 毫秒 + */ + public void cancle() { + mVibrator.cancel(); + } + + /** + * 重复震动 + */ + public void repeatVibrate(int repeat) { + if(repeat!=1||repeat!=-1){ + + repeat=-1; + + } + // 等待1秒,震动2秒,等待1秒,震动3秒 + long[] pattern = { 1000, 2000, 1000, 3000 }; + // -1表示不重复, 如果不是-1, 比如改成1, 表示从前面这个long数组的下标为1的元素开始重复. + mVibrator.vibrate(pattern, -1); + + } + + /** + * final Activity activity :调用该方法的Activity实例 long milliseconds :震动的时长,单位是毫秒 + * long[] pattern :自定义震动模式 。数组中数字的含义依次是[静止时长,震动时长,静止时长,震动时长。。。]时长的单位是毫秒 + * boolean isRepeat : 是否反复震动,如果是true,反复震动,如果是false,只震动一次 + */ + + public static void Vibrate(final Activity activity, long milliseconds) { + Vibrator vib = (Vibrator) activity + .getSystemService(Service.VIBRATOR_SERVICE); + vib.vibrate(milliseconds); + } + + public static void Vibrate(final Activity activity, long[] pattern, + boolean isRepeat) { + Vibrator vib = (Vibrator) activity + .getSystemService(Service.VIBRATOR_SERVICE); + vib.vibrate(pattern, isRepeat ? 1 : -1); + + } +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/util/WeChatIntentShareUtil.java b/app/src/main/java/com/tsgame/tsgame_niuniu/util/WeChatIntentShareUtil.java new file mode 100644 index 0000000..846349b --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/util/WeChatIntentShareUtil.java @@ -0,0 +1,417 @@ +package com.tsgame.tsgame_niuniu.util; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import android.text.TextUtils; +import android.util.Log; +import android.widget.Toast; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * 微信分享工具类 - 无需SDK,使用Intent实现 + */ +public class WeChatIntentShareUtil { + private static final String TAG = "WeChatShareUtil"; + + // 微信包名 + private static final String WECHAT_PACKAGE_NAME = "com.tencent.mm"; + + // 微信朋友圈分享界面Activity + private static final String WECHAT_MOMENTS_ACTIVITY = "com.tencent.mm.ui.tools.ShareToTimeLineUI"; + + // 微信好友分享界面Activity + private static final String WECHAT_FRIENDS_ACTIVITY = "com.tencent.mm.ui.tools.ShareImgUI"; + + // 分享场景 + public static final int SCENE_FRIENDS = 0; // 分享给好友 + public static final int SCENE_MOMENTS = 1; // 分享到朋友圈 + + private static WeChatIntentShareUtil instance; + private final Context mContext; + private WeChatShareCallback mCallback; + + private WeChatIntentShareUtil(Context context) { + this.mContext = context.getApplicationContext(); + } + + public static WeChatIntentShareUtil getInstance(Context context) { + if (instance == null && context != null) { + instance = new WeChatIntentShareUtil(context); + } + return instance; + } + + /** + * 设置分享回调 + * @param callback 回调接口 + */ + public void setShareCallback(WeChatShareCallback callback) { + this.mCallback = callback; + } + + /** + * 检查微信是否已安装 + * @return 是否安装 + */ + public boolean isWeChatInstalled() { + PackageManager pm = mContext.getPackageManager(); + try { + pm.getPackageInfo(WECHAT_PACKAGE_NAME, PackageManager.GET_ACTIVITIES); + return true; + } catch (PackageManager.NameNotFoundException e) { + return false; + } + } + + /** + * 分享纯文本到微信 + * @param activity 活动 + * @param text 要分享的文本 + * @param scene 分享场景:0-好友,1-朋友圈 + */ + public void shareTextToWeChat(Activity activity, String text, int scene) { + if (!isWeChatInstalled()) { + handleNotInstalled(activity); + return; + } + + try { + // 创建分享Intent + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_TEXT, text); + + // 指定微信包名 + intent.setPackage(WECHAT_PACKAGE_NAME); + + // 根据分享场景指定目标Activity + if (scene == SCENE_MOMENTS) { + // 微信朋友圈分享不支持纯文本分享,提示用户 + Toast.makeText(activity, "微信朋友圈不支持纯文本分享,请使用图文分享", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-1, "微信朋友圈不支持纯文本分享"); + } + return; + } + + try { + activity.startActivity(intent); + handleShareSuccess(); + } catch (Exception e) { + Log.e(TAG, "分享文本到微信失败: " + e.getMessage(), e); + handleShareException(activity, e); + } + } catch (Exception e) { + Log.e(TAG, "分享过程中出现异常: " + e.getMessage(), e); + handleShareException(activity, e); + } + } + + /** + * 分享图片到微信 + * @param activity 活动 + * @param localImagePath 本地图片路径 + * @param scene 分享场景:0-好友,1-朋友圈 + */ + public void shareImage(Activity activity, String localImagePath, int scene) { + if (!isWeChatInstalled()) { + handleNotInstalled(activity); + return; + } + + File imageFile = new File(localImagePath); + if (!imageFile.exists()) { + Toast.makeText(activity, "分享图片不存在", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-2, "图片文件不存在"); + } + return; + } + + try { + // 创建分享Intent + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("image/*"); + + // 根据Android版本使用不同的Uri方式 + Uri imageUri; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + // Android 7.0及以上使用FileProvider + imageUri = FileProviderUtil.getUriForFile(activity, imageFile); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } else { + // Android 7.0以下直接使用文件Uri + imageUri = Uri.fromFile(imageFile); + } + + intent.putExtra(Intent.EXTRA_STREAM, imageUri); + + // 指定微信包名 + intent.setPackage(WECHAT_PACKAGE_NAME); + + // 根据分享场景指定目标Activity + if (scene == SCENE_MOMENTS) { + // 分享到朋友圈 + intent.setClassName(WECHAT_PACKAGE_NAME, WECHAT_MOMENTS_ACTIVITY); + } else { + // 分享给好友 + intent.setClassName(WECHAT_PACKAGE_NAME, WECHAT_FRIENDS_ACTIVITY); + } + + try { + activity.startActivity(intent); + handleShareSuccess(); + } catch (Exception e) { + Log.e(TAG, "分享图片到微信失败: " + e.getMessage(), e); + + // 如果指定Activity失败,尝试使用通用分享 + try { + Intent generalIntent = new Intent(Intent.ACTION_SEND); + generalIntent.setType("image/*"); + generalIntent.putExtra(Intent.EXTRA_STREAM, imageUri); + generalIntent.setPackage(WECHAT_PACKAGE_NAME); + activity.startActivity(generalIntent); + handleShareSuccess(); + } catch (Exception ex) { + handleShareException(activity, ex); + } + } + } catch (Exception e) { + Log.e(TAG, "分享过程中出现异常: " + e.getMessage(), e); + handleShareException(activity, e); + } + } + + /** + * 分享多张图片到微信 + * @param activity 活动 + * @param imagePaths 图片路径列表 + * @param scene 分享场景:0-好友,1-朋友圈 + */ + public void shareImages(Activity activity, ArrayList imagePaths, int scene) { + if (!isWeChatInstalled()) { + handleNotInstalled(activity); + return; + } + + if (imagePaths == null || imagePaths.isEmpty()) { + Toast.makeText(activity, "分享图片为空", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-1, "分享图片为空"); + } + return; + } + + try { + ArrayList imageUris = new ArrayList<>(); + for (String path : imagePaths) { + File file = new File(path); + if (file.exists()) { + // 根据Android版本使用不同的Uri方式 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + // Android 7.0及以上使用FileProvider + Uri fileUri = FileProviderUtil.getUriForFile(activity, file); + imageUris.add(fileUri); + } else { + // Android 7.0以下直接使用文件Uri + imageUris.add(Uri.fromFile(file)); + } + } + } + + if (imageUris.isEmpty()) { + Toast.makeText(activity, "没有有效图片可分享", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-1, "没有有效图片可分享"); + } + return; + } + + Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE); + intent.setType("image/*"); + intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris); + intent.setPackage(WECHAT_PACKAGE_NAME); + + // 根据分享场景指定不同的Activity + if (scene == SCENE_MOMENTS) { + // 分享到朋友圈 + intent.setClassName(WECHAT_PACKAGE_NAME, WECHAT_MOMENTS_ACTIVITY); + } else { + // 分享给好友 + intent.setClassName(WECHAT_PACKAGE_NAME, WECHAT_FRIENDS_ACTIVITY); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } + + try { + activity.startActivity(intent); + handleShareSuccess(); + } catch (Exception e) { + Log.e(TAG, "多图分享失败,尝试使用通用分享: " + e.getMessage()); + + // 尝试使用通用分享 + try { + Intent generalIntent = new Intent(Intent.ACTION_SEND_MULTIPLE); + generalIntent.setType("image/*"); + generalIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris); + generalIntent.setPackage(WECHAT_PACKAGE_NAME); + activity.startActivity(generalIntent); + handleShareSuccess(); + } catch (Exception ex) { + handleShareException(activity, ex); + } + } + } catch (Exception e) { + handleShareException(activity, e); + } + } + + /** + * 分享Bitmap图片到微信 + * @param activity 活动 + * @param bitmap 位图 + * @param scene 分享场景:0-好友,1-朋友圈 + */ + public void shareBitmap(Activity activity, Bitmap bitmap, int scene) { + if (bitmap == null) { + Toast.makeText(activity, "分享图片为空", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-1, "分享图片为空"); + } + return; + } + + try { + File cacheDir = activity.getExternalCacheDir(); + if (cacheDir == null) { + cacheDir = activity.getCacheDir(); + } + + File imageFile = new File(cacheDir, "wechat_share_" + UUID.randomUUID().toString() + ".jpg"); + FileOutputStream fos = new FileOutputStream(imageFile); + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos); + fos.flush(); + fos.close(); + + // 保存成功,分享图片 + shareImage(activity, imageFile.getAbsolutePath(), scene); + } catch (Exception e) { + Toast.makeText(activity, "保存图片失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-2, "保存图片失败: " + e.getMessage()); + } + } + } + + /** + * 分享网页链接到微信 + * 注意:微信原生分享不支持直接分享链接,这里实际是分享文本 + * 真正的网页分享需要使用微信SDK和公众号 + * @param activity 活动 + * @param title 标题 + * @param description 描述 + * @param webUrl 网页链接 + * @param scene 分享场景:0-好友,1-朋友圈 + */ + public void shareWebPage(Activity activity, String webUrl, String title, String description, int scene) { + if (!isWeChatInstalled()) { + handleNotInstalled(activity); + return; + } + + try { + // 微信不支持直接分享网页链接,只能作为文本分享 + StringBuilder sb = new StringBuilder(); + if (!TextUtils.isEmpty(title)) { + sb.append(title).append("\n\n"); + } + if (!TextUtils.isEmpty(description)) { + sb.append(description).append("\n\n"); + } + if (!TextUtils.isEmpty(webUrl)) { + sb.append(webUrl); + } + + // 朋友圈不支持纯文本分享,需要准备一个默认图片 + if (scene == SCENE_MOMENTS) { + Toast.makeText(activity, "微信朋友圈不支持直接分享网页链接,将作为文本分享", Toast.LENGTH_SHORT).show(); + + // 尝试使用WebView截图分享 + // 实际项目中可以实现WebView加载页面并截图分享的功能 + // 这里为简化处理,可以使用应用图标作为默认图片 + try { + // 调用系统分享 + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_TEXT, sb.toString()); + intent.setPackage(WECHAT_PACKAGE_NAME); + activity.startActivity(intent); + handleShareSuccess(); + } catch (Exception e) { + Log.e(TAG, "分享文本到微信失败: " + e.getMessage(), e); + handleShareException(activity, e); + } + } else { + // 分享给好友,可以直接分享文本 + shareTextToWeChat(activity, sb.toString(), scene); + } + } catch (Exception e) { + Log.e(TAG, "分享过程中出现异常: " + e.getMessage(), e); + handleShareException(activity, e); + } + } + + /** + * 处理分享成功的情况 + */ + private void handleShareSuccess() { + if (mCallback != null) { + new Handler(Looper.getMainLooper()).postDelayed(() -> { + mCallback.onSuccess(); + }, 1000); + } + } + + /** + * 处理未安装微信的情况 + */ + private void handleNotInstalled(Activity activity) { + Toast.makeText(activity, "请先安装微信客户端", Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-1, "未安装微信客户端"); + } + } + + /** + * 处理分享异常 + */ + private void handleShareException(Activity activity, Exception e) { + Toast.makeText(activity, "分享失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + if (mCallback != null) { + mCallback.onError(-3, "分享失败: " + e.getMessage()); + } + } + + /** + * 微信分享回调接口 + */ + public interface WeChatShareCallback { + void onSuccess(); + void onError(int code, String message); + void onCancel(); + } +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/util/ZipUtils.java b/app/src/main/java/com/tsgame/tsgame_niuniu/util/ZipUtils.java new file mode 100644 index 0000000..30faaa9 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/util/ZipUtils.java @@ -0,0 +1,408 @@ +package com.tsgame.tsgame_niuniu.util; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; + +import android.util.Log; + +public class ZipUtils { + + private static final int BUFF_SIZE = 1024 * 1024; // 1M Byte + + /** + * 批量压缩文件(夹) + * + * @param resFileList + * 要压缩的文件(夹)列表 + * @param zipFile + * 生成的压缩文件 + * @throws IOException + * 当压缩过程出错时抛出 + */ + public static void zipFiles(Collection resFileList, File zipFile) + throws IOException { + ZipOutputStream zipout = new ZipOutputStream(new BufferedOutputStream( + new FileOutputStream(zipFile), BUFF_SIZE)); + + for (File resFile : resFileList) { + zipFile(resFile, zipout, ""); + } + zipout.close(); + } + + /** + * 批量压缩文件(夹) + * + * @param resFileList + * 要压缩的文件(夹)列表 + * @param zipFile + * 生成的压缩文件 + * @param comment + * 压缩文件的注释 + * @throws IOException + * 当压缩过程出错时抛出 + */ + public static void zipFiles(Collection resFileList, File zipFile, + String comment) throws IOException { + ZipOutputStream zipout = new ZipOutputStream(new BufferedOutputStream( + new FileOutputStream(zipFile), BUFF_SIZE)); + for (File resFile : resFileList) { + zipFile(resFile, zipout, ""); + } + zipout.setComment(comment); + zipout.close(); + } + + public static void Unzip(String zipFile, String targetDir) { + + File file = new File(targetDir); + if (!file.exists()) { + + file.mkdirs(); + } + + int BUFFER = 4096; // 这里缓冲区我们使用4KB, + String strEntry; // 保存每个zip的条目名称 + + try { + BufferedOutputStream dest = null; // 缓冲输出流 + FileInputStream fis = new FileInputStream(zipFile); + ZipInputStream zis = new ZipInputStream( + new BufferedInputStream(fis)); + ZipEntry entry; // 每个zip条目的实例 + while ((entry = zis.getNextEntry()) != null) { + try { + Log.i("Unzip: ", "=" + entry); + int count; + byte data[] = new byte[BUFFER]; + strEntry = entry.getName(); + + File entryFile = new File(targetDir + File.separator + + strEntry); + File entryDir = new File(entryFile.getParent()); + if (!entryDir.exists()) { + entryDir.mkdirs(); + } + + FileOutputStream fos = new FileOutputStream(entryFile); + dest = new BufferedOutputStream(fos, BUFFER); + while ((count = zis.read(data, 0, BUFFER)) != -1) { + dest.write(data, 0, count); + } + dest.flush(); + dest.close(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + zis.close(); + } catch (Exception cwj) { + cwj.printStackTrace(); + } + } + + public static int upZipFile1(File zipFile, String folderPath) + throws ZipException, IOException { + // public static void upZipFile() throws Exception{ + ZipFile zfile = new ZipFile(zipFile); + @SuppressWarnings("rawtypes") + Enumeration zList = zfile.entries(); + ZipEntry ze = null; + byte[] buf = new byte[1024]; + while (zList.hasMoreElements()) { + ze = (ZipEntry) zList.nextElement(); + System.out.println(ze.getName()); + if (ze.isDirectory()) { + Log.d("upZipFile", "ze.getName() = " + ze.getName()); + String dirstr = folderPath + ze.getName(); + // dirstr.trim(); + dirstr = new String(dirstr.getBytes("8859_1"), "GB2312"); + Log.d("upZipFile", "str = " + dirstr); + File f = new File(dirstr); + f.mkdir(); + continue; + } + + Log.d("upZipFile", "ze.getName() = " + ze.getName()); + OutputStream os = new BufferedOutputStream(new FileOutputStream( + getRealFileName(folderPath, ze.getName()))); + + InputStream is = new BufferedInputStream(zfile.getInputStream(ze)); + int readLen = 0; + while ((readLen = is.read(buf, 0, 1024)) != -1) { + os.write(buf, 0, readLen); + } + is.close(); + os.close(); + } + zfile.close(); + return 0; + } + + /** + * 给定根目录,返回一个相对路径所对应的实际文件名. + * + * @param baseDir + * 指定根目录 + * @param absFileName + * 相对路径名,来自于ZipEntry中的name + * @return java.io.File 实际的文件 + */ + public static File getRealFileName(String baseDir, String absFileName) { + String[] dirs = absFileName.split("/"); + File ret = new File(baseDir); + String substr = null; + if (dirs.length > 1) { + for (int i = 0; i < dirs.length - 1; i++) { + substr = dirs[i]; + try { + // substr.trim(); + substr = new String(substr.getBytes("8859_1"), "GB2312"); + + } catch (UnsupportedEncodingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + ret = new File(ret, substr); + + } + Log.d("upZipFile", "1ret = " + ret); + if (!ret.exists()) + ret.mkdirs(); + substr = dirs[dirs.length - 1]; + try { + // substr.trim(); + substr = new String(substr.getBytes("8859_1"), "GB2312"); + Log.d("upZipFile", "substr = " + substr); + } catch (UnsupportedEncodingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + ret = new File(ret, substr); + Log.d("upZipFile", "2ret = " + ret); + return ret; + } + + return ret; + } + + /** + * 解压缩一个文件 + * + * @param zipFile + * 压缩文件 + * @param folderPath + * 解压缩的目标目录 + * @throws IOException + * 当解压缩过程出错时抛出 + */ + @SuppressWarnings("resource") + public static void upZipFile(File zipFile, String folderPath) + throws ZipException, IOException { + File desDir = new File(folderPath); + if (!desDir.exists()) { + desDir.mkdirs(); + } + ZipFile zf = new ZipFile(zipFile); + + for (Enumeration entries = zf.entries(); entries.hasMoreElements();) { + ZipEntry entry = ((ZipEntry) entries.nextElement()); + InputStream in = zf.getInputStream(entry); + String str = folderPath + File.separator + entry.getName(); + str = new String(str.getBytes("8859_1"), "GB2312"); + File desFile = new File(str); + if (!desFile.exists()) { + File fileParentDir = desFile.getParentFile(); + if (!fileParentDir.exists()) { + fileParentDir.mkdirs(); + } + desFile.createNewFile(); + } + OutputStream out = new FileOutputStream(desFile); + byte buffer[] = new byte[BUFF_SIZE]; + int realLength; + while ((realLength = in.read(buffer)) > 0) { + out.write(buffer, 0, realLength); + } + in.close(); + out.close(); + } + } + + /** + * 解压文件名包含传入文字的文件 + * + * @param zipFile + * 压缩文件 + * @param folderPath + * 目标文件夹 + * @param nameContains + * 传入的文件匹配名 + * @throws ZipException + * 压缩格式有误时抛出 + * @throws IOException + * IO错误时抛出 + */ + public static ArrayList upZipSelectedFile(File zipFile, + String folderPath, String nameContains) throws ZipException, + IOException { + ArrayList fileList = new ArrayList(); + File desDir = new File(folderPath); + if (!desDir.exists()) { + desDir.mkdir(); + } + + ZipFile zf = new ZipFile(zipFile); + for (Enumeration entries = zf.entries(); entries.hasMoreElements();) { + ZipEntry entry = ((ZipEntry) entries.nextElement()); + if (entry.getName().contains(nameContains)) { + InputStream in = zf.getInputStream(entry); + String str = folderPath + File.separator + entry.getName(); + str = new String(str.getBytes("8859_1"), "GB2312"); + // str.getBytes("GB2312"),"8859_1" 输出 + // str.getBytes("8859_1"),"GB2312" 输入 + File desFile = new File(str); + if (!desFile.exists()) { + File fileParentDir = desFile.getParentFile(); + if (!fileParentDir.exists()) { + fileParentDir.mkdirs(); + } + desFile.createNewFile(); + } + OutputStream out = new FileOutputStream(desFile); + byte buffer[] = new byte[BUFF_SIZE]; + int realLength; + while ((realLength = in.read(buffer)) > 0) { + out.write(buffer, 0, realLength); + } + in.close(); + out.close(); + fileList.add(desFile); + } + } + return fileList; + } + + /** + * 获得压缩文件内文件列表 + * + * @param zipFile + * 压缩文件 + * @return 压缩文件内文件名称 + * @throws ZipException + * 压缩文件格式有误时抛出 + * @throws IOException + * 当解压缩过程出错时抛出 + */ + public static ArrayList getEntriesNames(File zipFile) + throws ZipException, IOException { + ArrayList entryNames = new ArrayList(); + Enumeration entries = getEntriesEnumeration(zipFile); + while (entries.hasMoreElements()) { + ZipEntry entry = ((ZipEntry) entries.nextElement()); + entryNames.add(new String(getEntryName(entry).getBytes("GB2312"), + "8859_1")); + } + return entryNames; + } + + /** + * 获得压缩文件内压缩文件对象以取得其属性 + * + * @param zipFile + * 压缩文件 + * @return 返回一个压缩文件列表 + * @throws ZipException + * 压缩文件格式有误时抛出 + * @throws IOException + * IO操作有误时抛出 + */ + public static Enumeration getEntriesEnumeration(File zipFile) + throws ZipException, IOException { + ZipFile zf = new ZipFile(zipFile); + return zf.entries(); + } + + /** + * 取得压缩文件对象的注释 + * + * @param entry + * 压缩文件对象 + * @return 压缩文件对象的注释 + * @throws UnsupportedEncodingException + */ + public static String getEntryComment(ZipEntry entry) + throws UnsupportedEncodingException { + return new String(entry.getComment().getBytes("GB2312"), "8859_1"); + } + + /** + * 取得压缩文件对象的名称 + * + * @param entry + * 压缩文件对象 + * @return 压缩文件对象的名称 + * @throws UnsupportedEncodingException + */ + public static String getEntryName(ZipEntry entry) + throws UnsupportedEncodingException { + return new String(entry.getName().getBytes("GB2312"), "8859_1"); + } + + /** + * 压缩文件 + * + * @param resFile + * 需要压缩的文件(夹) + * @param zipout + * 压缩的目的文件 + * @param rootpath + * 压缩的文件路径 + * @throws FileNotFoundException + * 找不到文件时抛出 + * @throws IOException + * 当压缩过程出错时抛出 + */ + private static void zipFile(File resFile, ZipOutputStream zipout, + String rootpath) throws FileNotFoundException, IOException { + + rootpath = rootpath + + (rootpath.trim().length() == 0 ? "" : File.separator) + + resFile.getName(); + rootpath = new String(rootpath.getBytes("8859_1"), "GB2312"); + if (resFile.isDirectory()) { + File[] fileList = resFile.listFiles(); + for (File file : fileList) { + zipFile(file, zipout, rootpath); + } + } else { + byte buffer[] = new byte[BUFF_SIZE]; + BufferedInputStream in = new BufferedInputStream( + new FileInputStream(resFile), BUFF_SIZE); + zipout.putNextEntry(new ZipEntry(rootpath)); + int realLength; + while ((realLength = in.read(buffer)) != -1) { + zipout.write(buffer, 0, realLength); + } + in.close(); + zipout.flush(); + zipout.closeEntry(); + } + } +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/util/apputil.java b/app/src/main/java/com/tsgame/tsgame_niuniu/util/apputil.java new file mode 100644 index 0000000..baa3727 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/util/apputil.java @@ -0,0 +1,164 @@ +package com.tsgame.tsgame_niuniu.util; + +import android.app.AlertDialog; +import android.content.ComponentName; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +import com.jx.jyhd.R; +import com.tsgame.tsgame_niuniu.system.Myapplication; + +public class apputil { + + + public static int photoPort1=4479; + + public static int photoPort=4480; + + public static int wxtype = 1; + + + public static int code = 0; + + public static int shaketype=1; //默认开启震动声 + + public static int Voicetype=1; //默认开启声音 + + //记录Activity + public static String activityname=""; + ConnectivityManager manager; + public static String Showmessage=""; + /** + * 判断网络是否连通 + * + * @param context + * @return + */ + public static boolean isNetworkConnected(Context context) { + ConnectivityManager cm = (ConnectivityManager) context + .getSystemService(context.CONNECTIVITY_SERVICE); + NetworkInfo info = cm.getActiveNetworkInfo(); + return info != null && info.isConnected(); + } + + + + /** + * 检测网络是否连接 + * + * @return + */ + public boolean checkNetworkState(Context context) { + boolean flag = false; + // 得到网络连接信息 + manager = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + // 去进行判断网络是否连接 + if (manager.getActiveNetworkInfo() != null) { + flag = manager.getActiveNetworkInfo().isAvailable(); + } + if (!flag) { + // setNetwork(); + } else { + isNetworkAvailable(); + } + + return flag; + } + + /** + * 网络未连接时,调用设置方法 + */ + private void setNetwork() { + // Toast.makeText(this, "wifi is closed!", Toast.LENGTH_SHORT).show(); + + AlertDialog.Builder builder = new AlertDialog.Builder( + Myapplication.application); + builder.setIcon(R.drawable.ic_launcher); + builder.setTitle("网络提示信息"); + builder.setMessage("网络不可用,如果继续,请先设置网络!"); + builder.setPositiveButton("设置", new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Intent intent = null; + /** + * 判断手机系统的版本!如果API大于10 就是3.0+ 因为3.0以上的版本的设置和3.0以下的设置不一样,调用的方法不同 + */ + + if (android.os.Build.VERSION.SDK_INT > 10) { + intent = new Intent( + android.provider.Settings.ACTION_WIFI_SETTINGS); + } else { + intent = new Intent(); + + ComponentName component = new ComponentName( + "com.android.settings", + "com.android.settings.WirelessSettings"); + intent.setComponent(component); + intent.setAction("android.intent.action.VIEW"); + } + Myapplication.application.startActivity(intent); + } + }); + + builder.setNegativeButton("取消", new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + } + }); + builder.create(); + builder.show(); + } + + /** + * 网络已经连接,然后去判断是wifi连接还是GPRS连接 设置一些自己的逻辑调用 + */ + + private void isNetworkAvailable() { + NetworkInfo networkINfo = manager.getActiveNetworkInfo(); + if (networkINfo != null + && networkINfo.getType() == ConnectivityManager.TYPE_WIFI) { + // return true; + } + + // State gprs = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) + // .getState(); + // State wifi = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI) + // .getState(); + // if (gprs == State.CONNECTED || gprs == State.CONNECTING) { + // // Toast.makeText(this, "wifi is open! gprs", + // // Toast.LENGTH_SHORT).show(); + // } + // // 判断为wifi状态下才加载广告,如果是GPRS手机网络则不加载! + // if (wifi == State.CONNECTED || wifi == State.CONNECTING) { + // // Toast.makeText(this, "wifi is open! wifi", + // // Toast.LENGTH_SHORT).show(); + // } + + } + + + + + /** + * 网络已经连接,然后去判断是wifi连接还是GPRS连接 设置一些自己的逻辑调用 + */ + + public static boolean isNetworkAvailable(Context context) { + // 得到网络连接信息 + ConnectivityManager manager = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkINfo = manager.getActiveNetworkInfo(); + if (networkINfo != null + && networkINfo.getType() == ConnectivityManager.TYPE_WIFI) { + return true; + } + + return false; + } +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/util/getAppinfo.java b/app/src/main/java/com/tsgame/tsgame_niuniu/util/getAppinfo.java new file mode 100644 index 0000000..c8f875c --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/util/getAppinfo.java @@ -0,0 +1,47 @@ +package com.tsgame.tsgame_niuniu.util; + + +import com.tsgame.tsgame_niuniu.system.Myapplication; + +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager.NameNotFoundException; + +public class getAppinfo { + public static String getAppVersionName() { + PackageInfo packageInfo; + try { + packageInfo = Myapplication.application.getPackageManager() + .getPackageInfo(Myapplication.application.getPackageName(), + 0); + return packageInfo.versionName; + } catch (NameNotFoundException e) { + e.printStackTrace(); + } + return "1.0"; + } + public static int getAppVersioncode() { + PackageInfo packageInfo; + try { + packageInfo = Myapplication.application.getPackageManager().getPackageInfo(Myapplication.application.getPackageName(),0); + return packageInfo.versionCode; + } catch (NameNotFoundException e) { + e.printStackTrace(); + } + return 1; + } + public static String getAppos() { + + return "ANDROID"; + } + + public static Long getTimeStamp() { + + return System.currentTimeMillis(); + } + + public static String getSign() { + + return ""; + } + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/util/initwebviewutil.java b/app/src/main/java/com/tsgame/tsgame_niuniu/util/initwebviewutil.java new file mode 100644 index 0000000..15d6461 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/util/initwebviewutil.java @@ -0,0 +1,245 @@ +package com.tsgame.tsgame_niuniu.util; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.ZipException; + +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Headers; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +import com.game.webgame.view.SpUtil; +import com.tsgame.tsgame_niuniu.system.Myapplication; + +import android.app.ProgressDialog; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Environment; +import android.os.Handler; +import android.util.Log; + +public class initwebviewutil { + Context context; + + private SharedPreferences sp; + + String kfile = Settingutil.kfile; + + private Handler hadler; + + public static String destFileDir = null; + + private static initwebviewutil webview = null; + + public static initwebviewutil getInstance() { + + if (webview == null) { + webview = new initwebviewutil(); + } + + return webview; + + } + + private final OkHttpClient okclient = new OkHttpClient(); + + public void sethandler(Handler hadler) { + this.hadler = hadler; + } + + public void isfirst() { + + sp = SpUtil.getSharePerference(Myapplication.application); + Boolean istrue = SpUtil.isFirst(sp); + + if (istrue) { + hadler.sendEmptyMessage(3); + + System.out.println("不是第一次"); + } else { + + System.out.println("第一次"); + init(); + + } + } + + public void init() { + + sp = SpUtil.getSharePerference(Myapplication.application); + + File sdFile = null; + + sdFile = Myapplication.application.getFilesDir(); + + // + // System.out.println(sdFile.getAbsolutePath()); + // +// if (Environment.getExternalStorageState().equals( +// Environment.MEDIA_MOUNTED)) { +// // 获取SDCard的路径 +// sdFile = Environment.getExternalStorageDirectory(); +// // Toast.makeText(context, sdFile.getAbsolutePath(), 1).show(); +// } else { +// sdFile = Environment.getDataDirectory(); +// // Toast.makeText(context, sdFile.getPath(), 1).show(); +// } + + getdate(sdFile); + SpUtil.setBooleanSharedPerference(sp, "isFirst", true); + hadler.sendEmptyMessage(3); + } + + private void getdate(File sdFile) { + // 方法测试此抽象路径名定义的文件或目录是否存在。 + // mkdir()只会建立一级的文件夹 + + String path1 = File.separator + Settingutil.filestart; + + String path2 = sdFile.getAbsolutePath() + File.separator + "tsgames" + + File.separator + Myapplication.application.getPackageName() + + File.separator + System.currentTimeMillis(); + + String path = path2 + path1; + ///data/user/0/com.jx.jyhd/files/tsgames/com.jx.jyhd/1505230174618/frdt0C1GG0t91P0McFo0rbA1he5yurbS/Shuangjian + + System.out.println("path="+path); + + + SpUtil.setStringSharedPerference(sp, "urlpath", path); + + //int end = path.length() - path1.length(); + + SpUtil.setStringSharedPerference(sp, "upurlpath", + path2); + + + + + //System.out.println(path.substring(0, end)+"----"); + + //System.out.println(SpUtil.getStringSharedPerference(sp, "urlpath")); + + sdFile = new File(path); + if (!sdFile.exists()) { + sdFile.mkdirs(); + Log.d("ASSETS", sdFile.getAbsolutePath()); + } else { + Log.d("ASSETS", sdFile.getAbsolutePath()); + } + + try { + String[] file = Myapplication.application.getAssets().list(kfile); + if (file.length > 0) { + for (int i = 0; i < file.length; i++) { + + System.out.println("***"+file[i]); + + // String filepath = sdFile.getAbsolutePath() + + // File.separator + // + file[i]; + listdate(sdFile, file[i]); + } + } + } catch (IOException e1) { + e1.printStackTrace(); + } + + } + + private void listdate(File sdFile, String filepath) { + String paths = kfile + File.separator + filepath; + try { + String[] file = Myapplication.application.getAssets().list(paths); + System.out.println("file.length="+file.length); + if (file.length > 0) { + File sdFiles = new File(sdFile.getAbsolutePath() + + File.separator + filepath); + sdFiles.mkdirs(); + for (int i = 0; i < file.length; i++) { + System.out.println(file[i]); + listdate(sdFile, filepath + File.separator + file[i]); + } + } else { + try { + byte[] buffer; + int length; + InputStream inStream; + FileOutputStream outStream; + inStream = Myapplication.application.getAssets() + .open(paths); + + outStream = new FileOutputStream(sdFile + File.separator + + filepath); + + System.out.println(sdFile.getAbsolutePath()); + + buffer = new byte[1024]; + while ((length = inStream.read(buffer)) > 0) { + outStream.write(buffer, 0, length); + } + inStream.close(); + outStream.close(); + + } catch (Exception e) { + e.printStackTrace(); + } + } + } catch (IOException e1) { + e1.printStackTrace(); + } + + + String urlpath1 = SpUtil.getStringSharedPerference(sp, "upurlpath"); + + String urlpath2 = SpUtil.getStringSharedPerference(sp, "urlpath"); + + String url = sdFile + File.separator + filepath; + + if (filepath.endsWith(".so")) { + File file = new File(url); + try { + + System.out.println("解压"); + ZipUtils.upZipFile1(file, urlpath2 + File.separator); + + } catch (ZipException e) { + + e.printStackTrace(); + } catch (IOException e) { + + e.printStackTrace(); + } + }else if(filepath.endsWith(".zip")){ + System.out.println("解压"); + File file = new File(url); + + try { + ZipUtils.upZipFile1(file, urlpath2 + File.separator); + + } catch (ZipException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + } + + delet(url); + } + + private void delet(String url) { + + File dir1 = new File(url); + + if (dir1.exists()) { + dir1.delete(); + } + + } +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/util/permission.java b/app/src/main/java/com/tsgame/tsgame_niuniu/util/permission.java new file mode 100644 index 0000000..202bb98 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/util/permission.java @@ -0,0 +1,5 @@ +package com.tsgame.tsgame_niuniu.util; + +public class permission { + +} diff --git a/app/src/main/java/com/tsgame/tsgame_niuniu/util/phoneutil.java b/app/src/main/java/com/tsgame/tsgame_niuniu/util/phoneutil.java new file mode 100644 index 0000000..b280df7 --- /dev/null +++ b/app/src/main/java/com/tsgame/tsgame_niuniu/util/phoneutil.java @@ -0,0 +1,351 @@ +package com.tsgame.tsgame_niuniu.util; + +import android.Manifest; +import android.app.Activity; +import android.content.ContentResolver; +import android.content.Context; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.provider.ContactsContract; +import android.provider.ContactsContract.CommonDataKinds.Phone; +import android.support.v4.app.ActivityCompat; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.util.Log; +import android.provider.ContactsContract.CommonDataKinds.Photo; +import com.google.gson.Gson; +import com.tsgame.tsgame_niuniu.Bean.LianxirenBean; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringWriter; +import java.io.Writer; +import java.net.NetworkInterface; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +/** + * 作者:YMI on 2018/4/23 16:35 + * 邮箱:18702631465@163.com + * QQ:1078561230 + */ +public class phoneutil { + private static final String marshmallowMacAddress = "02:00:00:00:00:00"; + private static final String fileAddressMac = "/sys/class/net/wlan0/address"; + + Context context1; + /** + * 国际移动用户识别码 + */ + private String IMSI; + + private TelephonyManager telephonyManager; + + public phoneutil(Context context) { + this.context1 = context; + telephonyManager = (TelephonyManager) context + .getSystemService(Context.TELEPHONY_SERVICE); + } + //获取mac + public String getAdresseMAC() { + WifiManager wifiMan = (WifiManager) context1.getSystemService(Context.WIFI_SERVICE); + WifiInfo wifiInf = wifiMan.getConnectionInfo(); + + if (wifiInf != null && marshmallowMacAddress.equals(wifiInf.getMacAddress())) { + String result = null; + try { + result = getAdressMacByInterface(); + if (result != null) { + return result; + } else { + result = getAddressMacByFile(wifiMan); + return result; + } + } catch (IOException e) { + Log.e("MobileAccess", "Erreur lecture propriete Adresse MAC"); + } catch (Exception e) { + Log.e("MobileAcces", "Erreur lecture propriete Adresse MAC "); + } + } else { + if (wifiInf != null && wifiInf.getMacAddress() != null) { + return wifiInf.getMacAddress(); + } else { + return ""; + } + } + return marshmallowMacAddress; + } + + private String getAdressMacByInterface() { + try { + List all = Collections.list(NetworkInterface.getNetworkInterfaces()); + for (NetworkInterface nif : all) { + if (nif.getName().equalsIgnoreCase("wlan0")) { + byte[] macBytes = nif.getHardwareAddress(); + if (macBytes == null) { + return ""; + } + + StringBuilder res1 = new StringBuilder(); + for (byte b : macBytes) { + res1.append(String.format("%02X:", b)); + } + + if (res1.length() > 0) { + res1.deleteCharAt(res1.length() - 1); + } + return res1.toString(); + } + } + + } catch (Exception e) { + Log.e("MobileAcces", "Erreur lecture propriete Adresse MAC "); + } + return null; + } + + private static String getAddressMacByFile(WifiManager wifiMan) throws Exception { + String ret; + int wifiState = wifiMan.getWifiState(); + + wifiMan.setWifiEnabled(true); + File fl = new File(fileAddressMac); + FileInputStream fin = new FileInputStream(fl); + ret = crunchifyGetStringFromStream(fin); + fin.close(); + + boolean enabled = WifiManager.WIFI_STATE_ENABLED == wifiState; + wifiMan.setWifiEnabled(enabled); + return ret; + } + + private static String crunchifyGetStringFromStream(InputStream crunchifyStream) throws IOException { + if (crunchifyStream != null) { + Writer crunchifyWriter = new StringWriter(); + + char[] crunchifyBuffer = new char[2048]; + try { + Reader crunchifyReader = new BufferedReader(new InputStreamReader(crunchifyStream, "UTF-8")); + int counter; + while ((counter = crunchifyReader.read(crunchifyBuffer)) != -1) { + crunchifyWriter.write(crunchifyBuffer, 0, counter); + } + } finally { + crunchifyStream.close(); + } + return crunchifyWriter.toString(); + } else { + return "No Contents"; + } + } + + + /** + * 获取手机服务商信息 + */ + + public String getProvidersName() { + String ProvidersName = "N/A"; + return ProvidersName; +// try { +// if (ActivityCompat.checkSelfPermission(context1, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { +// // TODO: Consider calling +// // ActivityCompat#requestPermissions +// // here to request the missing permissions, and then overriding +// // public void onRequestPermissionsResult(int requestCode, String[] permissions, +// // int[] grantResults) +// // to handle the case where the user grants the permission. See the documentation +// // for ActivityCompat#requestPermissions for more details. +// return ProvidersName; +// } +// +// +// +// +// String Operator = telephonyManager.getSimOperator(); +// // IOperator 返回SIM卡运营商的单个核细胞数+冶 READ_PHONE_STATE +// System.out.println(Operator); +// if (Operator.equals("46000") || Operator.equals("46002") || Operator.equals("46007")) { +// ProvidersName = "中国移动"; +// } else if (Operator.equals("46001")) { +// ProvidersName = "中国联通"; +// } else if (Operator.equals("46003")) { +// ProvidersName = "中国电信"; +// } +// } catch (Exception e) { +// e.printStackTrace(); +// } +// return ProvidersName; + } + + /** + * 获取当前手机系统版本号 + * + * @return 系统版本号 + */ + public static String getSystemVersion() { + return android.os.Build.VERSION.RELEASE; + } + + /** + * 获取手机型号 + * + * @return 手机型号 + */ + public static String getSystemModel() { + return android.os.Build.MODEL; + } + + /** + * 获取手机厂商 + * + * @return 手机品牌 + */ + public static String getDeviceBrand() { + return android.os.Build.BRAND; + } + + /** + * 获取手机IMEI(需要“android.permission.READ_PHONE_STATE”权限) + * + * @return 手机IMEI + */ + public static String getIMEI(Context ctx) { + return ""; +// try{ +// TelephonyManager tm = (TelephonyManager) ctx.getSystemService(Activity.TELEPHONY_SERVICE); +// if (tm != null) { +// if (ActivityCompat.checkSelfPermission(ctx, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { +// // TODO: Consider calling +// // ActivityCompat#requestPermissions +// // here to request the missing permissions, and then overriding +// // public void onRequestPermissionsResult(int requestCode, String[] permissions, +// // int[] grantResults) +// // to handle the case where the user grants the permission. See the documentation +// // for ActivityCompat#requestPermissions for more details. +// return ""; +// } +// return tm.getDeviceId(); +// } +// return null; +// } catch (Exception e) { +// +// e.printStackTrace(); +// +// return ""; +// } + } + /** + * 获取手机IMsI(需要“android.permission.READ_PHONE_STATE”权限) + * + * @return 手机IMsI + */ + public static String getIMsI(Context ctx) { + return ""; +// try{ +// +// TelephonyManager tm = (TelephonyManager) ctx.getSystemService(Activity.TELEPHONY_SERVICE); +// if (tm != null) { +// if (ActivityCompat.checkSelfPermission(ctx, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { +// // TODO: Consider calling +// // ActivityCompat#requestPermissions +// // here to request the missing permissions, and then overriding +// // public void onRequestPermissionsResult(int requestCode, String[] permissions, +// // int[] grantResults) +// // to handle the case where the user grants the permission. See the documentation +// // for ActivityCompat#requestPermissions for more details. +// return ""; +// } +// return tm.getSubscriberId(); +// } +// return null; +// } catch (Exception e) { +// Log.i("getIMsI","Error"); +// e.printStackTrace(); +// +// return ""; +// } + } + + /** 获取库Phon表字段 **/ + private static final String[] PHONES_PROJECTION = new String[] { + Phone.DISPLAY_NAME, Phone.NUMBER, Photo.PHOTO_ID,Phone.CONTACT_ID }; + /** 联系人显示名称 **/ + private static final int PHONES_DISPLAY_NAME_INDEX = 0; + + /** 电话号码 **/ + private static final int PHONES_NUMBER_INDEX = 1; + + /** 头像ID **/ + private static final int PHONES_PHOTO_ID_INDEX = 2; + + /** 联系人的ID **/ + private static final int PHONES_CONTACT_ID_INDEX = 3; + + + /** 得到手机通讯录联系人信息 **/ + public static String getPhoneContacts(Context mContext) { + return ""; +// ContentResolver resolver = mContext.getContentResolver(); +// List list=new ArrayList<>() ; +// // 获取手机联系人 +// Cursor phoneCursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, +// PHONES_PROJECTION, null, null, null); +// +// if (phoneCursor != null) { +// while (phoneCursor.moveToNext()) { +// +// // 得到手机号码 +// String phoneNumber = phoneCursor.getString(PHONES_NUMBER_INDEX); +// // 当手机号码为空的或者为空字段 跳过当前循环 +// if (TextUtils.isEmpty(phoneNumber)) +// continue; +// +// // 得到联系人名称 +// String contactName = phoneCursor +// .getString(PHONES_DISPLAY_NAME_INDEX); +// +// // 得到联系人ID +// Long contactid = phoneCursor.getLong(PHONES_CONTACT_ID_INDEX); +// +// // 得到联系人头像ID +// Long photoid = phoneCursor.getLong(PHONES_PHOTO_ID_INDEX); +// LianxirenBean bean=new LianxirenBean(); +// bean.setContactName(contactName); +// bean.setPhoneNumber(phoneNumber); +// list.add(bean); +// +// // 得到联系人头像Bitamp +//// Bitmap contactPhoto = null; +// +//// // photoid 大于0 表示联系人有头像 如果没有给此人设置头像则给他一个默认的 +//// if (photoid > 0) { +//// Uri uri = ContentUris.withAppendedId( +//// ContactsContract.Contacts.CONTENT_URI, contactid); +//// InputStream input = ContactsContract.Contacts +//// .openContactPhotoInputStream(resolver, uri); +//// contactPhoto = BitmapFactory.decodeStream(input); +//// } else { +//// contactPhoto = BitmapFactory.decodeResource(getResources(), +//// R.mipmap.ic_launcher); +//// } +// +// +// } +// +// phoneCursor.close(); +// } +// Gson gson=new Gson(); +// String name= gson.toJson(list); +// System.out.println("------"+name); +// return name; + + } +} diff --git a/app/src/main/java/com/tz/volleylrucache/cache/libcore/io/DiskLruCache.java b/app/src/main/java/com/tz/volleylrucache/cache/libcore/io/DiskLruCache.java new file mode 100644 index 0000000..0bbc5e3 --- /dev/null +++ b/app/src/main/java/com/tz/volleylrucache/cache/libcore/io/DiskLruCache.java @@ -0,0 +1,953 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.tz.volleylrucache.cache.libcore.io; + +import java.io.BufferedInputStream; +import java.io.BufferedWriter; +import java.io.Closeable; +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.reflect.Array; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + ****************************************************************************** + * Taken from the JB source code, can be found in: + * libcore/luni/src/main/java/libcore/io/DiskLruCache.java + * or direct link: + * https://android.googlesource.com/platform/libcore/+/android-4.1.1_r1/luni/src/main/java/libcore/io/DiskLruCache.java + ****************************************************************************** + * + * A cache that uses a bounded amount of space on a filesystem. Each cache + * entry has a string key and a fixed number of values. Values are byte + * sequences, accessible as streams or files. Each value must be between {@code + * 0} and {@code Integer.MAX_VALUE} bytes in length. + * + *

The cache stores its data in a directory on the filesystem. This + * directory must be exclusive to the cache; the cache may delete or overwrite + * files from its directory. It is an error for multiple processes to use the + * same cache directory at the same time. + * + *

This cache limits the number of bytes that it will store on the + * filesystem. When the number of stored bytes exceeds the limit, the cache will + * remove entries in the background until the limit is satisfied. The limit is + * not strict: the cache may temporarily exceed it while waiting for files to be + * deleted. The limit does not include filesystem overhead or the cache + * journal so space-sensitive applications should set a conservative limit. + * + *

Clients call {@link #edit} to create or update the values of an entry. An + * entry may have only one editor at one time; if a value is not available to be + * edited then {@link #edit} will return null. + *

    + *
  • When an entry is being created it is necessary to + * supply a full set of values; the empty value should be used as a + * placeholder if necessary. + *
  • When an entry is being edited, it is not necessary + * to supply data for every value; values default to their previous + * value. + *
+ * Every {@link #edit} call must be matched by a call to {@link libcore.io.mywardrobe.data.DiskLruCache.Editor#commit} + * or {@link libcore.io.mywardrobe.data.DiskLruCache.Editor#abort}. Committing is atomic: a read observes the full set + * of values as they were before or after the commit, but never a mix of values. + * + *

Clients call {@link #get} to read a snapshot of an entry. The read will + * observe the value at the time that {@link #get} was called. Updates and + * removals after the call do not impact ongoing reads. + * + *

This class is tolerant of some I/O errors. If files are missing from the + * filesystem, the corresponding entries will be dropped from the cache. If + * an error occurs while writing a cache value, the edit will fail silently. + * Callers should handle other problems by catching {@code IOException} and + * responding appropriately. + */ +public final class DiskLruCache implements Closeable { + static final String JOURNAL_FILE = "journal"; + static final String JOURNAL_FILE_TMP = "journal.tmp"; + static final String MAGIC = "libcore.io.DiskLruCache"; + static final String VERSION_1 = "1"; + static final long ANY_SEQUENCE_NUMBER = -1; + private static final String CLEAN = "CLEAN"; + private static final String DIRTY = "DIRTY"; + private static final String REMOVE = "REMOVE"; + private static final String READ = "READ"; + + private static final Charset UTF_8 = Charset.forName("UTF-8"); + private static final int IO_BUFFER_SIZE = 8 * 1024; + + /* + * This cache uses a journal file named "journal". A typical journal file + * looks like this: + * libcore.io.DiskLruCache + * 1 + * 100 + * 2 + * + * CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054 + * DIRTY 335c4c6028171cfddfbaae1a9c313c52 + * CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342 + * REMOVE 335c4c6028171cfddfbaae1a9c313c52 + * DIRTY 1ab96a171faeeee38496d8b330771a7a + * CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234 + * READ 335c4c6028171cfddfbaae1a9c313c52 + * READ 3400330d1dfc7f3f7f4b8d4d803dfcf6 + * + * The first five lines of the journal form its header. They are the + * constant string "libcore.io.DiskLruCache", the disk cache's version, + * the application's version, the value count, and a blank line. + * + * Each of the subsequent lines in the file is a record of the state of a + * cache entry. Each line contains space-separated values: a state, a key, + * and optional state-specific values. + * o DIRTY lines track that an entry is actively being created or updated. + * Every successful DIRTY action should be followed by a CLEAN or REMOVE + * action. DIRTY lines without a matching CLEAN or REMOVE indicate that + * temporary files may need to be deleted. + * o CLEAN lines track a cache entry that has been successfully published + * and may be read. A publish line is followed by the lengths of each of + * its values. + * o READ lines track accesses for LRU. + * o REMOVE lines track entries that have been deleted. + * + * The journal file is appended to as cache operations occur. The journal may + * occasionally be compacted by dropping redundant lines. A temporary file named + * "journal.tmp" will be used during compaction; that file should be deleted if + * it exists when the cache is opened. + */ + + private final File directory; + private final File journalFile; + private final File journalFileTmp; + private final int appVersion; + private final long maxSize; + private final int valueCount; + private long size = 0; + private Writer journalWriter; + private final LinkedHashMap lruEntries + = new LinkedHashMap(0, 0.75f, true); + private int redundantOpCount; + + /** + * To differentiate between old and current snapshots, each entry is given + * a sequence number each time an edit is committed. A snapshot is stale if + * its sequence number is not equal to its entry's sequence number. + */ + private long nextSequenceNumber = 0; + + /* From java.util.Arrays */ + @SuppressWarnings("unchecked") + private static T[] copyOfRange(T[] original, int start, int end) { + final int originalLength = original.length; // For exception priority compatibility. + if (start > end) { + throw new IllegalArgumentException(); + } + if (start < 0 || start > originalLength) { + throw new ArrayIndexOutOfBoundsException(); + } + final int resultLength = end - start; + final int copyLength = Math.min(resultLength, originalLength - start); + final T[] result = (T[]) Array + .newInstance(original.getClass().getComponentType(), resultLength); + System.arraycopy(original, start, result, 0, copyLength); + return result; + } + + /** + * Returns the remainder of 'reader' as a string, closing it when done. + * 灏唕eader娴佸墿浣欓儴鍒嗕互String杩斿洖锛屼笖鍦ㄥ畬鎴愬紡灏唕eader娴佸叧闂� + */ + public static String readFully(Reader reader) throws IOException { + try { + StringWriter writer = new StringWriter(); + char[] buffer = new char[1024]; + int count; + while ((count = reader.read(buffer)) != -1) { + writer.write(buffer, 0, count); + } + return writer.toString(); + } finally { + reader.close(); + } + } + + /** + * Returns the ASCII characters up to but not including the next "\r\n", or + * "\n". + * + * @throws java.io.EOFException if the stream is exhausted before the next newline + * character. + */ + public static String readAsciiLine(InputStream in) throws IOException { + // TODO: support UTF-8 here instead + + StringBuilder result = new StringBuilder(80); + while (true) { + int c = in.read(); + if (c == -1) { + throw new EOFException(); + } else if (c == '\n') { + break; + } + + result.append((char) c); + } + int length = result.length(); + if (length > 0 && result.charAt(length - 1) == '\r') { + result.setLength(length - 1); + } + return result.toString(); + } + + /** + * Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null. + */ + public static void closeQuietly(Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (RuntimeException rethrown) { + throw rethrown; + } catch (Exception ignored) { + } + } + } + + /** + * Recursively delete everything in {@code dir}. + */ + // TODO: this should specify paths as Strings rather than as Files + public static void deleteContents(File dir) throws IOException { + File[] files = dir.listFiles(); + if (files == null) { + throw new IllegalArgumentException("not a directory: " + dir); + } + for (File file : files) { + if (file.isDirectory()) { + deleteContents(file); + } + if (!file.delete()) { + throw new IOException("failed to delete file: " + file); + } + } + } + + /** This cache uses a single background thread to evict entries. */ + private final ExecutorService executorService = new ThreadPoolExecutor(0, 1, + 60L, TimeUnit.SECONDS, new LinkedBlockingQueue()); + private final Callable cleanupCallable = new Callable() { + @Override public Void call() throws Exception { + synchronized (DiskLruCache.this) { + if (journalWriter == null) { + return null; // closed + } + trimToSize(); + if (journalRebuildRequired()) { + rebuildJournal(); + redundantOpCount = 0; + } + } + return null; + } + }; + + private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) { + this.directory = directory; + this.appVersion = appVersion; + this.journalFile = new File(directory, JOURNAL_FILE); + this.journalFileTmp = new File(directory, JOURNAL_FILE_TMP); + this.valueCount = valueCount; + this.maxSize = maxSize; + } + + /** + * Opens the cache in {@code directory}, creating a cache if none exists + * there. + * + * @param directory a writable directory + * @param appVersion + * @param valueCount the number of values per cache entry. Must be positive. + * @param maxSize the maximum number of bytes this cache should use to store + * @throws java.io.IOException if reading or writing the cache directory fails + */ + public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize) + throws IOException { + if (maxSize <= 0) { + throw new IllegalArgumentException("maxSize <= 0"); + } + if (valueCount <= 0) { + throw new IllegalArgumentException("valueCount <= 0"); + } + + // prefer to pick up where we left off + DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); + if (cache.journalFile.exists()) { + try { + cache.readJournal(); + cache.processJournal(); + cache.journalWriter = new BufferedWriter(new FileWriter(cache.journalFile, true), + IO_BUFFER_SIZE); + return cache; + } catch (IOException journalIsCorrupt) { +// System.logW("DiskLruCache " + directory + " is corrupt: " +// + journalIsCorrupt.getMessage() + ", removing"); + cache.delete(); + } + } + + // create a new empty cache + directory.mkdirs(); + cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); + cache.rebuildJournal(); + return cache; + } + + private void readJournal() throws IOException { + InputStream in = new BufferedInputStream(new FileInputStream(journalFile), IO_BUFFER_SIZE); + try { + String magic = readAsciiLine(in); + String version = readAsciiLine(in); + String appVersionString = readAsciiLine(in); + String valueCountString = readAsciiLine(in); + String blank = readAsciiLine(in); + if (!MAGIC.equals(magic) + || !VERSION_1.equals(version) + || !Integer.toString(appVersion).equals(appVersionString) + || !Integer.toString(valueCount).equals(valueCountString) + || !"".equals(blank)) { + throw new IOException("unexpected journal header: [" + + magic + ", " + version + ", " + valueCountString + ", " + blank + "]"); + } + + while (true) { + try { + readJournalLine(readAsciiLine(in)); + } catch (EOFException endOfJournal) { + break; + } + } + } finally { + closeQuietly(in); + } + } + + private void readJournalLine(String line) throws IOException { + String[] parts = line.split(" "); + if (parts.length < 2) { + throw new IOException("unexpected journal line: " + line); + } + + String key = parts[1]; + if (parts[0].equals(REMOVE) && parts.length == 2) { + lruEntries.remove(key); + return; + } + + Entry entry = lruEntries.get(key); + if (entry == null) { + entry = new Entry(key); + lruEntries.put(key, entry); + } + + if (parts[0].equals(CLEAN) && parts.length == 2 + valueCount) { + entry.readable = true; + entry.currentEditor = null; + entry.setLengths(copyOfRange(parts, 2, parts.length)); + } else if (parts[0].equals(DIRTY) && parts.length == 2) { + entry.currentEditor = new Editor(entry); + } else if (parts[0].equals(READ) && parts.length == 2) { + // this work was already done by calling lruEntries.get() + } else { + throw new IOException("unexpected journal line: " + line); + } + } + + /** + * 璇ユ柟娉曠敤浜庡垵濮嬭绠梥ize鐨勫ぇ灏忥紝骞跺垹闄ゆ棤鏁堟枃浠� */ + private void processJournal() throws IOException { + deleteIfExists(journalFileTmp); + for (Iterator i = lruEntries.values().iterator(); i.hasNext(); ) { + Entry entry = i.next(); + if (entry.currentEditor == null) { + for (int t = 0; t < valueCount; t++) { + size += entry.lengths[t]; + } + } else { + entry.currentEditor = null; + for (int t = 0; t < valueCount; t++) { + deleteIfExists(entry.getCleanFile(t)); + deleteIfExists(entry.getDirtyFile(t)); + } + i.remove(); + } + } + } + + /** + * Creates a new journal that omits redundant information. This replaces the + * current journal if it exists. + * + */ + private synchronized void rebuildJournal() throws IOException { + if (journalWriter != null) { + journalWriter.close(); + } + + Writer writer = new BufferedWriter(new FileWriter(journalFileTmp), IO_BUFFER_SIZE); + writer.write(MAGIC); + writer.write("\n"); + writer.write(VERSION_1); + writer.write("\n"); + writer.write(Integer.toString(appVersion)); + writer.write("\n"); + writer.write(Integer.toString(valueCount)); + writer.write("\n"); + writer.write("\n"); + + for (Entry entry : lruEntries.values()) { + if (entry.currentEditor != null) { + writer.write(DIRTY + ' ' + entry.key + '\n'); + } else { + writer.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); + } + } + + writer.close(); + journalFileTmp.renameTo(journalFile); + journalWriter = new BufferedWriter(new FileWriter(journalFile, true), IO_BUFFER_SIZE); + } + + private static void deleteIfExists(File file) throws IOException { +// try { +// Libcore.os.remove(file.getPath()); +// } catch (ErrnoException errnoException) { +// if (errnoException.errno != OsConstants.ENOENT) { +// throw errnoException.rethrowAsIOException(); +// } +// } + if (file.exists() && !file.delete()) { + throw new IOException(); + } + } + + /** + * Returns a snapshot of the entry named {@code key}, or null if it doesn't + * exist is not currently readable. If a value is returned, it is moved to + * the head of the LRU queue. + */ + public synchronized Snapshot get(String key) throws IOException { + checkNotClosed(); + validateKey(key); + Entry entry = lruEntries.get(key); + if (entry == null) { + return null; + } + + if (!entry.readable) { + return null; + } + + /* + * Open all streams eagerly to guarantee that we see a single published + * snapshot. If we opened streams lazily then the streams could come + * from different edits. + */ + InputStream[] ins = new InputStream[valueCount]; + try { + for (int i = 0; i < valueCount; i++) { + ins[i] = new FileInputStream(entry.getCleanFile(i)); + } + } catch (FileNotFoundException e) { + // a file must have been deleted manually! + return null; + } + + redundantOpCount++; + journalWriter.append(READ + ' ' + key + '\n'); + if (journalRebuildRequired()) { + executorService.submit(cleanupCallable); + } + + return new Snapshot(key, entry.sequenceNumber, ins); + } + + /** + * Returns an editor for the entry named {@code key}, or null if another + * edit is in progress. + */ + public Editor edit(String key) throws IOException { + return edit(key, ANY_SEQUENCE_NUMBER); + } + + private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException { + checkNotClosed(); + validateKey(key); + Entry entry = lruEntries.get(key); + if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER + && (entry == null || entry.sequenceNumber != expectedSequenceNumber)) { + return null; // snapshot is stale + } + if (entry == null) { + entry = new Entry(key); + lruEntries.put(key, entry); + } else if (entry.currentEditor != null) { + return null; // another edit is in progress + } + + Editor editor = new Editor(entry); + entry.currentEditor = editor; + + // flush the journal before creating files to prevent file leaks + journalWriter.write(DIRTY + ' ' + key + '\n'); + journalWriter.flush(); + return editor; + } + + /** + * Returns the directory where this cache stores its data. + */ + public File getDirectory() { + return directory; + } + + /** + * Returns the maximum number of bytes that this cache should use to store + * its data. + */ + public long maxSize() { + return maxSize; + } + + /** + * Returns the number of bytes currently being used to store the values in + * this cache. This may be greater than the max size if a background + * deletion is pending. + */ + public synchronized long size() { + return size; + } + + private synchronized void completeEdit(Editor editor, boolean success) throws IOException { + Entry entry = editor.entry; + if (entry.currentEditor != editor) { + throw new IllegalStateException(); + } + + // if this edit is creating the entry for the first time, every index must have a value + if (success && !entry.readable) { + for (int i = 0; i < valueCount; i++) { + if (!entry.getDirtyFile(i).exists()) { + editor.abort(); + throw new IllegalStateException("edit didn't create file " + i); + } + } + } + + for (int i = 0; i < valueCount; i++) { + File dirty = entry.getDirtyFile(i); + if (success) { + if (dirty.exists()) { + File clean = entry.getCleanFile(i); + dirty.renameTo(clean); + long oldLength = entry.lengths[i]; + long newLength = clean.length(); + entry.lengths[i] = newLength; + size = size - oldLength + newLength; + } + } else { + deleteIfExists(dirty); + } + } + + redundantOpCount++; + entry.currentEditor = null; + if (entry.readable | success) { + entry.readable = true; + journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); + if (success) { + entry.sequenceNumber = nextSequenceNumber++; + } + } else { + lruEntries.remove(entry.key); + journalWriter.write(REMOVE + ' ' + entry.key + '\n'); + } + + if (size > maxSize || journalRebuildRequired()) { + executorService.submit(cleanupCallable); + } + } + + /** + * We only rebuild the journal when it will halve the size of the journal + * and eliminate at least 2000 ops. + */ + private boolean journalRebuildRequired() { + final int REDUNDANT_OP_COMPACT_THRESHOLD = 2000; + return redundantOpCount >= REDUNDANT_OP_COMPACT_THRESHOLD + && redundantOpCount >= lruEntries.size(); + } + + /** + * Drops the entry for {@code key} if it exists and can be removed. Entries + * actively being edited cannot be removed. + * + * @return true if an entry was removed. + */ + public synchronized boolean remove(String key) throws IOException { + checkNotClosed(); + validateKey(key); + Entry entry = lruEntries.get(key); + if (entry == null || entry.currentEditor != null) { + return false; + } + + for (int i = 0; i < valueCount; i++) { + File file = entry.getCleanFile(i); + if (!file.delete()) { + throw new IOException("failed to delete " + file); + } + size -= entry.lengths[i]; + entry.lengths[i] = 0; + } + + redundantOpCount++; + journalWriter.append(REMOVE + ' ' + key + '\n'); + lruEntries.remove(key); + + if (journalRebuildRequired()) { + executorService.submit(cleanupCallable); + } + + return true; + } + + /** + * Returns true if this cache has been closed. + */ + public boolean isClosed() { + return journalWriter == null; + } + + private void checkNotClosed() { + if (journalWriter == null) { + throw new IllegalStateException("cache is closed"); + } + } + + /** + * Force buffered operations to the filesystem. + */ + public synchronized void flush() throws IOException { + checkNotClosed(); + trimToSize(); + journalWriter.flush(); + } + + /** + * Closes this cache. Stored values will remain on the filesystem. + */ + public synchronized void close() throws IOException { + if (journalWriter == null) { + return; // already closed + } + for (Entry entry : new ArrayList(lruEntries.values())) { + if (entry.currentEditor != null) { + entry.currentEditor.abort(); + } + } + trimToSize(); + journalWriter.close(); + journalWriter = null; + } + + private void trimToSize() throws IOException { + while (size > maxSize) { +// Map.Entry toEvict = lruEntries.eldest(); + final Map.Entry toEvict = lruEntries.entrySet().iterator().next(); + remove(toEvict.getKey()); + } + } + + /** + * Closes the cache and deletes all of its stored values. This will delete + * all files in the cache directory including files that weren't created by + * the cache. + */ + public void delete() throws IOException { + close(); + deleteContents(directory); + } + + private void validateKey(String key) { + if (key.contains(" ") || key.contains("\n") || key.contains("\r")) { + throw new IllegalArgumentException( + "keys must not contain spaces or newlines: \"" + key + "\""); + } + } + + private static String inputStreamToString(InputStream in) throws IOException { + return readFully(new InputStreamReader(in, UTF_8)); + } + + /** + * A snapshot of the values for an entry. + */ + public final class Snapshot implements Closeable { + private final String key; + private final long sequenceNumber; + private final InputStream[] ins; + + private Snapshot(String key, long sequenceNumber, InputStream[] ins) { + this.key = key; + this.sequenceNumber = sequenceNumber; + this.ins = ins; + } + + /** + * Returns an editor for this snapshot's entry, or null if either the + * entry has changed since this snapshot was created or if another edit + * is in progress. + */ + public Editor edit() throws IOException { + return DiskLruCache.this.edit(key, sequenceNumber); + } + + /** + * Returns the unbuffered stream with the value for {@code index}. + */ + public InputStream getInputStream(int index) { + return ins[index]; + } + + /** + * Returns the string value for {@code index}. + */ + public String getString(int index) throws IOException { + return inputStreamToString(getInputStream(index)); + } + + @Override public void close() { + for (InputStream in : ins) { + closeQuietly(in); + } + } + } + + /** + * Edits the values for an entry. + */ + public final class Editor { + private final Entry entry; + private boolean hasErrors; + + private Editor(Entry entry) { + this.entry = entry; + } + + /** + * Returns an unbuffered input stream to read the last committed value, + * or null if no value has been committed. + */ + public InputStream newInputStream(int index) throws IOException { + synchronized (DiskLruCache.this) { + if (entry.currentEditor != this) { + throw new IllegalStateException(); + } + if (!entry.readable) { + return null; + } + return new FileInputStream(entry.getCleanFile(index)); + } + } + + /** + * Returns the last committed value as a string, or null if no value + * has been committed. + */ + public String getString(int index) throws IOException { + InputStream in = newInputStream(index); + return in != null ? inputStreamToString(in) : null; + } + + /** + * Returns a new unbuffered output stream to write the value at + * {@code index}. If the underlying output stream encounters errors + * when writing to the filesystem, this edit will be aborted when + * {@link #commit} is called. The returned output stream does not throw + * IOExceptions. + */ + public OutputStream newOutputStream(int index) throws IOException { + synchronized (DiskLruCache.this) { + if (entry.currentEditor != this) { + throw new IllegalStateException(); + } + return new FaultHidingOutputStream(new FileOutputStream(entry.getDirtyFile(index))); + } + } + + /** + * Sets the value at {@code index} to {@code value}. + */ + public void set(int index, String value) throws IOException { + Writer writer = null; + try { + writer = new OutputStreamWriter(newOutputStream(index), UTF_8); + writer.write(value); + } finally { + closeQuietly(writer); + } + } + + /** + * Commits this edit so it is visible to readers. This releases the + * edit lock so another edit may be started on the same key. + */ + public void commit() throws IOException { + if (hasErrors) { + completeEdit(this, false); + remove(entry.key); // the previous entry is stale + } else { + completeEdit(this, true); + } + } + + /** + * Aborts this edit. This releases the edit lock so another edit may be + * started on the same key. + */ + public void abort() throws IOException { + completeEdit(this, false); + } + + private class FaultHidingOutputStream extends FilterOutputStream { + private FaultHidingOutputStream(OutputStream out) { + super(out); + } + + @Override public void write(int oneByte) { + try { + out.write(oneByte); + } catch (IOException e) { + hasErrors = true; + } + } + + @Override public void write(byte[] buffer, int offset, int length) { + try { + out.write(buffer, offset, length); + } catch (IOException e) { + hasErrors = true; + } + } + + @Override public void close() { + try { + out.close(); + } catch (IOException e) { + hasErrors = true; + } + } + + @Override public void flush() { + try { + out.flush(); + } catch (IOException e) { + hasErrors = true; + } + } + } + } + + private final class Entry { + private final String key; + + /** Lengths of this entry's files. */ + private final long[] lengths; + + /** True if this entry has ever been published */ + private boolean readable; + + /** The ongoing edit or null if this entry is not being edited. */ + private Editor currentEditor; + + /** The sequence number of the most recently committed edit to this entry. */ + private long sequenceNumber; + + private Entry(String key) { + this.key = key; + this.lengths = new long[valueCount]; + } + + public String getLengths() throws IOException { + StringBuilder result = new StringBuilder(); + for (long size : lengths) { + result.append(' ').append(size); + } + return result.toString(); + } + + /** + * Set lengths using decimal numbers like "10123". + */ + private void setLengths(String[] strings) throws IOException { + if (strings.length != valueCount) { + throw invalidLengths(strings); + } + + try { + for (int i = 0; i < strings.length; i++) { + lengths[i] = Long.parseLong(strings[i]); + } + } catch (NumberFormatException e) { + throw invalidLengths(strings); + } + } + + private IOException invalidLengths(String[] strings) throws IOException { + throw new IOException("unexpected journal line: " + Arrays.toString(strings)); + } + + public File getCleanFile(int i) { + return new File(directory, key + "." + i); + } + + public File getDirtyFile(int i) { + return new File(directory, key + "." + i + ".tmp"); + } + } +} diff --git a/app/src/main/java/com/tz/volleylrucache/cache/libcore/io/Filecache.java b/app/src/main/java/com/tz/volleylrucache/cache/libcore/io/Filecache.java new file mode 100644 index 0000000..155cb59 --- /dev/null +++ b/app/src/main/java/com/tz/volleylrucache/cache/libcore/io/Filecache.java @@ -0,0 +1,63 @@ +package com.tz.volleylrucache.cache.libcore.io; + +import java.io.File; + +import android.app.ActivityManager; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Environment; + +import com.tsgame.tsgame_niuniu.system.Myapplication; + +public class Filecache { + private static String CACHE_DIR_NAME = "imagecache"; + private static DiskLruCache mDiskLruCache; + private static final int MEMORY_CACHE_MAX_SIZE = 1024 * 1024 * ((ActivityManager) Myapplication.application + .getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass() / 8; + + public Filecache() { + try { + if (mDiskLruCache == null) { + // 打开缓存目录 + mDiskLruCache = DiskLruCache.open( + getDiskCacheDir(Myapplication.application, + CACHE_DIR_NAME), + getAppVersion(Myapplication.application), // 版本号,跟app的版本号一直 + 1, // 缓存一个文件是否允许同一个文件缓存两个 + MEMORY_CACHE_MAX_SIZE);// 缓存的最大限制、 + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + private int getAppVersion(Context context) { + PackageInfo packageInfo; + try { + packageInfo = context.getPackageManager().getPackageInfo( + context.getPackageName(), 0); + return packageInfo.versionCode; + } catch (NameNotFoundException e) { + e.printStackTrace(); + } + return 1; + } + + private File getDiskCacheDir(Context context, String appLabel) { + + String path;// /mnt/sdcard/cache/appLabel + if (Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED)) { + // sd卡存储(/mnt/sdcard/cache) + path = context.getExternalCacheDir().getPath(); + } else { + // 没有SD卡,缓存到系统存储 + path = context.getCacheDir().getPath(); + } + return new File(path + File.separator + appLabel); + } + + +} diff --git a/app/src/main/java/com/xys/libzxing/zxing/activity/CaptureActivity.java b/app/src/main/java/com/xys/libzxing/zxing/activity/CaptureActivity.java new file mode 100644 index 0000000..85bab36 --- /dev/null +++ b/app/src/main/java/com/xys/libzxing/zxing/activity/CaptureActivity.java @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.xys.libzxing.zxing.activity; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Rect; +import android.os.Bundle; +import android.os.Handler; +import android.util.Log; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.Window; +import android.view.WindowManager; +import android.view.animation.Animation; +import android.view.animation.TranslateAnimation; +import android.widget.ImageView; +import android.widget.RelativeLayout; + +import com.google.zxing.Result; +import com.jx.jyhd.R; +import com.xys.libzxing.zxing.camera.CameraManager; +import com.xys.libzxing.zxing.decode.DecodeThread; +import com.xys.libzxing.zxing.utils.BeepManager; +import com.xys.libzxing.zxing.utils.CaptureActivityHandler; +import com.xys.libzxing.zxing.utils.InactivityTimer; + +import java.io.IOException; +import java.lang.reflect.Field; + +/** + * This activity opens the camera and does the actual scanning on a background + * thread. It draws a viewfinder to help the user place the barcode correctly, + * shows feedback as the image processing is happening, and then overlays the + * results when a scan is successful. + * + * @author dswitkin@google.com (Daniel Switkin) + * @author Sean Owen + */ +public final class CaptureActivity extends Activity implements SurfaceHolder.Callback { + + private static final String TAG = CaptureActivity.class.getSimpleName(); + + private CameraManager cameraManager; + private CaptureActivityHandler handler; + private InactivityTimer inactivityTimer; + private BeepManager beepManager; + + private SurfaceView scanPreview = null; + private RelativeLayout scanContainer; + private RelativeLayout scanCropView; + private ImageView scanLine; + + private Rect mCropRect = null; + private boolean isHasSurface = false; + + public Handler getHandler() { + return handler; + } + + public CameraManager getCameraManager() { + return cameraManager; + } + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + Window window = getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + setContentView(R.layout.activity_capture); + + scanPreview = (SurfaceView) findViewById(R.id.capture_preview); + scanContainer = (RelativeLayout) findViewById(R.id.capture_container); + scanCropView = (RelativeLayout) findViewById(R.id.capture_crop_view); + scanLine = (ImageView) findViewById(R.id.capture_scan_line); + + inactivityTimer = new InactivityTimer(this); + beepManager = new BeepManager(this); + + TranslateAnimation animation = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, 0.0f, Animation + .RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, + 0.9f); + animation.setDuration(4500); + animation.setRepeatCount(-1); + animation.setRepeatMode(Animation.RESTART); + scanLine.startAnimation(animation); + } + + @Override + protected void onResume() { + super.onResume(); + + // CameraManager must be initialized here, not in onCreate(). This is + // necessary because we don't + // want to open the camera driver and measure the screen size if we're + // going to show the help on + // first launch. That led to bugs where the scanning rectangle was the + // wrong size and partially + // off screen. + cameraManager = new CameraManager(getApplication()); + + handler = null; + + if (isHasSurface) { + // The activity was paused but not stopped, so the surface still + // exists. Therefore + // surfaceCreated() won't be called, so init the camera here. + initCamera(scanPreview.getHolder()); + } else { + // Install the callback and wait for surfaceCreated() to init the + // camera. + scanPreview.getHolder().addCallback(this); + } + + inactivityTimer.onResume(); + } + + @Override + protected void onPause() { + if (handler != null) { + handler.quitSynchronously(); + handler = null; + } + inactivityTimer.onPause(); + beepManager.close(); + cameraManager.closeDriver(); + if (!isHasSurface) { + scanPreview.getHolder().removeCallback(this); + } + super.onPause(); + } + + @Override + protected void onDestroy() { + inactivityTimer.shutdown(); + super.onDestroy(); + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + if (holder == null) { + Log.e(TAG, "*** WARNING *** surfaceCreated() gave us a null surface!"); + } + if (!isHasSurface) { + isHasSurface = true; + initCamera(holder); + } + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + isHasSurface = false; + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + + } + + /** + * A valid barcode has been found, so give an indication of success and show + * the results. + * + * @param rawResult The contents of the barcode. + * @param bundle The extras + */ + public void handleDecode(Result rawResult, Bundle bundle) { + inactivityTimer.onActivity(); + beepManager.playBeepSoundAndVibrate(); + + Intent resultIntent = new Intent(); + bundle.putInt("width", mCropRect.width()); + bundle.putInt("height", mCropRect.height()); + bundle.putString("result", rawResult.getText()); + + resultIntent.putExtras(bundle); + this.setResult(RESULT_OK, resultIntent); + CaptureActivity.this.finish(); + } + + private void initCamera(SurfaceHolder surfaceHolder) { + if (surfaceHolder == null) { + throw new IllegalStateException("No SurfaceHolder provided"); + } + if (cameraManager.isOpen()) { + Log.w(TAG, "initCamera() while already open -- late SurfaceView callback?"); + return; + } + try { + cameraManager.openDriver(surfaceHolder); + // Creating the handler starts the preview, which can also throw a + // RuntimeException. + if (handler == null) { + handler = new CaptureActivityHandler(this, cameraManager, DecodeThread.ALL_MODE); + } + + initCrop(); + } catch (IOException ioe) { + Log.w(TAG, ioe); + displayFrameworkBugMessageAndExit(); + } catch (RuntimeException e) { + // Barcode Scanner has seen crashes in the wild of this variety: + // java.?lang.?RuntimeException: Fail to connect to camera service + Log.w(TAG, "Unexpected error initializing camera", e); + displayFrameworkBugMessageAndExit(); + } + } + + private void displayFrameworkBugMessageAndExit() { + // camera error + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(R.string.app_name)); + builder.setMessage("Camera error"); + builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + + }); + builder.setOnCancelListener(new DialogInterface.OnCancelListener() { + + @Override + public void onCancel(DialogInterface dialog) { + finish(); + } + }); + builder.show(); + } + + public void restartPreviewAfterDelay(long delayMS) { + if (handler != null) { + handler.sendEmptyMessageDelayed(R.id.restart_preview, delayMS); + } + } + + public Rect getCropRect() { + return mCropRect; + } + + /** + * 初始化截取的矩形区域 + */ + private void initCrop() { + int cameraWidth = cameraManager.getCameraResolution().y; + int cameraHeight = cameraManager.getCameraResolution().x; + + /** 获取布局中扫描框的位置信息 */ + int[] location = new int[2]; + scanCropView.getLocationInWindow(location); + + int cropLeft = location[0]; + int cropTop = location[1] - getStatusBarHeight(); + + int cropWidth = scanCropView.getWidth(); + int cropHeight = scanCropView.getHeight(); + + /** 获取布局容器的宽高 */ + int containerWidth = scanContainer.getWidth(); + int containerHeight = scanContainer.getHeight(); + + /** 计算最终截取的矩形的左上角顶点x坐标 */ + int x = cropLeft * cameraWidth / containerWidth; + /** 计算最终截取的矩形的左上角顶点y坐标 */ + int y = cropTop * cameraHeight / containerHeight; + + /** 计算最终截取的矩形的宽度 */ + int width = cropWidth * cameraWidth / containerWidth; + /** 计算最终截取的矩形的高度 */ + int height = cropHeight * cameraHeight / containerHeight; + + /** 生成最终的截取的矩形 */ + mCropRect = new Rect(x, y, width + x, height + y); + } + + private int getStatusBarHeight() { + try { + Class c = Class.forName("com.android.internal.R$dimen"); + Object obj = c.newInstance(); + Field field = c.getField("status_bar_height"); + int x = Integer.parseInt(field.get(obj).toString()); + return getResources().getDimensionPixelSize(x); + } catch (Exception e) { + e.printStackTrace(); + } + return 0; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/xys/libzxing/zxing/camera/AutoFocusManager.java b/app/src/main/java/com/xys/libzxing/zxing/camera/AutoFocusManager.java new file mode 100644 index 0000000..268575d --- /dev/null +++ b/app/src/main/java/com/xys/libzxing/zxing/camera/AutoFocusManager.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.xys.libzxing.zxing.camera; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.hardware.Camera; +import android.os.AsyncTask; +import android.os.Build; +import android.util.Log; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.RejectedExecutionException; + +public class AutoFocusManager implements Camera.AutoFocusCallback { + + private static final String TAG = AutoFocusManager.class.getSimpleName(); + + private static final long AUTO_FOCUS_INTERVAL_MS = 2000L; + private static final Collection FOCUS_MODES_CALLING_AF; + + static { + FOCUS_MODES_CALLING_AF = new ArrayList(2); + FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_AUTO); + FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_MACRO); + } + + private final boolean useAutoFocus; + private final Camera camera; + private boolean stopped; + private boolean focusing; + private AsyncTask outstandingTask; + + public AutoFocusManager(Context context, Camera camera) { + this.camera = camera; + String currentFocusMode = camera.getParameters().getFocusMode(); + useAutoFocus = FOCUS_MODES_CALLING_AF.contains(currentFocusMode); + Log.i(TAG, "Current focus mode '" + currentFocusMode + "'; use auto focus? " + useAutoFocus); + start(); + } + + @Override + public synchronized void onAutoFocus(boolean success, Camera theCamera) { + focusing = false; + autoFocusAgainLater(); + } + + @SuppressLint("NewApi") + private synchronized void autoFocusAgainLater() { + if (!stopped && outstandingTask == null) { + AutoFocusTask newTask = new AutoFocusTask(); + try { + if (Build.VERSION.SDK_INT >= 11) { + newTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } else { + newTask.execute(); + } + outstandingTask = newTask; + } catch (RejectedExecutionException ree) { + Log.w(TAG, "Could not request auto focus", ree); + } + } + } + + public synchronized void start() { + if (useAutoFocus) { + outstandingTask = null; + if (!stopped && !focusing) { + try { + camera.autoFocus(this); + focusing = true; + } catch (RuntimeException re) { + // Have heard RuntimeException reported in Android 4.0.x+; + // continue? + Log.w(TAG, "Unexpected exception while focusing", re); + // Try again later to keep cycle going + autoFocusAgainLater(); + } + } + } + } + + private synchronized void cancelOutstandingTask() { + if (outstandingTask != null) { + if (outstandingTask.getStatus() != AsyncTask.Status.FINISHED) { + outstandingTask.cancel(true); + } + outstandingTask = null; + } + } + + public synchronized void stop() { + stopped = true; + if (useAutoFocus) { + cancelOutstandingTask(); + // Doesn't hurt to call this even if not focusing + try { + camera.cancelAutoFocus(); + } catch (RuntimeException re) { + // Have heard RuntimeException reported in Android 4.0.x+; + // continue? + Log.w(TAG, "Unexpected exception while cancelling focusing", re); + } + } + } + + private final class AutoFocusTask extends AsyncTask { + @Override + protected Object doInBackground(Object... voids) { + try { + Thread.sleep(AUTO_FOCUS_INTERVAL_MS); + } catch (InterruptedException e) { + // continue + } + start(); + return null; + } + } + +} diff --git a/app/src/main/java/com/xys/libzxing/zxing/camera/CameraConfigurationManager.java b/app/src/main/java/com/xys/libzxing/zxing/camera/CameraConfigurationManager.java new file mode 100644 index 0000000..0fb83f4 --- /dev/null +++ b/app/src/main/java/com/xys/libzxing/zxing/camera/CameraConfigurationManager.java @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.xys.libzxing.zxing.camera; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Point; +import android.hardware.Camera; +import android.util.Log; +import android.view.Display; +import android.view.WindowManager; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +/** + * 邮箱: 1076559197@qq.com | tauchen1990@gmail.com + *

+ * 作者: 陈涛 + *

+ * 日期: 2014年8月20日 + *

+ * 描述: 该类主要负责设置相机的参数信息,获取最佳的预览界面 + */ +public final class CameraConfigurationManager { + + private static final String TAG = "CameraConfiguration"; + + private static final int MIN_PREVIEW_PIXELS = 480 * 320; + private static final double MAX_ASPECT_DISTORTION = 0.15; + + private final Context context; + + // 屏幕分辨率 + private Point screenResolution; + // 相机分辨率 + private Point cameraResolution; + + public CameraConfigurationManager(Context context) { + this.context = context; + } + + public void initFromCameraParameters(Camera camera) { + Camera.Parameters parameters = camera.getParameters(); + WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + Display display = manager.getDefaultDisplay(); + Point theScreenResolution = new Point(); + theScreenResolution = getDisplaySize(display); + + screenResolution = theScreenResolution; + Log.i(TAG, "Screen resolution: " + screenResolution); + + /** 因为换成了竖屏显示,所以不替换屏幕宽高得出的预览图是变形的 */ + Point screenResolutionForCamera = new Point(); + screenResolutionForCamera.x = screenResolution.x; + screenResolutionForCamera.y = screenResolution.y; + + if (screenResolution.x < screenResolution.y) { + screenResolutionForCamera.x = screenResolution.y; + screenResolutionForCamera.y = screenResolution.x; + } + + cameraResolution = findBestPreviewSizeValue(parameters, screenResolutionForCamera); + Log.i(TAG, "Camera resolution x: " + cameraResolution.x); + Log.i(TAG, "Camera resolution y: " + cameraResolution.y); + } + + @SuppressWarnings("deprecation") + @SuppressLint("NewApi") + private Point getDisplaySize(final Display display) { + final Point point = new Point(); + try { + display.getSize(point); + } catch (NoSuchMethodError ignore) { + point.x = display.getWidth(); + point.y = display.getHeight(); + } + return point; + } + + public void setDesiredCameraParameters(Camera camera, boolean safeMode) { + Camera.Parameters parameters = camera.getParameters(); + + if (parameters == null) { + Log.w(TAG, "Device error: no camera parameters are available. Proceeding without configuration."); + return; + } + + Log.i(TAG, "Initial camera parameters: " + parameters.flatten()); + + if (safeMode) { + Log.w(TAG, "In camera config safe mode -- most settings will not be honored"); + } + + parameters.setPreviewSize(cameraResolution.x, cameraResolution.y); + camera.setParameters(parameters); + + Camera.Parameters afterParameters = camera.getParameters(); + Camera.Size afterSize = afterParameters.getPreviewSize(); + if (afterSize != null && (cameraResolution.x != afterSize.width || cameraResolution.y != afterSize + .height)) { + Log.w(TAG, "Camera said it supported preview size " + cameraResolution.x + 'x' + + cameraResolution.y + ", but after setting it, preview size is " + afterSize.width + 'x' + + afterSize.height); + cameraResolution.x = afterSize.width; + cameraResolution.y = afterSize.height; + } + + /** 设置相机预览为竖屏 */ + camera.setDisplayOrientation(90); + } + + public Point getCameraResolution() { + return cameraResolution; + } + + public Point getScreenResolution() { + return screenResolution; + } + + /** + * 从相机支持的分辨率中计算出最适合的预览界面尺寸 + * + * @param parameters + * @param screenResolution + * @return + */ + private Point findBestPreviewSizeValue(Camera.Parameters parameters, Point screenResolution) { + List rawSupportedSizes = parameters.getSupportedPreviewSizes(); + if (rawSupportedSizes == null) { + Log.w(TAG, "Device returned no supported preview sizes; using default"); + Camera.Size defaultSize = parameters.getPreviewSize(); + return new Point(defaultSize.width, defaultSize.height); + } + + // Sort by size, descending + List supportedPreviewSizes = new ArrayList(rawSupportedSizes); + Collections.sort(supportedPreviewSizes, new Comparator() { + @Override + public int compare(Camera.Size a, Camera.Size b) { + int aPixels = a.height * a.width; + int bPixels = b.height * b.width; + if (bPixels < aPixels) { + return -1; + } + if (bPixels > aPixels) { + return 1; + } + return 0; + } + }); + + if (Log.isLoggable(TAG, Log.INFO)) { + StringBuilder previewSizesString = new StringBuilder(); + for (Camera.Size supportedPreviewSize : supportedPreviewSizes) { + previewSizesString.append(supportedPreviewSize.width).append('x').append + (supportedPreviewSize.height).append(' '); + } + Log.i(TAG, "Supported preview sizes: " + previewSizesString); + } + + double screenAspectRatio = (double) screenResolution.x / (double) screenResolution.y; + + // Remove sizes that are unsuitable + Iterator it = supportedPreviewSizes.iterator(); + while (it.hasNext()) { + Camera.Size supportedPreviewSize = it.next(); + int realWidth = supportedPreviewSize.width; + int realHeight = supportedPreviewSize.height; + if (realWidth * realHeight < MIN_PREVIEW_PIXELS) { + it.remove(); + continue; + } + + boolean isCandidatePortrait = realWidth < realHeight; + int maybeFlippedWidth = isCandidatePortrait ? realHeight : realWidth; + int maybeFlippedHeight = isCandidatePortrait ? realWidth : realHeight; + + double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight; + double distortion = Math.abs(aspectRatio - screenAspectRatio); + if (distortion > MAX_ASPECT_DISTORTION) { + it.remove(); + continue; + } + + if (maybeFlippedWidth == screenResolution.x && maybeFlippedHeight == screenResolution.y) { + Point exactPoint = new Point(realWidth, realHeight); + Log.i(TAG, "Found preview size exactly matching screen size: " + exactPoint); + return exactPoint; + } + } + + // If no exact match, use largest preview size. This was not a great + // idea on older devices because + // of the additional computation needed. We're likely to get here on + // newer Android 4+ devices, where + // the CPU is much more powerful. + if (!supportedPreviewSizes.isEmpty()) { + Camera.Size largestPreview = supportedPreviewSizes.get(0); + Point largestSize = new Point(largestPreview.width, largestPreview.height); + Log.i(TAG, "Using largest suitable preview size: " + largestSize); + return largestSize; + } + + // If there is nothing at all suitable, return current preview size + Camera.Size defaultPreview = parameters.getPreviewSize(); + Point defaultSize = new Point(defaultPreview.width, defaultPreview.height); + Log.i(TAG, "No suitable preview sizes, using default: " + defaultSize); + + return defaultSize; + } +} diff --git a/app/src/main/java/com/xys/libzxing/zxing/camera/CameraManager.java b/app/src/main/java/com/xys/libzxing/zxing/camera/CameraManager.java new file mode 100644 index 0000000..6722f08 --- /dev/null +++ b/app/src/main/java/com/xys/libzxing/zxing/camera/CameraManager.java @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.xys.libzxing.zxing.camera; + +import android.content.Context; +import android.graphics.Point; +import android.hardware.Camera; +import android.hardware.Camera.Size; +import android.os.Handler; +import android.util.Log; +import android.view.SurfaceHolder; + +import com.xys.libzxing.zxing.camera.open.OpenCameraInterface; + +import java.io.IOException; + +/** + * This object wraps the Camera service object and expects to be the only one + * talking to it. The implementation encapsulates the steps needed to take + * preview-sized images, which are used for both preview and decoding. + * + * @author dswitkin@google.com (Daniel Switkin) + */ +public class CameraManager { + + private static final String TAG = CameraManager.class.getSimpleName(); + + private final Context context; + private final CameraConfigurationManager configManager; + /** + * Preview frames are delivered here, which we pass on to the registered + * handler. Make sure to clear the handler so it will only receive one + * message. + */ + private final PreviewCallback previewCallback; + private Camera camera; + private AutoFocusManager autoFocusManager; + private boolean initialized; + private boolean previewing; + private int requestedCameraId = -1; + + public CameraManager(Context context) { + this.context = context; + this.configManager = new CameraConfigurationManager(context); + previewCallback = new PreviewCallback(configManager); + } + + /** + * Opens the camera driver and initializes the hardware parameters. + * + * @param holder The surface object which the camera will draw preview frames + * into. + * @throws IOException Indicates the camera driver failed to open. + */ + public synchronized void openDriver(SurfaceHolder holder) throws IOException { + Camera theCamera = camera; + if (theCamera == null) { + + if (requestedCameraId >= 0) { + theCamera = OpenCameraInterface.open(requestedCameraId); + } else { + theCamera = OpenCameraInterface.open(); + } + + if (theCamera == null) { + throw new IOException(); + } + camera = theCamera; + } + theCamera.setPreviewDisplay(holder); + + if (!initialized) { + initialized = true; + configManager.initFromCameraParameters(theCamera); + } + + Camera.Parameters parameters = theCamera.getParameters(); + String parametersFlattened = parameters == null ? null : parameters.flatten(); // Save + // these, + // temporarily + try { + configManager.setDesiredCameraParameters(theCamera, false); + } catch (RuntimeException re) { + // Driver failed + Log.w(TAG, "Camera rejected parameters. Setting only minimal safe-mode parameters"); + Log.i(TAG, "Resetting to saved camera params: " + parametersFlattened); + // Reset: + if (parametersFlattened != null) { + parameters = theCamera.getParameters(); + parameters.unflatten(parametersFlattened); + try { + theCamera.setParameters(parameters); + configManager.setDesiredCameraParameters(theCamera, true); + } catch (RuntimeException re2) { + // Well, darn. Give up + Log.w(TAG, "Camera rejected even safe-mode parameters! No configuration"); + } + } + } + + } + + public synchronized boolean isOpen() { + return camera != null; + } + + /** + * Closes the camera driver if still in use. + */ + public synchronized void closeDriver() { + if (camera != null) { + camera.release(); + camera = null; + // Make sure to clear these each time we close the camera, so that + // any scanning rect + // requested by intent is forgotten. + } + } + + /** + * Asks the camera hardware to begin drawing preview frames to the screen. + */ + public synchronized void startPreview() { + Camera theCamera = camera; + if (theCamera != null && !previewing) { + theCamera.startPreview(); + previewing = true; + autoFocusManager = new AutoFocusManager(context, camera); + } + } + + /** + * Tells the camera to stop drawing preview frames. + */ + public synchronized void stopPreview() { + if (autoFocusManager != null) { + autoFocusManager.stop(); + autoFocusManager = null; + } + if (camera != null && previewing) { + camera.stopPreview(); + previewCallback.setHandler(null, 0); + previewing = false; + } + } + + /** + * A single preview frame will be returned to the handler supplied. The data + * will arrive as byte[] in the message.obj field, with width and height + * encoded as message.arg1 and message.arg2, respectively. + * + * @param handler The handler to send the message to. + * @param message The what field of the message to be sent. + */ + public synchronized void requestPreviewFrame(Handler handler, int message) { + Camera theCamera = camera; + if (theCamera != null && previewing) { + previewCallback.setHandler(handler, message); + theCamera.setOneShotPreviewCallback(previewCallback); + } + } + + /** + * Allows third party apps to specify the camera ID, rather than determine + * it automatically based on available cameras and their orientation. + * + * @param cameraId camera ID of the camera to use. A negative value means + * "no preference". + */ + public synchronized void setManualCameraId(int cameraId) { + requestedCameraId = cameraId; + } + + /** + * 获取相机分辨率 + * + * @return + */ + public Point getCameraResolution() { + return configManager.getCameraResolution(); + } + + public Size getPreviewSize() { + if (null != camera) { + return camera.getParameters().getPreviewSize(); + } + return null; + } +} diff --git a/app/src/main/java/com/xys/libzxing/zxing/camera/PreviewCallback.java b/app/src/main/java/com/xys/libzxing/zxing/camera/PreviewCallback.java new file mode 100644 index 0000000..4dbbcd9 --- /dev/null +++ b/app/src/main/java/com/xys/libzxing/zxing/camera/PreviewCallback.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.xys.libzxing.zxing.camera; + +import android.graphics.Point; +import android.hardware.Camera; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +public class PreviewCallback implements Camera.PreviewCallback { + + private static final String TAG = PreviewCallback.class.getSimpleName(); + + private final CameraConfigurationManager configManager; + private Handler previewHandler; + private int previewMessage; + + public PreviewCallback(CameraConfigurationManager configManager) { + this.configManager = configManager; + } + + public void setHandler(Handler previewHandler, int previewMessage) { + this.previewHandler = previewHandler; + this.previewMessage = previewMessage; + } + + @Override + public void onPreviewFrame(byte[] data, Camera camera) { + Point cameraResolution = configManager.getCameraResolution(); + Handler thePreviewHandler = previewHandler; + if (cameraResolution != null && thePreviewHandler != null) { + Message message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x, + cameraResolution.y, data); + message.sendToTarget(); + previewHandler = null; + } else { + Log.d(TAG, "Got preview callback, but no handler or resolution available"); + } + } + +} diff --git a/app/src/main/java/com/xys/libzxing/zxing/camera/copy/AutoFocusManager.java b/app/src/main/java/com/xys/libzxing/zxing/camera/copy/AutoFocusManager.java new file mode 100644 index 0000000..b05b237 --- /dev/null +++ b/app/src/main/java/com/xys/libzxing/zxing/camera/copy/AutoFocusManager.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.xys.libzxing.zxing.camera.copy; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.hardware.Camera; +import android.os.AsyncTask; +import android.os.Build; +import android.util.Log; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.RejectedExecutionException; + +public class AutoFocusManager implements Camera.AutoFocusCallback { + + private static final String TAG = AutoFocusManager.class.getSimpleName(); + + private static final long AUTO_FOCUS_INTERVAL_MS = 2000L; + private static final Collection FOCUS_MODES_CALLING_AF; + + static { + FOCUS_MODES_CALLING_AF = new ArrayList(2); + FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_AUTO); + FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_MACRO); + } + + private final boolean useAutoFocus; + private final Camera camera; + private boolean stopped; + private boolean focusing; + private AsyncTask outstandingTask; + + public AutoFocusManager(Context context, Camera camera) { + this.camera = camera; + String currentFocusMode = camera.getParameters().getFocusMode(); + useAutoFocus = FOCUS_MODES_CALLING_AF.contains(currentFocusMode); + Log.i(TAG, "Current focus mode '" + currentFocusMode + "'; use auto focus? " + useAutoFocus); + start(); + } + + @Override + public synchronized void onAutoFocus(boolean success, Camera theCamera) { + focusing = false; + autoFocusAgainLater(); + } + + @SuppressLint("NewApi") + private synchronized void autoFocusAgainLater() { + if (!stopped && outstandingTask == null) { + AutoFocusTask newTask = new AutoFocusTask(); + try { + if (Build.VERSION.SDK_INT >= 11) { + newTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } else { + newTask.execute(); + } + outstandingTask = newTask; + } catch (RejectedExecutionException ree) { + Log.w(TAG, "Could not request auto focus", ree); + } + } + } + + public synchronized void start() { + if (useAutoFocus) { + outstandingTask = null; + if (!stopped && !focusing) { + try { + camera.autoFocus(this); + focusing = true; + } catch (RuntimeException re) { + // Have heard RuntimeException reported in Android 4.0.x+; + // continue? + Log.w(TAG, "Unexpected exception while focusing", re); + // Try again later to keep cycle going + autoFocusAgainLater(); + } + } + } + } + + private synchronized void cancelOutstandingTask() { + if (outstandingTask != null) { + if (outstandingTask.getStatus() != AsyncTask.Status.FINISHED) { + outstandingTask.cancel(true); + } + outstandingTask = null; + } + } + + public synchronized void stop() { + stopped = true; + if (useAutoFocus) { + cancelOutstandingTask(); + // Doesn't hurt to call this even if not focusing + try { + camera.cancelAutoFocus(); + } catch (RuntimeException re) { + // Have heard RuntimeException reported in Android 4.0.x+; + // continue? + Log.w(TAG, "Unexpected exception while cancelling focusing", re); + } + } + } + + private final class AutoFocusTask extends AsyncTask { + @Override + protected Object doInBackground(Object... voids) { + try { + Thread.sleep(AUTO_FOCUS_INTERVAL_MS); + } catch (InterruptedException e) { + // continue + } + start(); + return null; + } + } + +} diff --git a/app/src/main/java/com/xys/libzxing/zxing/camera/copy/CameraConfigurationManager.java b/app/src/main/java/com/xys/libzxing/zxing/camera/copy/CameraConfigurationManager.java new file mode 100644 index 0000000..34bc8b6 --- /dev/null +++ b/app/src/main/java/com/xys/libzxing/zxing/camera/copy/CameraConfigurationManager.java @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.xys.libzxing.zxing.camera.copy; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Point; +import android.hardware.Camera; +import android.util.Log; +import android.view.Display; +import android.view.WindowManager; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +/** + * 邮箱: 1076559197@qq.com | tauchen1990@gmail.com + *

+ * 作者: 陈涛 + *

+ * 日期: 2014年8月20日 + *

+ * 描述: 该类主要负责设置相机的参数信息,获取最佳的预览界面 + */ +public final class CameraConfigurationManager { + + private static final String TAG = "CameraConfiguration"; + + private static final int MIN_PREVIEW_PIXELS = 480 * 320; + private static final double MAX_ASPECT_DISTORTION = 0.15; + + private final Context context; + + // 屏幕分辨率 + private Point screenResolution; + // 相机分辨率 + private Point cameraResolution; + + public CameraConfigurationManager(Context context) { + this.context = context; + } + + public void initFromCameraParameters(Camera camera) { + Camera.Parameters parameters = camera.getParameters(); + WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + Display display = manager.getDefaultDisplay(); + Point theScreenResolution = new Point(); + theScreenResolution = getDisplaySize(display); + + screenResolution = theScreenResolution; + Log.i(TAG, "Screen resolution: " + screenResolution); + + /** 因为换成了竖屏显示,所以不替换屏幕宽高得出的预览图是变形的 */ + Point screenResolutionForCamera = new Point(); + screenResolutionForCamera.x = screenResolution.x; + screenResolutionForCamera.y = screenResolution.y; + + if (screenResolution.x < screenResolution.y) { + screenResolutionForCamera.x = screenResolution.y; + screenResolutionForCamera.y = screenResolution.x; + } + + cameraResolution = findBestPreviewSizeValue(parameters, screenResolutionForCamera); + Log.i(TAG, "Camera resolution x: " + cameraResolution.x); + Log.i(TAG, "Camera resolution y: " + cameraResolution.y); + } + + @SuppressWarnings("deprecation") + @SuppressLint("NewApi") + private Point getDisplaySize(final Display display) { + final Point point = new Point(); + try { + display.getSize(point); + } catch (NoSuchMethodError ignore) { + point.x = display.getWidth(); + point.y = display.getHeight(); + } + return point; + } + + public void setDesiredCameraParameters(Camera camera, boolean safeMode) { + Camera.Parameters parameters = camera.getParameters(); + + if (parameters == null) { + Log.w(TAG, "Device error: no camera parameters are available. Proceeding without configuration."); + return; + } + + Log.i(TAG, "Initial camera parameters: " + parameters.flatten()); + + if (safeMode) { + Log.w(TAG, "In camera config safe mode -- most settings will not be honored"); + } + + parameters.setPreviewSize(cameraResolution.x, cameraResolution.y); + camera.setParameters(parameters); + + Camera.Parameters afterParameters = camera.getParameters(); + Camera.Size afterSize = afterParameters.getPreviewSize(); + if (afterSize != null && (cameraResolution.x != afterSize.width || cameraResolution.y != afterSize + .height)) { + Log.w(TAG, "Camera said it supported preview size " + cameraResolution.x + 'x' + + cameraResolution.y + ", but after setting it, preview size is " + afterSize.width + 'x' + + afterSize.height); + cameraResolution.x = afterSize.width; + cameraResolution.y = afterSize.height; + } + + /** 设置相机预览为竖屏 */ + camera.setDisplayOrientation(90); + } + + public Point getCameraResolution() { + return cameraResolution; + } + + public Point getScreenResolution() { + return screenResolution; + } + + /** + * 从相机支持的分辨率中计算出最适合的预览界面尺寸 + * + * @param parameters + * @param screenResolution + * @return + */ + private Point findBestPreviewSizeValue(Camera.Parameters parameters, Point screenResolution) { + List rawSupportedSizes = parameters.getSupportedPreviewSizes(); + if (rawSupportedSizes == null) { + Log.w(TAG, "Device returned no supported preview sizes; using default"); + Camera.Size defaultSize = parameters.getPreviewSize(); + return new Point(defaultSize.width, defaultSize.height); + } + + // Sort by size, descending + List supportedPreviewSizes = new ArrayList(rawSupportedSizes); + Collections.sort(supportedPreviewSizes, new Comparator() { + @Override + public int compare(Camera.Size a, Camera.Size b) { + int aPixels = a.height * a.width; + int bPixels = b.height * b.width; + if (bPixels < aPixels) { + return -1; + } + if (bPixels > aPixels) { + return 1; + } + return 0; + } + }); + + if (Log.isLoggable(TAG, Log.INFO)) { + StringBuilder previewSizesString = new StringBuilder(); + for (Camera.Size supportedPreviewSize : supportedPreviewSizes) { + previewSizesString.append(supportedPreviewSize.width).append('x').append + (supportedPreviewSize.height).append(' '); + } + Log.i(TAG, "Supported preview sizes: " + previewSizesString); + } + + double screenAspectRatio = (double) screenResolution.x / (double) screenResolution.y; + + // Remove sizes that are unsuitable + Iterator it = supportedPreviewSizes.iterator(); + while (it.hasNext()) { + Camera.Size supportedPreviewSize = it.next(); + int realWidth = supportedPreviewSize.width; + int realHeight = supportedPreviewSize.height; + if (realWidth * realHeight < MIN_PREVIEW_PIXELS) { + it.remove(); + continue; + } + + boolean isCandidatePortrait = realWidth < realHeight; + int maybeFlippedWidth = isCandidatePortrait ? realHeight : realWidth; + int maybeFlippedHeight = isCandidatePortrait ? realWidth : realHeight; + + double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight; + double distortion = Math.abs(aspectRatio - screenAspectRatio); + if (distortion > MAX_ASPECT_DISTORTION) { + it.remove(); + continue; + } + + if (maybeFlippedWidth == screenResolution.x && maybeFlippedHeight == screenResolution.y) { + Point exactPoint = new Point(realWidth, realHeight); + Log.i(TAG, "Found preview size exactly matching screen size: " + exactPoint); + return exactPoint; + } + } + + // If no exact match, use largest preview size. This was not a great + // idea on older devices because + // of the additional computation needed. We're likely to get here on + // newer Android 4+ devices, where + // the CPU is much more powerful. + if (!supportedPreviewSizes.isEmpty()) { + Camera.Size largestPreview = supportedPreviewSizes.get(0); + Point largestSize = new Point(largestPreview.width, largestPreview.height); + Log.i(TAG, "Using largest suitable preview size: " + largestSize); + return largestSize; + } + + // If there is nothing at all suitable, return current preview size + Camera.Size defaultPreview = parameters.getPreviewSize(); + Point defaultSize = new Point(defaultPreview.width, defaultPreview.height); + Log.i(TAG, "No suitable preview sizes, using default: " + defaultSize); + + return defaultSize; + } +} diff --git a/app/src/main/java/com/xys/libzxing/zxing/camera/copy/CameraManager.java b/app/src/main/java/com/xys/libzxing/zxing/camera/copy/CameraManager.java new file mode 100644 index 0000000..d24af79 --- /dev/null +++ b/app/src/main/java/com/xys/libzxing/zxing/camera/copy/CameraManager.java @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.xys.libzxing.zxing.camera.copy; + +import android.content.Context; +import android.graphics.Point; +import android.hardware.Camera; +import android.hardware.Camera.Size; +import android.os.Handler; +import android.util.Log; +import android.view.SurfaceHolder; + +import com.xys.libzxing.zxing.camera.open.OpenCameraInterface; + +import java.io.IOException; + +/** + * This object wraps the Camera service object and expects to be the only one + * talking to it. The implementation encapsulates the steps needed to take + * preview-sized images, which are used for both preview and decoding. + * + * @author dswitkin@google.com (Daniel Switkin) + */ +public class CameraManager { + + private static final String TAG = CameraManager.class.getSimpleName(); + + private final Context context; + private final CameraConfigurationManager configManager; + /** + * Preview frames are delivered here, which we pass on to the registered + * handler. Make sure to clear the handler so it will only receive one + * message. + */ + private final PreviewCallback previewCallback; + private Camera camera; + private AutoFocusManager autoFocusManager; + private boolean initialized; + private boolean previewing; + private int requestedCameraId = -1; + + public CameraManager(Context context) { + this.context = context; + this.configManager = new CameraConfigurationManager(context); + previewCallback = new PreviewCallback(configManager); + } + + /** + * Opens the camera driver and initializes the hardware parameters. + * + * @param holder The surface object which the camera will draw preview frames + * into. + * @throws IOException Indicates the camera driver failed to open. + */ + public synchronized void openDriver(SurfaceHolder holder) throws IOException { + Camera theCamera = camera; + if (theCamera == null) { + + if (requestedCameraId >= 0) { + theCamera = OpenCameraInterface.open(requestedCameraId); + } else { + theCamera = OpenCameraInterface.open(); + } + + if (theCamera == null) { + throw new IOException(); + } + camera = theCamera; + } + theCamera.setPreviewDisplay(holder); + + if (!initialized) { + initialized = true; + configManager.initFromCameraParameters(theCamera); + } + + Camera.Parameters parameters = theCamera.getParameters(); + String parametersFlattened = parameters == null ? null : parameters.flatten(); // Save + // these, + // temporarily + try { + configManager.setDesiredCameraParameters(theCamera, false); + } catch (RuntimeException re) { + // Driver failed + Log.w(TAG, "Camera rejected parameters. Setting only minimal safe-mode parameters"); + Log.i(TAG, "Resetting to saved camera params: " + parametersFlattened); + // Reset: + if (parametersFlattened != null) { + parameters = theCamera.getParameters(); + parameters.unflatten(parametersFlattened); + try { + theCamera.setParameters(parameters); + configManager.setDesiredCameraParameters(theCamera, true); + } catch (RuntimeException re2) { + // Well, darn. Give up + Log.w(TAG, "Camera rejected even safe-mode parameters! No configuration"); + } + } + } + + } + + public synchronized boolean isOpen() { + return camera != null; + } + + /** + * Closes the camera driver if still in use. + */ + public synchronized void closeDriver() { + if (camera != null) { + camera.release(); + camera = null; + // Make sure to clear these each time we close the camera, so that + // any scanning rect + // requested by intent is forgotten. + } + } + + /** + * Asks the camera hardware to begin drawing preview frames to the screen. + */ + public synchronized void startPreview() { + Camera theCamera = camera; + if (theCamera != null && !previewing) { + theCamera.startPreview(); + previewing = true; + autoFocusManager = new AutoFocusManager(context, camera); + } + } + + /** + * Tells the camera to stop drawing preview frames. + */ + public synchronized void stopPreview() { + if (autoFocusManager != null) { + autoFocusManager.stop(); + autoFocusManager = null; + } + if (camera != null && previewing) { + camera.stopPreview(); + previewCallback.setHandler(null, 0); + previewing = false; + } + } + + /** + * A single preview frame will be returned to the handler supplied. The data + * will arrive as byte[] in the message.obj field, with width and height + * encoded as message.arg1 and message.arg2, respectively. + * + * @param handler The handler to send the message to. + * @param message The what field of the message to be sent. + */ + public synchronized void requestPreviewFrame(Handler handler, int message) { + Camera theCamera = camera; + if (theCamera != null && previewing) { + previewCallback.setHandler(handler, message); + theCamera.setOneShotPreviewCallback(previewCallback); + } + } + + /** + * Allows third party apps to specify the camera ID, rather than determine + * it automatically based on available cameras and their orientation. + * + * @param cameraId camera ID of the camera to use. A negative value means + * "no preference". + */ + public synchronized void setManualCameraId(int cameraId) { + requestedCameraId = cameraId; + } + + /** + * 获取相机分辨率 + * + * @return + */ + public Point getCameraResolution() { + return configManager.getCameraResolution(); + } + + public Size getPreviewSize() { + if (null != camera) { + return camera.getParameters().getPreviewSize(); + } + return null; + } +} diff --git a/app/src/main/java/com/xys/libzxing/zxing/camera/copy/PreviewCallback.java b/app/src/main/java/com/xys/libzxing/zxing/camera/copy/PreviewCallback.java new file mode 100644 index 0000000..75c9e78 --- /dev/null +++ b/app/src/main/java/com/xys/libzxing/zxing/camera/copy/PreviewCallback.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.xys.libzxing.zxing.camera.copy; + +import android.graphics.Point; +import android.hardware.Camera; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +public class PreviewCallback implements Camera.PreviewCallback { + + private static final String TAG = PreviewCallback.class.getSimpleName(); + + private final CameraConfigurationManager configManager; + private Handler previewHandler; + private int previewMessage; + + public PreviewCallback(CameraConfigurationManager configManager) { + this.configManager = configManager; + } + + public void setHandler(Handler previewHandler, int previewMessage) { + this.previewHandler = previewHandler; + this.previewMessage = previewMessage; + } + + @Override + public void onPreviewFrame(byte[] data, Camera camera) { + Point cameraResolution = configManager.getCameraResolution(); + Handler thePreviewHandler = previewHandler; + if (cameraResolution != null && thePreviewHandler != null) { + Message message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x, + cameraResolution.y, data); + message.sendToTarget(); + previewHandler = null; + } else { + Log.d(TAG, "Got preview callback, but no handler or resolution available"); + } + } + +} diff --git a/app/src/main/java/com/xys/libzxing/zxing/camera/open/OpenCameraInterface.java b/app/src/main/java/com/xys/libzxing/zxing/camera/open/OpenCameraInterface.java new file mode 100644 index 0000000..11a6477 --- /dev/null +++ b/app/src/main/java/com/xys/libzxing/zxing/camera/open/OpenCameraInterface.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.xys.libzxing.zxing.camera.open; + +import android.hardware.Camera; +import android.util.Log; + +public class OpenCameraInterface { + + private static final String TAG = OpenCameraInterface.class.getName(); + + /** + * Opens the requested camera with {@link Camera#open(int)}, if one exists. + * + * @param cameraId camera ID of the camera to use. A negative value means + * "no preference" + * @return handle to {@link Camera} that was opened + */ + public static Camera open(int cameraId) { + + int numCameras = Camera.getNumberOfCameras(); + if (numCameras == 0) { + Log.w(TAG, "No cameras!"); + return null; + } + + boolean explicitRequest = cameraId >= 0; + + if (!explicitRequest) { + // Select a camera if no explicit camera requested + int index = 0; + while (index < numCameras) { + Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); + Camera.getCameraInfo(index, cameraInfo); + if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { + break; + } + index++; + } + + cameraId = index; + } + + Camera camera; + if (cameraId < numCameras) { + Log.i(TAG, "Opening camera #" + cameraId); + camera = Camera.open(cameraId); + } else { + if (explicitRequest) { + Log.w(TAG, "Requested camera does not exist: " + cameraId); + camera = null; + } else { + Log.i(TAG, "No camera facing back; returning camera #0"); + camera = Camera.open(0); + } + } + + return camera; + } + + /** + * Opens a rear-facing camera with {@link Camera#open(int)}, if one exists, + * or opens camera 0. + * + * @return handle to {@link Camera} that was opened + */ + public static Camera open() { + return open(-1); + } + +} diff --git a/app/src/main/java/com/xys/libzxing/zxing/decode/DecodeFormatManager.java b/app/src/main/java/com/xys/libzxing/zxing/decode/DecodeFormatManager.java new file mode 100644 index 0000000..9b16fb6 --- /dev/null +++ b/app/src/main/java/com/xys/libzxing/zxing/decode/DecodeFormatManager.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.xys.libzxing.zxing.decode; + +import com.google.zxing.BarcodeFormat; + +import java.util.Collection; +import java.util.EnumSet; +import java.util.Set; + +public class DecodeFormatManager { + + // 1D解码 + private static final Set PRODUCT_FORMATS; + private static final Set INDUSTRIAL_FORMATS; + private static final Set ONE_D_FORMATS; + + // 二维码解码 + private static final Set QR_CODE_FORMATS; + + static { + PRODUCT_FORMATS = EnumSet.of(BarcodeFormat.UPC_A, BarcodeFormat.UPC_E, BarcodeFormat.EAN_13, + BarcodeFormat.EAN_8, BarcodeFormat.RSS_14, BarcodeFormat.RSS_EXPANDED); + INDUSTRIAL_FORMATS = EnumSet.of(BarcodeFormat.CODE_39, BarcodeFormat.CODE_93, BarcodeFormat + .CODE_128, BarcodeFormat.ITF, BarcodeFormat.CODABAR); + ONE_D_FORMATS = EnumSet.copyOf(PRODUCT_FORMATS); + ONE_D_FORMATS.addAll(INDUSTRIAL_FORMATS); + + QR_CODE_FORMATS = EnumSet.of(BarcodeFormat.QR_CODE); + } + + public static Collection getQrCodeFormats() { + return QR_CODE_FORMATS; + } + + public static Collection getBarCodeFormats() { + return ONE_D_FORMATS; + } +} diff --git a/app/src/main/java/com/xys/libzxing/zxing/decode/DecodeHandler.java b/app/src/main/java/com/xys/libzxing/zxing/decode/DecodeHandler.java new file mode 100644 index 0000000..6fcb328 --- /dev/null +++ b/app/src/main/java/com/xys/libzxing/zxing/decode/DecodeHandler.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2010 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.xys.libzxing.zxing.decode; + +import android.graphics.Bitmap; +import android.graphics.Rect; +import android.hardware.Camera.Size; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +import com.google.zxing.BinaryBitmap; +import com.google.zxing.DecodeHintType; +import com.google.zxing.MultiFormatReader; +import com.google.zxing.PlanarYUVLuminanceSource; +import com.google.zxing.ReaderException; +import com.google.zxing.Result; +import com.google.zxing.common.HybridBinarizer; +import com.jx.jyhd.R; +import com.xys.libzxing.zxing.activity.CaptureActivity; + +import java.io.ByteArrayOutputStream; +import java.util.Map; + +public class DecodeHandler extends Handler { + + private final CaptureActivity activity; + private final MultiFormatReader multiFormatReader; + private boolean running = true; + + public DecodeHandler(CaptureActivity activity, Map hints) { + multiFormatReader = new MultiFormatReader(); + multiFormatReader.setHints(hints); + this.activity = activity; + } + + private static void bundleThumbnail(PlanarYUVLuminanceSource source, Bundle bundle) { + int[] pixels = source.renderThumbnail(); + int width = source.getThumbnailWidth(); + int height = source.getThumbnailHeight(); + Bitmap bitmap = Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.ARGB_8888); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.JPEG, 50, out); + bundle.putByteArray(DecodeThread.BARCODE_BITMAP, out.toByteArray()); + } + + @Override + public void handleMessage(Message message) { + if (!running) { + return; + } + if (message.what == R.id.decode) { + decode((byte[]) message.obj, message.arg1, message.arg2); + + } else if (message.what == R.id.quit) { + running = false; + Looper.myLooper().quit(); + + } + } + + /** + * Decode the data within the viewfinder rectangle, and time how long it + * took. For efficiency, reuse the same reader objects from one decode to + * the next. + * + * @param data The YUV preview frame. + * @param width The width of the preview frame. + * @param height The height of the preview frame. + */ + private void decode(byte[] data, int width, int height) { + Size size = activity.getCameraManager().getPreviewSize(); + + // 这里需要将获取的data翻转一下,因为相机默认拿的的横屏的数据 + byte[] rotatedData = new byte[data.length]; + for (int y = 0; y < size.height; y++) { + for (int x = 0; x < size.width; x++) + rotatedData[x * size.height + size.height - y - 1] = data[x + y * size.width]; + } + + // 宽高也要调整 + int tmp = size.width; + size.width = size.height; + size.height = tmp; + + Result rawResult = null; + PlanarYUVLuminanceSource source = buildLuminanceSource(rotatedData, size.width, size.height); + if (source != null) { + BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); + try { + rawResult = multiFormatReader.decodeWithState(bitmap); + } catch (ReaderException re) { + // continue + } finally { + multiFormatReader.reset(); + } + } + + Handler handler = activity.getHandler(); + if (rawResult != null) { + // Don't log the barcode contents for security. + if (handler != null) { + Message message = Message.obtain(handler, R.id.decode_succeeded, rawResult); + Bundle bundle = new Bundle(); + bundleThumbnail(source, bundle); + message.setData(bundle); + message.sendToTarget(); + } + } else { + if (handler != null) { + Message message = Message.obtain(handler, R.id.decode_failed); + message.sendToTarget(); + } + } + + } + + /** + * A factory method to build the appropriate LuminanceSource object based on + * the format of the preview buffers, as described by Camera.Parameters. + * + * @param data A preview frame. + * @param width The width of the image. + * @param height The height of the image. + * @return A PlanarYUVLuminanceSource instance. + */ + public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) { + Rect rect = activity.getCropRect(); + if (rect == null) { + return null; + } + // Go ahead and assume it's YUV rather than die. + return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top, rect.width(), rect + .height(), false); + } + +} diff --git a/app/src/main/java/com/xys/libzxing/zxing/decode/DecodeThread.java b/app/src/main/java/com/xys/libzxing/zxing/decode/DecodeThread.java new file mode 100644 index 0000000..b82fa55 --- /dev/null +++ b/app/src/main/java/com/xys/libzxing/zxing/decode/DecodeThread.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.xys.libzxing.zxing.decode; + +import android.os.Handler; +import android.os.Looper; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.DecodeHintType; +import com.xys.libzxing.zxing.activity.CaptureActivity; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.Map; +import java.util.concurrent.CountDownLatch; + +/** + * This thread does all the heavy lifting of decoding the images. + * + * @author dswitkin@google.com (Daniel Switkin) + */ +public class DecodeThread extends Thread { + + public static final String BARCODE_BITMAP = "barcode_bitmap"; + + public static final int BARCODE_MODE = 0X100; + public static final int QRCODE_MODE = 0X200; + public static final int ALL_MODE = 0X300; + + private final CaptureActivity activity; + private final Map hints; + private final CountDownLatch handlerInitLatch; + private Handler handler; + + public DecodeThread(CaptureActivity activity, int decodeMode) { + + this.activity = activity; + handlerInitLatch = new CountDownLatch(1); + + hints = new EnumMap(DecodeHintType.class); + + Collection decodeFormats = new ArrayList(); + decodeFormats.addAll(EnumSet.of(BarcodeFormat.AZTEC)); + decodeFormats.addAll(EnumSet.of(BarcodeFormat.PDF_417)); + + switch (decodeMode) { + case BARCODE_MODE: + decodeFormats.addAll(DecodeFormatManager.getBarCodeFormats()); + break; + + case QRCODE_MODE: + decodeFormats.addAll(DecodeFormatManager.getQrCodeFormats()); + break; + + case ALL_MODE: + decodeFormats.addAll(DecodeFormatManager.getBarCodeFormats()); + decodeFormats.addAll(DecodeFormatManager.getQrCodeFormats()); + break; + + default: + break; + } + + hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats); + } + + public Handler getHandler() { + try { + handlerInitLatch.await(); + } catch (InterruptedException ie) { + // continue? + } + return handler; + } + + @Override + public void run() { + Looper.prepare(); + handler = new DecodeHandler(activity, hints); + handlerInitLatch.countDown(); + Looper.loop(); + } + +} diff --git a/app/src/main/java/com/xys/libzxing/zxing/encoding/EncodingUtils.java b/app/src/main/java/com/xys/libzxing/zxing/encoding/EncodingUtils.java new file mode 100644 index 0000000..3b5815f --- /dev/null +++ b/app/src/main/java/com/xys/libzxing/zxing/encoding/EncodingUtils.java @@ -0,0 +1,106 @@ +package com.xys.libzxing.zxing.encoding; + +import android.graphics.Bitmap; +import android.graphics.Canvas; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.EncodeHintType; +import com.google.zxing.WriterException; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.qrcode.QRCodeWriter; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; + +import java.util.HashMap; +import java.util.Map; + +/** + * 二维码生成工具类 + */ +public class EncodingUtils { + + /** + * 创建二维码 + * + * @param content content + * @param widthPix widthPix + * @param heightPix heightPix + * @param logoBm logoBm + * @return 二维码 + */ + public static Bitmap createQRCode(String content, int widthPix, int heightPix, Bitmap logoBm) { + try { + if (content == null || "".equals(content)) { + return null; + } + // 配置参数 + Map hints = new HashMap(); + hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); + // 容错级别 + hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); + // 图像数据转换,使用了矩阵转换 + BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, widthPix, + heightPix, hints); + int[] pixels = new int[widthPix * heightPix]; + // 下面这里按照二维码的算法,逐个生成二维码的图片, + // 两个for循环是图片横列扫描的结果 + for (int y = 0; y < heightPix; y++) { + for (int x = 0; x < widthPix; x++) { + if (bitMatrix.get(x, y)) { + pixels[y * widthPix + x] = 0xff000000; + } else { + pixels[y * widthPix + x] = 0xffffffff; + } + } + } + // 生成二维码图片的格式,使用ARGB_8888 + Bitmap bitmap = Bitmap.createBitmap(widthPix, heightPix, Bitmap.Config.ARGB_8888); + bitmap.setPixels(pixels, 0, widthPix, 0, 0, widthPix, heightPix); + if (logoBm != null) { + bitmap = addLogo(bitmap, logoBm); + } + //必须使用compress方法将bitmap保存到文件中再进行读取。直接返回的bitmap是没有任何压缩的,内存消耗巨大! + return bitmap; + } catch (WriterException e) { + e.printStackTrace(); + } + return null; + } + + /** + * 在二维码中间添加Logo图案 + */ + private static Bitmap addLogo(Bitmap src, Bitmap logo) { + if (src == null) { + return null; + } + if (logo == null) { + return src; + } + //获取图片的宽高 + int srcWidth = src.getWidth(); + int srcHeight = src.getHeight(); + int logoWidth = logo.getWidth(); + int logoHeight = logo.getHeight(); + if (srcWidth == 0 || srcHeight == 0) { + return null; + } + if (logoWidth == 0 || logoHeight == 0) { + return src; + } + //logo大小为二维码整体大小的1/5 + float scaleFactor = srcWidth * 1.0f / 5 / logoWidth; + Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888); + try { + Canvas canvas = new Canvas(bitmap); + canvas.drawBitmap(src, 0, 0, null); + canvas.scale(scaleFactor, scaleFactor, srcWidth / 2, srcHeight / 2); + canvas.drawBitmap(logo, (srcWidth - logoWidth) / 2, (srcHeight - logoHeight) / 2, null); +// canvas.save(Canvas.ALL_SAVE_FLAG); + canvas.restore(); + } catch (Exception e) { + bitmap = null; + e.getStackTrace(); + } + return bitmap; + } +} diff --git a/app/src/main/java/com/xys/libzxing/zxing/utils/BeepManager.java b/app/src/main/java/com/xys/libzxing/zxing/utils/BeepManager.java new file mode 100644 index 0000000..e024d39 --- /dev/null +++ b/app/src/main/java/com/xys/libzxing/zxing/utils/BeepManager.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2010 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.xys.libzxing.zxing.utils; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.AssetFileDescriptor; +import android.media.AudioManager; +import android.media.MediaPlayer; +import android.os.Vibrator; +import android.preference.PreferenceManager; +import android.util.Log; + + +import java.io.Closeable; +import java.io.IOException; + +import com.jx.jyhd.R; + + + + +/** + * Manages beeps and vibrations for {@link CaptureActivity}. + */ +public class BeepManager implements MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener, Closeable { + + private static final String TAG = BeepManager.class.getSimpleName(); + + private static final float BEEP_VOLUME = 0.10f; + private static final long VIBRATE_DURATION = 200L; + + private final Activity activity; + private MediaPlayer mediaPlayer; + private boolean playBeep; + private boolean vibrate; + + public BeepManager(Activity activity) { + this.activity = activity; + this.mediaPlayer = null; + updatePrefs(); + } + + private static boolean shouldBeep(SharedPreferences prefs, Context activity) { + boolean shouldPlayBeep = true; + if (shouldPlayBeep) { + // See if sound settings overrides this + AudioManager audioService = (AudioManager) activity.getSystemService(Context.AUDIO_SERVICE); + if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) { + shouldPlayBeep = false; + } + } + return shouldPlayBeep; + } + + private synchronized void updatePrefs() { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity); + playBeep = shouldBeep(prefs, activity); + vibrate = true; + if (playBeep && mediaPlayer == null) { + // The volume on STREAM_SYSTEM is not adjustable, and users found it + // too loud, + // so we now play on the music stream. + activity.setVolumeControlStream(AudioManager.STREAM_MUSIC); + mediaPlayer = buildMediaPlayer(activity); + } + } + + public synchronized void playBeepSoundAndVibrate() { + if (playBeep && mediaPlayer != null) { + mediaPlayer.start(); + } + if (vibrate) { + Vibrator vibrator = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE); + vibrator.vibrate(VIBRATE_DURATION); + } + } + + private MediaPlayer buildMediaPlayer(Context activity) { + MediaPlayer mediaPlayer = new MediaPlayer(); + mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); + mediaPlayer.setOnCompletionListener(this); + mediaPlayer.setOnErrorListener(this); + try { + AssetFileDescriptor file = activity.getResources().openRawResourceFd(R.raw.beep); + try { + mediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(), file.getLength()); + } finally { + file.close(); + } + mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME); + mediaPlayer.prepare(); + return mediaPlayer; + } catch (IOException ioe) { + Log.w(TAG, ioe); + mediaPlayer.release(); + return null; + } + } + + @Override + public void onCompletion(MediaPlayer mp) { + // When the beep has finished playing, rewind to queue up another one. + mp.seekTo(0); + } + + @Override + public synchronized boolean onError(MediaPlayer mp, int what, int extra) { + if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) { + // we are finished, so put up an appropriate error toast if required + // and finish + activity.finish(); + } else { + // possibly media player error, so release and recreate + mp.release(); + mediaPlayer = null; + updatePrefs(); + } + return true; + } + + @Override + public synchronized void close() { + if (mediaPlayer != null) { + mediaPlayer.release(); + mediaPlayer = null; + } + } + +} diff --git a/app/src/main/java/com/xys/libzxing/zxing/utils/CaptureActivityHandler.java b/app/src/main/java/com/xys/libzxing/zxing/utils/CaptureActivityHandler.java new file mode 100644 index 0000000..d224315 --- /dev/null +++ b/app/src/main/java/com/xys/libzxing/zxing/utils/CaptureActivityHandler.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.xys.libzxing.zxing.utils; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; + +import com.google.zxing.Result; +import com.jx.jyhd.R; +import com.xys.libzxing.zxing.activity.CaptureActivity; +import com.xys.libzxing.zxing.camera.CameraManager; +import com.xys.libzxing.zxing.decode.DecodeThread; + +/** + * This class handles all the messaging which comprises the state machine for + * capture. + * + * @author dswitkin@google.com (Daniel Switkin) + */ +public class CaptureActivityHandler extends Handler { + + private final CaptureActivity activity; + private final DecodeThread decodeThread; + private final CameraManager cameraManager; + private State state; + + public CaptureActivityHandler(CaptureActivity activity, CameraManager cameraManager, int decodeMode) { + this.activity = activity; + decodeThread = new DecodeThread(activity, decodeMode); + decodeThread.start(); + state = State.SUCCESS; + + // Start ourselves capturing previews and decoding. + this.cameraManager = cameraManager; + cameraManager.startPreview(); + restartPreviewAndDecode(); + } + + @Override + public void handleMessage(Message message) { + if (message.what == R.id.restart_preview) { + restartPreviewAndDecode(); + + } else if (message.what == R.id.decode_succeeded) { + state = State.SUCCESS; + Bundle bundle = message.getData(); + + activity.handleDecode((Result) message.obj, bundle); + + } else if (message.what == R.id.decode_failed) {// We're decoding as fast as possible, so when one + // decode fails, + // start another. + state = State.PREVIEW; + cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode); + + } else if (message.what == R.id.return_scan_result) { + activity.setResult(Activity.RESULT_OK, (Intent) message.obj); + activity.finish(); + + } + } + + public void quitSynchronously() { + state = State.DONE; + cameraManager.stopPreview(); + Message quit = Message.obtain(decodeThread.getHandler(), R.id.quit); + quit.sendToTarget(); + try { + // Wait at most half a second; should be enough time, and onPause() + // will timeout quickly + decodeThread.join(500L); + } catch (InterruptedException e) { + // continue + } + + // Be absolutely sure we don't send any queued up messages + removeMessages(R.id.decode_succeeded); + removeMessages(R.id.decode_failed); + } + + private void restartPreviewAndDecode() { + if (state == State.SUCCESS) { + state = State.PREVIEW; + cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode); + } + } + + private enum State { + PREVIEW, SUCCESS, DONE + } + +} diff --git a/app/src/main/java/com/xys/libzxing/zxing/utils/InactivityTimer.java b/app/src/main/java/com/xys/libzxing/zxing/utils/InactivityTimer.java new file mode 100644 index 0000000..b262795 --- /dev/null +++ b/app/src/main/java/com/xys/libzxing/zxing/utils/InactivityTimer.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2010 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.xys.libzxing.zxing.utils; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.AsyncTask; +import android.os.BatteryManager; +import android.os.Build; +import android.util.Log; + +/** + * Finishes an activity after a period of inactivity if the device is on battery + * power. + */ +public class InactivityTimer { + + private static final String TAG = InactivityTimer.class.getSimpleName(); + + private static final long INACTIVITY_DELAY_MS = 5 * 60 * 1000L; + + private Activity activity; + private BroadcastReceiver powerStatusReceiver; + private boolean registered; + private AsyncTask inactivityTask; + + public InactivityTimer(Activity activity) { + this.activity = activity; + powerStatusReceiver = new PowerStatusReceiver(); + registered = false; + onActivity(); + } + + @SuppressLint("NewApi") + public synchronized void onActivity() { + cancel(); + inactivityTask = new InactivityAsyncTask(); + if (Build.VERSION.SDK_INT >= 11) { + inactivityTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } else { + inactivityTask.execute(); + } + } + + public synchronized void onPause() { + cancel(); + if (registered) { + activity.unregisterReceiver(powerStatusReceiver); + registered = false; + } else { + Log.w(TAG, "PowerStatusReceiver was never registered?"); + } + } + + public synchronized void onResume() { + if (registered) { + Log.w(TAG, "PowerStatusReceiver was already registered?"); + } else { + activity.registerReceiver(powerStatusReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + registered = true; + } + onActivity(); + } + + private synchronized void cancel() { + AsyncTask task = inactivityTask; + if (task != null) { + task.cancel(true); + inactivityTask = null; + } + } + + public void shutdown() { + cancel(); + } + + private class PowerStatusReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) { + // 0 indicates that we're on battery + boolean onBatteryNow = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) <= 0; + if (onBatteryNow) { + InactivityTimer.this.onActivity(); + } else { + InactivityTimer.this.cancel(); + } + } + } + } + + private class InactivityAsyncTask extends AsyncTask { + @Override + protected Object doInBackground(Object... objects) { + try { + Thread.sleep(INACTIVITY_DELAY_MS); + Log.i(TAG, "Finishing activity due to inactivity"); + activity.finish(); + } catch (InterruptedException e) { + // continue without killing + } + return null; + } + } + +} diff --git a/app/src/main/java/com/yue/util/DragViewUtil.java b/app/src/main/java/com/yue/util/DragViewUtil.java new file mode 100644 index 0000000..d5ee196 --- /dev/null +++ b/app/src/main/java/com/yue/util/DragViewUtil.java @@ -0,0 +1,104 @@ +package com.yue.util; + +import android.content.Context; +import android.view.MotionEvent; +import android.view.View; + + +/** + * 这个工具可以使任何一个view进行拖动。 + * + */ + +public class DragViewUtil { + public static void drag(Context con, View v) { + drag(con,v, 0); + } + + /** + * 拖动View方法 + * + * @param v view + * @param delay 延迟 + */ + public static void drag(Context con, View v, long delay) { + v.setOnTouchListener(new TouchListener(con,delay)); + } + + private static class TouchListener implements View.OnTouchListener { + private float startX; + private float startY; + private long downTime; + private long delay; + private int screenWidth = 0; + private int screenHeight = 0; + + private TouchListener() { + } + + private TouchListener(Context con, long delay) { + screenWidth = con.getResources().getDisplayMetrics().widthPixels; + screenHeight = con.getResources().getDisplayMetrics().heightPixels; + this.delay = delay; + } + + @Override + public boolean onTouch(View v, MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + + startX = event.getRawX(); + startY = event.getRawY(); + + downTime = System.currentTimeMillis(); + break; + case MotionEvent.ACTION_MOVE: + if (System.currentTimeMillis() - downTime >= delay) { + // 计算偏移量 + int dx = (int) (event.getRawX() - startX); + int dy = (int) (event.getRawY() - startY); + + // 计算控件的区域 + int left = v.getLeft() + dx; + int right = v.getRight() + dx; + int top = v.getTop() + dy; + int bottom = v.getBottom() + dy; + + // 超出屏幕检测 + if (left < 0) { + left = 0; + right = v.getWidth(); + } + + if (right > screenWidth) { + right = screenWidth; + left = screenWidth - v.getWidth(); + } + if (top < 0) { + top = 0; + bottom = v.getHeight(); + } + + if (bottom > screenHeight) { + bottom = screenHeight; + top = screenHeight - v.getHeight(); + } + + v.layout(left, top, right, bottom); + + startX = event.getRawX(); + startY = event.getRawY(); + +// RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) v.getLayoutParams(); +// layoutParams.leftMargin = (int)xDistance; +// layoutParams.topMargin = (int)yDistance; +// v.setLayoutParams(layoutParams); + + } + break; + } + + return false; + } + } +} diff --git a/app/src/main/java/com/yue/view/DragView.java b/app/src/main/java/com/yue/view/DragView.java new file mode 100644 index 0000000..e28d317 --- /dev/null +++ b/app/src/main/java/com/yue/view/DragView.java @@ -0,0 +1,72 @@ +package com.yue.view; + + +import android.annotation.SuppressLint; +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.widget.ImageView; + +/** + *自定义的view,能够随意拖动。 + * + */ +@SuppressLint("AppCompatCustomView") +public class DragView extends ImageView { + public DragView(Context context) { + super(context); + } + + public DragView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public DragView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @SuppressLint("NewApi") public DragView(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + // TODO Auto-generated constructor stub + } + + private float downX; + private float downY; + + private long downTime; + + @Override + public boolean onTouchEvent(MotionEvent event) { + super.onTouchEvent(event); + if (this.isEnabled()) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + downX = event.getX(); + downY = event.getY(); + break; + case MotionEvent.ACTION_MOVE: + final float xDistance = event.getX() - downX; + final float yDistance = event.getY() - downY; + if (xDistance != 0 && yDistance != 0) { + int l = (int) (getLeft() + xDistance); + int r = (int) (getRight() + xDistance); + int t = (int) (getTop() + yDistance); + int b = (int) (getBottom() + yDistance); + this.layout(l, t, r, b); + + } + break; + case MotionEvent.ACTION_UP: + setPressed(false); + break; + case MotionEvent.ACTION_CANCEL: + setPressed(false); + break; + } + return true; + } + return false; + } + +} diff --git a/app/src/main/java/com/yue/view/DragViewGroup.java b/app/src/main/java/com/yue/view/DragViewGroup.java new file mode 100644 index 0000000..a8efba4 --- /dev/null +++ b/app/src/main/java/com/yue/view/DragViewGroup.java @@ -0,0 +1,118 @@ +package com.yue.view; + + +import android.annotation.SuppressLint; +import android.content.Context; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.view.MotionEvent; +import android.widget.LinearLayout; + +/** + * 作者:YMI on 2017/10/30 11:00 + * 邮箱:18702631465@163.com + * QQ:1078561230 + */ + +public class DragViewGroup extends LinearLayout { + private int lastX,lastY,screenWidth,screenHeight; + + public DragViewGroup(Context context) { + this(context, null); + } + + public DragViewGroup(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + @SuppressLint("NewApi") public DragViewGroup(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + DisplayMetrics dm = getResources().getDisplayMetrics(); + screenWidth = dm.widthPixels; + screenHeight = dm.heightPixels;//减去下边的高度 + } + //定位 + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + //可以在这里确定这个viewGroup的:宽 = r-l.高 = b - t + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + + lastX = (int) event.getRawX(); + lastY = (int) event.getRawY(); + + + break; + case MotionEvent.ACTION_MOVE: + + // 计算偏移量 + int dx = (int) (event.getRawX() - lastX); + int dy = (int) (event.getRawY() - lastY); + + // 计算控件的区域 + int left = getLeft() + dx; + int right = getRight() + dx; + int top = getTop() + dy; + int bottom = getBottom() + dy; + + // 超出屏幕检测 + if (left < 0) { + left = 0; + right = getWidth(); + } + + if (right > screenWidth) { + right = screenWidth; + left = screenWidth - getWidth(); + } + if (top < 0) { + top = 0; + bottom = getHeight(); + } + + if (bottom > screenHeight) { + bottom = screenHeight; + top = screenHeight - getHeight(); + } + + layout(left, top, right, bottom); + + lastX = (int) event.getRawX(); + lastY = (int) event.getRawY(); + invalidate(); +// RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) v.getLayoutParams(); +// layoutParams.leftMargin = (int)xDistance; +// layoutParams.topMargin = (int)yDistance; +// v.setLayoutParams(layoutParams); + + break; + } + return true; + + + + } + +// @Override +// public boolean onInterceptTouchEvent(MotionEvent event) { +// int action = event.getAction() & MotionEvent.ACTION_MASK; +// //为了使手指按在Button等可点击的控件上任可以滑动,需要拦截滑动实践 +// //并且为了使坐标准确,在此处记录按下的点 +// switch (action) { +// case MotionEvent.ACTION_MOVE: +// return true; +// case MotionEvent.ACTION_DOWN: +// lastX =(int) event.getRawX(); +// lastY= (int) event.getRawY(); +// +// return false; +// } +// return false; +// } + +} diff --git a/app/src/main/java/com/yue/view/DragViewGroup1.java b/app/src/main/java/com/yue/view/DragViewGroup1.java new file mode 100644 index 0000000..35025c4 --- /dev/null +++ b/app/src/main/java/com/yue/view/DragViewGroup1.java @@ -0,0 +1,89 @@ +package com.yue.view; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.view.MotionEvent; +import android.widget.LinearLayout; + +/** + * 作者:YMI on 2017/10/30 11:00 + * 邮箱:18702631465@163.com + * QQ:1078561230 + */ + +public class DragViewGroup1 extends LinearLayout { + private int lastX,lastY,screenWidth,screenHeight; + + public DragViewGroup1(Context context) { + this(context, null); + } + + public DragViewGroup1(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public DragViewGroup1(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + DisplayMetrics dm = getResources().getDisplayMetrics(); + screenWidth = dm.widthPixels; + screenHeight = dm.heightPixels-50;//减去下边的高度 + } + //定位 + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + //可以在这里确定这个viewGroup的:宽 = r-l.高 = b - t + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + return super.onTouchEvent(event); + } + + //拦截touch事件 + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { +// LogTool.e("onInterceptTouchEvent"); + int action = ev.getAction(); + switch (action){ + case MotionEvent.ACTION_DOWN: + lastX = (int) ev.getRawX();//设定移动的初始位置相对位置 + lastY = (int) ev.getRawY(); + break; + case MotionEvent.ACTION_MOVE://移动 + //event.getRawX()事件点距离屏幕左上角的距离 + int dx = (int) ev.getRawX() - lastX; + int dy = (int) ev.getRawY() - lastY; + + int left = this.getLeft() + dx; + int top = this.getTop() + dy; + int right = this.getRight() + dx; + int bottom = this.getBottom() + dy; + if (left < 0) { //最左边 + left = 0; + right = left + this.getWidth(); + } + if (right > screenWidth) { //最右边 + right = screenWidth; + left = right - this.getWidth(); + } + if (top < 0) { //最上边 + top = 0; + bottom = top + this.getHeight(); + } + if (bottom > screenHeight) {//最下边 + bottom = screenHeight; + top = bottom - this.getHeight(); + } + this.layout(left, top, right, bottom);//设置控件的新位置 +// LogTool.e("position:" + left + ", " + top + ", " + right + ", " + bottom); + lastX = (int) ev.getRawX();//再次将滑动其实位置定位 + lastY = (int) ev.getRawY(); + break; + case MotionEvent.ACTION_UP: + break; + } + return super.onInterceptTouchEvent(ev); + } +} diff --git a/app/src/main/java/com/zhl/cbprogressbar/view/CBProgressBar.java b/app/src/main/java/com/zhl/cbprogressbar/view/CBProgressBar.java new file mode 100644 index 0000000..970837f --- /dev/null +++ b/app/src/main/java/com/zhl/cbprogressbar/view/CBProgressBar.java @@ -0,0 +1,339 @@ +package com.zhl.cbprogressbar.view; + + + + + +import com.jx.jyhd.R; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.View; + + +/** + * 自定义的progressBar + * @author zhl + */ +public class CBProgressBar extends View { + private static final int STYLE_HORIZONTAL = 0; + private static final int STYLE_ROUND = 1; + private static final int STYLE_SECTOR=2; + /**进度背景画笔**/ +// private Paint mBgpaint; + /**进度画笔**/ +// private Paint mPrgpaint; + /**进度文字画笔**/ +// private Paint mTextpaint; + /** + * 圆形进度条边框宽度 + **/ + private int strokeWidth=20; + /** + * 进度条中心X坐标 + **/ + private int centerX; + /** + * 进度条中心Y坐标 + **/ + private int centerY; + /** + * 进度提示文字大小 + **/ + private int percenttextsize = 18; + /** + * 进度提示文字颜色 + **/ + private int percenttextcolor = 0xff009ACD; + /** + * 进度条背景颜色 + **/ + private int progressBarBgColor = 0xff336363; + /** + * 进度颜色 + **/ + private int progressColor = 0xff00C5CD; + /** + * 扇形扫描进度的颜色 + */ + private int sectorColor=0xaaffffff; + /** + * 扇形扫描背景 + */ + private int unSweepColor = 0xaa5e5e5e; + /** + * 进度条样式(水平/圆形) + **/ + private int orientation = STYLE_HORIZONTAL; + /** + * 圆形进度条半径 + **/ + private int radius = 30; + /** + * 进度最大值 + **/ + private int max = 100; + /** + * 进度值 + **/ + private int progress = 0; + /** + * 水平进度条是否是空心 + **/ + private boolean isHorizonStroke; + /** + * 水平进度圆角值 + **/ + private int rectRound=5; + /**进度文字是否显示百分号**/ + private boolean showPercentSign; + private Paint mPaint; + + public CBProgressBar(Context context) { + this(context, null); + } + + public CBProgressBar(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public CBProgressBar(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.cbprogressbar); + percenttextcolor = array.getColor(R.styleable.cbprogressbar_percent_text_color, percenttextcolor); + progressBarBgColor = array.getColor(R.styleable.cbprogressbar_progressBarBgColor, progressBarBgColor); + progressColor = array.getColor(R.styleable.cbprogressbar_progressColor, progressColor); + sectorColor = array.getColor(R.styleable.cbprogressbar_sectorColor, sectorColor); + unSweepColor = array.getColor(R.styleable.cbprogressbar_unSweepColor, unSweepColor); + percenttextsize = (int) array.getDimension(R.styleable.cbprogressbar_percent_text_size, percenttextsize); + strokeWidth = (int) array.getDimension(R.styleable.cbprogressbar_stroke_width, strokeWidth); + rectRound = (int) array.getDimension(R.styleable.cbprogressbar_rect_round, rectRound); + orientation = array.getInteger(R.styleable.cbprogressbar_orientation, STYLE_HORIZONTAL); + isHorizonStroke = array.getBoolean(R.styleable.cbprogressbar_isHorizonStroke, false); + showPercentSign = array.getBoolean(R.styleable.cbprogressbar_showPercentSign, true); +// mBgpaint = new Paint(Paint.ANTI_ALIAS_FLAG); +// mPrgpaint = new Paint(Paint.ANTI_ALIAS_FLAG); +// mTextpaint = new Paint(Paint.ANTI_ALIAS_FLAG); + array.recycle(); + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + } + + + + @Override + protected void onDraw(Canvas canvas) { + centerX = getWidth() / 2; + centerY = getHeight() / 2; + radius = centerX - strokeWidth / 2; + if (orientation == STYLE_HORIZONTAL) { + drawHoriRectProgressBar(canvas, mPaint); + } else if(orientation == STYLE_ROUND) { + drawRoundProgressBar(canvas, mPaint); + }else{ + drawSectorProgressBar(canvas, mPaint); + } + } + + /** + * 绘制圆形进度条 + * + * @param canvas + */ + private void drawRoundProgressBar(Canvas canvas, Paint piant) { + // 初始化画笔属性 + piant.setColor(progressBarBgColor); + piant.setStyle(Paint.Style.STROKE); + piant.setStrokeWidth(strokeWidth); + // 画圆 + canvas.drawCircle(centerX, centerY, radius, piant); + // 画圆形进度 + piant.setColor(progressColor); + piant.setStyle(Paint.Style.STROKE); + piant.setStrokeWidth(strokeWidth); + RectF oval = new RectF(centerX - radius, centerY - radius, radius + centerX, radius + centerY); + canvas.drawArc(oval, -90, 360 * progress / max, false, piant); + // 画进度文字 + piant.setStyle(Paint.Style.FILL); + piant.setColor(percenttextcolor); + piant.setTextSize(percenttextsize); + + String percent = (int) (progress * 100 / max) + "%"; + Rect rect = new Rect(); + piant.getTextBounds(percent, 0, percent.length(), rect); + float textWidth = rect.width(); + float textHeight = rect.height(); + if (textWidth >= radius * 2) { + textWidth = radius * 2; + } + Paint.FontMetrics metrics = piant.getFontMetrics(); + + float baseline = (getMeasuredHeight()-metrics.bottom+metrics.top)/2-metrics.top; + canvas.drawText(percent, centerX - textWidth / 2, baseline, piant); + + } + + /** + * 绘制水平矩形进度条 + * + * @param canvas + */ + private void drawHoriRectProgressBar(Canvas canvas, Paint piant) { + // 初始化画笔属性 + piant.setColor(progressBarBgColor); + if (isHorizonStroke) { + piant.setStyle(Paint.Style.STROKE); + piant.setStrokeWidth(1); + } else { + piant.setStyle(Paint.Style.FILL); + } + // 画水平矩形 + canvas.drawRoundRect(new RectF(centerX - getWidth() / 2, centerY - getHeight() / 2, + centerX + getWidth() / 2, centerY + getHeight() / 2), rectRound, rectRound, piant); + + // 画水平进度 + piant.setStyle(Paint.Style.FILL); + piant.setColor(progressColor); + if(isHorizonStroke){ + canvas.drawRoundRect(new RectF(centerX - getWidth() / 2, centerY - getHeight() / 2, + ((progress * 100 / max) * getWidth()) / 100, centerY + getHeight() / 2), rectRound, rectRound, piant); + }else{ + piant.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + canvas.drawRoundRect(new RectF(centerX - getWidth() / 2, centerY - getHeight() / 2, + ((progress * 100 / max) * getWidth()) / 100, centerY + getHeight() / 2),rectRound, rectRound, piant); + piant.setXfermode(null); + } + + // 画进度文字 + piant.setStyle(Paint.Style.FILL); + piant.setColor(percenttextcolor); + piant.setTextSize(percenttextsize); + String percent = (int) (progress * 100 / max) + "%"; + Rect rect = new Rect(); + piant.getTextBounds(percent, 0, percent.length(), rect); + float textWidth = rect.width(); + float textHeight = rect.height(); + if (textWidth >= getWidth()) { + textWidth = getWidth(); + } + + Paint.FontMetrics metrics = piant.getFontMetrics(); + float baseline = (getMeasuredHeight()-metrics.bottom+metrics.top)/2-metrics.top; + canvas.drawText(percent, centerX - textWidth / 2, baseline, piant); + + } + + /** + * 绘制扇形扫描式进度 + * @param canvas + * @param piant + */ + private void drawSectorProgressBar(Canvas canvas, Paint piant) { + // 初始化画笔属性 + piant.setColor(sectorColor); + piant.setStyle(Paint.Style.STROKE); + piant.setStrokeWidth(2); + // 绘外圈 + canvas.drawCircle(centerX, centerY, radius, piant); + // 绘内圈 + piant.setColor(unSweepColor); + piant.setStyle(Paint.Style.FILL); + canvas.drawCircle(centerX, centerY, radius - 2, piant); + piant.setColor(sectorColor); + RectF oval = new RectF(centerX - radius+2, centerY - radius+2, radius + centerX-2, radius + centerY-2); + canvas.drawArc(oval,-90, 360 * progress / max, true, piant); + } + + public void setProgress(int progress) { + if (progress > max) { + progress = max; + } else { + this.progress = progress; + postInvalidate(); + } + } + + public void setMax(int max) { + this.max = max; + } + + public int getStrokeWidth() { + return strokeWidth; + } + + public void setStrokeWidth(int strokeWidth) { + this.strokeWidth = strokeWidth; + } + + public int getPercenttextsize() { + return percenttextsize; + } + + public void setPercenttextsize(int percenttextsize) { + this.percenttextsize = percenttextsize; + } + + public int getPercenttextcolor() { + return percenttextcolor; + } + + public void setPercenttextcolor(int percenttextcolor) { + this.percenttextcolor = percenttextcolor; + } + + public int getProgressBarBgColor() { + return progressBarBgColor; + } + + public void setProgressBarBgColor(int progressBarBgColor) { + this.progressBarBgColor = progressBarBgColor; + } + + public int getProgressColor() { + return progressColor; + } + + public void setProgressColor(int progressColor) { + this.progressColor = progressColor; + } + + public int getOrientation() { + return orientation; + } + + public void setOrientation(int orientation) { + this.orientation = orientation; + } + + public boolean isHorizonStroke() { + return isHorizonStroke; + } + + public void setHorizonStroke(boolean isHorizonStroke) { + this.isHorizonStroke = isHorizonStroke; + } + + public int getRectRound() { + return rectRound; + } + + public void setRectRound(int rectRound) { + this.rectRound = rectRound; + } + + public int getMax() { + return max; + } + + public int getProgress() { + return progress; + } + + +} diff --git a/app/src/main/java/com/zhl/cbprogressbar/view/CBbaseView.java b/app/src/main/java/com/zhl/cbprogressbar/view/CBbaseView.java new file mode 100644 index 0000000..4f73492 --- /dev/null +++ b/app/src/main/java/com/zhl/cbprogressbar/view/CBbaseView.java @@ -0,0 +1,189 @@ +package com.zhl.cbprogressbar.view; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff.Mode; +import android.util.AttributeSet; +import android.view.SurfaceHolder; +import android.view.SurfaceHolder.Callback; +import android.view.SurfaceView; + +/** + * 一个继承SurfaceView的绘图基类。提高绘图效率。如果不是做游戏等需要高效率绘图刷新的应用时,可以在view加载完成的时候调用stopRender( + * )停止绘图渲染 + * + */ +public abstract class CBbaseView extends SurfaceView implements Callback, + Runnable { + /**绘图渲染频率 正常**/ + public static final int RENDER_RATE_NORMAL = 0; + /** 绘图渲染频率 较慢 **/ + public static final int RENDER_RATE_SLOWLY = 1; + /** 绘图渲染频率 较慢 **/ + public static final int RENDER_RATE_FAST = 2; + + private long sleepMillions = 50; + /** 控制、访问Surface **/ + SurfaceHolder holder; + /** 用来绘图的子线程 **/ + Thread thread; + /** 是否要绘图 **/ + boolean isRender; + /** 画笔 **/ + Paint paint; + + public CBbaseView(Context context) { + this(context, null); + } + + public CBbaseView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public CBbaseView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + // 这两句设置防止 sufraceview出现黑色背景 + setZOrderOnTop(true); + // 1.获取Holder + holder = getHolder(); + holder.setFormat(PixelFormat.TRANSLUCENT); + // 初始化画笔 + paint = new Paint(Paint.ANTI_ALIAS_FLAG); + + // 2.监听Surface的生命周期 + holder.addCallback(this); + + } + + /** + * Callback-Surface被创建 + */ + public void surfaceCreated(SurfaceHolder holder) { + // 3.开启子线程 + thread = new Thread(this); + isRender = true; + thread.start(); + + } + + /** + * Callback-Surface的尺寸被改变 + */ + public void surfaceChanged(SurfaceHolder holder, int format, int width, + int height) { + } + + /** + * Callback-Surface被销毁 + */ + public void surfaceDestroyed(SurfaceHolder holder) { + System.out.println("surfaceDestroyed"); + isRender = false; + if (thread != null && thread.isAlive()) { + try { + thread.join(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + /** + * 绘图 + */ + public void run() { + Canvas canvas = null; + + while (isRender) { + try { + // 4.拿到Canvas进行绘图,并且缓存到Surface + canvas = holder.lockCanvas(); + if(canvas==null){ + break; + } + // 清理屏幕 + canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR); + + render(canvas, paint); + } finally { + // 5.解锁画布,回到主线程进行渲染 + if (canvas != null) { + holder.unlockCanvasAndPost(canvas); + } + } + // 休息50ms + try { + Thread.sleep(sleepMillions); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + /** + * 真正的绘图逻辑 + */ + protected abstract void render(Canvas canvas, Paint piant); + + /** + * 停止绘图(由于本类一直循环绘图,在view不需要一直加载的情况下 可以调用此方法停止绘图,停止绘图后 重新绘图需要调用reStart()) + */ + public void stopRender() { + // 停止渲染时 先睡一下 防止 之前的视图没有及时更新而停止渲染 + try { + Thread.sleep(sleepMillions); + } catch (InterruptedException e) { + e.printStackTrace(); + } + this.isRender = false; + } + + /** + * 重新开始绘图(重新开启一个绘图线程) + */ + public void reStartRender() { + thread = new Thread(this); + isRender = true; + thread.start(); + } + + /** + * 是否正在进行绘图渲染 + * + * @return true/false true:可以绘图 false: 需要调用restart()才能绘图 + */ + public boolean isRending() { + return this.isRender; + } + + /** + * 设置刷新频率 + * + * @params CBbaseView.RENDER_RATE_NORMAL,
+ * CBbaseView.RENDER_RATE_SLOWLY,
CBbaseView.RENDER_RATE_FAST + */ + public void setRenderRate(int rate) { + if (rate < 0) { + return; + } + switch (rate) { + case RENDER_RATE_NORMAL: + sleepMillions = 50; + break; + case RENDER_RATE_SLOWLY: + sleepMillions = 100; + break; + case RENDER_RATE_FAST: + sleepMillions = 30; + break; + + default: + + break; + } + } + +} diff --git a/app/src/main/java/com/zhl/cbprogressbar/view/Downloadprogress.java b/app/src/main/java/com/zhl/cbprogressbar/view/Downloadprogress.java new file mode 100644 index 0000000..c275548 --- /dev/null +++ b/app/src/main/java/com/zhl/cbprogressbar/view/Downloadprogress.java @@ -0,0 +1,54 @@ +package com.zhl.cbprogressbar.view; + + + +import com.jx.jyhd.R; + +import android.app.Dialog; +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; + +public class Downloadprogress { + static CBProgressBar cbProgress; + static TextView text; + private static Dialog mDialog; + + public static void show(Context mContext, int max) { + + mDialog = new Dialog(mContext, R.style.Theme_audioDialog); + + LayoutInflater inflater = LayoutInflater.from(mContext); + View view = inflater.inflate(R.layout.saaa, null); + cbProgress = (CBProgressBar) view.findViewById(R.id.my_progress); + cbProgress.setMax(max); + text = (TextView) view.findViewById(R.id.text); + text.setText("下载中..."); + mDialog.setContentView(view); + mDialog.setCancelable(false); + mDialog.show(); + + } + + public static void setProgress(int Progress) { + if (Progress > 0) { + cbProgress.setProgress(Progress); + } + + } + + public static void setText(String text1) { + if (mDialog != null) { + text.setText(text1); + } + + } + + public static void dismiss() { + if (mDialog != null) { + mDialog.dismiss(); + } + + } +} diff --git a/app/src/main/java/kr/co/namee/permissiongen/AllowPermissions.java b/app/src/main/java/kr/co/namee/permissiongen/AllowPermissions.java new file mode 100644 index 0000000..dc48ab2 --- /dev/null +++ b/app/src/main/java/kr/co/namee/permissiongen/AllowPermissions.java @@ -0,0 +1,15 @@ +package kr.co.namee.permissiongen; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Created by namee on 2015. 11. 17.. + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME ) +public @interface AllowPermissions { + String[] value(); +} diff --git a/app/src/main/java/kr/co/namee/permissiongen/PermissionFail.java b/app/src/main/java/kr/co/namee/permissiongen/PermissionFail.java new file mode 100644 index 0000000..6841d49 --- /dev/null +++ b/app/src/main/java/kr/co/namee/permissiongen/PermissionFail.java @@ -0,0 +1,16 @@ +package kr.co.namee.permissiongen; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Created by namee on 2015. 11. 18.. + * Register a method invoked when permission requests are denied. + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface PermissionFail { + int requestCode(); +} diff --git a/app/src/main/java/kr/co/namee/permissiongen/PermissionGen.java b/app/src/main/java/kr/co/namee/permissiongen/PermissionGen.java new file mode 100644 index 0000000..2e70ee5 --- /dev/null +++ b/app/src/main/java/kr/co/namee/permissiongen/PermissionGen.java @@ -0,0 +1,143 @@ +package kr.co.namee.permissiongen; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.pm.PackageManager; +import android.os.Build; +import android.support.v4.app.Fragment; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import kr.co.namee.permissiongen.internal.Utils; + +import static kr.co.namee.permissiongen.internal.Utils.getActivity; + +/** + * Created by namee on 2015. 11. 17.. + */ +public class PermissionGen { + private String[] mPermissions; + private int mRequestCode; + private Object object; + + private PermissionGen(Object object) { + this.object = object; + } + + public static PermissionGen with(Activity activity){ + return new PermissionGen(activity); + } + + public static PermissionGen with(Fragment fragment){ + return new PermissionGen(fragment); + } + public PermissionGen permissions(String... permissions){ + this.mPermissions = permissions; + return this; + } + + public PermissionGen addRequestCode(int requestCode){ + this.mRequestCode = requestCode; + return this; + } + + @TargetApi(value = Build.VERSION_CODES.M) + public void request(){ + requestPermissions(object, mRequestCode, mPermissions); + } + + public static void needPermission(Activity activity, int requestCode, String[] permissions){ + requestPermissions(activity, requestCode, permissions); + } + + public static void needPermission(Fragment fragment, int requestCode, String[] permissions){ + requestPermissions(fragment, requestCode, permissions); + } + + public static void needPermission(Activity activity, int requestCode, String permission){ + needPermission(activity, requestCode, new String[] { permission }); + } + + public static void needPermission(Fragment fragment, int requestCode, String permission){ + needPermission(fragment, requestCode, new String[] { permission }); + } + + @TargetApi(value = Build.VERSION_CODES.M) + private static void requestPermissions(Object object, int requestCode, String[] permissions){ + if(!Utils.isOverMarshmallow()) { + doExecuteSuccess(object, requestCode); + return; + } + List deniedPermissions = Utils.findDeniedPermissions(getActivity(object), permissions); + + if(deniedPermissions.size() > 0){ + if(object instanceof Activity){ + ((Activity)object).requestPermissions(deniedPermissions.toArray(new String[deniedPermissions.size()]), requestCode); + } else if(object instanceof Fragment){ + ((Fragment)object).requestPermissions(deniedPermissions.toArray(new String[deniedPermissions.size()]), requestCode); + } else { + throw new IllegalArgumentException(object.getClass().getName() + " is not supported"); + } + + } else { + doExecuteSuccess(object, requestCode); + } + } + + + private static void doExecuteSuccess(Object activity, int requestCode) { + Method executeMethod = Utils.findMethodWithRequestCode(activity.getClass(), + PermissionSuccess.class, requestCode); + + executeMethod(activity, executeMethod); + } + + private static void doExecuteFail(Object activity, int requestCode) { + Method executeMethod = Utils.findMethodWithRequestCode(activity.getClass(), + PermissionFail.class, requestCode); + + executeMethod(activity, executeMethod); + } + + private static void executeMethod(Object activity, Method executeMethod) { + if(executeMethod != null){ + try { + if(!executeMethod.isAccessible()) executeMethod.setAccessible(true); + Object[] object=null; + + executeMethod.invoke(activity, object); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + } + + public static void onRequestPermissionsResult(Activity activity, int requestCode, String[] permissions, + int[] grantResults) { + requestResult(activity, requestCode, permissions, grantResults); + } + + public static void onRequestPermissionsResult(Fragment fragment, int requestCode, String[] permissions, + int[] grantResults) { + requestResult(fragment, requestCode, permissions, grantResults); + } + + private static void requestResult(Object obj, int requestCode, String[] permissions, + int[] grantResults){ + List deniedPermissions = new ArrayList(); + for(int i=0; i 0){ + doExecuteFail(obj, requestCode); + } else { + doExecuteSuccess(obj, requestCode); + } + } +} diff --git a/app/src/main/java/kr/co/namee/permissiongen/PermissionSuccess.java b/app/src/main/java/kr/co/namee/permissiongen/PermissionSuccess.java new file mode 100644 index 0000000..51a6cb7 --- /dev/null +++ b/app/src/main/java/kr/co/namee/permissiongen/PermissionSuccess.java @@ -0,0 +1,16 @@ +package kr.co.namee.permissiongen; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Created by namee on 2015. 11. 17.. + * Register a method invoked when permission requests are succeeded. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface PermissionSuccess { + int requestCode(); +} diff --git a/app/src/main/java/kr/co/namee/permissiongen/internal/Utils.java b/app/src/main/java/kr/co/namee/permissiongen/internal/Utils.java new file mode 100644 index 0000000..0dd7400 --- /dev/null +++ b/app/src/main/java/kr/co/namee/permissiongen/internal/Utils.java @@ -0,0 +1,100 @@ +package kr.co.namee.permissiongen.internal; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.pm.PackageManager; +import android.os.Build; +import android.support.v4.app.Fragment; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import kr.co.namee.permissiongen.PermissionFail; +import kr.co.namee.permissiongen.PermissionSuccess; + +/** + * Created by namee on 2015. 11. 18.. + */ +final public class Utils { + private Utils(){} + + public static boolean isOverMarshmallow() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; + } + + @TargetApi(value = Build.VERSION_CODES.M) + public static List findDeniedPermissions(Activity activity, String... permission){ + List denyPermissions = new ArrayList(); + for(String value : permission){ + if(activity.checkSelfPermission(value) != PackageManager.PERMISSION_GRANTED){ + denyPermissions.add(value); + } + } + return denyPermissions; + } + + public static List findAnnotationMethods(Class clazz, Class clazz1){ + List methods = new ArrayList(); + for(Method method : clazz.getDeclaredMethods()){ + if(method.isAnnotationPresent(clazz1)){ + methods.add(method); + } + } + return methods; + } + + public static Method findMethodPermissionFailWithRequestCode(Class clazz, + Class permissionFailClass, int requestCode) { + for(Method method : clazz.getDeclaredMethods()){ + if(method.isAnnotationPresent(permissionFailClass)){ + if(requestCode == method.getAnnotation(PermissionFail.class).requestCode()){ + return method; + } + } + } + return null; + } + + public static boolean isEqualRequestCodeFromAnntation(Method m, Class clazz, int requestCode){ + if(clazz.equals(PermissionFail.class)){ + return requestCode == m.getAnnotation(PermissionFail.class).requestCode(); + } else if(clazz.equals(PermissionSuccess.class)){ + return requestCode == m.getAnnotation(PermissionSuccess.class).requestCode(); + } else { + return false; + } + } + + public static Method findMethodWithRequestCode(Class clazz, + Class annotation, int requestCode) { + for(Method method : clazz.getDeclaredMethods()){ + if(method.isAnnotationPresent(annotation)){ + if(isEqualRequestCodeFromAnntation(method, annotation, requestCode)){ + return method; + } + } + } + return null; + } + + public static Method findMethodPermissionSuccessWithRequestCode(Class clazz, + Class permissionFailClass, int requestCode) { + for(Method method : clazz.getDeclaredMethods()){ + if(method.isAnnotationPresent(permissionFailClass)){ + if(requestCode == method.getAnnotation(PermissionSuccess.class).requestCode()){ + return method; + } + } + } + return null; + } + + public static Activity getActivity(Object object){ + if(object instanceof Fragment){ + return ((Fragment)object).getActivity(); + } else if(object instanceof Activity){ + return (Activity) object; + } + return null; + } +} diff --git a/app/src/main/java/kr/co/namee/permissiongen/internal/ValidateUtil.java b/app/src/main/java/kr/co/namee/permissiongen/internal/ValidateUtil.java new file mode 100644 index 0000000..a3029a4 --- /dev/null +++ b/app/src/main/java/kr/co/namee/permissiongen/internal/ValidateUtil.java @@ -0,0 +1,38 @@ +package kr.co.namee.permissiongen.internal; + +import android.content.pm.PackageManager; + +/** + * Created by namee on 2015. 11. 17.. + */ +public class ValidateUtil { + public static boolean verifyGrants(int... grantResults) { + for (int result : grantResults) { + if (result != PackageManager.PERMISSION_GRANTED) { + return false; + } + } + return true; + } + + //public static boolean verifyPermissions(String[] perissions, Method method) { + // Map map = new HashMap<>(); + // for(String p : perissions){ + // map.put(p, p); + // } + // + // PermissionSuccess hasPermissions = method.getAnnotation(PermissionSuccess.class); + // + // String[] pems = hasPermissions.values(); + // if(perissions.length == pems.length){ + // boolean match = true; + // for(String pem : pems){ + // if(!map.get(pem).equals(pem)){ + // match = false; + // } + // } + // if(match) return true; + // } + // return false; + //} +} diff --git a/app/src/main/jniLibs/armeabi/libBugly.so b/app/src/main/jniLibs/armeabi/libBugly.so new file mode 100644 index 0000000..ee73de4 Binary files /dev/null and b/app/src/main/jniLibs/armeabi/libBugly.so differ diff --git a/app/src/main/jniLibs/armeabi/libagora-crypto.so b/app/src/main/jniLibs/armeabi/libagora-crypto.so new file mode 100644 index 0000000..57d929f Binary files /dev/null and b/app/src/main/jniLibs/armeabi/libagora-crypto.so differ diff --git a/app/src/main/jniLibs/armeabi/libagora-rtc-sdk-jni.so b/app/src/main/jniLibs/armeabi/libagora-rtc-sdk-jni.so new file mode 100644 index 0000000..444d4cc Binary files /dev/null and b/app/src/main/jniLibs/armeabi/libagora-rtc-sdk-jni.so differ diff --git a/app/src/main/jniLibs/armeabi/libjcore115.so b/app/src/main/jniLibs/armeabi/libjcore115.so new file mode 100644 index 0000000..86eea94 Binary files /dev/null and b/app/src/main/jniLibs/armeabi/libjcore115.so differ diff --git a/app/src/main/jniLibs/armeabi/liblbs.so b/app/src/main/jniLibs/armeabi/liblbs.so new file mode 100644 index 0000000..b558c45 Binary files /dev/null and b/app/src/main/jniLibs/armeabi/liblbs.so differ diff --git a/app/src/main/jniLibs/x86/libagora-crypto.so b/app/src/main/jniLibs/x86/libagora-crypto.so new file mode 100644 index 0000000..756fea0 Binary files /dev/null and b/app/src/main/jniLibs/x86/libagora-crypto.so differ diff --git a/app/src/main/jniLibs/x86/libagora-rtc-sdk-jni.so b/app/src/main/jniLibs/x86/libagora-rtc-sdk-jni.so new file mode 100644 index 0000000..62a1afa Binary files /dev/null and b/app/src/main/jniLibs/x86/libagora-rtc-sdk-jni.so differ diff --git a/app/src/main/res/anim/actionsheet_dialog_in.xml b/app/src/main/res/anim/actionsheet_dialog_in.xml new file mode 100644 index 0000000..e6ca8ba --- /dev/null +++ b/app/src/main/res/anim/actionsheet_dialog_in.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/app/src/main/res/anim/actionsheet_dialog_out.xml b/app/src/main/res/anim/actionsheet_dialog_out.xml new file mode 100644 index 0000000..5439a7a --- /dev/null +++ b/app/src/main/res/anim/actionsheet_dialog_out.xml @@ -0,0 +1,5 @@ + + diff --git a/app/src/main/res/drawable-hdpi/adj.png b/app/src/main/res/drawable-hdpi/adj.png new file mode 100644 index 0000000..3cfd3cd Binary files /dev/null and b/app/src/main/res/drawable-hdpi/adj.png differ diff --git a/app/src/main/res/drawable-hdpi/border_bg.9.png b/app/src/main/res/drawable-hdpi/border_bg.9.png new file mode 100644 index 0000000..62671c5 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/border_bg.9.png differ diff --git a/app/src/main/res/drawable-hdpi/bottom_bg.9.png b/app/src/main/res/drawable-hdpi/bottom_bg.9.png new file mode 100644 index 0000000..7bf8e44 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/bottom_bg.9.png differ diff --git a/app/src/main/res/drawable-hdpi/cancel.png b/app/src/main/res/drawable-hdpi/cancel.png new file mode 100644 index 0000000..3d0d6f3 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/cancel.png differ diff --git a/app/src/main/res/drawable-hdpi/corners_bg.xml b/app/src/main/res/drawable-hdpi/corners_bg.xml new file mode 100644 index 0000000..f990635 --- /dev/null +++ b/app/src/main/res/drawable-hdpi/corners_bg.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/app/src/main/res/drawable-hdpi/dialog_loading_bg.9.png b/app/src/main/res/drawable-hdpi/dialog_loading_bg.9.png new file mode 100644 index 0000000..792e1bf Binary files /dev/null and b/app/src/main/res/drawable-hdpi/dialog_loading_bg.9.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_launcher.png b/app/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000..288b665 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/drawable-hdpi/icon.png b/app/src/main/res/drawable-hdpi/icon.png new file mode 100644 index 0000000..6ef1bfb Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon.png differ diff --git a/app/src/main/res/drawable-hdpi/icon_black_holo.png b/app/src/main/res/drawable-hdpi/icon_black_holo.png new file mode 100644 index 0000000..d0ec91c Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon_black_holo.png differ diff --git a/app/src/main/res/drawable-hdpi/jpush_ic_richpush_actionbar_back.png b/app/src/main/res/drawable-hdpi/jpush_ic_richpush_actionbar_back.png new file mode 100644 index 0000000..c9f4e4d Binary files /dev/null and b/app/src/main/res/drawable-hdpi/jpush_ic_richpush_actionbar_back.png differ diff --git a/app/src/main/res/drawable-hdpi/jpush_ic_richpush_actionbar_divider.png b/app/src/main/res/drawable-hdpi/jpush_ic_richpush_actionbar_divider.png new file mode 100644 index 0000000..f289651 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/jpush_ic_richpush_actionbar_divider.png differ diff --git a/app/src/main/res/drawable-hdpi/logo.png b/app/src/main/res/drawable-hdpi/logo.png new file mode 100644 index 0000000..62557d2 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo.png differ diff --git a/app/src/main/res/drawable-hdpi/logo1.png b/app/src/main/res/drawable-hdpi/logo1.png new file mode 100644 index 0000000..7f1b5f9 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo1.png differ diff --git a/app/src/main/res/drawable-hdpi/logo10.png b/app/src/main/res/drawable-hdpi/logo10.png new file mode 100644 index 0000000..b29e66d Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo10.png differ diff --git a/app/src/main/res/drawable-hdpi/logo11.png b/app/src/main/res/drawable-hdpi/logo11.png new file mode 100644 index 0000000..98841d8 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo11.png differ diff --git a/app/src/main/res/drawable-hdpi/logo12.png b/app/src/main/res/drawable-hdpi/logo12.png new file mode 100644 index 0000000..88d711d Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo12.png differ diff --git a/app/src/main/res/drawable-hdpi/logo13.png b/app/src/main/res/drawable-hdpi/logo13.png new file mode 100644 index 0000000..d071bb7 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo13.png differ diff --git a/app/src/main/res/drawable-hdpi/logo14.png b/app/src/main/res/drawable-hdpi/logo14.png new file mode 100644 index 0000000..5ce5b8b Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo14.png differ diff --git a/app/src/main/res/drawable-hdpi/logo15.png b/app/src/main/res/drawable-hdpi/logo15.png new file mode 100644 index 0000000..03aabff Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo15.png differ diff --git a/app/src/main/res/drawable-hdpi/logo16.png b/app/src/main/res/drawable-hdpi/logo16.png new file mode 100644 index 0000000..d089667 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo16.png differ diff --git a/app/src/main/res/drawable-hdpi/logo17.png b/app/src/main/res/drawable-hdpi/logo17.png new file mode 100644 index 0000000..9333668 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo17.png differ diff --git a/app/src/main/res/drawable-hdpi/logo18.png b/app/src/main/res/drawable-hdpi/logo18.png new file mode 100644 index 0000000..b8e215a Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo18.png differ diff --git a/app/src/main/res/drawable-hdpi/logo19.png b/app/src/main/res/drawable-hdpi/logo19.png new file mode 100644 index 0000000..165007a Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo19.png differ diff --git a/app/src/main/res/drawable-hdpi/logo2.png b/app/src/main/res/drawable-hdpi/logo2.png new file mode 100644 index 0000000..15ac19a Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo2.png differ diff --git a/app/src/main/res/drawable-hdpi/logo20.png b/app/src/main/res/drawable-hdpi/logo20.png new file mode 100644 index 0000000..f2869fe Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo20.png differ diff --git a/app/src/main/res/drawable-hdpi/logo21.png b/app/src/main/res/drawable-hdpi/logo21.png new file mode 100644 index 0000000..f7d9216 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo21.png differ diff --git a/app/src/main/res/drawable-hdpi/logo22.png b/app/src/main/res/drawable-hdpi/logo22.png new file mode 100644 index 0000000..dbcf781 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo22.png differ diff --git a/app/src/main/res/drawable-hdpi/logo3.png b/app/src/main/res/drawable-hdpi/logo3.png new file mode 100644 index 0000000..f6fc55e Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo3.png differ diff --git a/app/src/main/res/drawable-hdpi/logo4.png b/app/src/main/res/drawable-hdpi/logo4.png new file mode 100644 index 0000000..65793ec Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo4.png differ diff --git a/app/src/main/res/drawable-hdpi/logo5.png b/app/src/main/res/drawable-hdpi/logo5.png new file mode 100644 index 0000000..282ec09 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo5.png differ diff --git a/app/src/main/res/drawable-hdpi/logo6.png b/app/src/main/res/drawable-hdpi/logo6.png new file mode 100644 index 0000000..285bf1e Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo6.png differ diff --git a/app/src/main/res/drawable-hdpi/logo7.png b/app/src/main/res/drawable-hdpi/logo7.png new file mode 100644 index 0000000..edcefca Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo7.png differ diff --git a/app/src/main/res/drawable-hdpi/logo8.png b/app/src/main/res/drawable-hdpi/logo8.png new file mode 100644 index 0000000..bc56faa Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo8.png differ diff --git a/app/src/main/res/drawable-hdpi/logo9.png b/app/src/main/res/drawable-hdpi/logo9.png new file mode 100644 index 0000000..5236a4f Binary files /dev/null and b/app/src/main/res/drawable-hdpi/logo9.png differ diff --git a/app/src/main/res/drawable-hdpi/recorder.png b/app/src/main/res/drawable-hdpi/recorder.png new file mode 100644 index 0000000..e12231f Binary files /dev/null and b/app/src/main/res/drawable-hdpi/recorder.png differ diff --git a/app/src/main/res/drawable-hdpi/richpush_btn_selector.xml b/app/src/main/res/drawable-hdpi/richpush_btn_selector.xml new file mode 100644 index 0000000..c6dd002 --- /dev/null +++ b/app/src/main/res/drawable-hdpi/richpush_btn_selector.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/richpush_progressbar.xml b/app/src/main/res/drawable-hdpi/richpush_progressbar.xml new file mode 100644 index 0000000..a1d9b8f --- /dev/null +++ b/app/src/main/res/drawable-hdpi/richpush_progressbar.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/sharedemologo.png b/app/src/main/res/drawable-hdpi/sharedemologo.png new file mode 100644 index 0000000..254b4be Binary files /dev/null and b/app/src/main/res/drawable-hdpi/sharedemologo.png differ diff --git a/app/src/main/res/drawable-hdpi/stripes.png b/app/src/main/res/drawable-hdpi/stripes.png new file mode 100644 index 0000000..13564ae Binary files /dev/null and b/app/src/main/res/drawable-hdpi/stripes.png differ diff --git a/app/src/main/res/drawable-hdpi/tiledstripes.xml b/app/src/main/res/drawable-hdpi/tiledstripes.xml new file mode 100644 index 0000000..339fb9e --- /dev/null +++ b/app/src/main/res/drawable-hdpi/tiledstripes.xml @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/top_bg.9.png b/app/src/main/res/drawable-hdpi/top_bg.9.png new file mode 100644 index 0000000..15a703a Binary files /dev/null and b/app/src/main/res/drawable-hdpi/top_bg.9.png differ diff --git a/app/src/main/res/drawable-hdpi/v1.png b/app/src/main/res/drawable-hdpi/v1.png new file mode 100644 index 0000000..9ca1a73 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/v1.png differ diff --git a/app/src/main/res/drawable-hdpi/v2.png b/app/src/main/res/drawable-hdpi/v2.png new file mode 100644 index 0000000..e47ac2c Binary files /dev/null and b/app/src/main/res/drawable-hdpi/v2.png differ diff --git a/app/src/main/res/drawable-hdpi/v3.png b/app/src/main/res/drawable-hdpi/v3.png new file mode 100644 index 0000000..b8df544 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/v3.png differ diff --git a/app/src/main/res/drawable-hdpi/v4.png b/app/src/main/res/drawable-hdpi/v4.png new file mode 100644 index 0000000..2f341e6 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/v4.png differ diff --git a/app/src/main/res/drawable-hdpi/v5.png b/app/src/main/res/drawable-hdpi/v5.png new file mode 100644 index 0000000..6f75e9c Binary files /dev/null and b/app/src/main/res/drawable-hdpi/v5.png differ diff --git a/app/src/main/res/drawable-hdpi/v6.png b/app/src/main/res/drawable-hdpi/v6.png new file mode 100644 index 0000000..b62cc0e Binary files /dev/null and b/app/src/main/res/drawable-hdpi/v6.png differ diff --git a/app/src/main/res/drawable-hdpi/v7.png b/app/src/main/res/drawable-hdpi/v7.png new file mode 100644 index 0000000..26c21a8 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/v7.png differ diff --git a/app/src/main/res/drawable-hdpi/v_anim1.png b/app/src/main/res/drawable-hdpi/v_anim1.png new file mode 100644 index 0000000..044965e Binary files /dev/null and b/app/src/main/res/drawable-hdpi/v_anim1.png differ diff --git a/app/src/main/res/drawable-hdpi/v_anim2.png b/app/src/main/res/drawable-hdpi/v_anim2.png new file mode 100644 index 0000000..76f963e Binary files /dev/null and b/app/src/main/res/drawable-hdpi/v_anim2.png differ diff --git a/app/src/main/res/drawable-hdpi/v_anim3.png b/app/src/main/res/drawable-hdpi/v_anim3.png new file mode 100644 index 0000000..8c51c8c Binary files /dev/null and b/app/src/main/res/drawable-hdpi/v_anim3.png differ diff --git a/app/src/main/res/drawable-hdpi/voice_to_short.png b/app/src/main/res/drawable-hdpi/voice_to_short.png new file mode 100644 index 0000000..9ed0dc1 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/voice_to_short.png differ diff --git a/app/src/main/res/drawable-hdpi/welcome.png b/app/src/main/res/drawable-hdpi/welcome.png new file mode 100644 index 0000000..f0cc25b Binary files /dev/null and b/app/src/main/res/drawable-hdpi/welcome.png differ diff --git a/app/src/main/res/drawable-hdpi/welcome1.png b/app/src/main/res/drawable-hdpi/welcome1.png new file mode 100644 index 0000000..be7b444 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/welcome1.png differ diff --git a/app/src/main/res/drawable-hdpi/welcome10.png b/app/src/main/res/drawable-hdpi/welcome10.png new file mode 100644 index 0000000..49d6cdf Binary files /dev/null and b/app/src/main/res/drawable-hdpi/welcome10.png differ diff --git a/app/src/main/res/drawable-hdpi/welcome11.png b/app/src/main/res/drawable-hdpi/welcome11.png new file mode 100644 index 0000000..2fb311c Binary files /dev/null and b/app/src/main/res/drawable-hdpi/welcome11.png differ diff --git a/app/src/main/res/drawable-hdpi/welcome13.png b/app/src/main/res/drawable-hdpi/welcome13.png new file mode 100644 index 0000000..bce2bf9 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/welcome13.png differ diff --git a/app/src/main/res/drawable-hdpi/welcome3.png b/app/src/main/res/drawable-hdpi/welcome3.png new file mode 100644 index 0000000..ea5d927 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/welcome3.png differ diff --git a/app/src/main/res/drawable-hdpi/welcome6.png b/app/src/main/res/drawable-hdpi/welcome6.png new file mode 100644 index 0000000..6ac1ca4 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/welcome6.png differ diff --git a/app/src/main/res/drawable-hdpi/welcome7.png b/app/src/main/res/drawable-hdpi/welcome7.png new file mode 100644 index 0000000..afcff44 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/welcome7.png differ diff --git a/app/src/main/res/drawable-hdpi/welcome8.png b/app/src/main/res/drawable-hdpi/welcome8.png new file mode 100644 index 0000000..e6fe34c Binary files /dev/null and b/app/src/main/res/drawable-hdpi/welcome8.png differ diff --git a/app/src/main/res/drawable-hdpi/welcome9.png b/app/src/main/res/drawable-hdpi/welcome9.png new file mode 100644 index 0000000..259750c Binary files /dev/null and b/app/src/main/res/drawable-hdpi/welcome9.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_launcher.png b/app/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000..6ae570b Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/drawable-mdpi/logo.png b/app/src/main/res/drawable-mdpi/logo.png new file mode 100644 index 0000000..325c5a5 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/logo.png differ diff --git a/app/src/main/res/drawable-mdpi/logo1.png b/app/src/main/res/drawable-mdpi/logo1.png new file mode 100644 index 0000000..12e096c Binary files /dev/null and b/app/src/main/res/drawable-mdpi/logo1.png differ diff --git a/app/src/main/res/drawable-mdpi/logo11.png b/app/src/main/res/drawable-mdpi/logo11.png new file mode 100644 index 0000000..8d0e342 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/logo11.png differ diff --git a/app/src/main/res/drawable-mdpi/logo12.png b/app/src/main/res/drawable-mdpi/logo12.png new file mode 100644 index 0000000..8245e3f Binary files /dev/null and b/app/src/main/res/drawable-mdpi/logo12.png differ diff --git a/app/src/main/res/drawable-mdpi/logo13.png b/app/src/main/res/drawable-mdpi/logo13.png new file mode 100644 index 0000000..851e873 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/logo13.png differ diff --git a/app/src/main/res/drawable-mdpi/logo14.png b/app/src/main/res/drawable-mdpi/logo14.png new file mode 100644 index 0000000..f708c82 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/logo14.png differ diff --git a/app/src/main/res/drawable-mdpi/logo15.png b/app/src/main/res/drawable-mdpi/logo15.png new file mode 100644 index 0000000..0561ec8 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/logo15.png differ diff --git a/app/src/main/res/drawable-mdpi/logo17.png b/app/src/main/res/drawable-mdpi/logo17.png new file mode 100644 index 0000000..7c15832 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/logo17.png differ diff --git a/app/src/main/res/drawable-mdpi/logo19.png b/app/src/main/res/drawable-mdpi/logo19.png new file mode 100644 index 0000000..4989d8c Binary files /dev/null and b/app/src/main/res/drawable-mdpi/logo19.png differ diff --git a/app/src/main/res/drawable-mdpi/logo2.png b/app/src/main/res/drawable-mdpi/logo2.png new file mode 100644 index 0000000..8c7ba2a Binary files /dev/null and b/app/src/main/res/drawable-mdpi/logo2.png differ diff --git a/app/src/main/res/drawable-mdpi/logo3.png b/app/src/main/res/drawable-mdpi/logo3.png new file mode 100644 index 0000000..19c47f3 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/logo3.png differ diff --git a/app/src/main/res/drawable-mdpi/logo4.png b/app/src/main/res/drawable-mdpi/logo4.png new file mode 100644 index 0000000..bf87f75 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/logo4.png differ diff --git a/app/src/main/res/drawable-mdpi/logo5.png b/app/src/main/res/drawable-mdpi/logo5.png new file mode 100644 index 0000000..c788b62 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/logo5.png differ diff --git a/app/src/main/res/drawable-mdpi/logo6.png b/app/src/main/res/drawable-mdpi/logo6.png new file mode 100644 index 0000000..0944e8b Binary files /dev/null and b/app/src/main/res/drawable-mdpi/logo6.png differ diff --git a/app/src/main/res/drawable-mdpi/logo7.png b/app/src/main/res/drawable-mdpi/logo7.png new file mode 100644 index 0000000..6ae854f Binary files /dev/null and b/app/src/main/res/drawable-mdpi/logo7.png differ diff --git a/app/src/main/res/drawable-mdpi/logo8.png b/app/src/main/res/drawable-mdpi/logo8.png new file mode 100644 index 0000000..78b6667 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/logo8.png differ diff --git a/app/src/main/res/drawable-mdpi/logo9.png b/app/src/main/res/drawable-mdpi/logo9.png new file mode 100644 index 0000000..11ee9b6 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/logo9.png differ diff --git a/app/src/main/res/drawable-mdpi/welcome13.png b/app/src/main/res/drawable-mdpi/welcome13.png new file mode 100644 index 0000000..1c4e530 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/welcome13.png differ diff --git a/app/src/main/res/drawable-mdpi/welcome9.png b/app/src/main/res/drawable-mdpi/welcome9.png new file mode 100644 index 0000000..da4bfb0 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/welcome9.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_launcher.png b/app/src/main/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000..d4fb7cd Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo.png b/app/src/main/res/drawable-xhdpi/logo.png new file mode 100644 index 0000000..cd8116d Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo1.png b/app/src/main/res/drawable-xhdpi/logo1.png new file mode 100644 index 0000000..d68f03b Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo1.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo10.png b/app/src/main/res/drawable-xhdpi/logo10.png new file mode 100644 index 0000000..78fb72d Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo10.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo11.png b/app/src/main/res/drawable-xhdpi/logo11.png new file mode 100644 index 0000000..850b215 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo11.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo12.png b/app/src/main/res/drawable-xhdpi/logo12.png new file mode 100644 index 0000000..41e205c Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo12.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo13.png b/app/src/main/res/drawable-xhdpi/logo13.png new file mode 100644 index 0000000..af1fc4d Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo13.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo14.png b/app/src/main/res/drawable-xhdpi/logo14.png new file mode 100644 index 0000000..ea04015 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo14.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo15.png b/app/src/main/res/drawable-xhdpi/logo15.png new file mode 100644 index 0000000..e0c9a23 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo15.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo16.png b/app/src/main/res/drawable-xhdpi/logo16.png new file mode 100644 index 0000000..e8fc3b4 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo16.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo17.png b/app/src/main/res/drawable-xhdpi/logo17.png new file mode 100644 index 0000000..d2f76f1 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo17.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo18.png b/app/src/main/res/drawable-xhdpi/logo18.png new file mode 100644 index 0000000..8339c14 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo18.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo19.png b/app/src/main/res/drawable-xhdpi/logo19.png new file mode 100644 index 0000000..a3cf53c Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo19.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo2.png b/app/src/main/res/drawable-xhdpi/logo2.png new file mode 100644 index 0000000..17e2722 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo2.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo20.png b/app/src/main/res/drawable-xhdpi/logo20.png new file mode 100644 index 0000000..e652346 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo20.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo21.png b/app/src/main/res/drawable-xhdpi/logo21.png new file mode 100644 index 0000000..cff6e8c Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo21.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo22.png b/app/src/main/res/drawable-xhdpi/logo22.png new file mode 100644 index 0000000..1c1d6a9 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo22.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo3.png b/app/src/main/res/drawable-xhdpi/logo3.png new file mode 100644 index 0000000..d310a04 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo3.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo4.png b/app/src/main/res/drawable-xhdpi/logo4.png new file mode 100644 index 0000000..7f3798a Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo4.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo5.png b/app/src/main/res/drawable-xhdpi/logo5.png new file mode 100644 index 0000000..d20ea5c Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo5.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo6.png b/app/src/main/res/drawable-xhdpi/logo6.png new file mode 100644 index 0000000..6809334 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo6.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo7.png b/app/src/main/res/drawable-xhdpi/logo7.png new file mode 100644 index 0000000..5a9097f Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo7.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo8.png b/app/src/main/res/drawable-xhdpi/logo8.png new file mode 100644 index 0000000..b26b2eb Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo8.png differ diff --git a/app/src/main/res/drawable-xhdpi/logo9.png b/app/src/main/res/drawable-xhdpi/logo9.png new file mode 100644 index 0000000..f6eab53 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/logo9.png differ diff --git a/app/src/main/res/drawable-xhdpi/qr_code_bg.9.png b/app/src/main/res/drawable-xhdpi/qr_code_bg.9.png new file mode 100644 index 0000000..dc6316d Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/qr_code_bg.9.png differ diff --git a/app/src/main/res/drawable-xhdpi/scan_line.png b/app/src/main/res/drawable-xhdpi/scan_line.png new file mode 100644 index 0000000..531e83d Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/scan_line.png differ diff --git a/app/src/main/res/drawable-xhdpi/shadow.png b/app/src/main/res/drawable-xhdpi/shadow.png new file mode 100644 index 0000000..6be3091 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/shadow.png differ diff --git a/app/src/main/res/drawable-xhdpi/sharelogodemo1.png b/app/src/main/res/drawable-xhdpi/sharelogodemo1.png new file mode 100644 index 0000000..e6ef15d Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/sharelogodemo1.png differ diff --git a/app/src/main/res/drawable-xhdpi/welcome1.png b/app/src/main/res/drawable-xhdpi/welcome1.png new file mode 100644 index 0000000..da6acb3 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/welcome1.png differ diff --git a/app/src/main/res/drawable-xhdpi/welcome11.png b/app/src/main/res/drawable-xhdpi/welcome11.png new file mode 100644 index 0000000..aa2765b Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/welcome11.png differ diff --git a/app/src/main/res/drawable-xhdpi/welcome3.png b/app/src/main/res/drawable-xhdpi/welcome3.png new file mode 100644 index 0000000..6a7c3af Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/welcome3.png differ diff --git a/app/src/main/res/drawable-xhdpi/welcome9.png b/app/src/main/res/drawable-xhdpi/welcome9.png new file mode 100644 index 0000000..27d5c6c Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/welcome9.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo.png b/app/src/main/res/drawable-xxhdpi/logo.png new file mode 100644 index 0000000..8648229 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo1.png b/app/src/main/res/drawable-xxhdpi/logo1.png new file mode 100644 index 0000000..21edca0 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo1.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo10.png b/app/src/main/res/drawable-xxhdpi/logo10.png new file mode 100644 index 0000000..46ac84a Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo10.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo11.png b/app/src/main/res/drawable-xxhdpi/logo11.png new file mode 100644 index 0000000..6d62f9b Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo11.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo12.png b/app/src/main/res/drawable-xxhdpi/logo12.png new file mode 100644 index 0000000..d739835 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo12.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo13.png b/app/src/main/res/drawable-xxhdpi/logo13.png new file mode 100644 index 0000000..9708a5e Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo13.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo14.png b/app/src/main/res/drawable-xxhdpi/logo14.png new file mode 100644 index 0000000..d1d645a Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo14.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo15.png b/app/src/main/res/drawable-xxhdpi/logo15.png new file mode 100644 index 0000000..e622e46 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo15.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo16.png b/app/src/main/res/drawable-xxhdpi/logo16.png new file mode 100644 index 0000000..6f8fa21 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo16.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo17.png b/app/src/main/res/drawable-xxhdpi/logo17.png new file mode 100644 index 0000000..867ba83 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo17.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo18.png b/app/src/main/res/drawable-xxhdpi/logo18.png new file mode 100644 index 0000000..833d275 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo18.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo19.png b/app/src/main/res/drawable-xxhdpi/logo19.png new file mode 100644 index 0000000..4909f5d Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo19.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo2.png b/app/src/main/res/drawable-xxhdpi/logo2.png new file mode 100644 index 0000000..f6c592d Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo2.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo20.png b/app/src/main/res/drawable-xxhdpi/logo20.png new file mode 100644 index 0000000..5f3c856 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo20.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo21.png b/app/src/main/res/drawable-xxhdpi/logo21.png new file mode 100644 index 0000000..55f119c Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo21.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo22.png b/app/src/main/res/drawable-xxhdpi/logo22.png new file mode 100644 index 0000000..a3a668c Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo22.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo3.png b/app/src/main/res/drawable-xxhdpi/logo3.png new file mode 100644 index 0000000..9ebf586 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo3.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo4.png b/app/src/main/res/drawable-xxhdpi/logo4.png new file mode 100644 index 0000000..ed3cad3 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo4.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo5.png b/app/src/main/res/drawable-xxhdpi/logo5.png new file mode 100644 index 0000000..497252e Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo5.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo6.png b/app/src/main/res/drawable-xxhdpi/logo6.png new file mode 100644 index 0000000..df8830d Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo6.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo7.png b/app/src/main/res/drawable-xxhdpi/logo7.png new file mode 100644 index 0000000..2f6e3ed Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo7.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo8.png b/app/src/main/res/drawable-xxhdpi/logo8.png new file mode 100644 index 0000000..ea4fcb4 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo8.png differ diff --git a/app/src/main/res/drawable-xxhdpi/logo9.png b/app/src/main/res/drawable-xxhdpi/logo9.png new file mode 100644 index 0000000..c4c48e9 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/logo9.png differ diff --git a/app/src/main/res/drawable-xxhdpi/sharelogo3.png b/app/src/main/res/drawable-xxhdpi/sharelogo3.png new file mode 100644 index 0000000..ed3cad3 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/sharelogo3.png differ diff --git a/app/src/main/res/drawable-xxhdpi/welcome9.png b/app/src/main/res/drawable-xxhdpi/welcome9.png new file mode 100644 index 0000000..fe15279 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/welcome9.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/logo17.png b/app/src/main/res/drawable-xxxhdpi/logo17.png new file mode 100644 index 0000000..a8c1a7e Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/logo17.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/logo18.png b/app/src/main/res/drawable-xxxhdpi/logo18.png new file mode 100644 index 0000000..89323f8 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/logo18.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/logo20.png b/app/src/main/res/drawable-xxxhdpi/logo20.png new file mode 100644 index 0000000..850d649 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/logo20.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/logo22.png b/app/src/main/res/drawable-xxxhdpi/logo22.png new file mode 100644 index 0000000..f5c6edd Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/logo22.png differ diff --git a/app/src/main/res/drawable/btn_cancel.xml b/app/src/main/res/drawable/btn_cancel.xml new file mode 100644 index 0000000..356d07c --- /dev/null +++ b/app/src/main/res/drawable/btn_cancel.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/src/main/res/drawable/dialogexit.xml b/app/src/main/res/drawable/dialogexit.xml new file mode 100644 index 0000000..4476d8f --- /dev/null +++ b/app/src/main/res/drawable/dialogexit.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/douyin.png b/app/src/main/res/drawable/douyin.png new file mode 100644 index 0000000..92ec0f9 Binary files /dev/null and b/app/src/main/res/drawable/douyin.png differ diff --git a/app/src/main/res/drawable/qq.png b/app/src/main/res/drawable/qq.png new file mode 100644 index 0000000..f178dbc Binary files /dev/null and b/app/src/main/res/drawable/qq.png differ diff --git a/app/src/main/res/drawable/select_background.xml b/app/src/main/res/drawable/select_background.xml new file mode 100644 index 0000000..e4fdb27 --- /dev/null +++ b/app/src/main/res/drawable/select_background.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/shanredown.xml b/app/src/main/res/drawable/shanredown.xml new file mode 100644 index 0000000..334feb4 --- /dev/null +++ b/app/src/main/res/drawable/shanredown.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/shapcancel.xml b/app/src/main/res/drawable/shapcancel.xml new file mode 100644 index 0000000..2f09765 --- /dev/null +++ b/app/src/main/res/drawable/shapcancel.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/src/main/res/drawable/sharebackground.xml b/app/src/main/res/drawable/sharebackground.xml new file mode 100644 index 0000000..fb2da9e --- /dev/null +++ b/app/src/main/res/drawable/sharebackground.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/sharefriend.xml b/app/src/main/res/drawable/sharefriend.xml new file mode 100644 index 0000000..d08fcf3 --- /dev/null +++ b/app/src/main/res/drawable/sharefriend.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shareup.xml b/app/src/main/res/drawable/shareup.xml new file mode 100644 index 0000000..a1ca343 --- /dev/null +++ b/app/src/main/res/drawable/shareup.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/wechat.png b/app/src/main/res/drawable/wechat.png new file mode 100644 index 0000000..a814a18 Binary files /dev/null and b/app/src/main/res/drawable/wechat.png differ diff --git a/app/src/main/res/layout/activity_capture.xml b/app/src/main/res/layout/activity_capture.xml new file mode 100644 index 0000000..2a37072 --- /dev/null +++ b/app/src/main/res/layout/activity_capture.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..8926277 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/app/src/main/res/layout/activity_mapxj.xml b/app/src/main/res/layout/activity_mapxj.xml new file mode 100644 index 0000000..8421605 --- /dev/null +++ b/app/src/main/res/layout/activity_mapxj.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + +``` + +#### 原生端集成示例 +```java +public class GameWebViewActivity extends Activity { + private BridgeWebView webView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_webview); + + // 初始化WebView + webView = findViewById(R.id.webview); + setupWebView(); + registerHandlers(); + + // 加载游戏页面 + webView.loadUrl("file:///android_asset/game.html"); + } + + private void setupWebView() { + WebSettings settings = webView.getSettings(); + settings.setJavaScriptEnabled(true); + settings.setDomStorageEnabled(true); + settings.setAllowFileAccess(true); + settings.setAllowContentAccess(true); + + // 设置UserAgent + String userAgent = settings.getUserAgentString(); + settings.setUserAgentString(userAgent + " TSGame/1.0"); + } + + private void registerHandlers() { + // 注册登录处理 + webView.registerHandler("accreditlogin", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + if("2".equals(data)) { + // 触发微信登录 + wechatLogin(); + } + function.onCallBack("success"); + } + }); + + // 注册分享处理 + webView.registerHandler("friendsSharetypeUrlToptitleDescript", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + try { + JSONObject shareData = new JSONObject(data); + String type = shareData.getString("type"); + String shareType = shareData.getString("sharefriend"); + + if("1".equals(shareType)) { + // 微信好友分享 + shareToWechatFriend(shareData); + } else if("2".equals(shareType)) { + // 微信朋友圈分享 + shareToWechatTimeline(shareData); + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + }); + + // 注册设备信息处理 + webView.registerHandler("getphoneInfo", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + JSONObject deviceInfo = getDeviceInfo(); + function.onCallBack(deviceInfo.toString()); + } + }); + + // 注册定位处理 + webView.registerHandler("startlocation", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + if("1".equals(data)) { + startContinuousLocation(); + } else { + startSingleLocation(); + } + } + }); + + // 注册拍照处理 + webView.registerHandler("opencamera", new BridgeHandler() { + @Override + public void handler(String data, CallBackFunction function) { + cameraCallback = function; + openCamera(); + } + }); + } + + private void wechatLogin() { + // 微信登录实现 + SendAuth.Req req = new SendAuth.Req(); + req.scope = "snsapi_userinfo"; + req.state = "tsgame_login"; + api.sendReq(req); + } + + private JSONObject getDeviceInfo() { + JSONObject info = new JSONObject(); + try { + info.put("model", Build.MODEL); + info.put("brand", Build.BRAND); + info.put("version", Build.VERSION.RELEASE); + info.put("sdk", Build.VERSION.SDK_INT); + + DisplayMetrics dm = getResources().getDisplayMetrics(); + info.put("screenWidth", dm.widthPixels); + info.put("screenHeight", dm.heightPixels); + info.put("density", dm.density); + } catch (JSONException e) { + e.printStackTrace(); + } + return info; + } + + // 微信登录成功回调 + public void onWechatLoginSuccess(String openId, String nickname, String headUrl) { + JSONObject userInfo = new JSONObject(); + try { + userInfo.put("openid", openId); + userInfo.put("nickname", nickname); + userInfo.put("headimgurl", headUrl); + + // 回调给JS + webView.callHandler("sharelogin", userInfo.toString(), null); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + // 定位成功回调 + public void onLocationSuccess(double lat, double lng, String address) { + JSONObject location = new JSONObject(); + try { + location.put("latitude", String.valueOf(lat)); + location.put("longitude", String.valueOf(lng)); + location.put("address", address); + + // 回调给JS + webView.callHandler("locationinfo", location.toString(), null); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if(webView != null) { + webView.removeAllViews(); + webView.destroy(); + } + } +} +``` + +这个完整的集成示例展示了: +1. 前端HTML页面如何初始化Bridge连接 +2. 如何注册监听原生回调 +3. 如何调用各种原生API +4. 原生端如何注册Handler处理JS调用 +5. 如何实现完整的登录、分享、定位等功能流程 + +通过这个示例,开发者可以快速理解和集成TSGame的WebView与原生交互功能。 + +#### JS端调用原生方法示例 +```javascript +// 1. 获取设备信息 +WebViewJavascriptBridge.callHandler('getphoneInfo', '', function(response) { + console.log('设备信息:', response); +}); + +// 2. 微信分享 +var shareData = { + type: "1", + sharefriend: "1", + webpageUrl: "https://example.com", + title: "分享标题", + description: "分享描述" +}; +WebViewJavascriptBridge.callHandler('friendsSharetypeUrlToptitleDescript', + JSON.stringify(shareData)); + +// 3. 震动效果 +WebViewJavascriptBridge.callHandler('vibrator', '500'); +``` + +#### 原生端调用JS方法示例 +```java +// 1. 发送用户登录信息给JS +JSONObject userInfo = new JSONObject(); +userInfo.put("openid", openid); +userInfo.put("nickname", nickname); +x5webview.callHandler("sharelogin", userInfo.toString(), + new CallBackFunction() { + @Override + public void onCallBack(String data) { + // JS的回调处理 + } + }); + +// 2. 通知JS分享结果 +JSONObject result = new JSONObject(); +result.put("success", 1); +result.put("type", "1"); +x5webview.callHandler("sharesuccess", result.toString(), null); +``` + +### 注意事项 + +#### 数据传递规范 +1. **数据格式**: 所有传递的数据都是字符串格式,复杂数据需要JSON序列化 +2. **异步回调**: 大部分API都支持异步回调机制 +3. **错误处理**: 需要在JS和原生端都做好异常处理 +4. **线程安全**: 原生端调用JS必须在主线程进行 +5. **生命周期**: 注意WebView生命周期,避免内存泄漏 + +#### WebView与原生通信注意事项 +1. **消息队列**: 使用消息队列机制确保数据不丢失 +2. **特殊字符转义**: JSON字符串中的特殊字符需要转义处理 +3. **回调函数**: 每个API调用可以包含一个回调函数 +4. **超时处理**: 长时间无响应的API调用需要超时机制 + +#### 性能优化建议 +1. **减少频繁调用**: 避免在短时间内频繁调用原生API +2. **数据压缩**: 传递大量数据时考虑压缩或分批传输 +3. **内存管理**: 及时释放不需要的WebView资源 +4. **缓存策略**: 合理利用WebView缓存机制 + +#### 安全性考虑 +1. **数据校验**: 对JS传入的数据进行严格校验 +2. **权限控制**: 敏感API需要权限检查 +3. **防注入**: 防范恶意JS代码注入 +4. **HTTPS通信**: 敏感数据传输使用HTTPS + +#### 兼容性处理 +1. **Android版本**: 针对不同Android版本做适配 +2. **设备差异**: 考虑不同设备的硬件差异 +3. **WebView版本**: 处理不同WebView内核版本的差异 +4. **网络环境**: 适配不同网络环境下的功能表现 + +### 3. 主要Activity流转 + +``` +weclomeactivity1 (启动页) + ↓ (配置加载完成) +webviewActivity/NewwebviewActivity (主游戏页面) + ↓ (外部链接) +openwebActivity1 (外部页面) + ↓ (微信回调) +WXEntryActivity (微信相关) +``` + +### 4. 关键配置文件 + +#### version.xml (版本配置) +```xml + + 1 + game001 + 游戏名称 + +``` + +#### app_data.js (运行时配置) +```javascript +var app_version = 1; +var app_gameconfig = 'config_url'; +var app_gamedir = 'game_directory'; +var app_gamestart = 'start_file'; +var app_agent = 'agent_id'; +var app_channel = 'channel_id'; +var app_market = 'market_id'; +``` + +## 平台技术栈与第三方服务 + +### Android平台 +#### 开发工具和框架 +- **Gradle**: 7.0+ (构建工具) +- **Android SDK**: API 33 +- **最低支持**: API 21 (Android 5.0) +- **开发语言**: Java 1.8 / Kotlin 1.8 +- **IDE**: Android Studio + +#### 第三方SDK集成 +| 功能模块 | Android SDK | 版本 | +|---------|-------------|------| +| **WebView** | 腾讯X5 WebView | 44286 | +| **网络请求** | OkHttp | 4.12.0 | +| **JSON解析** | Gson | 2.8.9 | +| **微信SDK** | 微信开放平台SDK | 6.8.11 | +| **地图定位** | 高德地图SDK | 5.2.0 | +| **音视频** | 声网Agora SDK | 最新版 | +| **统计分析** | 友盟统计 | 7.5.0 | +| **崩溃收集** | 腾讯Bugly | 3.4.4 | +| **二维码扫描** | ZXing | 3.5.0 | + +### iOS平台 +#### 开发工具和框架 +- **Xcode**: 14.0+ +- **iOS SDK**: iOS 16.0 +- **最低支持**: iOS 11.0 +- **开发语言**: Objective-C / Swift 5.0 +- **依赖管理**: CocoaPods / Swift Package Manager + +#### 第三方SDK集成 +| 功能模块 | iOS SDK | 版本 | +|---------|---------|------| +| **WebView** | WKWebView (系统) | - | +| **网络请求** | AFNetworking / Alamofire | 5.0+ | +| **JSON解析** | 系统JSONSerialization | - | +| **微信SDK** | 微信开放平台SDK | 1.9.2 | +| **地图定位** | 高德地图SDK / CoreLocation | 9.0+ | +| **音视频** | 声网Agora SDK | 最新版 | +| **统计分析** | 友盟统计 / Firebase | 最新版 | +| **崩溃收集** | Bugly / Crashlytics | 最新版 | +| **二维码扫描** | AVFoundation (系统) | - | + +### HarmonyOS平台 +#### 开发工具和框架 +- **DevEco Studio**: 4.0+ +- **HarmonyOS SDK**: API 9 +- **最低支持**: API 8 (HarmonyOS 3.0) +- **开发语言**: ArkTS / TypeScript +- **应用模型**: Stage模型 + +#### 第三方SDK集成 +| 功能模块 | HarmonyOS SDK | 版本 | +|---------|---------------|------| +| **WebView** | Web组件 (系统) | - | +| **网络请求** | @ohos.net.http | 系统API | +| **JSON解析** | JSON (系统) | - | +| **微信SDK** | 微信开放平台SDK | 待适配 | +| **地图定位** | 华为地图服务 | 最新版 | +| **音视频** | 声网Agora SDK | 最新版 | +| **统计分析** | 华为分析服务 | 最新版 | +| **崩溃收集** | 华为崩溃服务 | 最新版 | +| **二维码扫描** | @ohos.multimedia.camera | 系统API | + +### 跨平台共享组件 +- **H5游戏引擎**: HTML5 + CSS3 + JavaScript +- **JS Bridge**: 统一接口定义 +- **音视频通话**: 声网Agora SDK(全平台支持) +- **数据存储**: 本地存储 + 云端同步 +- **配置管理**: JSON配置文件 + +## 跨平台权限管理 + +### Android权限配置 +#### 核心权限 +```xml + + + + + +``` + +#### 定位权限 +```xml + + + + + +``` + +#### 音频权限 +```xml + + +``` + +#### 其他权限 +```xml + + + + +``` + +### iOS权限配置 +#### Info.plist配置 +```xml + +NSCameraUsageDescription +应用需要使用相机进行拍照功能 + +NSMicrophoneUsageDescription +应用需要使用麦克风进行语音通话 + +NSLocationWhenInUseUsageDescription +应用需要获取位置信息提供定位服务 + +NSLocationAlwaysAndWhenInUseUsageDescription +应用需要获取位置信息提供定位服务 + +NSPhotoLibraryUsageDescription +应用需要访问相册选择图片 + +NSContactsUsageDescription +应用需要访问通讯录获取联系人信息 +``` + +#### App Transport Security +```xml +NSAppTransportSecurity + + NSAllowsArbitraryLoads + + +``` + +### HarmonyOS权限配置 +#### module.json5配置 +```json +{ + "requestPermissions": [ + { + "name": "ohos.permission.INTERNET", + "reason": "网络访问", + "usedScene": { + "abilities": ["EntryAbility"], + "when": "inuse" + } + }, + { + "name": "ohos.permission.LOCATION", + "reason": "获取位置信息", + "usedScene": { + "abilities": ["EntryAbility"], + "when": "inuse" + } + }, + { + "name": "ohos.permission.CAMERA", + "reason": "拍照功能", + "usedScene": { + "abilities": ["EntryAbility"], + "when": "inuse" + } + }, + { + "name": "ohos.permission.MICROPHONE", + "reason": "录音功能", + "usedScene": { + "abilities": ["EntryAbility"], + "when": "inuse" + } + }, + { + "name": "ohos.permission.READ_MEDIA", + "reason": "读取媒体文件", + "usedScene": { + "abilities": ["EntryAbility"], + "when": "inuse" + } + }, + { + "name": "ohos.permission.WRITE_MEDIA", + "reason": "写入媒体文件", + "usedScene": { + "abilities": ["EntryAbility"], + "when": "inuse" + } + } + ] +} +``` + +### 权限动态申请代码示例 + +#### Android权限申请 +```java +// 检查和申请权限 +private void checkPermissions() { + String[] permissions = { + Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.CAMERA, + Manifest.permission.RECORD_AUDIO, + Manifest.permission.ACCESS_FINE_LOCATION + }; + + List permissionsToRequest = new ArrayList<>(); + for (String permission : permissions) { + if (ContextCompat.checkSelfPermission(this, permission) + != PackageManager.PERMISSION_GRANTED) { + permissionsToRequest.add(permission); + } + } + + if (!permissionsToRequest.isEmpty()) { + ActivityCompat.requestPermissions(this, + permissionsToRequest.toArray(new String[0]), + REQUEST_PERMISSIONS); + } +} +``` + +#### iOS权限申请 +```objc +// 请求相机权限 +- (void)requestCameraPermission { + AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; + if (status == AVAuthorizationStatusNotDetermined) { + [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { + dispatch_async(dispatch_get_main_queue(), ^{ + if (granted) { + // 权限获取成功 + } else { + // 权限被拒绝 + } + }); + }]; + } +} + +// 请求定位权限 +- (void)requestLocationPermission { + CLLocationManager *locationManager = [[CLLocationManager alloc] init]; + [locationManager requestWhenInUseAuthorization]; +} +``` + +#### HarmonyOS权限申请 +```typescript +// 申请权限 +import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl'; + +async requestPermissions() { + const atManager = abilityAccessCtrl.createAtManager(); + const permissions: Permissions[] = [ + 'ohos.permission.CAMERA', + 'ohos.permission.MICROPHONE', + 'ohos.permission.LOCATION' + ]; + + try { + await atManager.requestPermissionsFromUser(this.context, permissions); + console.log('权限申请成功'); + } catch (error) { + console.log('权限申请失败:', error); + } +} +``` + +## 安全配置 + +### 签名配置 +- **Keystore**: gamehall.keystore +- **密码**: tswl2015 +- **别名**: gamehall +- **签名版本**: v1 + v2 + +### 网络安全 +- `usesCleartextTraffic="true"` - 允许HTTP流量 +- 支持HTTPS和HTTP混合请求 + +### 文件权限 +- 使用FileProvider共享文件 +- 适配Android 7.0+文件访问限制 + +## 跨平台构建和发布 + +### Android平台构建 +#### 环境要求 +- **JDK**: OpenJDK 11+ +- **Android Studio**: 2022.1.1+ +- **Gradle**: 7.0+ +- **Android SDK**: API 33 + +#### 构建命令 +```bash +# 调试版本 +./gradlew assembleDebug + +# 发布版本 +./gradlew assembleRelease + +# 清理项目 +./gradlew clean + +# 生成签名APK +./gradlew assembleRelease -Pandroid.injected.signing.store.file=keystore/gamehall.keystore +``` + +#### 签名配置 +```gradle +// app/build.gradle +android { + signingConfigs { + release { + storeFile file('../keystore/gamehall.keystore') + storePassword 'tswl2015' + keyAlias 'gamehall' + keyPassword 'tswl2015' + } + } + + buildTypes { + release { + signingConfig signingConfigs.release + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} +``` + +### iOS平台构建 +#### 环境要求 +- **macOS**: 12.0+ +- **Xcode**: 14.0+ +- **iOS SDK**: 16.0+ +- **CocoaPods**: 1.11+ + +#### 构建步骤 +```bash +# 安装依赖 +cd ios +pod install + +# 清理项目 +xcodebuild clean -workspace TSGame.xcworkspace -scheme TSGame + +# 构建Debug版本 +xcodebuild build -workspace TSGame.xcworkspace -scheme TSGame -configuration Debug + +# 构建Release版本 +xcodebuild archive -workspace TSGame.xcworkspace -scheme TSGame -configuration Release -archivePath build/TSGame.xcarchive + +# 导出IPA +xcodebuild -exportArchive -archivePath build/TSGame.xcarchive -exportPath build/ipa -exportOptionsPlist ExportOptions.plist +``` + +#### 证书配置 +```xml + + + + + + method + app-store + teamID + YOUR_TEAM_ID + provisioningProfiles + + com.jx.jyhd + YOUR_PROVISIONING_PROFILE + + + +``` + +### HarmonyOS平台构建 +#### 环境要求 +- **DevEco Studio**: 4.0+ +- **HarmonyOS SDK**: API 9 +- **Node.js**: 16.0+ +- **npm**: 8.0+ + +#### 构建步骤 +```bash +# 清理项目 +hvigorw clean + +# 构建Debug版本 +hvigorw assembleHap --mode module -p module=entry@default -p debuggable=true + +# 构建Release版本 +hvigorw assembleHap --mode module -p module=entry@default -p debuggable=false + +# 构建APP包 +hvigorw assembleApp --mode module -p module=entry@default +``` + +#### 签名配置 +```json5 +// build-profile.json5 +{ + "app": { + "signingConfigs": [ + { + "name": "default", + "type": "HarmonyOS", + "material": { + "certpath": "path/to/certificate.p12", + "storePassword": "your_password", + "keyAlias": "your_key_alias", + "keyPassword": "your_key_password", + "profile": "path/to/profile.p7b", + "signAlg": "SHA256withECDSA", + "verify": true, + "compatibleVersion": 9 + } + } + ] + } +} +``` + +### 自动化构建配置 + +#### CI/CD流水线 (GitHub Actions) +```yaml +# .github/workflows/build.yml +name: Multi-Platform Build + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main ] + +jobs: + build-android: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'adopt' + - name: Build Android APK + run: | + cd android + ./gradlew assembleRelease + - name: Upload APK + uses: actions/upload-artifact@v3 + with: + name: android-apk + path: android/app/build/outputs/apk/release/ + + build-ios: + runs-on: macos-latest + steps: + - uses: actions/checkout@v3 + - name: Set up Xcode + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: '14.0' + - name: Install CocoaPods + run: | + cd ios + pod install + - name: Build iOS + run: | + cd ios + xcodebuild build -workspace TSGame.xcworkspace -scheme TSGame -configuration Release + + build-harmonyos: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: '16' + - name: Build HarmonyOS + run: | + cd harmonyos + npm install + hvigorw assembleHap --mode module -p module=entry@default +``` + +### 发布配置 + +#### Android发布 +- **Google Play Store**: 上传AAB包,配置应用签名 +- **国内应用市场**: 上传APK包到各大应用商店 +- **企业分发**: 配置内部分发渠道 + +#### iOS发布 +- **App Store**: 通过App Store Connect上传IPA +- **TestFlight**: 内测版本分发 +- **企业证书**: 企业内部分发 + +#### HarmonyOS发布 +- **华为应用市场**: 上传HAP/APP包 +- **企业分发**: 通过华为开发者平台配置 + +## 跨平台开发指南 + +### 平台适配策略 +#### 1. 功能对等原则 +确保各平台实现相同的核心功能,但可根据平台特性进行优化: +- **必须功能**: 游戏核心玩法、登录认证、基础分享 +- **平台特色**: 分享渠道、推送通知 +- **性能优化**: 根据平台特性调整渲染和网络策略 + +#### 2. 统一接口设计 +所有平台实现相同的JS Bridge API接口: +```typescript +// bridge-api.d.ts - 统一接口定义 +interface TSGameBridge { + // 用户认证 + accreditLogin(type: string): Promise; + + // 设备信息 + getPhoneInfo(): Promise; + getNetworkStatus(): Promise; + + // 多媒体 + openCamera(): Promise; + playAudio(config: AudioConfig): Promise; + + // 系统交互 + vibrate(duration: number): Promise; + showNotification(message: string): Promise; + + // 平台特定功能(可选) + platformSpecific?: { + [key: string]: any; + }; +} +``` + +#### 3. 平台差异处理 +```javascript +// platform-detector.js +const Platform = { + isAndroid: () => /Android/i.test(navigator.userAgent), + isIOS: () => /iPhone|iPad|iPod/i.test(navigator.userAgent), + isHarmonyOS: () => /HarmonyOS/i.test(navigator.userAgent), + + // 根据平台调用不同的API + shareToSocial: (data) => { + if (Platform.isAndroid()) { + return TSGameBridge.shareToWechat(data); + } else if (Platform.isIOS()) { + return TSGameBridge.shareToSystem(data); + } else if (Platform.isHarmonyOS()) { + return TSGameBridge.shareToHuawei(data); + } + } +}; +``` + +### 开发环境搭建 + +#### 1. Android开发环境 +```bash +# 安装Android Studio +# 配置环境变量 +export ANDROID_HOME=/path/to/android-sdk +export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools + +# 创建项目 +cd android +./gradlew build +``` + +#### 2. iOS开发环境 +```bash +# 安装Xcode (仅限macOS) +# 安装CocoaPods +sudo gem install cocoapods + +# 创建项目 +cd ios +pod init +pod install +open TSGame.xcworkspace +``` + +#### 3. HarmonyOS开发环境 +```bash +# 下载DevEco Studio +# 安装HarmonyOS SDK +# 创建项目 +cd harmonyos +hvigorw assembleHap +``` + +### 代码复用策略 + +#### 1. 共享Web资源 +```javascript +// shared/webview/js/game-core.js +class GameCore { + constructor() { + this.platform = this.detectPlatform(); + this.bridge = this.initBridge(); + } + + detectPlatform() { + if (/Android/i.test(navigator.userAgent)) return 'android'; + if (/iPhone|iPad/i.test(navigator.userAgent)) return 'ios'; + if (/HarmonyOS/i.test(navigator.userAgent)) return 'harmonyos'; + return 'unknown'; + } + + initBridge() { + // 统一的桥接初始化逻辑 + return new PlatformBridge(this.platform); + } +} +``` + +#### 2. 平台抽象层 +```java +// Android抽象层 +public abstract class PlatformService { + public abstract void login(String type, Callback callback); + public abstract void share(ShareData data, Callback callback); + public abstract DeviceInfo getDeviceInfo(); +} + +public class AndroidPlatformService extends PlatformService { + @Override + public void login(String type, Callback callback) { + // Android特定的登录实现 + } +} +``` + +```objc +// iOS抽象层 +@protocol TSPlatformService +- (void)loginWithType:(NSString *)type callback:(void(^)(NSDictionary *result))callback; +- (void)shareData:(NSDictionary *)data callback:(void(^)(BOOL success))callback; +- (NSDictionary *)getDeviceInfo; +@end + +@interface TSIOSPlatformService : NSObject +@end +``` + +```typescript +// HarmonyOS抽象层 +abstract class PlatformService { + abstract login(type: string): Promise; + abstract share(data: ShareData): Promise; + abstract getDeviceInfo(): DeviceInfo; +} + +class HarmonyOSPlatformService extends PlatformService { + async login(type: string): Promise { + // HarmonyOS特定的登录实现 + } +} +``` + +### 测试策略 + +#### 1. 单元测试 +```javascript +// 跨平台测试用例 +describe('Bridge API Tests', () => { + test('should get device info on all platforms', async () => { + const deviceInfo = await TSGameBridge.getPhoneInfo(); + expect(deviceInfo).toHaveProperty('model'); + expect(deviceInfo).toHaveProperty('version'); + expect(deviceInfo).toHaveProperty('platform'); + }); + + test('should handle network status correctly', async () => { + const network = await TSGameBridge.getNetworkStatus(); + expect(['1', '2', '3']).toContain(network); + }); +}); +``` + +#### 2. 集成测试 +```yaml +# test-plan.yml +test_scenarios: + - name: "登录流程测试" + platforms: ["android", "ios", "harmonyos"] + steps: + - "打开应用" + - "点击登录按钮" + - "验证登录结果" + + - name: "分享功能测试" + platforms: ["android", "ios", "harmonyos"] + steps: + - "进入游戏页面" + - "点击分享按钮" + - "选择分享平台" + - "验证分享成功" +``` + +### 性能优化建议 + +#### 1. WebView优化 +```javascript +// 通用WebView优化配置 +const webViewConfig = { + android: { + hardwareAccelerated: true, + cacheMode: 'LOAD_CACHE_ELSE_NETWORK', + domStorageEnabled: true + }, + ios: { + allowsInlineMediaPlayback: true, + mediaTypesRequiringUserActionForPlayback: 'none', + scrollView: { bounces: false } + }, + harmonyos: { + javaScriptAccess: true, + domStorageAccess: true, + imageAccess: true + } +}; +``` + +#### 2. 资源加载优化 +```javascript +// 预加载关键资源 +class ResourceManager { + preloadAssets() { + const criticalAssets = [ + 'images/logo.png', + 'audio/bgm.mp3', + 'fonts/game-font.woff2' + ]; + + return Promise.all( + criticalAssets.map(asset => this.loadAsset(asset)) + ); + } + + loadAsset(url) { + return new Promise((resolve, reject) => { + const ext = url.split('.').pop(); + if (['png', 'jpg', 'gif'].includes(ext)) { + const img = new Image(); + img.onload = resolve; + img.onerror = reject; + img.src = url; + } else if (['mp3', 'wav'].includes(ext)) { + const audio = new Audio(); + audio.oncanplaythrough = resolve; + audio.onerror = reject; + audio.src = url; + } + }); + } +} +``` + +### 维护建议 + +#### 1. 版本管理 +```json +// version-config.json +{ + "version": "3.6.3", + "platforms": { + "android": { + "versionCode": 36300, + "minSdkVersion": 21, + "targetSdkVersion": 33 + }, + "ios": { + "buildNumber": "36300", + "minimumOSVersion": "11.0" + }, + "harmonyos": { + "versionCode": 36300, + "minAPIVersion": 8, + "targetAPIVersion": 9 + } + } +} +``` + +#### 2. 更新策略 +- **强制更新**: 影响安全性和关键功能的更新 +- **建议更新**: 新功能和体验优化 +- **静默更新**: 资源文件和配置更新 +- **灰度发布**: 分阶段推送给不同用户群体 + +#### 3. 兼容性处理 +```javascript +// 版本兼容性检查 +class CompatibilityChecker { + checkPlatformSupport() { + const requirements = { + android: { minVersion: 21 }, + ios: { minVersion: '11.0' }, + harmonyos: { minAPIVersion: 8 } + }; + + const current = this.getCurrentPlatformVersion(); + const required = requirements[this.platform]; + + return this.compareVersions(current, required.minVersion) >= 0; + } +} +``` + +## 项目总结与展望 + +### 技术特色 +1. **跨平台统一**: 基于WebView + JS Bridge的跨平台解决方案 +2. **功能完备**: 涵盖认证、分享、定位、音视频等完整功能 +3. **性能优化**: 针对不同平台特性进行深度优化 +4. **易于维护**: 统一的API接口和代码架构 + +### 适用场景 +- **棋牌游戏**: 完整的棋牌游戏解决方案 +- **社交游戏**: 支持实时音视频和社交分享 +- **地方特色应用**: 可快速适配不同地区需求 +- **跨平台应用**: 一套代码适配多个平台 + +### 开发优势 +- **开发效率**: H5游戏 + 原生能力,快速开发 +- **维护成本**: 统一的业务逻辑,降低维护成本 +- **用户体验**: 原生性能 + Web灵活性 +- **迭代速度**: 支持热更新,快速迭代 + +### 扩展方向 +1. **平台支持**: 扩展到更多平台(Windows、Web) +2. **技术升级**: 升级到最新的SDK版本和技术栈 +3. **功能增强**: 添加更多游戏类型和社交功能 +4. **性能优化**: 进一步优化启动速度和运行性能 + +### 常见问题解答 + +#### Q: 如何在现有项目基础上开发iOS版本? +A: +1. 复制`shared/`目录下的所有Web资源 +2. 创建iOS项目,实现相同的JS Bridge接口 +3. 根据iOS平台特性调整权限配置和第三方SDK +4. 参考本文档的iOS开发指南进行适配 + +#### Q: HarmonyOS版本开发有什么注意事项? +A: +1. 使用ArkTS语言开发,语法类似TypeScript +2. 权限管理更加严格,需要详细配置使用场景 +3. 部分第三方SDK可能需要寻找替代方案 +4. 遵循华为应用市场的审核规范 + +#### Q: 如何保证各平台功能一致性? +A: +1. 使用统一的API接口定义 +2. 建立跨平台测试用例 +3. 定期进行功能对比测试 +4. 维护详细的功能兼容性文档 + +#### Q: 性能优化的重点是什么? +A: +1. WebView初始化和资源加载优化 +2. JS Bridge通信效率优化 +3. 内存管理和垃圾回收优化 +4. 网络请求和数据缓存优化 + +### 技术支持 +- **文档更新**: 定期更新技术文档和API说明 +- **问题反馈**: 通过Issue跟踪和解决技术问题 +- **技术交流**: 建立开发者交流群组 +- **版本发布**: 提供稳定的版本发布和更新通知 + +--- + +**文档版本**: v2.0 +**更新时间**: 2025年7月5日 +**适用版本**: TSGame 3.6.3+ +**支持平台**: Android、iOS、HarmonyOS + +> 本文档为TSGame跨平台项目的完整技术说明,涵盖了项目架构、开发指南、API参考等所有必要信息。开发者可以基于本文档快速理解项目结构,并在任意支持的平台上实现相同功能的应用。