Compare commits
32 Commits
mymessagem
...
63580b111c
| Author | SHA1 | Date | |
|---|---|---|---|
| 63580b111c | |||
| 3b60a3b713 | |||
| 3231cd557a | |||
| 6c8867e15c | |||
| 610d3811db | |||
| 2d949eb5a3 | |||
| e6940805d9 | |||
| 1641424276 | |||
| 5d1cdff283 | |||
| da66cea1e5 | |||
| 5eb7441dc7 | |||
| 5f3168e17f | |||
| e3c4bab6c9 | |||
| 2af6427ca8 | |||
| b8c70bef98 | |||
| 7713d6c460 | |||
| 73c69bd665 | |||
| a076fe50cd | |||
| 1512b76c36 | |||
| 850b9af6ec | |||
| 31c1592086 | |||
| b3976a8633 | |||
| ea896228d7 | |||
| d49ecb3943 | |||
| ad3aecf867 | |||
| c417d9732a | |||
| 7bd1357c8c | |||
| 16a2c3c0c8 | |||
| b747d83972 | |||
| f2788dda96 | |||
| ea3a66bebe | |||
| a53a0cbcdc |
205
README.md
205
README.md
@@ -1,104 +1,103 @@
|
||||
WinBoLL 源生态计划项目说明书
|
||||
# WinBoLL 源生态计划项目说明书
|
||||
|
||||
## 一、项目概述
|
||||
|
||||
### 1. 核心定位
|
||||
WinBoLL 手机源码计划,旨在通过核心项目 WinBoLL 构建手机端与服务器端的 Android 项目的开发源码生态。实现手机与服务器的源码的联合开发。
|
||||
|
||||
### 2. 仓库架构
|
||||
#### **仓库类型:功能说明**
|
||||
☆ 基础项目分支 WinBoLL:手机端安卓应用开发基础模板。
|
||||
☆ 应用项目分支 APPBase、AES、PowerBell、Positions**:安卓应用单一管理系列项目。
|
||||
☆ 源码汇总管理 OriginMaster**:各类分支源码合并存档,不适宜作为开发库使用。
|
||||
|
||||
### 3. 源码合并管理推送路线图
|
||||
⚠️ **注意**:仅仅展示不同应用模块源码的综合管理路线。分支合并操作时,必须具备 Git 管理经验。
|
||||
|
||||
★ WinBoLL → APPBase → OriginMaster
|
||||
★ WinBoLL → AES → OriginMaster
|
||||
★ WinBoLL → PowerBell → OriginMaster
|
||||
★ WinBoLL → Positions → OriginMaster
|
||||
|
||||
## 二、WinBoLL 项目核心信息
|
||||
|
||||
### 1. 项目简介
|
||||
☆ WinBoLL 项目是为手机端开发Android 项目的需求而设计的项目。
|
||||
|
||||
### 2. 官方资源
|
||||
#### ☆ 官方网站**:https://www.winboll.cc/
|
||||
#### ☆ 源码地址:
|
||||
★ Gitea:https://gitea.winboll.cc/Studio/WinBoLL.git
|
||||
★ GitHub:https://github.com/ZhanGSKen/WinBoLL.git
|
||||
★ 码云:https://gitee.com/zhangsken/winboll.git
|
||||
|
||||
## 三、应用编译环境检查问题
|
||||
### 核心判断条件:
|
||||
☆ WinBoLL 项目以文件夹 `"/sdcard/WinBoLLStudio/APKs"` 是否存在为判断环境编译输出条件,因为编译输出的APK文件需要一个可供保存的环境。
|
||||
|
||||
☆ 文件夹"/sdcard/WinBoLLStudio/APKs" 目录条件设置方法:
|
||||
***Linux 服务器端方面***:建立 `/sdcard/WinBoLLStudio/APKs` 目录即可。
|
||||
***手机开发端方面***:建立 `"/sdcard/WinBoLLStudio/APKs"` 目录(即 `"/storage/emulated/0/WinBoLLStudio/APKs"` 目录) 即可。
|
||||
|
||||
## 四、前置条件
|
||||
|
||||
### 1. WinBoLL APP 开发环境配置介绍
|
||||
#### WinBoLL APK 编译输出内容包括:
|
||||
☆ "/sdcard/WinBoLLStudio/APKs"` 目录内的所有应用分支的 APK 文件。
|
||||
☆ "/sdcard/AppProjects/app.apk"文件。
|
||||
#### WinBoLL APK 源码命名空间规范
|
||||
☆ WinBoLL 项目使用 "cc.winboll.studio" 作为源码命名空间。在此命名空间下进行源码定义。
|
||||
|
||||
## 五、核心需求规划
|
||||
|
||||
### 1. WinBoLL 应用安全验证需求
|
||||
#### ☆ 支持访问 https://console.winboll.cc/ 服务器以校验应用包签名与版本。
|
||||
|
||||
### 2. 手机端源码开发管理需求
|
||||
#### ☆ 支持切换不同 WinBoLL 分支,以开发不同安卓应用。
|
||||
|
||||
## 六、编译与使用指南
|
||||
|
||||
### 1. 项目初始化(必须)
|
||||
#### 1. 复制 `settings.gradle-demo` 为 `settings.gradle`。编辑 `settings.gradle` 文件内容,取消对应项目模块注释。
|
||||
#### 2. 复制 `gradle.properties-androidx-demo` (Android X 项目) 或 `gradle.properties-android-demo` (基本 Android 项目) 为 `gradle.properties`。
|
||||
#### 3. 复制(可选)`local.properties-demo` 为 `local.properties`,编辑 `local.properties` 文件内容,配置 Android SDK 目录。
|
||||
#### 4. **签名设置**:
|
||||
☆ **调试编译秘钥制作**:使用 Termux 应用终端,cd 进入 GenKeyStore 目录,运行 `bash gen_debug_keystore.sh` 脚本即可生成应用调试秘钥。
|
||||
☆ **应用秘钥配置方法**:拷贝调试编译秘钥制作生成的 `appkey.jks` 与 `appkey.keystore` 文件到项目根目录即可。
|
||||
|
||||
## 七、应用编译命令介绍
|
||||
|
||||
### (1)类库型模块配置要点
|
||||
#### 1. **优先修改配置文件**:优先修改应用测试项目(目录为 `"<WinBoLl根目录>/<类库测试应用>/"`)内 `build.properties` 文件,设置对应的类库项目名称:`libraryProject=<类库项目模块名>`。
|
||||
#### 2. **编译优先启动步骤**:使用 Termux 应用,进入 `"<WinBoLl根目录>"`,运行 `$ bash .winboll/bashPublishAPKAddTag.sh <类库测试项目模块名>` 命令。运行后可生成测试项目与类库项目的编译参数文件 `build.properties`。生成的 `build.properties` 文件有两份,一份在测试项目模块的文件夹内,一份在类库项目本身的模块文件夹内。
|
||||
#### 3. **最后类库编译发布步骤**:使用 Termux 应用,进入 `"<WinBoLl根目录>"`,运行 `$ bash .winboll/bashPublishLIBAddTag.sh <类库项目模块名>` 命令。运行后可发布至 WinBoLL Nexus Maven 库、本地 maven 目录或者是通用默认的 Gradle Maven 库。
|
||||
|
||||
### (2)单一应用型模块与类库测试型模块配置要点
|
||||
#### ☆ APK 编译方法:
|
||||
使用 Termux 应用,进入 `"<WinBoLl根目录>"`,运行 `$ bash .winboll/bashPublishAPKAddTag.sh <应用项目模块名>`。
|
||||
#### ☆ 运行后的 APK 输出路径:
|
||||
★ 默认路径 (`$ bash gradlew assembleBetaDebug` 任务):APK 在 `/sdcard/WinBoLLStudio/APKs/<项目根目录名称>/debug/` 目录。
|
||||
★ 默认路径 (`$ bash assembleStageRelease` 任务):APK 在 `/sdcard/WinBoLLStudio/APKs/<项目根目录名称>/tag/` 目录。
|
||||
★ 额外输出路径:(假设 `winboll.properties` 文件已配置 `ExtraAPKOutputPath` 属性) 输出至 `ExtraAPKOutputPath` 属性配置的目录下。
|
||||
|
||||
### (3)手机端应用调试命令介绍
|
||||
#### ☆ Beta 渠道调试命令
|
||||
$bash gradlew assembleBetaDebug
|
||||
|
||||
#### ☆ Stage 渠道调试命令
|
||||
$bash gradlew assembleStageDebug
|
||||
|
||||
### (4)服务器端开发命令介绍
|
||||
##### ☆ Stage 渠道应用发布命令为:
|
||||
("<WinBoLl根目录>/settings.gradle"文件需要配置编译模块开启参数,拷贝 settings.gradle-demo 为 settings.gradle 文件取消对应的分支配置部分即可。)
|
||||
$bash .winboll/bashPublishAPKAddTag.sh <应用项目模块名>
|
||||
或者是
|
||||
$bash gradlew assembleStageRelease
|
||||
|
||||
一、项目概述
|
||||
|
||||
1. 核心定位
|
||||
|
||||
【OriginMaster】WinBoLL 源生态计划,旨在通过核心项目 WinBoLL 联动系列开发库,构建手机端 Android 项目开发与多端编译同步的完整生态,实现手机与电脑的源码同步开发。
|
||||
|
||||
2. 仓库架构
|
||||
|
||||
仓库类型 包含仓库 功能说明
|
||||
开发库 WinBoLL、APPBase、AES、PowerBell、Positions 核心开发依赖库,其中 WinBoLL 可作为应用开发的基础继承模板
|
||||
分支汇总存档库 OriginMaster 仅用于汇总各开发库分支,不适宜作为开发库克隆使用,非应用开发基础库
|
||||
|
||||
3. 源码推送路径
|
||||
|
||||
- WinBoLL → APPBase → OriginMaster
|
||||
- WinBoLL → AES → OriginMaster
|
||||
- WinBoLL → PowerBell → OriginMaster
|
||||
- WinBoLL → Positions → OriginMaster
|
||||
|
||||
二、WinBoLL APP 核心信息
|
||||
|
||||
1. 项目简介
|
||||
|
||||
WinBoLL Studio Android 应用开源项目,专注于手机端 Android 开发与多端编译同步。
|
||||
|
||||
2. 官方资源
|
||||
|
||||
- 官方网站:https://www.winboll.cc/
|
||||
- 源码地址:
|
||||
- Gitea:https://gitea.winboll.cc/Studio/WinBoLL.git
|
||||
- GitHub:https://github.com/ZhanGSKen/WinBoLL.git
|
||||
- 码云:https://gitee.com/zhangsken/winboll.git
|
||||
- 托管类库源码:
|
||||
- APPBase(jitpack.io):https://github.com/ZhanGSKen/APPBase.git
|
||||
- AES(jitpack.io):https://github.com/ZhanGSKen/AES.git
|
||||
|
||||
三、通用特征文件夹前置(/sdcard)
|
||||
|
||||
- Linux 系统文件夹直接使用 /sdcard 。
|
||||
- 手机 SD 卡存储( /storage/emulated/0 )挂载的别名也可为 /sdcard 。
|
||||
|
||||
四、前置条件
|
||||
|
||||
1. WinBoLL-APP 配置
|
||||
|
||||
- APK 编译输出目录: /sdcard/WinBoLLStudio/APKs/ ,以及 /sdcard/AppProjects/ (命名为 app.apk )
|
||||
- 签名与命名空间:支持应用签名验证定制化,与衍生 APP 共享 cc.winboll.studio 命名空间
|
||||
|
||||
五、核心需求规划
|
||||
|
||||
1. 主机端需求
|
||||
|
||||
- 支持 winboll.cc 域名的用户注册登录服务
|
||||
- 支持 https://console.winboll.cc/api 访问
|
||||
|
||||
2. APP 端需求
|
||||
|
||||
- 实现手机端 Android 应用开发与管理功能
|
||||
|
||||
六、编译与使用指南
|
||||
|
||||
1. 项目初始化(必须)
|
||||
|
||||
1. 复制 settings.gradle-demo 为 settings.gradle ,取消对应项目模块注释
|
||||
2. 复制 gradle.properties-androidx-demo 或 gradle.properties-android-demo 为 gradle.properties
|
||||
3. (可选)复制 local.properties-demo 为 local.properties ,配置 Android SDK 目录
|
||||
4. 签名设置:
|
||||
- 调试编译:进入 GenKeyStore 目录执行 bash gen_debug_keystore.sh
|
||||
- 非必须:clone keystore 模块,拷贝 appkey.jks 与 appkey.keystore 到项目根目录
|
||||
|
||||
2. 编译命令
|
||||
|
||||
(1)类库型项目
|
||||
|
||||
1. 修改测试项目 build.properties ,设置 libraryProject=<类库项目模块名>
|
||||
2. 编译测试项目: bash .winboll/bashPublishAPKAddTag.sh <应用项目模块名>
|
||||
3. 编译类库项目: bash .winboll/bashPublishLIBAddTag.sh <类库项目模块名> (发布至 WinBoLL Nexus Maven 库)
|
||||
|
||||
(2)应用型项目
|
||||
|
||||
- 编译命令: bash .winboll/bashPublishAPKAddTag.sh <应用项目模块名>
|
||||
|
||||
(3)调试编译
|
||||
|
||||
- Beta 调试: bash gradlew assembleBetaDebug
|
||||
- Stage 调试: bash gradlew assembleStageDebug
|
||||
|
||||
(4)发布编译
|
||||
|
||||
- Stage 发布:bash .winboll/bashPublishAPKAddTag.sh <应用项目模块名>
|
||||
或者执行 bash gradlew assembleStageRelease
|
||||
|
||||
3. 编译输出路径
|
||||
|
||||
- 默认路径(assembleBetaDebug任务): /sdcard/WinBoLLStudio/APKs/<项目根目录名称>/debug/
|
||||
- 默认路径(assembleStageRelease任务): /sdcard/WinBoLLStudio/APKs/<项目根目录名称>/tag/
|
||||
- 额外路径:若 winboll.properties 配置 ExtraAPKOutputPath ,APK 同步拷贝至该ExtraAPKOutputPath路径
|
||||
|
||||
4. 版本号命名规则
|
||||
|
||||
- Stage 渠道: V<应用开发环境编号><应用功能变更号><应用调试阶段号> (示例: APPBase_15.7.0 )
|
||||
- Beta 渠道: V<应用开发环境编号><应用功能变更号><应用调试阶段号>-beta<调试编译计数>_<调试编译时间(分钟+秒钟)> (示例: APPBase_15.9.6-beta8_5413 )
|
||||
|
||||
## 八、WinBoLL 应用 APK 版本号命名规则
|
||||
### ☆ Stage 渠道:
|
||||
#### V<应用开发环境编号><应用功能变更号><应用调试阶段号> (示例: APPBase_15.7.0 )
|
||||
### ☆ Beta 渠道:
|
||||
#### V<应用开发环境编号><应用功能变更号><应用调试阶段号>-beta<调试编译计数>_<调试编译时间(分钟+秒钟)> (示例: APPBase_15.9.6-beta8_5413 )
|
||||
|
||||
44
build.gradle
44
build.gradle
@@ -1,6 +1,15 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
buildscript {
|
||||
repositories {
|
||||
maven { url 'https://maven.aliyun.com/repository/public/' }
|
||||
maven { url 'https://maven.aliyun.com/repository/google/' }
|
||||
maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' }
|
||||
maven { url 'https://dl.bintray.com/ppartisan/maven/' }
|
||||
maven { url "https://clojars.org/repo/" }
|
||||
maven { url "https://jitpack.io" }
|
||||
mavenCentral()
|
||||
google()
|
||||
|
||||
mavenLocal {
|
||||
// 设置本地Maven仓库路径
|
||||
url 'file:///sdcard/.m2/repository/'
|
||||
@@ -11,19 +20,6 @@ buildscript {
|
||||
maven { url "https://nexus.winboll.cc/repository/maven-public/" }
|
||||
// "WinBoLL Snapshot"
|
||||
maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" }
|
||||
|
||||
maven { url 'https://maven.aliyun.com/repository/public/' }
|
||||
maven { url 'https://maven.aliyun.com/repository/google/' }
|
||||
maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' }
|
||||
maven { url 'https://dl.bintray.com/ppartisan/maven/' }
|
||||
maven { url "https://clojars.org/repo/" }
|
||||
maven { url "https://jitpack.io" }
|
||||
mavenCentral()
|
||||
google()
|
||||
//println "mavenLocal : ==========="
|
||||
//println mavenLocal().url
|
||||
//println "mavenLocal : ==========="
|
||||
//mavenLocal()
|
||||
}
|
||||
dependencies {
|
||||
// 适配MIUI12
|
||||
@@ -35,6 +31,15 @@ buildscript {
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
maven { url 'https://maven.aliyun.com/repository/public/' }
|
||||
maven { url 'https://maven.aliyun.com/repository/google/' }
|
||||
maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' }
|
||||
maven { url 'https://dl.bintray.com/ppartisan/maven/' }
|
||||
maven { url "https://clojars.org/repo/" }
|
||||
maven { url "https://jitpack.io" }
|
||||
mavenCentral()
|
||||
google()
|
||||
|
||||
mavenLocal {
|
||||
// 设置本地Maven仓库路径
|
||||
url 'file:///sdcard/.m2/repository/'
|
||||
@@ -45,19 +50,6 @@ allprojects {
|
||||
maven { url "https://nexus.winboll.cc/repository/maven-public/" }
|
||||
// "WinBoLL Snapshot"
|
||||
maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" }
|
||||
|
||||
maven { url 'https://maven.aliyun.com/repository/public/' }
|
||||
maven { url 'https://maven.aliyun.com/repository/google/' }
|
||||
maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' }
|
||||
maven { url 'https://dl.bintray.com/ppartisan/maven/' }
|
||||
maven { url "https://clojars.org/repo/" }
|
||||
maven { url "https://jitpack.io" }
|
||||
mavenCentral()
|
||||
google()
|
||||
//println "mavenLocal : ==========="
|
||||
//println mavenLocal().url
|
||||
//println "mavenLocal : ==========="
|
||||
//mavenLocal()
|
||||
}
|
||||
ext {
|
||||
// 定义全局变量,常用于版本管理
|
||||
|
||||
@@ -18,16 +18,19 @@ def genVersionName(def versionName){
|
||||
}
|
||||
|
||||
android {
|
||||
|
||||
// 关键:改为你已安装的 SDK 32(≥ targetSdkVersion 30,兼容已安装环境)
|
||||
compileSdkVersion 32
|
||||
|
||||
// 直接使用已安装的构建工具 33.0.3(无需修改)
|
||||
buildToolsVersion "33.0.3"
|
||||
compileSdkVersion 30
|
||||
|
||||
buildToolsVersion "30.0.3"
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId "cc.winboll.studio.mymessagemanager"
|
||||
minSdkVersion 23
|
||||
minSdkVersion 26
|
||||
targetSdkVersion 30
|
||||
versionCode 8
|
||||
// versionName 更新后需要手动设置
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Wed Feb 11 05:29:19 HKT 2026
|
||||
#Fri May 08 20:38:36 CST 2026
|
||||
stageCount=8
|
||||
libraryProject=
|
||||
baseVersion=15.12
|
||||
publishVersion=15.12.7
|
||||
buildCount=0
|
||||
buildCount=18
|
||||
baseBetaVersion=15.12.8
|
||||
|
||||
@@ -216,6 +216,8 @@
|
||||
|
||||
<activity android:name="cc.winboll.studio.mymessagemanager.activitys.SMSRecycleActivity"/>
|
||||
|
||||
<activity android:name="cc.winboll.studio.mymessagemanager.activitys.SMSRecycle2Activity"/>
|
||||
|
||||
<activity android:name="cc.winboll.studio.mymessagemanager.unittest.UnitTestActivity"/>
|
||||
|
||||
<activity android:name="cc.winboll.studio.mymessagemanager.activitys.TTSFloatSettingsActivity"/>
|
||||
|
||||
@@ -12,6 +12,8 @@ import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.RadioGroup;
|
||||
import android.widget.Switch;
|
||||
import android.widget.Toast;
|
||||
import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
|
||||
@@ -40,6 +42,7 @@ public class AppSettingsActivity extends WinBoLLActivity implements IWinBoLLActi
|
||||
//EditText metProtectModerRefuseChars;
|
||||
EditText metProtectModerReplaceChars;
|
||||
String mszProtectModerRefuseChars = "";
|
||||
RadioGroup mRadioGroupRecycleBin;
|
||||
|
||||
@Override
|
||||
public Activity getActivity() {
|
||||
@@ -83,6 +86,13 @@ public class AppSettingsActivity extends WinBoLLActivity implements IWinBoLLActi
|
||||
metProtectModerReplaceChars = findViewById(R.id.activityappsettingsEditText4);
|
||||
metProtectModerReplaceChars.setText(mAppConfigUtil.mAppConfigBean.getProtectModerReplaceChars());
|
||||
|
||||
mRadioGroupRecycleBin = findViewById(R.id.activityappsettingsRadioGroup1);
|
||||
if (mAppConfigUtil.mAppConfigBean.getRecycleBinClass().equals("SMSRecycle2Activity")) {
|
||||
mRadioGroupRecycleBin.check(R.id.activityappsettingsRadioButton2);
|
||||
} else {
|
||||
mRadioGroupRecycleBin.check(R.id.activityappsettingsRadioButton1);
|
||||
}
|
||||
|
||||
mAOHPCTCSeekBar = findViewById(R.id.activityappsettingsAOHPCTCSeekBar1);
|
||||
mAOHPCTCSeekBar.setThumb(getDrawable(R.drawable.cursor_pointer));
|
||||
mAOHPCTCSeekBar.setThumbOffset(0);
|
||||
@@ -92,6 +102,11 @@ public class AppSettingsActivity extends WinBoLLActivity implements IWinBoLLActi
|
||||
public void onOHPCommit() {
|
||||
mAppConfigUtil.reLoadConfig();
|
||||
mAppConfigUtil.mAppConfigBean.setIsSMSRecycleProtectMode(mswSMSRecycleProtectMode.isChecked());
|
||||
if (mRadioGroupRecycleBin.getCheckedRadioButtonId() == R.id.activityappsettingsRadioButton2) {
|
||||
mAppConfigUtil.mAppConfigBean.setRecycleBinClass("SMSRecycle2Activity");
|
||||
} else {
|
||||
mAppConfigUtil.mAppConfigBean.setRecycleBinClass("SMSRecycleActivity");
|
||||
}
|
||||
//mAppConfigUtil.mAppConfigBean.setProtectModerRefuseChars(metProtectModerRefuseChars.getText().toString());
|
||||
mAppConfigUtil.mAppConfigBean.setProtectModerRefuseChars(mszProtectModerRefuseChars);
|
||||
mAppConfigUtil.mAppConfigBean.setProtectModerReplaceChars(metProtectModerReplaceChars.getText().toString());
|
||||
|
||||
@@ -329,7 +329,13 @@ public class MainActivity extends WinBoLLActivity {
|
||||
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(i);
|
||||
} else if (nItemId == R.id.app_smsrecycle) {
|
||||
Intent i = new Intent(MainActivity.this, SMSRecycleActivity.class);
|
||||
Class<?> recycleClass;
|
||||
if (mAppConfigUtil.mAppConfigBean.getRecycleBinClass().equals("SMSRecycle2Activity")) {
|
||||
recycleClass = SMSRecycle2Activity.class;
|
||||
} else {
|
||||
recycleClass = SMSRecycleActivity.class;
|
||||
}
|
||||
Intent i = new Intent(MainActivity.this, recycleClass);
|
||||
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(i);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
package cc.winboll.studio.mymessagemanager.activitys;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import cc.winboll.studio.libaes.dialogs.YesNoAlertDialog;
|
||||
import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
|
||||
import cc.winboll.studio.mymessagemanager.R;
|
||||
import cc.winboll.studio.mymessagemanager.adapters.SMSRecycle2Adapter;
|
||||
import cc.winboll.studio.mymessagemanager.utils.SMSRecycleUtil;
|
||||
import cc.winboll.studio.mymessagemanager.views.ProtectModeTextView;
|
||||
import com.baoyz.widget.PullRefreshLayout;
|
||||
import java.io.File;
|
||||
|
||||
public class SMSRecycle2Activity extends WinBoLLActivity implements IWinBoLLActivity {
|
||||
|
||||
public static final String TAG = "SMSRecycle2Activity";
|
||||
private static final String SP_NAME = "smsrecycle2_config";
|
||||
private static final String KEY_SCALE = "recycle2_scale";
|
||||
|
||||
Toolbar mToolbar;
|
||||
RecyclerView mRecyclerView;
|
||||
SMSRecycle2Adapter mSMSRecycle2Adapter;
|
||||
ProtectModeTextView mSampleProtectModeTextView;
|
||||
SharedPreferences mSP;
|
||||
|
||||
@Override
|
||||
public Activity getActivity() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_smsrecycle2);
|
||||
mToolbar = findViewById(R.id.activitysmsrecycle2ASupportToolbar1);
|
||||
mToolbar.setSubtitle(getString(R.string.activity_name_about));
|
||||
setSupportActionBar(mToolbar);
|
||||
|
||||
mSP = getSharedPreferences(SP_NAME, MODE_PRIVATE);
|
||||
|
||||
mSampleProtectModeTextView = findViewById(R.id.activitysmsrecycle2SampleProtectModeTextView);
|
||||
mSampleProtectModeTextView.setContentTextWithScale(
|
||||
"调节本短信下方刻度滑条,可预览文本打乱效果;同时该进度条数值将作为回收站短信全局默认初始值。\n"
|
||||
+ "刻度0 = 保持原文不打乱;\n"
|
||||
+ "刻度数值越小,字符分组越细碎,文本打乱混乱程度越大;\n"
|
||||
+ "刻度数值越大,字符连串分组越长,文本打乱混乱程度越小。",
|
||||
mSP.getInt(KEY_SCALE, 0));
|
||||
|
||||
mSampleProtectModeTextView.setOnScaleChangedListener(new ProtectModeTextView.OnScaleChangedListener() {
|
||||
@Override
|
||||
public void onScaleChanged(int progress) {
|
||||
mSP.edit().putInt(KEY_SCALE, progress).apply();
|
||||
mSMSRecycle2Adapter.setScaleProgress(progress);
|
||||
mSMSRecycle2Adapter.notifyDataSetChanged();
|
||||
}
|
||||
});
|
||||
|
||||
initView();
|
||||
}
|
||||
|
||||
void initView() {
|
||||
mRecyclerView = findViewById(R.id.activitysmsrecycle2RecyclerView1);
|
||||
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
|
||||
mRecyclerView.setLayoutManager(layoutManager);
|
||||
|
||||
mSMSRecycle2Adapter = new SMSRecycle2Adapter(this, mSP.getInt(KEY_SCALE, 0));
|
||||
mRecyclerView.setAdapter(mSMSRecycle2Adapter);
|
||||
|
||||
final PullRefreshLayout pullRefreshLayout = findViewById(R.id.activitysmsrecycle2PullRefreshLayout1);
|
||||
pullRefreshLayout.setOnRefreshListener(new PullRefreshLayout.OnRefreshListener() {
|
||||
@Override
|
||||
public void onRefresh() {
|
||||
mSMSRecycle2Adapter.loadSMSRecycleList();
|
||||
mSMSRecycle2Adapter.notifyDataSetChanged();
|
||||
pullRefreshLayout.setRefreshing(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.toolbar_smsrecycle, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int nItemId = item.getItemId();
|
||||
if (nItemId == R.id.item_cleansmsrecycle) {
|
||||
YesNoAlertDialog.show(this, "回收站清空确认", "是否清空回收站", mDeleteListener);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
YesNoAlertDialog.OnDialogResultListener mDeleteListener = new YesNoAlertDialog.OnDialogResultListener() {
|
||||
|
||||
@Override
|
||||
public void onNo() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onYes() {
|
||||
File file = new File(SMSRecycleUtil.getSMSRecycleListDataPath(SMSRecycle2Activity.this));
|
||||
file.delete();
|
||||
mSMSRecycle2Adapter.loadSMSRecycleList();
|
||||
mSMSRecycle2Adapter.notifyDataSetChanged();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package cc.winboll.studio.mymessagemanager.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import cc.winboll.studio.mymessagemanager.R;
|
||||
import cc.winboll.studio.mymessagemanager.beans.SMSRecycleBean;
|
||||
import cc.winboll.studio.mymessagemanager.utils.AddressUtils;
|
||||
import cc.winboll.studio.mymessagemanager.utils.SMSRecycleUtil;
|
||||
import cc.winboll.studio.mymessagemanager.views.DateAgoTextView;
|
||||
import cc.winboll.studio.mymessagemanager.views.ProtectModeTextView;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class SMSRecycle2Adapter extends RecyclerView.Adapter<SMSRecycle2Adapter.ViewHolder> {
|
||||
|
||||
public static final String TAG = "SMSRecycle2Adapter";
|
||||
|
||||
Context mContext;
|
||||
ArrayList<SMSRecycleBean> mDataList;
|
||||
String mszSMSRecycleListDataPath;
|
||||
int mScaleProgress;
|
||||
|
||||
public SMSRecycle2Adapter(Context context, int scaleProgress) {
|
||||
mContext = context;
|
||||
mScaleProgress = scaleProgress;
|
||||
mszSMSRecycleListDataPath = SMSRecycleUtil.getSMSRecycleListDataPath(mContext);
|
||||
mDataList = new ArrayList<SMSRecycleBean>();
|
||||
mDataList = loadSMSRecycleList();
|
||||
}
|
||||
|
||||
public void setScaleProgress(int scaleProgress) {
|
||||
mScaleProgress = scaleProgress;
|
||||
}
|
||||
|
||||
public ArrayList<SMSRecycleBean> loadSMSRecycleList() {
|
||||
ArrayList<SMSRecycleBean> list = new ArrayList<SMSRecycleBean>();
|
||||
SMSRecycleBean.loadBeanListFromFile(mszSMSRecycleListDataPath, list, SMSRecycleBean.class);
|
||||
SMSRecycleBean.sortSMSByDeleteDateDesc(list, true);
|
||||
mDataList.clear();
|
||||
mDataList.addAll(list);
|
||||
return mDataList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listview_smsrecycle2, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
SMSRecycleBean item = mDataList.get(position);
|
||||
holder.mtvAddress.setText(AddressUtils.getFormattedAddress(item.getAddress()));
|
||||
holder.mdatvDeleteDate.setDate(item.getDeleteDate());
|
||||
holder.mProtectModeTextView.setContentTextWithScale(item.getBody(), mScaleProgress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mDataList.size();
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView mtvAddress;
|
||||
DateAgoTextView mdatvDeleteDate;
|
||||
ProtectModeTextView mProtectModeTextView;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
mtvAddress = itemView.findViewById(R.id.listviewsmsrecycle2TextViewAddress);
|
||||
mdatvDeleteDate = itemView.findViewById(R.id.listviewsmsrecycle2DateAgoTextViewDelete);
|
||||
mProtectModeTextView = itemView.findViewById(R.id.listviewsmsrecycle2ProtectModeTextView);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,8 @@ public class AppConfigBean extends BaseBean {
|
||||
String protectModerRefuseChars = "设定被和谐的字符";
|
||||
// 保护式预览拒绝显示的字符集的替代字符
|
||||
String protectModerReplaceChars = "当前替代显示字符";
|
||||
// 回收站打开的窗口类名 SMSRecycleActivity / SMSRecycle2Activity
|
||||
String recycleBinClass = "SMSRecycleActivity";
|
||||
//int appThemeID = ThemeUtil.getThemeID(ThemeUtil.BaseTheme.DEFAULT);
|
||||
|
||||
public void setProtectModerRefuseChars(String protectModerRefuseChars) {
|
||||
@@ -47,6 +49,14 @@ public class AppConfigBean extends BaseBean {
|
||||
return protectModerReplaceChars;
|
||||
}
|
||||
|
||||
public void setRecycleBinClass(String recycleBinClass) {
|
||||
this.recycleBinClass = recycleBinClass;
|
||||
}
|
||||
|
||||
public String getRecycleBinClass() {
|
||||
return recycleBinClass;
|
||||
}
|
||||
|
||||
public void setIsSMSRecycleProtectMode(boolean isSMSRecycleProtectMode) {
|
||||
this.isSMSRecycleProtectMode = isSMSRecycleProtectMode;
|
||||
}
|
||||
@@ -142,6 +152,7 @@ public class AppConfigBean extends BaseBean {
|
||||
jsonWriter.name("isSMSRecycleProtectMode").value(bean.isSMSRecycleProtectMode());
|
||||
jsonWriter.name("protectModerRefuseChars").value(bean.getProtectModerRefuseChars());
|
||||
jsonWriter.name("protectModerReplaceChars").value(bean.getProtectModerReplaceChars());
|
||||
jsonWriter.name("recycleBinClass").value(bean.getRecycleBinClass());
|
||||
//jsonWriter.name("appThemeID").value(bean.getAppThemeID());
|
||||
}
|
||||
|
||||
@@ -171,6 +182,8 @@ public class AppConfigBean extends BaseBean {
|
||||
bean.setProtectModerRefuseChars(jsonReader.nextString());
|
||||
} else if (name.equals("protectModerReplaceChars")) {
|
||||
bean.setProtectModerReplaceChars(jsonReader.nextString());
|
||||
} else if (name.equals("recycleBinClass")) {
|
||||
bean.setRecycleBinClass(jsonReader.nextString());
|
||||
} /*else if (name.equals("appThemeID")) {
|
||||
bean.setAppThemeID(jsonReader.nextInt());
|
||||
}*/ else {
|
||||
|
||||
@@ -11,20 +11,29 @@ import android.view.View;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.LogView;
|
||||
import cc.winboll.studio.mymessagemanager.R;
|
||||
import cc.winboll.studio.mymessagemanager.views.ProtectModeTextView;
|
||||
|
||||
public class UnitTestActivity extends Activity {
|
||||
|
||||
public static final String TAG = "UnitTestActivity";
|
||||
|
||||
LogView mLogView;
|
||||
|
||||
// 新增自定义控件
|
||||
ProtectModeTextView mProtectModeTv;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_unittest);
|
||||
|
||||
|
||||
mLogView = findViewById(R.id.logview);
|
||||
mLogView.start();
|
||||
|
||||
// 初始化ProtectModeTextView
|
||||
mProtectModeTv = findViewById(R.id.protect_mode_tv);
|
||||
// 设置测试文本,可自行修改
|
||||
String testText = "abcdefghijklmnopqrstuvwxyz消息管理 隐私保护 文本随机组合 滑动刻度测试1234567890";
|
||||
mProtectModeTv.setContentText(testText);
|
||||
}
|
||||
|
||||
public void onMain(View view) {
|
||||
@@ -34,3 +43,4 @@ public class UnitTestActivity extends Activity {
|
||||
AddressUtils_Test.main(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
package cc.winboll.studio.mymessagemanager.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
import cc.winboll.studio.mymessagemanager.R;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* 保护模式自定义控件
|
||||
* 最终规则:
|
||||
* 1. 刻度范围 0~12
|
||||
* 2. 刻度值 = 每一组截取【相邻字符个数】
|
||||
* 3. 从头到尾按固定长度切块分组
|
||||
* 4. 所有分组收集后随机打乱再拼接输出
|
||||
* 5. 刻度0 = 不打乱,显示原文
|
||||
* 6. 按原生字符计算(包含空格、标点)
|
||||
*/
|
||||
public class ProtectModeTextView extends LinearLayout {
|
||||
|
||||
public interface OnScaleChangedListener {
|
||||
void onScaleChanged(int progress);
|
||||
}
|
||||
|
||||
private TextView tvContent;
|
||||
private SeekBar seekBarScale;
|
||||
private String originText;
|
||||
private List<Character> charAllList;
|
||||
private final Random random = new Random();
|
||||
private OnScaleChangedListener mOnScaleChangedListener;
|
||||
|
||||
public ProtectModeTextView(Context context) {
|
||||
super(context);
|
||||
initView(context);
|
||||
}
|
||||
|
||||
public ProtectModeTextView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initView(context);
|
||||
}
|
||||
|
||||
public ProtectModeTextView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
initView(context);
|
||||
}
|
||||
|
||||
private void initView(Context context) {
|
||||
LayoutInflater.from(context).inflate(R.layout.layout_protect_mode_textview, this, true);
|
||||
tvContent = findViewById(R.id.tv_content);
|
||||
seekBarScale = findViewById(R.id.seek_bar_scale);
|
||||
|
||||
// 刻度 0 ~ 12
|
||||
seekBarScale.setMax(12);
|
||||
seekBarScale.setProgress(0);
|
||||
|
||||
charAllList = new ArrayList<>();
|
||||
|
||||
seekBarScale.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
handleTextLogic(progress);
|
||||
if (fromUser && mOnScaleChangedListener != null) {
|
||||
mOnScaleChangedListener.onScaleChanged(progress);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {}
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {}
|
||||
});
|
||||
}
|
||||
|
||||
public void setOnScaleChangedListener(OnScaleChangedListener listener) {
|
||||
mOnScaleChangedListener = listener;
|
||||
}
|
||||
|
||||
public void setContentTextWithScale(String text, int scaleProgress) {
|
||||
this.originText = text;
|
||||
convertToCharList(text);
|
||||
seekBarScale.setProgress(scaleProgress);
|
||||
handleTextLogic(scaleProgress);
|
||||
}
|
||||
|
||||
public void setContentText(String text) {
|
||||
this.originText = text;
|
||||
convertToCharList(text);
|
||||
handleTextLogic(seekBarScale.getProgress());
|
||||
}
|
||||
|
||||
private void convertToCharList(String text) {
|
||||
charAllList.clear();
|
||||
if (text == null || text.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
char[] chars = text.toCharArray();
|
||||
for (char c : chars) {
|
||||
charAllList.add(c);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleTextLogic(int groupSize) {
|
||||
if (charAllList.isEmpty()) {
|
||||
tvContent.setText(originText);
|
||||
return;
|
||||
}
|
||||
|
||||
// 刻度0 原样不打乱
|
||||
if (groupSize <= 0) {
|
||||
tvContent.setText(originText);
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> groupList = new ArrayList<>();
|
||||
int totalLen = charAllList.size();
|
||||
|
||||
// 从头到尾 按 groupSize 个相邻字符切块
|
||||
int index = 0;
|
||||
while (index < totalLen) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// 每一组取 groupSize 个相邻字符
|
||||
for (int i = 0; i < groupSize && index < totalLen; i++) {
|
||||
sb.append(charAllList.get(index));
|
||||
index++;
|
||||
}
|
||||
groupList.add(sb.toString());
|
||||
}
|
||||
|
||||
// 所有分组随机打乱
|
||||
Collections.shuffle(groupList, random);
|
||||
|
||||
// 拼接输出
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (String item : groupList) {
|
||||
result.append(item);
|
||||
}
|
||||
|
||||
tvContent.setText(result.toString());
|
||||
}
|
||||
|
||||
public String getOriginText() {
|
||||
return originText;
|
||||
}
|
||||
|
||||
public void resetSeekBar() {
|
||||
seekBarScale.setProgress(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,6 +119,54 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_frame"
|
||||
android:padding="12dp"
|
||||
android:layout_marginBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="回收站模式设置:"
|
||||
android:paddingLeft="5dp"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="2dp"
|
||||
android:background="#999999"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<RadioGroup
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/activityappsettingsRadioGroup1"
|
||||
android:paddingLeft="5dp">
|
||||
|
||||
<RadioButton
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:text="简洁模式(SMSRecycleActivity)"
|
||||
android:id="@+id/activityappsettingsRadioButton1"
|
||||
android:gravity="center_vertical"
|
||||
android:textSize="14sp"/>
|
||||
|
||||
<RadioButton
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:text="自由模式(SMSRecycle2Activity)"
|
||||
android:id="@+id/activityappsettingsRadioButton2"
|
||||
android:gravity="center_vertical"
|
||||
android:textSize="14sp"/>
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<cc.winboll.studio.libaes.views.ASupportToolbar
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/toolbar_height"
|
||||
android:id="@+id/activitysmsrecycle2ASupportToolbar1"/>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_frame"
|
||||
android:padding="8dp"
|
||||
android:layout_margin="4dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="刻度值调节示例(对所有列表项生效):"
|
||||
android:textSize="12sp"
|
||||
android:paddingLeft="4dp"
|
||||
android:paddingBottom="4dp"/>
|
||||
|
||||
<cc.winboll.studio.mymessagemanager.views.ProtectModeTextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/activitysmsrecycle2SampleProtectModeTextView"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.baoyz.widget.PullRefreshLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1.0"
|
||||
android:id="@+id/activitysmsrecycle2PullRefreshLayout1">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:isScrollContainer="true"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:reverseLayout="false"
|
||||
android:id="@+id/activitysmsrecycle2RecyclerView1"/>
|
||||
|
||||
</com.baoyz.widget.PullRefreshLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -1,44 +1,52 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="500dp">
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="right">
|
||||
<!-- 新增:自定义ProtectModeTextView -->
|
||||
<cc.winboll.studio.mymessagemanager.views.ProtectModeTextView
|
||||
android:id="@+id/protect_mode_tv"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="15dp"/>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Test Main"
|
||||
android:onClick="onMain"
|
||||
android:textAllCaps="false"/>
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="right">
|
||||
|
||||
</LinearLayout>
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Test Main"
|
||||
android:onClick="onMain"
|
||||
android:textAllCaps="false"/>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
|
||||
<cc.winboll.studio.libappbase.LogView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1.0"
|
||||
android:id="@+id/logview"/>
|
||||
</ScrollView>
|
||||
|
||||
<cc.winboll.studio.libappbase.LogView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1.0"
|
||||
android:id="@+id/logview"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="16sp"
|
||||
android:gravity="center"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/seek_bar_scale"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_frame"
|
||||
android:padding="10dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/listviewsmsrecycle2TextViewAddress"
|
||||
android:padding="5dp"
|
||||
android:textSize="16sp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="5dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/text_smsdeletetime"/>
|
||||
|
||||
<cc.winboll.studio.mymessagemanager.views.DateAgoTextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Text"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="10dp"
|
||||
android:id="@+id/listviewsmsrecycle2DateAgoTextViewDelete"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<cc.winboll.studio.mymessagemanager.views.ProtectModeTextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/listviewsmsrecycle2ProtectModeTextView"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Thu Jan 29 17:03:53 HKT 2026
|
||||
stageCount=15
|
||||
#Wed Apr 08 17:37:24 GMT 2026
|
||||
stageCount=26
|
||||
libraryProject=
|
||||
baseVersion=15.11
|
||||
publishVersion=15.11.14
|
||||
buildCount=0
|
||||
baseBetaVersion=15.11.15
|
||||
publishVersion=15.11.25
|
||||
buildCount=30
|
||||
baseBetaVersion=15.11.26
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
tools:ignore="QueryAllPackagesPermission" />
|
||||
<!-- 可选:兼容低版本系统 -->
|
||||
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
|
||||
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
@@ -291,6 +291,18 @@
|
||||
|
||||
<activity android:name="cc.winboll.studio.winboll.unittest.TermuxEnvTestActivity"/>
|
||||
|
||||
<activity
|
||||
android:name=".termux.NfcTermuxBridgeActivity"
|
||||
android:exported="true"> <!-- 必须设置为 true,允许外部应用调用 -->
|
||||
|
||||
<!-- 接收 ACTION_BUILD 意图 -->
|
||||
<intent-filter>
|
||||
<action android:name="cc.winboll.studio.winboll.termux.NfcTermuxBridgeActivity.ACTION_BUILD" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package cc.winboll.studio.winboll.models;
|
||||
|
||||
/**
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/03/15 08:46
|
||||
*/
|
||||
public class NfcTermuxCmd {
|
||||
public String script; // 要执行的预制脚本名(如 auth.sh)
|
||||
public String[] args; // 脚本参数
|
||||
public String workDir; // 工作目录
|
||||
public boolean background; // 是否后台执行
|
||||
public String resultDir; // 结果输出目录(可为 null)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* 源码说明与描述:
|
||||
* NFC 与 Termux 桥接活动,用于接收外部应用(包调用)传递的 JSON 指令并执行 Termux 脚本命令。
|
||||
* 支持 ACTION_BUILD(后台执行)与 ACTION_BUILD_VIEW(终端窗口唤起)两种动作。
|
||||
*
|
||||
* 作者:豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* 创建时间:2025-03-15 14:00:00
|
||||
* 最后编辑时间:2026-03-16 10:00:00
|
||||
*/
|
||||
package cc.winboll.studio.winboll.termux;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.ToastUtils;
|
||||
import cc.winboll.studio.winboll.models.NfcTermuxCmd;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
public class NfcTermuxBridgeActivity extends Activity {
|
||||
|
||||
// ========================= 常量与静态属性 =========================
|
||||
public static final String TAG = "NfcTermuxBridgeActivity";
|
||||
|
||||
// 外部应用调用时使用的 Action 常量
|
||||
public static final String ACTION_BUILD = "cc.winboll.studio.winboll.termux.NfcTermuxBridgeActivity.ACTION_BUILD";
|
||||
|
||||
private static final Gson GSON = new Gson();
|
||||
|
||||
// ========================= 生命周期方法 =========================
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
LogUtils.d(TAG, "onCreate() 调用,savedInstanceState: " + (savedInstanceState != null ? "非空" : "空"));
|
||||
dispatchIntent(getIntent());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
LogUtils.d(TAG, "onNewIntent() 调用,intent: " + (intent != null ? intent.toString() : "null"));
|
||||
if (intent != null) {
|
||||
LogUtils.d(TAG, "onNewIntent() action: " + intent.getAction());
|
||||
LogUtils.d(TAG, "onNewIntent() data: " + intent.getDataString());
|
||||
LogUtils.d(TAG, "onNewIntent() extras: " + intent.getExtras());
|
||||
LogUtils.d(TAG, "onNewIntent() flags: " + intent.getFlags());
|
||||
LogUtils.d(TAG, "onNewIntent() component: " + intent.getComponent());
|
||||
} else {
|
||||
LogUtils.w(TAG, "onNewIntent() intent is null");
|
||||
}
|
||||
dispatchIntent(intent);
|
||||
}
|
||||
|
||||
// ========================= 统一 Intent 分发(合并去重) =========================
|
||||
/**
|
||||
* 统一分发 Intent,根据 Action 路由到不同业务逻辑
|
||||
* @param intent 外部传入的 Intent
|
||||
*/
|
||||
private void dispatchIntent(Intent intent) {
|
||||
LogUtils.d(TAG, "dispatchIntent() 分发 intent");
|
||||
if (intent == null) {
|
||||
LogUtils.w(TAG, "dispatchIntent() intent is null");
|
||||
return;
|
||||
}
|
||||
|
||||
String action = intent.getAction();
|
||||
if (ACTION_BUILD.equals(action)) {
|
||||
ToastUtils.show("ACTION_BUILD 命中");
|
||||
onOpenTermuxProjectBuild(intent);
|
||||
} else {
|
||||
LogUtils.w(TAG, "dispatchIntent() 未知 Action: " + action);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
// ========================= 核心业务方法 =========================
|
||||
/**
|
||||
* 处理 ACTION_BUILD 动作:后台执行 NFC 指令
|
||||
*/
|
||||
// private void handleNfcIntent(Intent intent) {
|
||||
// LogUtils.d(TAG, "handleNfcIntent() 调用");
|
||||
// if (intent == null) {
|
||||
// LogUtils.w(TAG, "handleNfcIntent() intent 为空");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// try {
|
||||
// String json = intent.getStringExtra(Intent.EXTRA_TEXT);
|
||||
// LogUtils.d(TAG, "handleNfcIntent() json: " + json);
|
||||
//
|
||||
// if (json == null || json.isEmpty()) {
|
||||
// LogUtils.e(TAG, "handleNfcIntent() 指令为空");
|
||||
// showToast("指令为空");
|
||||
// finish();
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// NfcTermuxCmd cmd = GSON.fromJson(json, NfcTermuxCmd.class);
|
||||
// LogUtils.d(TAG, "handleNfcIntent() cmd: " + cmd);
|
||||
//
|
||||
// if (cmd.script == null || cmd.script.isEmpty()) {
|
||||
// LogUtils.e(TAG, "handleNfcIntent() script 为空");
|
||||
// showToast("script 不能为空");
|
||||
// finish();
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// //String scriptPath = "/data/data/com.termux/files/home/TermuxWorkSpaces/BashShells/AutoNFC/" + cmd.script;
|
||||
// String scriptPath = "/data/data/com.termux/files/home/TermuxWorkSpaces/BashShells/AutoNFC/" + "BuildWinBoLLProject.sh";
|
||||
// LogUtils.d(TAG, "handleNfcIntent() 脚本路径: " + scriptPath);
|
||||
//
|
||||
// boolean success = TermuxCommandExecutor.executeCommand(
|
||||
// this, scriptPath, cmd.args, cmd.workDir, cmd.background, cmd.resultDir
|
||||
// );
|
||||
// LogUtils.d(TAG, "handleNfcIntent() 执行结果: " + success);
|
||||
//
|
||||
// if (success) {
|
||||
// showToast("指令已发送: " + cmd.script);
|
||||
// LogUtils.i(TAG, "执行成功: " + scriptPath);
|
||||
// } else {
|
||||
// showToast("指令发送失败");
|
||||
// LogUtils.e(TAG, "执行失败");
|
||||
// }
|
||||
//
|
||||
// } catch (Exception e) {
|
||||
// LogUtils.e(TAG, "handleNfcIntent() 异常: " + e.getMessage(), e);
|
||||
// showToast("解析失败");
|
||||
// } finally {
|
||||
// finish();
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* 处理 ACTION_BUILD_VIEW 动作:唤起 Termux 窗口执行命令
|
||||
*/
|
||||
public void onOpenTermuxProjectBuild(Intent intent) {
|
||||
LogUtils.d(TAG, "onOpenTermuxProjectBuildView() 调用");
|
||||
if (intent == null) {
|
||||
LogUtils.w(TAG, "onOpenTermuxProjectBuildView() intent 为空");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
String json = intent.getStringExtra(Intent.EXTRA_TEXT);
|
||||
LogUtils.d(TAG, "onOpenTermuxProjectBuildView() json: " + json);
|
||||
|
||||
if (json == null || json.isEmpty()) {
|
||||
LogUtils.e(TAG, "onOpenTermuxProjectBuildView() 指令为空");
|
||||
showToast("指令为空");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
NfcTermuxCmd cmd = GSON.fromJson(json, NfcTermuxCmd.class);
|
||||
LogUtils.d(TAG, "onOpenTermuxProjectBuildView() cmd: " + cmd);
|
||||
|
||||
if (cmd.script == null || cmd.script.isEmpty()) {
|
||||
LogUtils.e(TAG, "onOpenTermuxProjectBuildView() script 为空");
|
||||
showToast("script 不能为空");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder targetCmd = new StringBuilder();
|
||||
String nfcScriptFolder = "/data/data/com.termux/files/home/TermuxWorkSpaces/BashShells/AutoNFC/";
|
||||
targetCmd.append("cd " + nfcScriptFolder + " && ");
|
||||
//targetCmd.append("stdbuf -o0 -e0 -i0 bash ").append(cmd.script).append(" ");
|
||||
targetCmd.append("stdbuf -o0 -e0 -i0 bash ").append("BuildWinBoLLProject.sh").append(" ");
|
||||
if (cmd.args != null) {
|
||||
for (String arg : cmd.args) {
|
||||
targetCmd.append(arg).append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
LogUtils.d(TAG, "onOpenTermuxProjectBuildView() 命令: " + targetCmd);
|
||||
boolean cmdSuccess = TermuxCommandExecutor.executeTerminalCommand(this, targetCmd.toString());
|
||||
LogUtils.d(TAG, "onOpenTermuxProjectBuildView() 执行结果: " + cmdSuccess);
|
||||
|
||||
if (cmdSuccess) {
|
||||
showToast("指令已发送: " + cmd.script);
|
||||
} else {
|
||||
showToast("指令发送失败");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "onOpenTermuxProjectBuildView() 异常: " + e.getMessage(), e);
|
||||
showToast("解析失败");
|
||||
} finally {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
// ========================= 公共静态测试方法 =========================
|
||||
/**
|
||||
* 内部测试方法:发送 ACTION_BUILD 指令
|
||||
*/
|
||||
public static void testCommand(Context context) {
|
||||
LogUtils.d(TAG, "testCommand()");
|
||||
try {
|
||||
String testJson = "{\"script\":\"BuildWinBoLLProject.sh\",\"args\":[\"DebugTemp\"],\"workDir\":null,\"background\":true,\"resultDir\":null}";
|
||||
Intent intent = new Intent(context, NfcTermuxBridgeActivity.class);
|
||||
intent.setAction(ACTION_BUILD); // 指定 Action
|
||||
intent.putExtra(Intent.EXTRA_TEXT, testJson);
|
||||
context.startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "testCommand() 失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部测试方法:发送 ACTION_BUILD_VIEW 指令
|
||||
*/
|
||||
// public static void testViewCommand(Context context) {
|
||||
// LogUtils.d(TAG, "testViewCommand()");
|
||||
// try {
|
||||
// String testJson = "{\"script\":\"BuildWinBoLLProjectView.sh\",\"args\":[\"DebugTemp\"],\"workDir\":null,\"background\":true,\"resultDir\":null}";
|
||||
// Intent intent = new Intent(context, NfcTermuxBridgeActivity.class);
|
||||
// intent.setAction(ACTION_BUILD_VIEW); // 指定 Action
|
||||
// intent.putExtra(Intent.EXTRA_TEXT, testJson);
|
||||
// context.startActivity(intent);
|
||||
// } catch (Exception e) {
|
||||
// LogUtils.e(TAG, "testViewCommand() 失败: " + e.getMessage());
|
||||
// }
|
||||
// }
|
||||
|
||||
// ========================= 工具方法 =========================
|
||||
/**
|
||||
* 统一显示 Toast,确保在主线程调用
|
||||
*/
|
||||
private void showToast(final String message) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(NfcTermuxBridgeActivity.this, message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cc.winboll.studio.winboll.unittest;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
@@ -7,11 +8,11 @@ import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.winboll.MainActivity;
|
||||
import cc.winboll.studio.libappbase.ToastUtils;
|
||||
import cc.winboll.studio.winboll.R;
|
||||
import cc.winboll.studio.winboll.activities.BaseWinBoLLActivity;
|
||||
import cc.winboll.studio.winboll.termux.NfcTermuxBridgeActivity;
|
||||
import cc.winboll.studio.winboll.termux.TermuxCommandExecutor;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
@@ -19,7 +20,6 @@ import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import android.app.Activity;
|
||||
|
||||
/**
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
@@ -38,8 +38,8 @@ public class TermuxEnvTestActivity extends BaseWinBoLLActivity {
|
||||
|
||||
// 常量属性(置顶排列)
|
||||
public static final String TAG = "TermuxEnvTestActivity";
|
||||
private static final String TERMUX_HOME_PATH = "/sdcard/WinBoLLStudio";
|
||||
private static final String CMD_RESULT_FILE = TERMUX_HOME_PATH + "/.authcenter_cmd_result.tmp";
|
||||
private static final String TERMUX_HOME_PATH = "/data/data/com.termux/files/home/TermuxWorkSpaces";
|
||||
private static final String CMD_RESULT_FILE = TERMUX_HOME_PATH + "/CMD_RESULT_FILE.log";
|
||||
|
||||
// 成员属性(常量后排列)
|
||||
private Toolbar mToolbar;
|
||||
@@ -103,12 +103,12 @@ public class TermuxEnvTestActivity extends BaseWinBoLLActivity {
|
||||
((AppCompatActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LogUtils.d(TAG, "initToolbar() 导航栏返回按钮点击");
|
||||
getActivity().finish();
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LogUtils.d(TAG, "initToolbar() 导航栏返回按钮点击");
|
||||
getActivity().finish();
|
||||
}
|
||||
});
|
||||
|
||||
LogUtils.d(TAG, "initToolbar() 初始化完成");
|
||||
}
|
||||
@@ -158,7 +158,7 @@ public class TermuxEnvTestActivity extends BaseWinBoLLActivity {
|
||||
/**
|
||||
* 测试执行Gradle命令(实时输出版,唤起Termux窗口)
|
||||
*/
|
||||
public void onTestTermuxCMD(View view) {
|
||||
public void onTestTermuxGradleBuildCMD(View view) {
|
||||
LogUtils.d(TAG, "onTestTermuxCMD() 按钮点击,执行Gradle命令(实时输出)");
|
||||
tvMessage.append("\n【测试:执行Gradle命令(实时输出)】\n");
|
||||
|
||||
@@ -171,7 +171,7 @@ public class TermuxEnvTestActivity extends BaseWinBoLLActivity {
|
||||
|
||||
// 2. 定义核心路径(确保路径与Termux中一致)
|
||||
String gradleFullPath = "/data/data/com.termux/files/home/gradle/gradle-7.5.1/bin/gradle";
|
||||
String projectPath = TERMUX_HOME_PATH + "/Sources/WinBoLL"; // 项目目录
|
||||
String projectPath = TERMUX_HOME_PATH + "/Sources/DebugTemp"; // 项目目录
|
||||
|
||||
// 3. 构造命令(核心:用stdbuf禁用缓冲,实现实时输出)
|
||||
String targetCmd = "";
|
||||
@@ -216,7 +216,17 @@ public class TermuxEnvTestActivity extends BaseWinBoLLActivity {
|
||||
tvMessage.append("💡 若未实时输出,请在Termux中执行:pkg install coreutils(安装stdbuf)\n");
|
||||
tvMessage.append("-------------------------\n");
|
||||
}
|
||||
|
||||
public void onTestWinBoLLProjectBuild(View view) {
|
||||
ToastUtils.show("onTestWinBoLLProjectBuild");
|
||||
NfcTermuxBridgeActivity.testCommand(this);
|
||||
}
|
||||
|
||||
// public void onTestWinBoLLProjectBuildView(View view) {
|
||||
// ToastUtils.show("onTestWinBoLLProjectBuildView");
|
||||
// NfcTermuxBridgeActivity.testViewCommand(this);
|
||||
// }
|
||||
|
||||
public void onOpenTermuxBash(View view) {
|
||||
LogUtils.d(TAG, "onTestTermuxCMD() 按钮点击,执行Gradle命令(实时输出)");
|
||||
tvMessage.append("\n【测试:执行Gradle命令(实时输出)】\n");
|
||||
@@ -230,7 +240,7 @@ public class TermuxEnvTestActivity extends BaseWinBoLLActivity {
|
||||
|
||||
// 2. 定义核心路径(确保路径与Termux中一致)
|
||||
String gradleFullPath = "/data/data/com.termux/files/home/gradle/gradle-7.5.1/bin/gradle";
|
||||
String projectPath = TERMUX_HOME_PATH + "/Sources/WinBoLL"; // 项目目录
|
||||
String projectPath = TERMUX_HOME_PATH + "/"; // 项目目录
|
||||
|
||||
// 3. 构造命令(核心:用stdbuf禁用缓冲,实现实时输出)
|
||||
String targetCmd = "";
|
||||
@@ -275,7 +285,7 @@ public class TermuxEnvTestActivity extends BaseWinBoLLActivity {
|
||||
tvMessage.append("💡 若未实时输出,请在Termux中执行:pkg install coreutils(安装stdbuf)\n");
|
||||
tvMessage.append("-------------------------\n");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 跨包读取Termux命令结果文件(保留原功能,兼容其他场景)
|
||||
*/
|
||||
@@ -399,7 +409,7 @@ public class TermuxEnvTestActivity extends BaseWinBoLLActivity {
|
||||
String filePath = file.getAbsolutePath();
|
||||
String fileSize = file.isFile() ? " | 大小:" + formatFileSize(file.length()) : "";
|
||||
String filePerm = " | 权限:r:" + file.canRead() + "/w:" + file.canWrite();
|
||||
|
||||
|
||||
result.append(fileType);
|
||||
result.append(" ");
|
||||
result.append(fileName);
|
||||
|
||||
@@ -16,25 +16,35 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="right">
|
||||
|
||||
|
||||
<Button
|
||||
android:textAllCaps="false"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="OpenTermuxBash"
|
||||
android:text="Open Termux Bash"
|
||||
android:onClick="onOpenTermuxBash"/>
|
||||
|
||||
<Button
|
||||
android:textAllCaps="false"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="TestTermuxCMD"
|
||||
android:onClick="onTestTermuxCMD"/>
|
||||
android:text="Test Termux Gradle Build CMD"
|
||||
android:onClick="onTestTermuxGradleBuildCMD"/>
|
||||
|
||||
<Button
|
||||
android:textAllCaps="false"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="TestTermuxEnv"
|
||||
android:text="Test Termux Env"
|
||||
android:onClick="onTestTermuxEnv"/>
|
||||
|
||||
<Button
|
||||
android:textAllCaps="false"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Test WinBoLL Project Build"
|
||||
android:onClick="onTestWinBoLLProjectBuild"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ScrollView
|
||||
|
||||
Reference in New Issue
Block a user