Compare commits

..

21 Commits

Author SHA1 Message Date
ZhanGSKen
841d526b0d <powerbell>APK 15.2.0 release Publish. 2025-03-31 15:06:43 +08:00
ZhanGSKen
11d2db6bf9 更新应用简介。 2025-03-31 15:05:02 +08:00
ZhanGSKen
93d8fa15db 修改主题配置,修复日志菜单栏显示问题。 2025-03-31 14:59:54 +08:00
ZhanGSKen
99ff741a22 更新类库,设置版本号。 2025-03-31 14:53:33 +08:00
ZhanGSKen
5bc7581db1 Merge remote-tracking branch 'origin/androidxdemo' into powerbell 2025-03-31 14:39:31 +08:00
ZhanGSKen
fde0712439 Merge remote-tracking branch 'origin/appbase' into powerbell 2025-03-31 14:39:26 +08:00
ZhanGSKen
4ff54c785e <powerbell>APK 15.0.3 release Publish. 2025-03-25 02:43:07 +08:00
ZhanGSKen
b961468e1e <powerbell>APK 15.0.2 release Publish. 2025-03-25 02:42:42 +08:00
ZhanGSKen
575ef9aac0 内容提供配置调整 2025-03-25 02:42:10 +08:00
ZhanGSKen
16b118f83b <powerbell>APK 15.0.1 release Publish. 2025-03-25 02:36:56 +08:00
ZhanGSKen
1eeba4e4c6 <powerbell>APK 15.0.0 release Publish. 2025-03-25 02:34:56 +08:00
ZhanGSKen
66eb8e06ea 应用介绍页基本调试完成 2025-03-25 02:30:45 +08:00
ZhanGSKen
51775620db 更新类库,调试应用介绍... 2025-03-24 20:24:31 +08:00
ZhanGSKen
deaa9caadd Merge remote-tracking branch 'origin/appbase' into powerbell 2025-03-24 14:33:17 +08:00
ZhanGSKen
58af5ba074 <powerbell>APK 4.0.7 release Publish. 2025-03-22 16:06:33 +08:00
ZhanGSKen
19743d30ef 修复编译参数 2025-03-22 16:05:10 +08:00
ZhanGSKen
3c2b720e20 调整背景图片设置窗口按钮布局 2025-03-22 16:03:08 +08:00
ZhanGSKen
5a052e4b22 添加电池报告窗口雏形 2025-03-22 15:54:18 +08:00
ZhanGSKen
4ccf6824a6 <powerbell>APK 4.0.6 release Publish. 2025-03-22 06:01:46 +08:00
ZhanGSKen
508c8b0b97 适配小米15,修改通知模块。 2025-03-22 05:53:58 +08:00
ZhanGSKen
0d21994291 编译配置精简 2025-03-22 03:06:40 +08:00
522 changed files with 47407 additions and 6885 deletions

View File

@@ -1,4 +1,4 @@
## WinBoLL 主机编译事项提醒 ## WinBoll 主机编译事项提醒
## 类库类型源码发布 ## 类库类型源码发布
# 类库发布使用以下面命令 # 类库发布使用以下面命令

View File

@@ -37,7 +37,7 @@ fi
# 使用grep找到包含"publishVersion="的那一行然后用awk提取其后的值 # 使用grep找到包含"publishVersion="的那一行然后用awk提取其后的值
PUBLISH_VERSION=$(grep -o "publishVersion=.*" $1/build.properties | awk -F '=' '{print $2}') PUBLISH_VERSION=$(grep -o "publishVersion=.*" $1/build.properties | awk -F '=' '{print $2}')
echo "< $1/build.properties publishVersion : ${PUBLISH_VERSION} >" echo "< $1/build.properties publishVersion : ${PUBLISH_VERSION} >"
## 设新的 WinBoLL 标签 ## 设新的 WinBoll 标签
# 脚本调试时使用 # 脚本调试时使用
#tag="v7.6.4-test1" #tag="v7.6.4-test1"
# 正式设置标签时使用 # 正式设置标签时使用

View File

@@ -38,24 +38,24 @@ function askAddWorkflowsTag {
fi fi
} }
function addWinBoLLTag { function addWinBollTag {
# 就读取脚本 .winboll/winboll_app_build.gradle 生成的 publishVersion。 # 就读取脚本 .winboll/winboll_app_build.gradle 生成的 publishVersion。
# 如果文件中有 publishVersion 这一项, # 如果文件中有 publishVersion 这一项,
# 使用grep找到包含"publishVersion="的那一行然后用awk提取其后的值 # 使用grep找到包含"publishVersion="的那一行然后用awk提取其后的值
PUBLISH_VERSION=$(grep -o "publishVersion=.*" $1/build.properties | awk -F '=' '{print $2}') PUBLISH_VERSION=$(grep -o "publishVersion=.*" $1/build.properties | awk -F '=' '{print $2}')
echo "< $1/build.properties publishVersion : ${PUBLISH_VERSION} >" echo "< $1/build.properties publishVersion : ${PUBLISH_VERSION} >"
## 设新的 WinBoLL 标签 ## 设新的 WinBoll 标签
# 脚本调试时使用 # 脚本调试时使用
#tag="projectname-v7.6.4-test1" #tag="projectname-v7.6.4-test1"
# 正式设置标签时使用 # 正式设置标签时使用
tag=$1"-v"${PUBLISH_VERSION} tag=$1"-v"${PUBLISH_VERSION}
echo "< WinBoLL Tag To: $tag >"; echo "< WinBoll Tag To: $tag >";
# 检查是否已经添加了 WinBoLL Tag # 检查是否已经添加了 WinBoll Tag
if [ "$(git tag -l ${tag})" == "${tag}" ]; then if [ "$(git tag -l ${tag})" == "${tag}" ]; then
echo -e "< WinBoLL Tag ${tag} exist! >" echo -e "< WinBoll Tag ${tag} exist! >"
return 1 # WinBoLL标签重复 return 1 # WinBoll标签重复
fi fi
# 添加WinBoLL标签 # 添加WinBoll标签
git tag -a ${tag} -F $1/app_update_description.txt git tag -a ${tag} -F $1/app_update_description.txt
return 0 return 0
} }
@@ -119,22 +119,22 @@ if [[ $? -eq 0 ]]; then
echo $result echo $result
# 发布应用 # 发布应用
echo "Publishing WinBoLL APK ..." echo "Publishing WinBoll APK ..."
# 脚本调试时使用 # 脚本调试时使用
#bash gradlew :$1:assembleBetaDebug #bash gradlew :$1:assembleBetaDebug
# 正式发布 # 正式发布
bash gradlew :$1:assembleStageRelease bash gradlew :$1:assembleStageRelease
echo "Publishing WinBoLL APK OK." echo "Publishing WinBoll APK OK."
# 添加 WinBoLL 标签 # 添加 WinBoll 标签
result=$(addWinBoLLTag $1) result=$(addWinBollTag $1)
echo $result echo $result
if [[ $? -eq 0 ]]; then if [[ $? -eq 0 ]]; then
echo $result echo $result
# WinBoLL 标签添加成功 # WinBoll 标签添加成功
else else
echo -e "${0}: addWinBoLLTag $1\n${result}\nAdd WinBoLL tag cancel." echo -e "${0}: addWinBollTag $1\n${result}\nAdd WinBoll tag cancel."
exit 1 # addWinBoLLTag 异常 exit 1 # addWinBollTag 异常
fi fi
# 添加 GitHub 工作流标签 # 添加 GitHub 工作流标签

View File

@@ -38,24 +38,24 @@ function askAddWorkflowsTag {
fi fi
} }
function addWinBoLLTag { function addWinBollTag {
# 就读取脚本 .winboll/winboll_app_build.gradle 生成的 publishVersion。 # 就读取脚本 .winboll/winboll_app_build.gradle 生成的 publishVersion。
# 如果文件中有 publishVersion 这一项, # 如果文件中有 publishVersion 这一项,
# 使用grep找到包含"publishVersion="的那一行然后用awk提取其后的值 # 使用grep找到包含"publishVersion="的那一行然后用awk提取其后的值
PUBLISH_VERSION=$(grep -o "publishVersion=.*" $1/build.properties | awk -F '=' '{print $2}') PUBLISH_VERSION=$(grep -o "publishVersion=.*" $1/build.properties | awk -F '=' '{print $2}')
echo "< $1/build.properties publishVersion : ${PUBLISH_VERSION} >" echo "< $1/build.properties publishVersion : ${PUBLISH_VERSION} >"
## 设新的 WinBoLL 标签 ## 设新的 WinBoll 标签
# 脚本调试时使用 # 脚本调试时使用
#tag="v7.6.4-test1" #tag="v7.6.4-test1"
# 正式调试版设置标签时使用 # 正式调试版设置标签时使用
tag=$1"-v"${PUBLISH_VERSION}"-debug" tag=$1"-v"${PUBLISH_VERSION}"-debug"
echo "< WinBoLL Tag To: $tag >"; echo "< WinBoll Tag To: $tag >";
# 检查是否已经添加了 WinBoLL Tag # 检查是否已经添加了 WinBoll Tag
if [ "$(git tag -l ${tag})" == "${tag}" ]; then if [ "$(git tag -l ${tag})" == "${tag}" ]; then
echo -e "< WinBoLL Tag ${tag} exist! >" echo -e "< WinBoll Tag ${tag} exist! >"
return 1 # WinBoLL标签重复 return 1 # WinBoll标签重复
fi fi
# 添加WinBoLL标签 # 添加WinBoll标签
git tag -a ${tag} -F $1/app_update_description.txt git tag -a ${tag} -F $1/app_update_description.txt
return 0 return 0
} }
@@ -119,22 +119,22 @@ if [[ $? -eq 0 ]]; then
echo $result echo $result
# 发布应用 # 发布应用
echo "Publishing WinBoLL Debug APK ..." echo "Publishing WinBoll Debug APK ..."
# 脚本调试时使用 # 脚本调试时使用
#bash gradlew :$1:assembleBetaDebug #bash gradlew :$1:assembleBetaDebug
# 正式发布调试版 # 正式发布调试版
bash gradlew :$1:assembleStageDebug bash gradlew :$1:assembleStageDebug
echo "Publishing WinBoLL Debug APK OK." echo "Publishing WinBoll Debug APK OK."
# 添加 WinBoLL 标签 # 添加 WinBoll 标签
result=$(addWinBoLLTag $1) result=$(addWinBollTag $1)
echo $result echo $result
if [[ $? -eq 0 ]]; then if [[ $? -eq 0 ]]; then
echo $result echo $result
# WinBoLL 标签添加成功 # WinBoll 标签添加成功
else else
echo -e "${0}: addWinBoLLTag $1\n${result}\nAdd WinBoLL tag cancel." echo -e "${0}: addWinBollTag $1\n${result}\nAdd WinBoll tag cancel."
exit 1 # addWinBoLLTag 异常 exit 1 # addWinBollTag 异常
fi fi
# 添加 GitHub 工作流标签 # 添加 GitHub 工作流标签

View File

@@ -8,7 +8,7 @@ if [ -z "$1" ]; then
fi fi
## 正式发布使用 ## 正式发布使用
git pull && bash gradlew :$1:publishReleasePublicationToWinBoLLReleaseRepository && bash .winboll/bashCommitLibReleaseBuildFlagInfo.sh $1 git pull && bash gradlew :$1:publishReleasePublicationToWinBollReleaseRepository && bash .winboll/bashCommitLibReleaseBuildFlagInfo.sh $1
## 调试使用 ## 调试使用
#bash gradlew :$1:publishSnapshotWinBoLLPublicationToWinBoLLSnapshotRepository && bash .winboll/bashCommitLibReleaseBuildFlagInfo.sh $1 #bash gradlew :$1:publishSnapshotWinBollPublicationToWinBollSnapshotRepository && bash .winboll/bashCommitLibReleaseBuildFlagInfo.sh $1

View File

@@ -1,4 +1,4 @@
// WinBoLL 应用签名配置 // WinBoll 应用签名配置
// //
android { android {
@@ -31,18 +31,18 @@ android {
} }
} }
flavorDimensions "WinBoLLApp" flavorDimensions "WinBollApp"
productFlavors { productFlavors {
beta { beta {
// 检查编译标志位配置 // 检查编译标志位配置
assert (winbollBuildProps['buildCount'] != null) assert (winbollBuildProps['buildCount'] != null)
dimension "WinBoLLApp" dimension "WinBollApp"
applicationIdSuffix ".beta" applicationIdSuffix ".beta"
LocalDateTime localDateTimeNow = LocalDateTime.now(ZoneId.of("Asia/Shanghai")); LocalDateTime localDateTimeNow = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
versionNameSuffix "-beta" + winbollBuildProps['buildCount'] + "_" + localDateTimeNow.format('mmss') versionNameSuffix "-beta" + winbollBuildProps['buildCount'] + "_" + localDateTimeNow.format('mmss')
} }
stage { stage {
dimension "WinBoLLApp" dimension "WinBollApp"
} }
} }
@@ -61,7 +61,7 @@ android {
} }
// //
// WinBoLL 应用包输出配置 // WinBoll 应用包输出配置
// 1. 配置 Stage Release 版应用包输出 // 1. 配置 Stage Release 版应用包输出
// 2. 配置 Beta Debug 版应用包输出 // 2. 配置 Beta Debug 版应用包输出
// //
@@ -74,13 +74,13 @@ android {
//def outputFileName="${rootProject.name}_${versionName}.apk" //def outputFileName="${rootProject.name}_${versionName}.apk"
def outputFileName=project.rootDir.name + "_${versionName}.apk" def outputFileName=project.rootDir.name + "_${versionName}.apk"
// 创建 WinBoLL Studio 发布接口文件夹 // 创建 WinBoll Studio 发布接口文件夹
File fWinBoLLStudioDir = file("/sdcard/WinBoLLStudio/APKs"); File fWinBollStudioDir = file("/sdcard/WinBollStudio/APKs");
if(!fWinBoLLStudioDir.exists()) { if(!fWinBollStudioDir.exists()) {
//fWinBoLLStudioDir.mkdirs(); //fWinBollStudioDir.mkdirs();
// 如果没有发布接口文件就不用进行APK发布和源码管理操作 // 如果没有发布接口文件就不用进行APK发布和源码管理操作
// 当前编译环境不是 WinBoLL 主机, 以下将忽略APK发布和源码管理操作。 // 当前编译环境不是 WinBoll 主机, 以下将忽略APK发布和源码管理操作。
println 'The current compilation environment is not in WinBoLL host, and the following APK publishing and source management operations will be ignore.' println 'The current compilation environment is not in WinBoll host, and the following APK publishing and source management operations will be ignore.'
} else { } else {
/// WINBOLL 主机的 APK 发布和源码管理操作 /// /// WINBOLL 主机的 APK 发布和源码管理操作 ///
variant.getAssembleProvider().get().doFirst { variant.getAssembleProvider().get().doFirst {
@@ -91,15 +91,15 @@ android {
// //
variant.getAssembleProvider().get().doLast { variant.getAssembleProvider().get().doLast {
variant.outputs.forEach{ file-> variant.outputs.forEach{ file->
// 如果正在调试,就拷贝到 WinBoLL 备份管理文件夹 // 如果正在调试,就拷贝到 WinBoll 备份管理文件夹
// //
if(variant.flavorName == "beta"&&variant.buildType.name == "debug"){ if(variant.flavorName == "beta"&&variant.buildType.name == "debug"){
//File outBuildBckDir = new File(fWinBoLLStudioDir, "/${rootProject.name}/${variant.buildType.name}") //File outBuildBckDir = new File(fWinBollStudioDir, "/${rootProject.name}/${variant.buildType.name}")
File outBuildBckDir = new File(fWinBoLLStudioDir, "/" + project.rootDir.name + "/${variant.buildType.name}") File outBuildBckDir = new File(fWinBollStudioDir, "/" + project.rootDir.name + "/${variant.buildType.name}")
// 创建目标路径目录 // 创建目标路径目录
if(!outBuildBckDir.exists()) { if(!outBuildBckDir.exists()) {
outBuildBckDir.mkdirs(); outBuildBckDir.mkdirs();
println "Output Folder Created.(WinBoLLStudio) : " + outBuildBckDir.getAbsolutePath() println "Output Folder Created.(WinBollStudio) : " + outBuildBckDir.getAbsolutePath()
} }
if(outBuildBckDir.exists()) { if(outBuildBckDir.exists()) {
copy{ copy{
@@ -108,7 +108,7 @@ android {
rename { rename {
String fileName -> "${outputFileName}" String fileName -> "${outputFileName}"
} }
println "Output APK (WinBoLLStudio): " + outBuildBckDir.getAbsolutePath() + "/${outputFileName}" println "Output APK (WinBollStudio): " + outBuildBckDir.getAbsolutePath() + "/${outputFileName}"
} }
// 检查编译标志位配置 // 检查编译标志位配置
assert (winbollBuildProps['buildCount'] != null) assert (winbollBuildProps['buildCount'] != null)
@@ -137,7 +137,7 @@ android {
} }
} }
// 如果正在发布,就拷贝到 WinBoLL 标签管理文件夹 // 如果正在发布,就拷贝到 WinBoll 标签管理文件夹
// //
if((variant.flavorName == "stage"&&variant.buildType.name == "debug") if((variant.flavorName == "stage"&&variant.buildType.name == "debug")
|| (variant.flavorName == "stage"&&variant.buildType.name == "release")){ || (variant.flavorName == "stage"&&variant.buildType.name == "release")){
@@ -151,8 +151,8 @@ android {
String szCommonTagAPKName = project.rootDir.name + "_" + szShortVersionName + ".apk" String szCommonTagAPKName = project.rootDir.name + "_" + szShortVersionName + ".apk"
println "CommonTagAPKName is : " + szCommonTagAPKName println "CommonTagAPKName is : " + szCommonTagAPKName
//File outTagDir = new File(fWinBoLLStudioDir, "/${rootProject.name}/tag/") //File outTagDir = new File(fWinBollStudioDir, "/${rootProject.name}/tag/")
File outTagDir = new File(fWinBoLLStudioDir, "/" + project.rootDir.name + "/tag/") File outTagDir = new File(fWinBollStudioDir, "/" + project.rootDir.name + "/tag/")
// 创建目标路径目录 // 创建目标路径目录
if(!outTagDir.exists()) { if(!outTagDir.exists()) {
outTagDir.mkdirs(); outTagDir.mkdirs();

View File

@@ -1,4 +1,4 @@
// 本机和 WinBoLL Maven 仓库传输配置。 // 本机和 WinBoll Maven 仓库传输配置。
// //
def getDefaultVersion(){ def getDefaultVersion(){
@@ -9,12 +9,12 @@ def getDefaultVersion(){
} }
def siteUrl = 'https://winboll.cc/?page=studio/details.php&app=${rootProject.name}' // 项目主页 def siteUrl = 'https://winboll.cc/?page=studio/details.php&app=${rootProject.name}' // 项目主页
def gitUrl = 'https://gitea.winboll.cc/WinBoLL/${rootProject.name}' // 项目的git地址 def gitUrl = 'https://gitea.winboll.cc/WinBoll/${rootProject.name}' // 项目的git地址
def DefaultGroupId = 'cc.winboll.studio' // 类库所有者groupId def DefaultGroupId = 'cc.winboll.studio' // 类库所有者groupId
def DefaultVersion = getDefaultVersion() // 版本号 def DefaultVersion = getDefaultVersion() // 版本号
def DeveloperId='zhangsken' // 开发者账号 def DeveloperId='zhangsken' // 开发者账号
def DeveloperName='ZhanGSKen' // 开发者名称 def DeveloperName='ZhanGSKen' // 开发者名称
def DeveloperEMail='zhangsken@188.com' // 开发者邮箱地址 def DeveloperEMail='ZhanGSKen@QQ.COM' // 开发者邮箱地址
def LicenseName='The Apache Software License, Version 2.0' def LicenseName='The Apache Software License, Version 2.0'
def LicenseUrl='http://www.apache.org/licenses/LICENSE-2.0.txt' def LicenseUrl='http://www.apache.org/licenses/LICENSE-2.0.txt'
@@ -27,10 +27,10 @@ afterEvaluate {
properties.load(file("${RootProjectDir}/${winbollFilePath}").newDataInputStream()) properties.load(file("${RootProjectDir}/${winbollFilePath}").newDataInputStream())
def NexusUserName = properties.getProperty("Nexus.name") def NexusUserName = properties.getProperty("Nexus.name")
def NexusPassword = properties.getProperty("Nexus.password") def NexusPassword = properties.getProperty("Nexus.password")
// WinBoLL Release 仓库 // WinBoll Release 仓库
maven{ maven{
//仓库的名字和地址 //仓库的名字和地址
name = "WinBoLLRelease" name = "WinBollRelease"
url="https://nexus.winboll.cc/repository/maven-releases/" url="https://nexus.winboll.cc/repository/maven-releases/"
// 仓库用户名密码 // 仓库用户名密码
credentials { credentials {
@@ -38,10 +38,10 @@ afterEvaluate {
password = NexusPassword password = NexusPassword
} }
} }
// WinBoLL Snapshot 仓库 // WinBoll Snapshot 仓库
maven{ maven{
//仓库的名字和地址 //仓库的名字和地址
name = "WinBoLLSnapshot" name = "WinBollSnapshot"
url="https://nexus.winboll.cc/repository/maven-snapshots/" url="https://nexus.winboll.cc/repository/maven-snapshots/"
// 仓库用户名密码 // 仓库用户名密码
credentials { credentials {
@@ -101,9 +101,9 @@ afterEvaluate {
} }
} }
// WinBoLL Maven Release 仓库传输任务 // WinBoll Maven Release 仓库传输任务
// //
releaseWinBoLL(MavenPublication) { releaseWinBoll(MavenPublication) {
// 需要使用的变体假设有free和pay两个变体可以选择一个 // 需要使用的变体假设有free和pay两个变体可以选择一个
//from components.free //from components.free
@@ -154,9 +154,9 @@ afterEvaluate {
} // 创建名为 release 的任务结束 } // 创建名为 release 的任务结束
// WinBoLL Maven Snapshot 仓库传输任务 // WinBoll Maven Snapshot 仓库传输任务
// //
snapshotWinBoLL(MavenPublication) { snapshotWinBoll(MavenPublication) {
// 需要使用的变体假设有free和pay两个变体可以选择一个 // 需要使用的变体假设有free和pay两个变体可以选择一个
//from components.free //from components.free

127
README.md
View File

@@ -1,23 +1,23 @@
# ☁ ☁ ☁ WinBoLL APP ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ # ☁ ☁ ☁ WinBoll APP ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁
# ☁ ☁ WinBoLL Studio Android 应用开源项目。☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ # ☁ ☁ 这是 WinBoll 系列 APP 汇总项目。☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁
# ☁ ☁ ☁ WinBoLL 网站地址 https://www.winboll.cc/ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁ # ☁ ☁ ☁ WinBoll 网站地址 https://www.winboll.cc/studio/app/ ☁ ☁ ☁ ☁ ☁ ☁ ☁ ☁
## WinBoLL 提问 ## WinBoll 提问
同样是 /sdcard 目录,在开发 Android 应用时, 同样是 /sdcard 目录,在开发 Android 应用时,
能否实现手机编译与电脑编译的源码同步。 能否实现手机编译与电脑编译的源码同步。
☁因而 WinBoLL 项目组诞生了。 ☁因而 WinBoll 项目组诞生了。
## WinBoLL 项目组研发计划 ## WinBoll 项目组研发计划
致力于把 WinBoLL-APP 应用在手机端 Android 项目开发。 致力于把 WinBoll-APP 应用在手机端 Android 项目开发。
也在探索 https://gitea.winboll.cc/<WinBoLL 项目组>/APP.git 应用于 WinBoLL-APP APK 分发。 也在探索 https://gitea.winboll.cc/<WinBoll 项目组>/WinBoll-APP.git 应用于 WinBoll-APP APK 分发。
更想进阶 https://github.com/<WinBoLL 项目组>/APP.git 应用于 WinBoLL-APP Beta APK 分发。 更想进阶 https://github.com/<WinBoll 项目组>/WinBoll-APP.git 应用于 WinBoll-APP Beta APK 分发。
## WinBoLL-APP 汗下... ## WinBoll-APP 汗下...
#### ☁应用何置如此呢。且观用户云云。 #### ☁应用何置如此呢。且观用户云云。
#### ☁ 正当下 ☁ ### #### ☁ 正当下 ☁ ###
#### ☁ 且容傻家叙说 ☁ WinBoLL-APP 应用场景 #### ☁ 且容傻家叙说 ☁ WinBoll-APP 应用场景
### ☁ WinBoLL 设备资源概述 ### ☁ WinBoll 设备资源概述
#### ☁ 1. Raid Disk. #### ☁ 1. Raid Disk.
概述:这是一个矩阵存储类设备。 概述:这是一个矩阵存储类设备。
优点:该设备具有数据容错存储功能, 优点:该设备具有数据容错存储功能,
@@ -40,79 +40,74 @@
设备位于操作系统内部文件系统。 设备位于操作系统内部文件系统。
数据持久性与操作系统挂钩。 数据持久性与操作系统挂钩。
#### ☁ 4. WinBoLL 用户资源概述。 #### ☁ 4. WinBoll 用户资源概述。
1> /home/<用户名> 位于 WinBoLL 操作系统目录下。 1> /home/<用户名> 位于 WinBoll 操作系统目录下。
2> /rdisk/<用户名> 挂载用户 Raid Disk. 2> /rdisk/<用户名> 挂载用户 Raid Disk.
3> /data/<用户名> 挂载用户 Data Disk. 3> /data/<用户名> 挂载用户 Data Disk.
4> /sdcard/<用户名> 挂载用户 SSD Disk. 4> /sdcard/<用户名> 挂载用户 SSD Disk.
#### ☁ 5. WinBoLL-APP 用户资源概述。 #### ☁ 5. WinBoll-APP 用户资源概述。
1> /sdcard 挂载用户手机 SD 存储/storage/emulated/0 1> /sdcard 挂载用户手机 SD 存储/storage/emulated/0
### ☁ 稍稍歇 ☁ ### ### ☁ 稍稍歇 ☁ ###
### ☁ 急急停 ☁ WinBoLL 应用前置条件 ### ☁ 急急停 ☁ WinBoll 应用前置条件
☁ WinBoLL 主机建立 1Panel MySQL 应用。 ☁ WinBoll 主机建立 1Panel MySQL 应用。
☁ WinBoLL 主机建立 1Panel Gitea 应用。 ☁ WinBoll 主机建立 1Panel Gitea 应用。
☁ WinBoLL 主机设置 WinBoLL 应用为非登录状态。 ☁ WinBoll 主机设置 WinBoll 应用为非登录状态。
☁ WinBoLL 主机建立 WinBoLL 账户与 WinBoLL 用户组。 ☁ WinBoll 主机建立 WinBoll 账户与 WinBoll 用户组。
☁ WinBoLL 账户 User ID 为: J ☁ WinBoll 账户 User ID 为: winboll
☁ WinBoLL 用户组 Group ID 为: Studio ☁ WinBoll 用户组 Group ID 为: winboll
☁ WinBoLL 主机 WinBoLL 1Panel Gitea 建立 WinBoLL 工作组。 ☁ WinBoll 主机 WinBoll 1Panel Gitea 建立 WinBoll 工作组。
☁ WinBoLL 主机 WinBoLL 1Panel Gitea 用户项目 APK 编译输出目录为 /sdcard/WinBoLLStudio/<用户名>/APKs/ ☁ WinBoll 主机 WinBoll 1Panel Gitea 用户项目 APK 编译输出目录为 /sdcard/<用户名>/WinBoll/app/
☁ WinBoLL 项目配置文件示例为 "<WinBoLL 项目根目录>/.winboll/winboll.properties-demo"(WinBoLL 项目已设置) ☁ WinBoll 项目配置文件示例为 "<WinBoll 项目根目录>/.winboll/winboll.properties-demo"(WinBoll 项目已设置)
☁ WinBoLL 项目配置文件为 "<WinBoLL 项目根目录>/.winboll/winboll.properties" ☁ WinBoll 项目配置文件为 "<WinBoll 项目根目录>/.winboll/winboll.properties"
☁ WinBoLL 项目配置文件设定为源码提交时忽略。(WinBoLL 项目已设置) ☁ WinBoll 项目配置文件设定为源码提交时忽略。(WinBoll 项目已设置)
☁ Gradle 项目配置文件示例为 "<WinBoLL 项目根目录>/.winboll/local.properties-demo"(WinBoLL 项目已设置) ☁ Gradle 项目配置文件示例为 "<WinBoll 项目根目录>/.winboll/local.properties-demo"(WinBoll 项目已设置)
☁ Gradle 项目配置文件为 "<WinBoLL 项目根目录>/local.properties"(WinBoLL 项目已设置) ☁ Gradle 项目配置文件为 "<WinBoll 项目根目录>/local.properties"(WinBoll 项目已设置)
☁ Gradle 项目配置文件设定为源码提交时忽略。(WinBoLL 项目已设置) ☁ Gradle 项目配置文件设定为源码提交时忽略。(WinBoll 项目已设置)
### ☁ 登高处 ☁ WinBoLL 应用需求规划 ### ☁ 登高处 ☁ WinBoll 应用需求规划
☁ WinBoLL 主机建立 WinBoLL 客户端用户数据库为 MySQL winbollclient 数据库。 ☁ WinBoll 主机建立 WinBoll 客户端用户数据库为 MySQL winbollclient 数据库。
☁ WinBoLL 主机设置 WinBoLL 客户端用户信息存储在 winbollclient 数据库中。 ☁ WinBoll 主机设置 WinBoll 客户端用户信息存储在 winbollclient 数据库中。
☁ MySQL winbollclient 数据库中 ☁ MySQL winbollclient 数据库中
WinBoLL 客户端用户信息设定为: WinBoll 客户端用户信息设定为:
<用户名, 验证密码, 验证邮箱, 验证手机, 唯一存储令牌Token, 备用验证邮箱> <用户名, 验证密码, 验证邮箱, 验证手机, 唯一存储令牌Token, 备用验证邮箱>
☁ WinBoLL 项目源码仓库托管在 WinBoLL 1Panel Gitea 目录 /opt/1panel/apps/gitea/gitea/data/git/repositories/studio/app.git中。 ☁ WinBoll 项目源码仓库托管在 WinBoll 1Panel Gitea 目录 /opt/1panel/apps/gitea/gitea/data/git/repositories/winboll/winboll.git中。
☁ WinBoLL 主机提供 WinBoLL 1Panel Gitea 应用的 WinBoLL 项目源码仓库存取功能。Gitea 应用已提供) ☁ WinBoll 主机提供 WinBoll 1Panel Gitea 应用的 WinBoll 项目源码仓库存取功能。Gitea 应用已提供)
☁ WinBoLL 主机提供 WinBoLL Gitea 项目仓库存档功能。Gitea 应用已提供) ☁ WinBoll 主机提供 WinBoll Gitea 项目仓库存档功能。Gitea 应用已提供)
☁ 提供 WinBoLL 客户端用户登录功能。Gitea 应用已提供) ☁ 提供 WinBoll 客户端用户登录功能。Gitea 应用已提供)
### ☁ 看远方 ☁ ### ### ☁ 看远方 ☁ ###
### ☁ 心忧虑 ☁ WinBoLL-APP 应用前置需求 ### ☁ 心忧虑 ☁ WinBoll-APP 应用前置需求
☁ WinBoLL-APP WinBoLL 项目根目录设定为手机的 /sdcard/WinBoLLStudio/Sources 目录。(需要用户手动建立文件夹) ☁ WinBoll-APP WinBoll 项目根目录设定为手机的 /sdcard/WinBoll 目录。(需要用户手动建立文件夹)
☁ WinBoLL-APP 具有手机 /sdcard/WinBoLL 目录的存储权限。(需要手机操作系统授权) ☁ WinBoll-APP 具有手机 /sdcard/WinBoll 目录的存储权限。(需要手机操作系统授权)
☁ WinBoLL-APP WinBoLL 项目仓库源码存储路径为 /sdcard/WinBoLLStudio/Sources/APP.git需要用户手动建立文件夹 ☁ WinBoll-APP WinBoll 项目仓库源码存储路径为 /sdcard/WinBoll/repositories/winboll.git需要用户手动建立文件夹
☁ WinBoLL-APP 项目 APK 编译输出目录为 /sdcard/WinBoLLStudio/APKs/ ☁ WinBoll-APP 项目 APK 编译输出目录为 /sdcard/WinBoll/app/
☁ WinBoLL-APP 应用签名验证可定制化。WinBoLL 项目已提供) ☁ WinBoll-APP 应用签名验证可定制化。WinBoll 项目已提供)
☁ WinBoLL-APP 与系列衍生 APP 应用共享 cc.winboll.studio 命名空间资源。WinBoLL 项目已提供) ☁ WinBoll-APP 与系列衍生 APP 应用共享 cc.winboll.studio 命名空间资源。WinBoll 项目已提供)
☁ WinBoLL-APP 用户客户端信息存储在命名空间为 WinBoLL APP MySQLLite 应用的 winbollappclient 数据库中。 ☁ WinBoll-APP 用户客户端信息存储在命名空间为 WinBoll APP MySQLLite 应用的 winbollappclient 数据库中。
☁ WinBoLL-APP MySQLLite 应用的 winbollappclient 数据库中, ☁ WinBoll-APP MySQLLite 应用的 winbollappclient 数据库中,
WinBoLL 用户客户端信息设定为: WinBoll 用户客户端信息设定为:
<用户名, 唯一存储令牌Token> <用户名, 唯一存储令牌Token>
### ☁ 云游四方 ☁ ### ### ☁ 云游四方 ☁ ###
### ☁ 呔! ☁ WinBoLL-APP 应用需求规划 ### ☁ 呔! ☁ WinBoll-APP 应用需求规划
如要使用 WinBoLL Android 项目的 Gradle 编译功能,则需要设置以下两个文件夹。 WinBoll-APP 提供手机目录 /sdcard/WinBoll 的 WinBoll 项目源码管理功能。
☁ 1. 则需要建立数据存储目录 /sdcard/WinBoLLStudio/APKs。
WinBoLL 项目源码编译出来的安装包会拷贝一份到 /sdcard/WinBoLLStudio/APKs 目录下。
☁ 2. 则需要建立数据存储目录 /sdcard/AppProjects。
WinBoLL 项目源码编译出来的安装包会拷贝一份并命名 "app.apk" 的安装文件为到 /sdcard/AppProjects 目录下。
### ☁ 吁! ☁ WinBoll-APP 共享计划前景
☁ WinBoll-APP 将会实现 https://winboll.cc/api 访问功能。
☁ WinBoll-APP 将会实现手机端 Android 应用的开发与管理功能。
###吁! ☁ WinBoLL-APP 共享计划前景 ## ☁ WinBoll ☁ WinBoll 主机忧虑
☁ WinBoLL-APP 将会实现 https://winboll.cc/api 访问功能。 ☁ WinBoll 将会提供 gitea.winboll.cc 域名用户注册登录功能。
☁ WinBoLL-APP 将会实现手机端 Android 应用的开发与管理功能 ☁ WinBoll 将会提供 WinBoll-APP 及其衍生应用的 Gitea 仓库管理服务
☁ WinBoll 将会提供 winboll.cc 域名 WinBoll 项目组注册登录功能。
## ☁ WinBoLL ☁ WinBoLL 主机忧虑
☁ WinBoLL 将会提供 gitea.winboll.cc 域名用户注册登录功能。
☁ WinBoLL 将会提供 WinBoLL-APP 及其衍生应用的 Gitea 仓库管理服务。
☁ WinBoLL 将会提供 winboll.cc 域名 WinBoLL 项目组注册登录功能。
# 本项目要实际运用需要注意以下几个步骤: # 本项目要实际运用需要注意以下几个步骤:
# 在项目根目录下: # 在项目根目录下:
## 1. 项目模块编译环境设置(必须)settings.gradle-demo 要复制为 settings.gradle并取消相应项目模块的注释。 ## 1. 项目模块编译环境设置(必须)settings.gradle-demo 要复制为 settings.gradle并取消相应项目模块的注释。
## 2. 项目 Android SDK 编译环境设置(可选)local.properties-demo 要复制为 local.properties并按需要设置 Android SDK 目录。 ## 2. 项目 Android SDK 编译环境设置(可选)local.properties-demo 要复制为 local.properties并按需要设置 Android SDK 目录。
## 3. 类库型模块编译环境设置(可选)winboll.properties-demo 要复制为 winboll.properties并按需要设置 WinBoLL Maven 库登录用户信息。 ## 3. 类库型模块编译环境设置(可选)winboll.properties-demo 要复制为 winboll.properties并按需要设置 WinBoll Maven 库登录用户信息。
# ☆类库型项目编译方法 # ☆类库型项目编译方法
@@ -121,12 +116,12 @@
设置属性 libraryProject=<类库项目模块文件夹名称> 设置属性 libraryProject=<类库项目模块文件夹名称>
### 再编译测试项目 ### 再编译测试项目
$ bash .winboll/bashPublishAPKAddTag.sh <应用项目模块文件夹名称> $ bash .winboll/bashPublishAPKAddTag.sh <应用项目模块文件夹名称>
#### 测试项目编译后,编译器会复制一份 APK 到以下路径:"/sdcard/WinBoLLStudio/APKs/<项目根目录名称>/tag/" 文件夹。 #### 测试项目编译后,编译器会复制一份 APK 到以下路径:"/sdcard/WinBollStudio/APKs/<项目根目录名称>/tag/" 文件夹。
### 最后编译类库项目 ### 最后编译类库项目
$ bash .winboll/bashPublishLIBAddTag.sh <类库项目模块文件夹名称> $ bash .winboll/bashPublishLIBAddTag.sh <类库项目模块文件夹名称>
#### 类库模块编译命令执行后,编译器会发布到 WinBoLL Nexus Maven 库Maven 库地址可以参阅根项目目录配置 build.gradle 文件。 #### 类库模块编译命令执行后,编译器会发布到 WinBoll Nexus Maven 库Maven 库地址可以参阅根项目目录配置 build.gradle 文件。
# ☆应用型项目编译方法 # ☆应用型项目编译方法
## 直接调用以下命令编译应用型项目 ## 直接调用以下命令编译应用型项目
$ bash .winboll/bashPublishAPKAddTag.sh <应用项目模块文件夹名称> $ bash .winboll/bashPublishAPKAddTag.sh <应用项目模块文件夹名称>
#### 应用模块编译命令执行后,编译器会复制一份 APK 到以下路径:"/sdcard/WinBoLLStudio/APKs/<项目根目录名称>/tag/" 文件夹。 #### 应用模块编译命令执行后,编译器会复制一份 APK 到以下路径:"/sdcard/WinBollStudio/APKs/<项目根目录名称>/tag/" 文件夹。

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Thu Apr 03 11:14:05 HKT 2025 #Mon Mar 31 02:04:47 HKT 2025
stageCount=7 stageCount=4
libraryProject=libaes libraryProject=libaes
baseVersion=15.2 baseVersion=15.2
publishVersion=15.2.6 publishVersion=15.2.3
buildCount=0 buildCount=0
baseBetaVersion=15.2.7 baseBetaVersion=15.2.4

View File

@@ -86,8 +86,6 @@ public class AboutActivity extends WinBollActivity implements IWinBollActivity {
appInfo.setAppHomePage("https://www.winboll.cc/studio/details.php?app=AES"); appInfo.setAppHomePage("https://www.winboll.cc/studio/details.php?app=AES");
appInfo.setAppAPKName("AES"); appInfo.setAppAPKName("AES");
appInfo.setAppAPKFolderName("AES"); appInfo.setAppAPKFolderName("AES");
//appInfo.setIsAddDebugTools(false);
appInfo.setIsAddDebugTools(BuildConfig.DEBUG);
return new AboutView(mContext, appInfo); return new AboutView(mContext, appInfo);
} }
} }

View File

@@ -5,26 +5,19 @@ package cc.winboll.studio.aes;
* @Date 2024/06/13 19:03:58 * @Date 2024/06/13 19:03:58
* @Describe AES应用类 * @Describe AES应用类
*/ */
import android.view.Gravity;
import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libappbase.GlobalApplication;
import com.hjq.toast.ToastUtils; import com.hjq.toast.ToastUtils;
public class App extends GlobalApplication { public class App extends GlobalApplication {
public static final String TAG = "App"; public static final String TAG = "App";
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
// 初始化 Toast 框架
ToastUtils.init(this); ToastUtils.init(this);
// 设置 Toast 布局样式 //ToastUtils.show("App onCreate");
ToastUtils.setView(R.layout.view_toast);
//ToastUtils.setStyle(new WhiteToastStyle());
ToastUtils.setGravity(Gravity.BOTTOM, 0, 200);
} }
} }

View File

@@ -6,7 +6,6 @@ import androidx.appcompat.app.AppCompatActivity;
import cc.winboll.studio.libaes.beans.AESThemeBean; import cc.winboll.studio.libaes.beans.AESThemeBean;
import cc.winboll.studio.libaes.utils.AESThemeUtil; import cc.winboll.studio.libaes.utils.AESThemeUtil;
import cc.winboll.studio.libappbase.winboll.IWinBollActivity; import cc.winboll.studio.libappbase.winboll.IWinBollActivity;
import android.view.MenuItem;
/** /**
* @Author ZhanGSKen@AliYun.Com * @Author ZhanGSKen@AliYun.Com
@@ -48,13 +47,4 @@ public class WinBollActivity extends AppCompatActivity implements IWinBollActivi
//setTheme(AESThemeBean.getThemeStyle(getThemeType())); //setTheme(AESThemeBean.getThemeStyle(getThemeType()));
setTheme(AESThemeUtil.getThemeTypeID(getApplicationContext())); setTheme(AESThemeUtil.getThemeTypeID(getApplicationContext()));
} }
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
} }

View File

@@ -49,8 +49,7 @@ dependencies {
// Android 类库 // Android 类库
//api 'com.android.support:appcompat-v7:28.0.0' //api 'com.android.support:appcompat-v7:28.0.0'
api('com.android.support:appcompat-v7:28.0.0'){ api('com.android.support:appcompat-v7:28.0.0'){
//exclude group: "com.android.support", module: "support-vector-drawable" exclude group: "com.android.support", module: "support-vector-drawable"
exclude group: "com.android.support:animated-vector-drawable:28.0.0"
} }
// https://mvnrepository.com/artifact/com.android.support/support-compat // https://mvnrepository.com/artifact/com.android.support/support-compat
api 'com.android.support:support-compat:28.0.0' // 保留原有依赖(可选) api 'com.android.support:support-compat:28.0.0' // 保留原有依赖(可选)
@@ -67,6 +66,6 @@ dependencies {
// https://mvnrepository.com/artifact/com.android.support/recyclerview-v7 // https://mvnrepository.com/artifact/com.android.support/recyclerview-v7
api 'com.android.support:recyclerview-v7:28.0.0' api 'com.android.support:recyclerview-v7:28.0.0'
api 'cc.winboll.studio:libapputils:15.2.2' api 'cc.winboll.studio:libapputils:15.2.1'
api 'cc.winboll.studio:libappbase:15.2.2' api 'cc.winboll.studio:libappbase:15.2.2'
} }

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Thu Apr 03 03:17:18 GMT 2025 #Sat Mar 29 04:34:14 GMT 2025
stageCount=0 stageCount=0
libraryProject= libraryProject=
baseVersion=15.0 baseVersion=15.0
publishVersion=15.0.0 publishVersion=15.0.0
buildCount=21 buildCount=15
baseBetaVersion=15.0.1 baseBetaVersion=15.0.1

View File

@@ -67,7 +67,7 @@ dependencies {
//api 'androidx.vectordrawable:vectordrawable-animated:1.1.0' //api 'androidx.vectordrawable:vectordrawable-animated:1.1.0'
//api 'androidx.fragment:fragment:1.1.0' //api 'androidx.fragment:fragment:1.1.0'
api 'cc.winboll.studio:libaes:15.2.6' api 'cc.winboll.studio:libaes:15.2.3'
api 'cc.winboll.studio:libapputils:15.2.2' api 'cc.winboll.studio:libapputils:15.2.1'
api 'cc.winboll.studio:libappbase:15.2.2' api 'cc.winboll.studio:libappbase:15.2.2'
} }

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Thu Apr 03 03:15:55 GMT 2025 #Mon Mar 31 03:57:35 GMT 2025
stageCount=0 stageCount=0
libraryProject= libraryProject=
baseVersion=15.0 baseVersion=15.0
publishVersion=15.0.0 publishVersion=15.0.0
buildCount=18 buildCount=12
baseBetaVersion=15.0.1 baseBetaVersion=15.0.1

View File

@@ -14,7 +14,6 @@ import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.Gravity;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.ViewGroup; import android.view.ViewGroup;
@@ -22,9 +21,7 @@ import android.widget.HorizontalScrollView;
import android.widget.ScrollView; import android.widget.ScrollView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import cc.winboll.studio.androidxdemo.R;
import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libappbase.GlobalApplication;
import com.hjq.toast.ToastUtils;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.Closeable; import java.io.Closeable;
@@ -49,14 +46,6 @@ public class App extends GlobalApplication {
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
// 初始化 Toast 框架
ToastUtils.init(this);
// 设置 Toast 布局样式
ToastUtils.setView(R.layout.view_toast);
//ToastUtils.setStyle(new WhiteToastStyle());
ToastUtils.setGravity(Gravity.BOTTOM, 0, 200);
//CrashHandler.getInstance().registerGlobal(this); //CrashHandler.getInstance().registerGlobal(this);
//CrashHandler.getInstance().registerPart(this); //CrashHandler.getInstance().registerPart(this);
} }

View File

@@ -4,7 +4,6 @@ import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libappbase.LogView; import cc.winboll.studio.libappbase.LogView;
import com.hjq.toast.ToastUtils;
public class MainActivity extends AppCompatActivity { public class MainActivity extends AppCompatActivity {
@@ -19,8 +18,6 @@ public class MainActivity extends AppCompatActivity {
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
mLogView = findViewById(R.id.logview); mLogView = findViewById(R.id.logview);
ToastUtils.show("onCreate");
} }
@Override @Override

0
app/app.md Normal file
View File

0
app/app.perl Normal file
View File

0
app/app.php Normal file
View File

0
app/app.py Normal file
View File

0
app/app.sh Normal file
View File

0
app/app.txt Normal file
View File

View File

@@ -18,19 +18,18 @@ def genVersionName(def versionName){
} }
android { android {
compileSdkVersion 32 compileSdkVersion 32
buildToolsVersion "32.0.0" buildToolsVersion "33.0.3"
defaultConfig { defaultConfig {
applicationId "cc.winboll.studio.appbase" applicationId "cc.winboll.studio.app"
minSdkVersion 24 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 30
versionCode 1 versionCode 1
// versionName // versionName
// .winboll/winbollBuildProps.properties stageCount=0 // build.gradle stageCount=0
// Gradle编译环境下合起来的 versionName "${versionName}.0" // Gradle编译环境下合起来的 versionName "${versionName}.0"
versionName "15.2" versionName "1.8"
if(true) { if(true) {
versionName = genVersionName("${versionName}") versionName = genVersionName("${versionName}")
} }
@@ -42,9 +41,14 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
} }
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
} }
dependencies { dependencies {
api project(':libappbase') api project(':winboll-shared')
api fileTree(dir: 'libs', include: ['*.jar']) api fileTree(dir: 'libs', include: ['*.jar'])
} }

8
app/build.properties Normal file
View File

@@ -0,0 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Sun Jan 05 07:55:24 HKT 2025
stageCount=17
libraryProject=winboll-shared
baseVersion=1.8
publishVersion=1.8.16
buildCount=0
baseBetaVersion=1.8.17

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" >
<application
tools:replace="android:icon"
android:icon="@drawable/ic_winbollbeta">
<!-- Put flavor specific code here -->
</application>
</manifest>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">WinBoll-APP+</string>
</resources>

View File

@@ -0,0 +1,48 @@
<?xml version='1.0' encoding='utf-8'?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="cc.winboll.studio.app">
<!-- BIND_AUTOFILL_SERVICE -->
<uses-permission android:name="android.permission.BIND_AUTOFILL_SERVICE"/>
<application
android:name=".App"
android:allowBackup="true"
android:icon="@drawable/ic_winboll"
android:label="@string/app_name"
android:theme="@style/WinBoll.SupportThemeNoActionBar"
android:supportsRtl="true">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleTask"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/studio_provider"/>
</provider>
</application>
</manifest>

View File

@@ -0,0 +1,24 @@
package cc.winboll.studio.app;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2024/12/08 15:10:51
* @Describe 全局应用类
*/
import cc.winboll.studio.shared.app.WinBollApplication;
import cc.winboll.studio.shared.log.LogUtils;
public class App extends WinBollApplication {
public static final String TAG = "App";
@Override
public void onCreate() {
// 必须在调用基类前设置应用调试标志,
// 这样可以预先设置日志与数据的存储根目录。
//setIsDebug(BuildConfig.DEBUG);
super.onCreate();
LogUtils.d(TAG, "onCreate");
}
}

View File

@@ -0,0 +1,168 @@
package cc.winboll.studio.app;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.shared.app.WinBollActivity;
import cc.winboll.studio.shared.app.WinBollActivityManager;
import cc.winboll.studio.shared.app.WinBollApplication;
import cc.winboll.studio.shared.log.LogUtils;
import cc.winboll.studio.shared.util.UriUtils;
import cc.winboll.studio.shared.view.StringToQrCodeView;
import cc.winboll.studio.shared.view.YesNoAlertDialog;
import cc.winboll.studio.unittest.UnitTestActivity;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.UUID;
final public class MainActivity extends WinBollActivity {
public static final String TAG = "MainActivity";
public static final int REQUEST_HOME_ACTIVITY = 0;
public static final int REQUEST_ABOUT_ACTIVITY = 1;
@Override
protected boolean isEnableDisplayHomeAsUp() {
return false;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// 接收并处理 Intent 数据,函数 Intent 处理接收就直接返回
if (prosessIntents(getIntent())) return;
// 以下正常创建主窗口
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 设置 WinBoll 应用 UI 类型
WinBollApplication.setWinBollUI_TYPE(WinBollApplication.WinBollUI_TYPE.Aplication);
//ToastUtils.show("WinBollUI_TYPE " + WinBollApplication.getWinBollUI_TYPE());
LogUtils.d(TAG, "BuildConfig.DEBUG : " + Boolean.toString(BuildConfig.DEBUG));
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
setSubTitle("");
}
//
// 处理传入的 Intent 数据
//
boolean prosessIntents(Intent intent) {
if (intent == null
|| intent.getAction() == null
|| intent.getAction().equals(""))
return false;
if (intent.getAction().equals(StringToQrCodeView.ACTION_UNITTEST_QRCODE)) {
try {
WinBollActivity clazzActivity = UnitTestActivity.class.newInstance();
String tag = clazzActivity.getTag();
LogUtils.d(TAG, "String tag = clazzActivity.getTag(); tag " + tag);
Intent subIntent = new Intent(this, UnitTestActivity.class);
subIntent.setAction(intent.getAction());
File file = new File(getCacheDir(), UUID.randomUUID().toString());
//取出文件uri
Uri uri = intent.getData();
if (uri == null) {
uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
}
//获取文件真实地址
String szSrcPath = UriUtils.getFileFromUri(getApplication(), uri);
if (TextUtils.isEmpty(szSrcPath)) {
return false;
}
Files.copy(Paths.get(szSrcPath), Paths.get(file.getPath()));
//startWinBollActivity(subIntent, tag);
WinBollActivityManager.getInstance(this).startWinBollActivity(this, subIntent, UnitTestActivity.class);
} catch (IllegalAccessException | InstantiationException | IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
// 函数处理异常返回失败
return false;
}
} else {
LogUtils.d(TAG, "prosessIntents|" + intent.getAction() + "|yet");
return false;
}
return true;
}
@Override
public String getTag() {
return TAG;
}
@Override
protected boolean isAddWinBollToolBar() {
return true;
}
@Override
public void onBackPressed() {
exit();
}
void exit() {
YesNoAlertDialog.OnDialogResultListener listener = new YesNoAlertDialog.OnDialogResultListener(){
@Override
public void onYes() {
WinBollActivityManager.getInstance(getApplicationContext()).finishAll();
}
@Override
public void onNo() {
}
};
YesNoAlertDialog.show(this, "[ " + getString(R.string.app_name) + " ]", "Exit(Yes/No).\nIs close all activity?", listener);
}
@Override
protected Toolbar initToolBar() {
return findViewById(R.id.activitymainToolbar1);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar_winboll_app_main, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.item_unittest) {
WinBollActivityManager.getInstance(this).startWinBollActivity(this, UnitTestActivity.class);
} else if (item.getItemId() == R.id.item_exit) {
exit();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (resultCode) {
case REQUEST_HOME_ACTIVITY : {
LogUtils.d(TAG, "REQUEST_HOME_ACTIVITY");
break;
}
case REQUEST_ABOUT_ACTIVITY : {
LogUtils.d(TAG, "REQUEST_ABOUT_ACTIVITY");
break;
}
default : {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
}

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:clickable="true">
<item android:drawable="@drawable/ic_launcher_background"/>
<item
android:left="15dp"
android:top="15dp"
android:right="15dp"
android:bottom="15dp"
android:drawable="@drawable/ic_launcher_foreground"/>
</layer-list>

View File

@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="@color/colorPrimary"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M16.61,15.15C16.15,15.15 15.77,14.78 15.77,14.32S16.15,13.5 16.61,13.5H16.61C17.07,13.5 17.45,13.86 17.45,14.32C17.45,14.78 17.07,15.15 16.61,15.15M7.41,15.15C6.95,15.15 6.57,14.78 6.57,14.32C6.57,13.86 6.95,13.5 7.41,13.5H7.41C7.87,13.5 8.24,13.86 8.24,14.32C8.24,14.78 7.87,15.15 7.41,15.15M16.91,10.14L18.58,7.26C18.67,7.09 18.61,6.88 18.45,6.79C18.28,6.69 18.07,6.75 18,6.92L16.29,9.83C14.95,9.22 13.5,8.9 12,8.91C10.47,8.91 9,9.24 7.73,9.82L6.04,6.91C5.95,6.74 5.74,6.68 5.57,6.78C5.4,6.87 5.35,7.08 5.44,7.25L7.1,10.13C4.25,11.69 2.29,14.58 2,18H22C21.72,14.59 19.77,11.7 16.91,10.14H16.91Z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="180"
android:endColor="#FFFFFFFF"
android:startColor="#FFFFFFFF"
android:type="linear" />
<corners android:radius="10dp" />
</shape>

View File

@@ -0,0 +1,29 @@
<?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="match_parent">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/activitymainToolbar1"/>
<LinearLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:gravity="center"
android:layout_weight="1.0">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, WinBoll!"/>
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,32 @@
<?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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_gradient"
android:gravity="center"
android:orientation="vertical"
android:padding="10dp">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_launcher"/>
<TextView
android:id="@android:id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:textColor="#FF000000"
android:textSize="16sp"/>
</LinearLayout>
</LinearLayout>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
</menu> </menu>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- WinBoll 默认方案 -->
<color name="colorPrimary">#FF196ABC</color>
<color name="colorPrimaryDark">#FF002B57</color>
<color name="colorAccent">#FF80BFFF</color>
<color name="colorToastFrame">#FFA9A9A9</color>
<color name="colorToastShadow">#FF000000</color>
<color name="colorToastBackgroung">#FFFFFFFF</color>
</resources>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">WinBoll-APP</string>
</resources>

View File

@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
</resources>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external_storage_root"
path="." />
<files-path
name="files_path"
path="." />
<cache-path
name="cache_path"
path="." />
<!--/storage/emulated/0/Android/data/...-->
<external-files-path
name="external_file_path"
path="." />
<!--代表app 外部存储区域根目录下的文件 Context.getExternalCacheDir目录下的目录-->
<external-cache-path
name="external_cache_path"
path="." />
<!--配置root-path。这样子可以读取到sd卡和一些应用分身的目录否则微信分身保存的图片就会导致 java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/999/tencent/MicroMsg/WeiXin/export1544062754693.jpg在小米6的手机上微信分身有这个crash华为没有
-->
<root-path
name="root_path"
path="" />
</paths>

View File

@@ -25,12 +25,12 @@ android {
defaultConfig { defaultConfig {
applicationId "cc.winboll.studio.appbase" applicationId "cc.winboll.studio.appbase"
minSdkVersion 24 minSdkVersion 24
targetSdkVersion 30 targetSdkVersion 29
versionCode 1 versionCode 1
// versionName 更新后需要手动设置 // versionName 更新后需要手动设置
// .winboll/winbollBuildProps.properties 文件的 stageCount=0 // .winboll/winbollBuildProps.properties 文件的 stageCount=0
// Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
versionName "15.7" versionName "15.2"
if(true) { if(true) {
versionName = genVersionName("${versionName}") versionName = genVersionName("${versionName}")
} }

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Tue Apr 29 13:40:21 HKT 2025 #Sat Mar 29 11:28:02 HKT 2025
stageCount=6 stageCount=3
libraryProject=libappbase libraryProject=libappbase
baseVersion=15.7 baseVersion=15.2
publishVersion=15.7.5 publishVersion=15.2.2
buildCount=0 buildCount=0
baseBetaVersion=15.7.6 baseBetaVersion=15.2.3

View File

@@ -5,7 +5,7 @@
<application <application
android:name=".App" android:name=".App"
android:icon="@drawable/ic_miapp" android:icon="@drawable/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/MyAPPBaseTheme" android:theme="@style/MyAPPBaseTheme"
android:resizeableActivity="true" android:resizeableActivity="true"

View File

@@ -4,11 +4,11 @@ import android.app.Activity;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.Toolbar;
import cc.winboll.studio.appbase.R; import cc.winboll.studio.appbase.R;
import cc.winboll.studio.appbase.activities.NewActivity; import cc.winboll.studio.appbase.activities.NewActivity;
import cc.winboll.studio.appbase.services.MainService; import cc.winboll.studio.appbase.services.MainService;
@@ -22,6 +22,7 @@ import cc.winboll.studio.libappbase.sos.SOS;
import cc.winboll.studio.libappbase.utils.ToastUtils; import cc.winboll.studio.libappbase.utils.ToastUtils;
import cc.winboll.studio.libappbase.widgets.StatusWidget; import cc.winboll.studio.libappbase.widgets.StatusWidget;
import cc.winboll.studio.libappbase.winboll.IWinBollActivity; import cc.winboll.studio.libappbase.winboll.IWinBollActivity;
import cc.winboll.studio.libappbase.dialogs.YesNoAlertDialog;
public class MainActivity extends WinBollActivityBase implements IWinBollActivity { public class MainActivity extends WinBollActivityBase implements IWinBollActivity {
@@ -47,7 +48,7 @@ public class MainActivity extends WinBollActivityBase implements IWinBollActivit
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
mToolbar = findViewById(R.id.toolbar); mToolbar = findViewById(R.id.toolbar);
setActionBar(mToolbar); setSupportActionBar(mToolbar);
CheckBox cbIsDebugMode = findViewById(R.id.activitymainCheckBox1); CheckBox cbIsDebugMode = findViewById(R.id.activitymainCheckBox1);
cbIsDebugMode.setChecked(GlobalApplication.isDebuging()); cbIsDebugMode.setChecked(GlobalApplication.isDebuging());

View File

@@ -8,6 +8,7 @@ package cc.winboll.studio.appbase;
import android.app.Activity; import android.app.Activity;
import android.os.Bundle; import android.os.Bundle;
import android.os.PersistableBundle; import android.os.PersistableBundle;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem; import android.view.MenuItem;
import cc.winboll.studio.appbase.App; import cc.winboll.studio.appbase.App;
import cc.winboll.studio.appbase.R; import cc.winboll.studio.appbase.R;
@@ -16,7 +17,7 @@ import cc.winboll.studio.libappbase.dialogs.YesNoAlertDialog;
import cc.winboll.studio.libappbase.winboll.IWinBollActivity; import cc.winboll.studio.libappbase.winboll.IWinBollActivity;
import cc.winboll.studio.libappbase.winboll.WinBollActivityManager; import cc.winboll.studio.libappbase.winboll.WinBollActivityManager;
public class WinBollActivityBase extends Activity implements IWinBollActivity { public class WinBollActivityBase extends AppCompatActivity implements IWinBollActivity {
public static final String TAG = "WinBollActivityBase"; public static final String TAG = "WinBollActivityBase";

View File

@@ -7,10 +7,10 @@ package cc.winboll.studio.appbase.activities;
*/ */
import android.app.Activity; import android.app.Activity;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.Toolbar;
import cc.winboll.studio.appbase.R; import cc.winboll.studio.appbase.R;
import cc.winboll.studio.appbase.WinBollActivityBase; import cc.winboll.studio.appbase.WinBollActivityBase;
import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libappbase.GlobalApplication;
@@ -41,7 +41,7 @@ public class New2Activity extends WinBollActivityBase implements IWinBollActivit
// mLogView = findViewById(R.id.logview); // mLogView = findViewById(R.id.logview);
// mLogView.start(); // mLogView.start();
mToolbar = findViewById(R.id.toolbar); mToolbar = findViewById(R.id.toolbar);
setActionBar(mToolbar); setSupportActionBar(mToolbar);
} }

View File

@@ -6,10 +6,10 @@ package cc.winboll.studio.appbase.activities;
*/ */
import android.app.Activity; import android.app.Activity;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.Toolbar;
import cc.winboll.studio.appbase.R; import cc.winboll.studio.appbase.R;
import cc.winboll.studio.appbase.WinBollActivityBase; import cc.winboll.studio.appbase.WinBollActivityBase;
import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libappbase.GlobalApplication;
@@ -39,7 +39,7 @@ public class NewActivity extends WinBollActivityBase implements IWinBollActivity
// mLogView = findViewById(R.id.logview); // mLogView = findViewById(R.id.logview);
// mLogView.start(); // mLogView.start();
mToolbar = findViewById(R.id.toolbar); mToolbar = findViewById(R.id.toolbar);
setActionBar(mToolbar); setSupportActionBar(mToolbar);
} }

View File

@@ -5,7 +5,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<android.widget.Toolbar <android.support.v7.widget.Toolbar
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/toolbar"/> android:id="@+id/toolbar"/>

View File

@@ -6,7 +6,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<android.widget.Toolbar <android.support.v7.widget.Toolbar
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/toolbar"/> android:id="@+id/toolbar"/>

View File

@@ -6,7 +6,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<android.widget.Toolbar <android.support.v7.widget.Toolbar
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/toolbar"/> android:id="@+id/toolbar"/>

View File

@@ -19,17 +19,17 @@ def genVersionName(def versionName){
android { android {
compileSdkVersion 32 compileSdkVersion 32
buildToolsVersion "32.0.0" buildToolsVersion "33.0.3"
defaultConfig { defaultConfig {
applicationId "cc.winboll.studio.apputils" applicationId "cc.winboll.studio.apputils"
minSdkVersion 26 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 30
versionCode 1 versionCode 1
// versionName 更新后需要手动设置 // versionName 更新后需要手动设置
// 项目模块目录的 build.gradle 文件的 stageCount=0 // 项目模块目录的 build.gradle 文件的 stageCount=0
// Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
versionName "15.2" versionName "9.2"
if(true) { if(true) {
versionName = genVersionName("${versionName}") versionName = genVersionName("${versionName}")
} }
@@ -41,9 +41,15 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
} }
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
} }
dependencies { dependencies {
api project(':libapputils') api project(':libapputils')
api 'cc.winboll.studio:libappbase:1.0.3'
api fileTree(dir: 'libs', include: ['*.jar']) api fileTree(dir: 'libs', include: ['*.jar'])
} }

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Sat Mar 29 12:14:55 HKT 2025 #Sat Jan 18 13:03:10 HKT 2025
stageCount=2 stageCount=2
libraryProject=libapputils libraryProject=libapputils
baseVersion=15.2 baseVersion=9.2
publishVersion=15.2.1 publishVersion=9.2.1
buildCount=0 buildCount=0
baseBetaVersion=15.2.2 baseBetaVersion=9.2.2

View File

@@ -8,7 +8,7 @@
android:allowBackup="true" android:allowBackup="true"
android:icon="@drawable/ic_winboll" android:icon="@drawable/ic_winboll"
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/MyUtilsTheme" android:theme="@style/WinBoll.SupportThemeNoActionBar"
android:supportsRtl="true"> android:supportsRtl="true">
<activity <activity
@@ -27,13 +27,9 @@
</activity> </activity>
<activity android:name=".TestStringToQRCodeViewActivity"/> <activity android:name=".TestWinBollActivity"/>
<activity android:name=".TestBBMorseCodeActivity"/> <activity android:name=".TestStringToQrCodeViewActivity"/>
<activity android:name=".AssetsHtmlActivity"/>
<activity android:name=".QRCodeDecodeActivity"/>
</application> </application>

View File

@@ -5,16 +5,27 @@ package cc.winboll.studio.apputils;
* @Date 2024/12/08 15:10:51 * @Date 2024/12/08 15:10:51
* @Describe 全局应用类 * @Describe 全局应用类
*/ */
import android.app.Application; import android.view.Gravity;
import android.content.Context; import cc.winboll.studio.libapputils.app.WinBollApplication;
import cc.winboll.studio.libappbase.GlobalApplication; import com.hjq.toast.ToastUtils;
import com.hjq.toast.style.WhiteToastStyle;
public class App extends GlobalApplication { public class App extends WinBollApplication {
public static final String TAG = "App"; public static final String TAG = "App";
public static final String _ACTION_DEBUGVIEW = WinBollApplication.class.getName() + "_ACTION_DEBUGVIEW";
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
// 初始化 Toast 框架
//
ToastUtils.init(this);
// 设置 Toast 布局样式
//ToastUtils.setView(R.layout.view_toast);
ToastUtils.setStyle(new WhiteToastStyle());
ToastUtils.setGravity(Gravity.BOTTOM, 0, 200);
} }
} }

View File

@@ -1,60 +1,38 @@
package cc.winboll.studio.apputils; package cc.winboll.studio.apputils;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.Toast; import android.widget.Toast;
import android.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.apputils.R; import cc.winboll.studio.libapputils.activities.AssetsHtmlActivity;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libapputils.activities.QRCodeDecodeActivity;
import cc.winboll.studio.libappbase.LogView; import cc.winboll.studio.libapputils.app.WinBollActivity;
import cc.winboll.studio.libappbase.utils.ToastUtils; import cc.winboll.studio.libapputils.app.WinBollActivityManager;
import java.util.List; import cc.winboll.studio.libapputils.log.LogActivity;
import java.util.Set; import cc.winboll.studio.libapputils.log.LogUtils;
import com.hjq.toast.ToastUtils;
final public class MainActivity extends Activity { final public class MainActivity extends WinBollActivity {
public static final String TAG = "MainActivity"; public static final String TAG = "MainActivity";
public static final int REQUEST_QRCODEDECODE_ACTIVITY = 0; public static final int REQUEST_QRCODEDECODE_ACTIVITY = 0;
Toolbar mToolbar; @Override
LogView mLogView; protected boolean isEnableDisplayHomeAsUp() {
// return false;
// @Override }
// public Activity getActivity() {
// return this;
// }
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
mLogView = findViewById(R.id.logview); //Toolbar toolbar = findViewById(R.id.activitymainToolbar1);
mLogView.start(); //setActionBar(toolbar);
// 初始化工具栏
mToolbar = findViewById(R.id.toolbar);
setActionBar(mToolbar);
// if (isEnableDisplayHomeAsUp()) {
// // 显示后退按钮
// getActionBar().setDisplayHomeAsUpEnabled(true);
// }
// getActionBar().setSubtitle(getTag());
checkResolveActivity();
archiveInstance();
// 接收并处理 Intent 数据,函数 Intent 处理接收就直接返回 // 接收并处理 Intent 数据,函数 Intent 处理接收就直接返回
//if (prosessIntents(getIntent())) return; //if (prosessIntents(getIntent())) return;
@@ -66,94 +44,44 @@ final public class MainActivity extends Activity {
// LogUtils.d(TAG, "BuildConfig.DEBUG : " + Boolean.toString(BuildConfig.DEBUG)); // LogUtils.d(TAG, "BuildConfig.DEBUG : " + Boolean.toString(BuildConfig.DEBUG));
} }
boolean checkResolveActivity() {
PackageManager packageManager = getPackageManager();
//Intent intent = new Intent("your_action_here");
Intent intent = getIntent();
if (intent != null) {
List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (resolveInfoList.size() > 0) {
// 传入的Intent action在Activity清单的intent-filter的action节点里有定义
if (intent.getAction() != null) {
// if (intent.getAction().equals(cc.winboll.studio.libapputils.intent.action.DEBUGVIEW)) {
// App.setIsDebug(true);
// //ToastUtils.show!("WinBollApplication.setIsDebug(true) by action : " + intent.getAction());
//
// }
}
return true;
} else {
// 传入的Intent action在Activity清单的intent-filter的action节点里没有定义
//ToastUtils.show("false : " + intent.getAction());
return false;
}
}
// action在清单文件中没有声明
ToastUtils.show("false");
return false;
}
void archiveInstance() {
Intent intent = getIntent();
StringBuilder sb = new StringBuilder("\n### Archive Instance ###\n");
if (intent != null) {
ComponentName componentName = intent.getComponent();
if (componentName != null) {
String packageName = componentName.getPackageName();
//Log.d("AppStarter", "启动本应用的应用包名: " + packageName);
sb.append("启动本应用的应用包名: \n" + packageName);
}
sb.append("\nImplicit Intent Tracker \n接收到的 Intent 动作: \n" + intent.getAction());
Set<String> categories = intent.getCategories();
if (categories != null) {
for (String category : categories) {
sb.append("\n接收到的 Intent 类别 :\n" + category);
}
}
Uri data = intent.getData();
if (data != null) {
sb.append("\n接收到的 Intent 数据 :\n" + data.toString());
}
} else {
sb.append("Intent is null.");
}
sb.append("\n\n");
LogUtils.d(TAG, sb.toString());
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// 缓存当前 activity
//WinBollActivityManager.getInstance(this).add(this);
}
@Override
public void onDestroy() {
//WinBollActivityManager.getInstance(this).registeRemove(this);
super.onDestroy();
}
public void onTestLogClick(View view) { public void onTestLogClick(View view) {
LogUtils.d(TAG, "onTestLogClick"); LogUtils.d(TAG, "onTestLogClick");
Toast.makeText(getApplication(), "onTestLogClick", Toast.LENGTH_SHORT).show(); Toast.makeText(getApplication(), "onTestLogClick", Toast.LENGTH_SHORT).show();
} }
public void onTestLogActivity(View view) { public void onLogUtilsClick(View view) {
// Intent intent = new Intent(this, LogActivity.class); Intent intent = new Intent(this, LogActivity.class);
// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
// intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
// startActivity(intent); startActivity(intent);
//WinBollActivityManager.getInstance().printAvtivityListInfo();
//WinBollActivityManager.getInstance(this).startWinBollActivity(this, LogActivity.class);
} }
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// setSubTitle("");
}
@Override
public void onBackPressed() {
// exit();
}
// void exit() {
// YesNoAlertDialog.OnDialogResultListener listener = new YesNoAlertDialog.OnDialogResultListener(){
//
// @Override
// public void onYes() {
// WinBollActivityManager.getInstance(getApplicationContext()).finishAll();
// }
//
// @Override
// public void onNo() {
// }
// };
// YesNoAlertDialog.show(this, "[ " + getString(R.string.app_name) + " ]", "Exit(Yes/No).\nIs close all activity?", listener);
// }
// //
// 处理传入的 Intent 数据 // 处理传入的 Intent 数据
// //
@@ -198,106 +126,57 @@ final public class MainActivity extends Activity {
} }
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public String getTag() {
//ToastUtils.show("onCreateOptionsMenu"); return TAG;
getMenuInflater().inflate(R.menu.toolbar_main, menu); }
// if (isAddWinBollToolBar()) {
// //ToastUtils.show("mIWinBoll.isAddWinBollToolBar()");
// getMenuInflater().inflate(R.menu.toolbar_winboll_shared_main, menu);
// }
if (App.isDebuging()) {
getMenuInflater().inflate(R.menu.toolbar_studio_debug, menu);
}
@Override
protected boolean isAddWinBollToolBar() {
return true;
}
@Override
protected Toolbar initToolBar() {
return findViewById(R.id.activitymainToolbar1);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar_main, menu);
return super.onCreateOptionsMenu(menu); return super.onCreateOptionsMenu(menu);
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.item_exit) { if (item.getItemId() == R.id.item_testwinboll) {
//exit(); WinBollActivityManager.getInstance(this).startWinBollActivity(this, TestWinBollActivity.class);
return true;
} else if (item.getItemId() == R.id.item_teststringtoqrcodeview) { } else if (item.getItemId() == R.id.item_teststringtoqrcodeview) {
Intent intent = new Intent(this, TestStringToQRCodeViewActivity.class); WinBollActivityManager.getInstance(this).startWinBollActivity(this, TestStringToQrCodeViewActivity.class);
startActivityForResult(intent, REQUEST_QRCODEDECODE_ACTIVITY);
//WinBollActivityManager.getInstance(this).startWinBollActivity(this, TestStringToQrCodeViewActivity.class);
} else if (item.getItemId() == R.id.item_testqrcodedecodeactivity) { } else if (item.getItemId() == R.id.item_testqrcodedecodeactivity) {
Intent intent = new Intent(this, QRCodeDecodeActivity.class); Intent intent = new Intent(this, QRCodeDecodeActivity.class);
startActivityForResult(intent, REQUEST_QRCODEDECODE_ACTIVITY); startActivityForResult(intent, REQUEST_QRCODEDECODE_ACTIVITY);
} else if (item.getItemId() == R.id.item_testcrashreport) {
for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
getString(i);
}
return true;
} else if (item.getItemId() == R.id.item_log) {
//WinBollActivityManager.getInstance(this).startWinBollActivity(this, LogActivity.class);
return true;
} else if (item.getItemId() == R.id.item_exitdebug) {
//AboutView.setApp2NormalMode(this);
return true;
} else if (item.getItemId() == android.R.id.home) {
//WinBollActivityManager.getInstance(this).finish(this);
return true;
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
// void exit() { public void onTestJavascriptHtmlActivity(View view) {
// YesNoAlertDialog.OnDialogResultListener listener = new YesNoAlertDialog.OnDialogResultListener(){
//
// @Override
// public void onYes() {
// //WinBollActivityManager.getInstance(getApplicationContext()).finishAll();
// }
//
// @Override
// public void onNo() {
// }
// };
// YesNoAlertDialog.show(this, "[ " + getString(R.string.app_name) + " ]", "Exit(Yes/No).\nIs close all activity?", listener);
//
// }
@Override
public void onBackPressed() {
// if (WinBollActivityManager.getInstance(getApplicationContext()).isFirstIWinBollActivity(this)) {
// exit();
// } else {
// WinBollActivityManager.getInstance(this).finish(this);
// super.onBackPressed();
// }
}
public void onTestAssetsHtmlActivity(View view) {
Intent intent = new Intent(this, AssetsHtmlActivity.class); Intent intent = new Intent(this, AssetsHtmlActivity.class);
intent.putExtra(AssetsHtmlActivity.EXTRA_HTMLFILENAME, "javascript_test.html"); intent.putExtra(AssetsHtmlActivity.EXTRA_HTMLFILENAME, "javascript_test.html");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); WinBollActivityManager.getInstance(this).startWinBollActivity(this, intent, AssetsHtmlActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
startActivity(intent);
//WinBollActivityManager.getInstance(this).startWinBollActivity(this, intent, AssetsHtmlActivity.class);
} }
@Override @Override
protected void onResume() { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onResume(); switch (requestCode) {
mLogView.start(); case REQUEST_QRCODEDECODE_ACTIVITY : {
String text = data.getStringExtra(QRCodeDecodeActivity.EXTRA_RESULT);
ToastUtils.show(text);
break;
}
default : {
ToastUtils.show(String.format("%d, %d", requestCode, resultCode));
super.onActivityResult(requestCode, resultCode, data);
}
}
} }
/*@Override
protected void onActivithyResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_QRCODEDECODE_ACTIVITY : {
if (data != null) {
String text = data.getStringExtra(QRCodeDecodeActivity.EXTRA_RESULT);
ToastUtils.show(text);
}
break;
}
default : {
//ToastUtils.show(String.format("%d, %d", requestCode, resultCode));
super.prosessActivityResult(requestCode, resultCode, data);
}
}
}*/
} }

View File

@@ -1,20 +0,0 @@
package cc.winboll.studio.apputils;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/03/23 16:14:45
*/
import android.app.Activity;
import android.os.Bundle;
public class TestBBMorseCodeActivity extends Activity {
public static final String TAG = "TestBBMorseCodeActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_testbbmorsecode);
}
}

View File

@@ -1,36 +0,0 @@
package cc.winboll.studio.apputils;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2025/01/17 19:50:46
*/
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toolbar;
import cc.winboll.studio.apputils.R;
import cc.winboll.studio.libapputils.views.StringToQrCodeView;
public class TestStringToQRCodeViewActivity extends Activity {
public static final String TAG = "TestStringToQrCodeViewActivity";
StringToQrCodeView mStringToQrCodeView;
//
// @Override
// public Activity getActivity() {
// return this;
// }
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_teststringtoqrcodeview);
// 初始化工具栏
Toolbar mToolbar = findViewById(R.id.toolbar);
mToolbar.setSubtitle(TAG);
setActionBar(mToolbar);
mStringToQrCodeView = findViewById(R.id.activityteststringtoqrcodeviewStringToQrCodeView1);
}
}

View File

@@ -0,0 +1,50 @@
package cc.winboll.studio.apputils;
import android.os.Bundle;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libapputils.app.WinBollActivity;
import cc.winboll.studio.libapputils.view.StringToQrCodeView;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2025/01/17 19:50:46
*/
public class TestStringToQrCodeViewActivity extends WinBollActivity {
public static final String TAG = "TestStringToQrCodeViewActivity";
StringToQrCodeView mStringToQrCodeView;
@Override
public String getTag() {
return TAG;
}
@Override
protected Toolbar initToolBar() {
return findViewById(R.id.activityteststringtoqrcodeviewToolbar1);
}
@Override
protected boolean isEnableDisplayHomeAsUp() {
return true;
}
@Override
protected boolean isAddWinBollToolBar() {
return true;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_teststringtoqrcodeview);
mStringToQrCodeView = findViewById(R.id.activityteststringtoqrcodeviewStringToQrCodeView1);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
setSubTitle(TAG);
}
}

View File

@@ -0,0 +1,52 @@
package cc.winboll.studio.apputils;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libapputils.activities.AssetsHtmlActivity;
import cc.winboll.studio.libapputils.app.WinBollActivity;
import cc.winboll.studio.libapputils.app.WinBollActivityManager;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2025/01/13 15:09:46
*/
public class TestWinBollActivity extends WinBollActivity {
public static final String TAG = "TestWinBollActivity";
@Override
public String getTag() {
return TAG;
}
@Override
protected Toolbar initToolBar() {
return findViewById(R.id.activitytestwinbollToolbar1);
}
@Override
protected boolean isEnableDisplayHomeAsUp() {
return true;
}
@Override
protected boolean isAddWinBollToolBar() {
return true;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_testwinboll);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
setSubTitle(TAG);
}
}

View File

@@ -1,52 +0,0 @@
package cc.winboll.studio.apputils;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/03/28 17:11:37
* @Describe 应用活动窗口基类
*/
import android.app.Activity;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.support.v7.app.AppCompatActivity;
import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.winboll.IWinBollActivity;
import cc.winboll.studio.libappbase.winboll.WinBollActivityManager;
public class WinBollActivityBase extends AppCompatActivity implements IWinBollActivity {
public static final String TAG = "WinBollActivityBase";
@Override
public Activity getActivity() {
return this;
}
@Override
public String getTag() {
return TAG;
}
WinBollActivityManager getWinBollActivityManager() {
return WinBollActivityManager.getInstance(GlobalApplication.getInstance());
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWinBollActivityManager().add(this);
}
@Override
public void onPostCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
super.onPostCreate(savedInstanceState, persistentState);
}
@Override
protected void onDestroy() {
super.onDestroy();
getWinBollActivityManager().registeRemove(this);
}
}

View File

@@ -1,21 +0,0 @@
<?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">
<android.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/toolbar"/>
<cc.winboll.studio.libapputils.views.SimpleWebView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0"
android:id="@+id/activityassetshtmlSimpleWebView1"/>
</LinearLayout>

View File

@@ -5,10 +5,10 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<android.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/toolbar"/> android:id="@+id/activitymainToolbar1"/>
<LinearLayout <LinearLayout
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
@@ -27,39 +27,32 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="TestLog" android:text="TestLog"
android:textAllCaps="false" android:textAllCaps="false"
android:onClick="onTestLogClick"/> android:onClick="onTestLogClick"/>
<Button <Button
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="TestLogActivity" android:text="LogUtils"
android:textAllCaps="false" android:textAllCaps="false"
android:onClick="onTestLogActivity"/> android:onClick="onLogUtilsClick"/>
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:orientation="horizontal" android:orientation="horizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="right"> android:gravity="right">
<Button <Button
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textAllCaps="false" android:textAllCaps="false"
android:text="TestAssetsHtmlActivity" android:text="Test Javascript Html Activity"
android:onClick="onTestAssetsHtmlActivity"/> android:onClick="onTestJavascriptHtmlActivity"/>
</LinearLayout> </LinearLayout>
<cc.winboll.studio.libappbase.LogView
android:layout_width="match_parent"
android:layout_height="0dp"
android:text="Button"
android:id="@+id/logview"
android:layout_weight="1.0"/>
</LinearLayout> </LinearLayout>

View File

@@ -1,20 +0,0 @@
<?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">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="QRCodeDecodeActivity"/>
<com.journeyapps.barcodescanner.DecoratedBarcodeView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/activityqrcodedecodeDecoratedBarcodeView1"/>
</LinearLayout>

View File

@@ -6,10 +6,10 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<android.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/toolbar"/> android:id="@+id/activityteststringtoqrcodeviewToolbar1"/>
<LinearLayout <LinearLayout
android:orientation="vertical" android:orientation="vertical"
@@ -17,7 +17,7 @@
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1.0"> android:layout_weight="1.0">
<cc.winboll.studio.libapputils.views.StringToQrCodeView <cc.winboll.studio.libapputils.view.StringToQrCodeView
android:layout_width="300dp" android:layout_width="300dp"
android:layout_height="300dp" android:layout_height="300dp"
android:id="@+id/activityteststringtoqrcodeviewStringToQrCodeView1"/> android:id="@+id/activityteststringtoqrcodeviewStringToQrCodeView1"/>

View File

@@ -7,7 +7,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="#FF36B5B3"> android:background="#FF36B5B3">
<android.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/activitytestwinbollToolbar1"/> android:id="@+id/activitytestwinbollToolbar1"/>

View File

@@ -0,0 +1,32 @@
<?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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_gradient"
android:gravity="center"
android:orientation="vertical"
android:padding="10dp">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_launcher"/>
<TextView
android:id="@android:id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:textColor="#FF000000"
android:textSize="16sp"/>
</LinearLayout>
</LinearLayout>

View File

@@ -1,13 +1,16 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/item_testwinboll"
android:title="TestWinBollActivity"
app:showAsAction="ifRoom"/>
<item <item
android:id="@+id/item_teststringtoqrcodeview" android:id="@+id/item_teststringtoqrcodeview"
android:title="TestStringToQRCodeViewActivity"/> android:title="TestStringToQrCodeViewActivity"
app:showAsAction="ifRoom"/>
<item <item
android:id="@+id/item_testqrcodedecodeactivity" android:id="@+id/item_testqrcodedecodeactivity"
android:title="TestQRCodeDecodeActivity"/> android:title="TestQRCodeDecodeActivity"
<item app:showAsAction="ifRoom"/>
android:id="@+id/item_testcrashreport"
android:title="TestCrashReportActivity"/>
</menu> </menu>

View File

@@ -4,4 +4,7 @@
<color name="colorPrimary">#FF196ABC</color> <color name="colorPrimary">#FF196ABC</color>
<color name="colorPrimaryDark">#FF002B57</color> <color name="colorPrimaryDark">#FF002B57</color>
<color name="colorAccent">#FF80BFFF</color> <color name="colorAccent">#FF80BFFF</color>
<color name="colorToastFrame">#FFA9A9A9</color>
<color name="colorToastShadow">#FF000000</color>
<color name="colorToastBackgroung">#FFFFFFFF</color>
</resources> </resources>

View File

@@ -1,14 +1,3 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="MyUtilsTheme" parent="UtilsTheme">
<item name="attrColorPrimary">@color/colorPrimary</item>
<item name="themeGlobalCrashActivity">@style/MyUtilsGlobalCrashActivityTheme</item>
</style>
<style name="MyUtilsGlobalCrashActivityTheme" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar">
<item name="colorTittle">#FFF2F2F2</item>
<item name="colorTittleBackgound">#FF55ABF8</item>
<item name="colorText">#FF55ABF8</item>
<item name="colorTextBackgound">#FFF2F2F2</item>
</style>
</resources> </resources>

View File

@@ -1,15 +1,10 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
repositories { repositories {
// 本地 Maven 仓库(默认路径为 ~/.m2/repository
mavenLocal()
// 或自定义本地仓库路径
maven { url "file:///sdcard/.m2/repository" }
// Nexus Maven 库地址 // Nexus Maven 库地址
// "WinBoLL Release" // "WinBoll Release"
maven { url "https://nexus.winboll.cc/repository/maven-public/" } maven { url "https://nexus.winboll.cc/repository/maven-public/" }
// "WinBoLL Snapshot" // "WinBoll Snapshot"
maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" } maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" }
maven { url 'https://maven.aliyun.com/repository/public/' } maven { url 'https://maven.aliyun.com/repository/public/' }
@@ -20,7 +15,7 @@ buildscript {
maven { url "https://jitpack.io" } maven { url "https://jitpack.io" }
mavenCentral() mavenCentral()
google() google()
//mavenLocal() mavenLocal()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.2.1' // 对应 compileSdkVersion 32 classpath 'com.android.tools.build:gradle:7.2.1' // 对应 compileSdkVersion 32
@@ -32,9 +27,9 @@ buildscript {
allprojects { allprojects {
repositories { repositories {
// Nexus Maven 库地址 // Nexus Maven 库地址
// "WinBoLL Release" // "WinBoll Release"
maven { url "https://nexus.winboll.cc/repository/maven-public/" } maven { url "https://nexus.winboll.cc/repository/maven-public/" }
// "WinBoLL Snapshot" // "WinBoll Snapshot"
maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" } maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" }
maven { url 'https://maven.aliyun.com/repository/public/' } maven { url 'https://maven.aliyun.com/repository/public/' }
@@ -56,7 +51,7 @@ allprojects {
bashCommitAppPublishBuildFlagInfoFilePath = ".winboll/bashCommitAppPublishBuildFlagInfo.sh" bashCommitAppPublishBuildFlagInfoFilePath = ".winboll/bashCommitAppPublishBuildFlagInfo.sh"
winbollFilePath = "winboll.properties" winbollFilePath = "winboll.properties"
keyPropsFilePath = "current.keystore" keyPropsFilePath = "winboll-x/current.keystore"
// 定义 lint 输出文件 // 定义 lint 输出文件
lintXmlReportFilePath = "build/reports/lint-results.xml" lintXmlReportFilePath = "build/reports/lint-results.xml"
lintHTMLReportFilePath = "build/reports/lint-results.html" lintHTMLReportFilePath = "build/reports/lint-results.html"

View File

@@ -19,17 +19,17 @@ def genVersionName(def versionName){
android { android {
compileSdkVersion 32 compileSdkVersion 32
buildToolsVersion "32.0.0" buildToolsVersion "33.0.3"
defaultConfig { defaultConfig {
applicationId "cc.winboll.studio.contacts" applicationId "cc.winboll.studio.contacts"
minSdkVersion 24 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 30
versionCode 1 versionCode 1
// versionName 更新后需要手动设置 // versionName 更新后需要手动设置
// 项目模块目录的 build.gradle 文件的 stageCount=0 // 项目模块目录的 build.gradle 文件的 stageCount=0
// Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
versionName "15.2" versionName "1.0"
if(true) { if(true) {
versionName = genVersionName("${versionName}") versionName = genVersionName("${versionName}")
} }
@@ -41,48 +41,31 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
} }
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
} }
dependencies { dependencies {
api fileTree(dir: 'libs', include: ['*.jar']) // 二维码使用的类库
// 权限请求框架https://github.com/getActivity/XXPermissions
api 'com.github.getActivity:XXPermissions:18.63'
// 下拉控件
api 'com.baoyz.pullrefreshlayout:library:1.2.0'
// 拼音搜索
// https://mvnrepository.com/artifact/com.github.open-android/pinyin4j
api 'com.github.open-android:pinyin4j:2.5.0'
// SSH
api 'com.jcraft:jsch:0.1.55'
// Html 解析
api 'org.jsoup:jsoup:1.13.1'
// 二维码类库
api 'com.google.zxing:core:3.4.1' api 'com.google.zxing:core:3.4.1'
api 'com.journeyapps:zxing-android-embedded:3.6.0' api 'com.journeyapps:zxing-android-embedded:3.6.0'
// 应用介绍页类库
api 'io.github.medyo:android-about-page:2.0.0' api 'io.github.medyo:android-about-page:2.0.0'
// 吐司类库
api 'com.github.getActivity:ToastUtils:10.5' api 'com.github.getActivity:ToastUtils:10.5'
// 网络连接类库 api 'com.jcraft:jsch:0.1.55'
api 'org.jsoup:jsoup:1.13.1'
api 'com.squareup.okhttp3:okhttp:4.4.1' api 'com.squareup.okhttp3:okhttp:4.4.1'
// AndroidX 类库
/*implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.viewpager:viewpager:1.0.0'
implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
implementation 'androidx.vectordrawable:vectordrawable-animated:1.1.0'
implementation 'androidx.fragment:fragment:1.1.0'
implementation 'com.google.android.material:material:1.4.0'
*/
api 'androidx.appcompat:appcompat:1.1.0' api 'androidx.appcompat:appcompat:1.1.0'
api 'androidx.viewpager:viewpager:1.0.0'
api 'androidx.fragment:fragment:1.1.0'
api 'com.google.android.material:material:1.4.0' api 'com.google.android.material:material:1.4.0'
//api 'androidx.viewpager:viewpager:1.0.0'
//api 'androidx.vectordrawable:vectordrawable:1.1.0'
//api 'androidx.vectordrawable:vectordrawable-animated:1.1.0'
//api 'androidx.fragment:fragment:1.1.0'
api 'cc.winboll.studio:libaes:15.2.4' api 'cc.winboll.studio:libapputils:9.3.2'
api 'cc.winboll.studio:libapputils:15.2.1' api 'cc.winboll.studio:libappbase:1.5.6'
api 'cc.winboll.studio:libappbase:15.2.2'
api fileTree(dir: 'libs', include: ['*.jar'])
} }

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Sun Apr 13 02:46:09 HKT 2025 #Tue Feb 25 00:17:29 HKT 2025
stageCount=8 stageCount=2
libraryProject= libraryProject=
baseVersion=15.2 baseVersion=1.0
publishVersion=15.2.7 publishVersion=1.0.1
buildCount=0 buildCount=0
baseBetaVersion=15.2.8 baseBetaVersion=1.0.2

View File

@@ -29,13 +29,9 @@
<!-- 更改您的音频设置 --> <!-- 更改您的音频设置 -->
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<!-- 读取通话记录 --> <uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<!-- 录音 -->
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<application <application
android:name=".App" android:name=".App"
android:allowBackup="true" android:allowBackup="true"
@@ -69,7 +65,7 @@
<activity <activity
android:name=".phonecallui.PhoneCallActivity" android:name=".phonecallui.PhoneCallActivity"
android:launchMode="singleTask" android:launchMode="singleInstance"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
@@ -186,10 +182,6 @@
</provider> </provider>
<activity android:name="cc.winboll.studio.contacts.activities.UnitTestActivity"/>
<activity android:name="cc.winboll.studio.contacts.activities.AboutActivity"/>
</application> </application>
</manifest> </manifest>

View File

@@ -5,10 +5,9 @@ package cc.winboll.studio.contacts;
* @Date 2024/12/08 15:10:51 * @Date 2024/12/08 15:10:51
* @Describe 全局应用类 * @Describe 全局应用类
*/ */
import android.view.Gravity;
import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.winboll.WinBollActivityManager; import cc.winboll.studio.libappbase.LogUtils;
import com.hjq.toast.ToastUtils; import cc.winboll.studio.libapputils.app.WinBollActivityManager;
public class App extends GlobalApplication { public class App extends GlobalApplication {
@@ -18,20 +17,12 @@ public class App extends GlobalApplication {
public void onCreate() { public void onCreate() {
// 必须在调用基类前设置应用调试标志, // 必须在调用基类前设置应用调试标志,
// 这样可以预先设置日志与数据的存储根目录。 // 这样可以预先设置日志与数据的存储根目录。
//setIsDebuging(BuildConfig.DEBUG); setIsDebuging(this, BuildConfig.DEBUG);
super.onCreate(); super.onCreate();
// 设置 WinBoll 应用 UI 类型 // 设置 WinBoll 应用 UI 类型
WinBollActivityManager.getInstance(this).setWinBollUI_TYPE(WinBollActivityManager.WinBollUI_TYPE.Aplication); WinBollActivityManager.getInstance(this).setWinBollUI_TYPE(WinBollActivityManager.WinBollUI_TYPE.Aplication);
//LogUtils.d(TAG, "onCreate"); LogUtils.d(TAG, "onCreate");
// 初始化 Toast 框架
ToastUtils.init(this);
// 设置 Toast 布局样式
//ToastUtils.setView(R.layout.toast_custom_view);
//ToastUtils.setStyle(new WhiteToastStyle());
ToastUtils.setGravity(Gravity.BOTTOM, 0, 200);
} }
} }

View File

@@ -1,44 +1,52 @@
package cc.winboll.studio.contacts; package cc.winboll.studio.contacts;
import android.Manifest; import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.role.RoleManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.provider.Settings;
import android.telecom.TelecomManager; import android.telecom.TelecomManager;
import android.telephony.PhoneStateListener; import android.view.LayoutInflater;
import android.telephony.TelephonyManager;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.WindowManager;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.Switch;
import android.widget.Toast; import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager; import androidx.viewpager.widget.ViewPager;
import cc.winboll.studio.contacts.R; import cc.winboll.studio.contacts.R;
import cc.winboll.studio.contacts.activities.SettingsActivity; import cc.winboll.studio.contacts.activities.CallActivity;
import cc.winboll.studio.contacts.adapters.MyPagerAdapter;
import cc.winboll.studio.contacts.beans.MainServiceBean; import cc.winboll.studio.contacts.beans.MainServiceBean;
import cc.winboll.studio.contacts.fragments.CallLogFragment;
import cc.winboll.studio.contacts.fragments.ContactsFragment;
import cc.winboll.studio.contacts.fragments.LogFragment;
import cc.winboll.studio.contacts.services.MainService; import cc.winboll.studio.contacts.services.MainService;
import cc.winboll.studio.libaes.winboll.APPInfo;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.LogView; import cc.winboll.studio.libappbase.LogView;
import cc.winboll.studio.libappbase.winboll.IWinBollActivity; import cc.winboll.studio.libapputils.app.IWinBollActivity;
import cc.winboll.studio.libapputils.app.WinBollActivityManager;
import cc.winboll.studio.libapputils.bean.APPInfo;
import cc.winboll.studio.libapputils.view.YesNoAlertDialog;
import cc.winboll.studio.contacts.listenphonecall.CallListenerService;
import com.google.android.material.tabs.TabLayout; import com.google.android.material.tabs.TabLayout;
import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import android.content.DialogInterface;
import cc.winboll.studio.contacts.activities.SettingsActivity;
final public class MainActivity extends AppCompatActivity implements IWinBollActivity, ViewPager.OnPageChangeListener, View.OnClickListener { final public class MainActivity extends AppCompatActivity implements IWinBollActivity, ViewPager.OnPageChangeListener, View.OnClickListener {
@@ -49,13 +57,11 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct
public static final String ACTION_SOS = "cc.winboll.studio.libappbase.WinBoll.ACTION_SOS"; public static final String ACTION_SOS = "cc.winboll.studio.libappbase.WinBoll.ACTION_SOS";
static MainActivity _MainActivity;
LogView mLogView; LogView mLogView;
Toolbar mToolbar; Toolbar mToolbar;
CheckBox cbMainService; CheckBox cbMainService;
MainServiceBean mMainServiceBean; MainServiceBean mMainServiceBean;
private TabLayout tabLayout; ViewPager viewPager;
private ViewPager viewPager;
private List<View> views; //用来存放放进ViewPager里面的布局 private List<View> views; //用来存放放进ViewPager里面的布局
//实例化存储imageView导航原点的集合 //实例化存储imageView导航原点的集合
ImageView[] imageViews; ImageView[] imageViews;
@@ -64,20 +70,15 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct
LinearLayout linearLayout;//下标所在在LinearLayout布局里 LinearLayout linearLayout;//下标所在在LinearLayout布局里
int currentPoint = 0;//当前被选中中页面的下标 int currentPoint = 0;//当前被选中中页面的下标
private TelephonyManager telephonyManager;
private MyPhoneStateListener phoneStateListener;
List<Fragment> fragmentList;
List<String> tabTitleList;
private static final int DIALER_REQUEST_CODE = 1; private static final int DIALER_REQUEST_CODE = 1;
@Override @Override
public Activity getActivity() { public AppCompatActivity getActivity() {
return this; return this;
} }
// @Override @Override
// public APPInfo getAppInfo() { public APPInfo getAppInfo() {
// String szBranchName = "contacts"; // String szBranchName = "contacts";
// //
// APPInfo appInfo = AboutActivityFactory.buildDefaultAPPInfo(); // APPInfo appInfo = AboutActivityFactory.buildDefaultAPPInfo();
@@ -92,8 +93,8 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct
// appInfo.setAppAPKName("Contacts"); // appInfo.setAppAPKName("Contacts");
// appInfo.setAppAPKFolderName("Contacts"); // appInfo.setAppAPKFolderName("Contacts");
// return appInfo; // return appInfo;
// return null; return null;
// } }
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@@ -101,51 +102,28 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct
//if (prosessIntents(getIntent())) return; //if (prosessIntents(getIntent())) return;
// 以下正常创建主窗口 // 以下正常创建主窗口
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
_MainActivity = this;
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
// 初始化工具栏 // 初始化工具栏
mToolbar = findViewById(R.id.activitymainToolbar1); mToolbar = findViewById(R.id.activitymainToolbar1);
setSupportActionBar(mToolbar); setSupportActionBar(mToolbar);
// if (isEnableDisplayHomeAsUp()) { if (isEnableDisplayHomeAsUp()) {
// // 显示后退按钮 // 显示后退按钮
// getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// } }
getSupportActionBar().setSubtitle(getTag()); getSupportActionBar().setSubtitle(getTag());
tabLayout = findViewById(R.id.tabLayout); initData();
viewPager = findViewById(R.id.viewPager); initView();
//initPoint();//调用初始化导航原点的方法
viewPager.addOnPageChangeListener(this);//滑动事件
// 创建Fragment列表和标题列表 ViewPager viewPager = findViewById(R.id.activitymainViewPager1);
fragmentList = new ArrayList<>(); MyPagerAdapter pagerAdapter = new MyPagerAdapter(getSupportFragmentManager());
tabTitleList = new ArrayList<>(); viewPager.setAdapter(pagerAdapter);
fragmentList.add(CallLogFragment.newInstance(0)); TabLayout tabLayout = findViewById(R.id.activitymainTabLayout1);
fragmentList.add(ContactsFragment.newInstance(1));
fragmentList.add(LogFragment.newInstance(2));
tabTitleList.add("通话记录");
tabTitleList.add("联系人");
tabTitleList.add("应用日志");
// 设置ViewPager的适配器
MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager(), fragmentList, tabTitleList);
viewPager.setAdapter(adapter);
// 关联TabLayout和ViewPager
tabLayout.setupWithViewPager(viewPager); tabLayout.setupWithViewPager(viewPager);
// initData();
// initView();
// //initPoint();//调用初始化导航原点的方法
// viewPager.addOnPageChangeListener(this);//滑动事件
//ViewPager viewPager = findViewById(R.id.activitymainViewPager1);
//MyPagerAdapter pagerAdapter = new MyPagerAdapter(getSupportFragmentManager());
//viewPager.setAdapter(pagerAdapter);
//TabLayout tabLayout = findViewById(R.id.activitymainTabLayout1);
//tabLayout.setupWithViewPager(viewPager);
// mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); // mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class);
// if (mMainServiceBean == null) { // if (mMainServiceBean == null) {
// mMainServiceBean = new MainServiceBean(); // mMainServiceBean = new MainServiceBean();
@@ -162,86 +140,36 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct
// } // }
// } // }
// }); // });
MainService.startMainService(MainActivity.this);
MainServiceBean mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class);
if (mMainServiceBean == null) {
mMainServiceBean = new MainServiceBean();
MainServiceBean.saveBean(this, mMainServiceBean);
}
if (mMainServiceBean.isEnable()) {
MainService.startMainService(this);
}
// 初始化TelephonyManager和PhoneStateListener
telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
phoneStateListener = new MyPhoneStateListener();
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
}
// ViewPager的适配器
private class MyPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragmentList;
private List<String> tabTitleList;
public MyPagerAdapter(FragmentManager fm, List<Fragment> fragmentList, List<String> tabTitleList) {
super(fm);
this.fragmentList = fragmentList;
this.tabTitleList = tabTitleList;
}
@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
@Override
public int getCount() {
return fragmentList.size();
}
@Override
public CharSequence getPageTitle(int position) {
return tabTitleList.get(position);
}
}
public static void dialPhoneNumber(String phoneNumber) {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(android.net.Uri.parse("tel:" + phoneNumber));
if (ActivityCompat.checkSelfPermission(_MainActivity, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
return;
}
_MainActivity.startActivity(intent);
} }
//初始化view即显示的图片 //初始化view即显示的图片
// void initView() { void initView() {
// viewPager = findViewById(R.id.activitymainViewPager1); viewPager = findViewById(R.id.activitymainViewPager1);
// pagerAdapter = new MyPagerAdapter(getSupportFragmentManager()); pagerAdapter = new MyPagerAdapter(getSupportFragmentManager());
// viewPager.setAdapter(pagerAdapter); viewPager.setAdapter(pagerAdapter);
// //adapter = new MyPagerAdapter(views); //adapter = new MyPagerAdapter(views);
// //viewPager = findViewById(R.id.activitymainViewPager1); //viewPager = findViewById(R.id.activitymainViewPager1);
// //viewPager.setAdapter(adapter); //viewPager.setAdapter(adapter);
// //linearLayout = findViewById(R.id.activitymainLinearLayout1); //linearLayout = findViewById(R.id.activitymainLinearLayout1);
// //initPoint();//初始化页面下方的点 //initPoint();//初始化页面下方的点
// viewPager.setOnPageChangeListener(this); viewPager.setOnPageChangeListener(this);
//
// } }
//初始化所要显示的布局 //初始化所要显示的布局
// void initData() { void initData() {
// LayoutInflater inflater = LayoutInflater.from(getActivity()); ViewPager viewPager = findViewById(R.id.activitymainViewPager1);
// View view1 = inflater.inflate(R.layout.fragment_call_log, viewPager, false); LayoutInflater inflater = LayoutInflater.from(getActivity());
// View view2 = inflater.inflate(R.layout.fragment_contacts, viewPager, false); View view1 = inflater.inflate(R.layout.fragment_call, viewPager, false);
// View view3 = inflater.inflate(R.layout.fragment_log, viewPager, false); View view2 = inflater.inflate(R.layout.fragment_contacts, viewPager, false);
// View view3 = inflater.inflate(R.layout.fragment_log, viewPager, false);
// views = new ArrayList<>();
// views.add(view1); views = new ArrayList<>();
// views.add(view2); views.add(view1);
// views.add(view3); views.add(view2);
// } views.add(view3);
}
// void initPoint() { // void initPoint() {
// imageViews = new ImageView[5];//实例化5个图片 // imageViews = new ImageView[5];//实例化5个图片
@@ -303,23 +231,6 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct
//setSubTitle(""); //setSubTitle("");
} }
private class MyPhoneStateListener extends PhoneStateListener {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
LogUtils.d(TAG, "电话已挂断");
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
LogUtils.d(TAG, "正在通话中");
break;
case TelephonyManager.CALL_STATE_RINGING:
LogUtils.d(TAG, "来电: " + incomingNumber);
break;
}
}
}
@Override @Override
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();
@@ -376,25 +287,40 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct
return TAG; return TAG;
} }
// @Override @Override
// public void onBackPressed() { public Toolbar initToolBar() {
// exit(); return findViewById(R.id.activitymainToolbar1);
// } }
//
// void exit() { @Override
// YesNoAlertDialog.OnDialogResultListener listener = new YesNoAlertDialog.OnDialogResultListener(){ public boolean isAddWinBollToolBar() {
// return true;
// @Override }
// public void onYes() {
// WinBollActivityManager.getInstance(getApplicationContext()).finishAll(); @Override
// } public boolean isEnableDisplayHomeAsUp() {
// return false;
// @Override }
// public void onNo() {
// } @Override
// }; public void onBackPressed() {
// YesNoAlertDialog.show(this, "[ " + getString(R.string.app_name) + " ]", "Exit(Yes/No).\nIs close all activity?", listener); exit();
// } }
void exit() {
YesNoAlertDialog.OnDialogResultListener listener = new YesNoAlertDialog.OnDialogResultListener(){
@Override
public void onYes() {
WinBollActivityManager.getInstance(getApplicationContext()).finishAll();
}
@Override
public void onNo() {
}
};
YesNoAlertDialog.show(this, "[ " + getString(R.string.app_name) + " ]", "Exit(Yes/No).\nIs close all activity?", listener);
}
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
@@ -405,7 +331,11 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.item_settings) { if (item.getItemId() == R.id.item_call) {
Intent intent = new Intent(this, CallActivity.class);
startActivity(intent);
//WinBollActivityManager.getInstance(this).startWinBollActivity(this, CallActivity.class);
} else if (item.getItemId() == R.id.item_settings) {
Intent intent = new Intent(this, SettingsActivity.class); Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent); startActivity(intent);
//WinBollActivityManager.getInstance(this).startWinBollActivity(this, CallActivity.class); //WinBollActivityManager.getInstance(this).startWinBollActivity(this, CallActivity.class);

View File

@@ -0,0 +1,35 @@
package cc.winboll.studio.contacts;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/20 21:14:52
* @Describe PhoneCallManager
*/
import android.telecom.Call;
import android.telecom.VideoProfile;
public class PhoneCallManager {
public static final String TAG = "PhoneCallManager";
public static Call call;
/**
* 接听电话
*/
public void answer() {
if (call != null) {
call.answer(VideoProfile.STATE_AUDIO_ONLY);
}
}
/**
* 断开电话,包括来电时的拒接以及接听后的挂断
*/
public void disconnect() {
if (call != null) {
call.disconnect();
}
}
}

View File

@@ -1,91 +0,0 @@
package cc.winboll.studio.contacts.activities;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/03/31 15:15:54
* @Describe 应用介绍窗口
*/
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.contacts.R;
import cc.winboll.studio.libaes.winboll.APPInfo;
import cc.winboll.studio.libaes.winboll.AboutView;
import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.winboll.IWinBollActivity;
public class AboutActivity extends WinBollActivity implements IWinBollActivity {
public static final String TAG = "AboutActivity";
Context mContext;
Toolbar mToolbar;
@Override
public Activity getActivity() {
return this;
}
@Override
public String getTag() {
return TAG;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
setContentView(R.layout.activity_about);
mToolbar = findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
mToolbar.setSubtitle(TAG);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
AboutView aboutView = CreateAboutView();
// 在 Activity 的 onCreate 或其他生命周期方法中调用
// LinearLayout layout = new LinearLayout(this);
// layout.setOrientation(LinearLayout.VERTICAL);
// // 创建布局参数(宽度和高度)
// ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
// ViewGroup.LayoutParams.MATCH_PARENT,
// ViewGroup.LayoutParams.MATCH_PARENT
// );
// addContentView(aboutView, params);
LinearLayout layout = findViewById(R.id.aboutviewroot_ll);
// 创建布局参数(宽度和高度)
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
);
layout.addView(aboutView, params);
GlobalApplication.getWinBollActivityManager().add(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
GlobalApplication.getWinBollActivityManager().registeRemove(this);
}
public AboutView CreateAboutView() {
String szBranchName = "contacts";
APPInfo appInfo = new APPInfo();
appInfo.setAppName("Contacts");
appInfo.setAppIcon(cc.winboll.studio.libaes.R.drawable.ic_winboll);
appInfo.setAppDescription("通讯录与拨号");
appInfo.setAppGitName("APP");
appInfo.setAppGitOwner("Studio");
appInfo.setAppGitAPPBranch(szBranchName);
appInfo.setAppGitAPPSubProjectFolder(szBranchName);
appInfo.setAppHomePage("https://www.winboll.cc/studio/details.php?app=Contacts");
appInfo.setAppAPKName("Contacts");
appInfo.setAppAPKFolderName("Contacts");
return new AboutView(mContext, appInfo);
}
}

View File

@@ -34,7 +34,6 @@ public class CallActivity extends AppCompatActivity {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main); //setContentView(R.layout.activity_main);
setContentView(R.layout.activity_call); setContentView(R.layout.activity_call);

View File

@@ -4,6 +4,7 @@ package cc.winboll.studio.contacts.activities;
* @Author ZhanGSKen@AliYun.Com * @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/21 05:37:42 * @Date 2025/02/21 05:37:42
*/ */
import android.app.NotificationManager;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
@@ -14,33 +15,17 @@ import android.os.Bundle;
import android.provider.Settings; import android.provider.Settings;
import android.view.View; import android.view.View;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.EditText;
import android.widget.SeekBar;
import android.widget.Switch; import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import cc.winboll.studio.contacts.R; import cc.winboll.studio.contacts.R;
import cc.winboll.studio.contacts.adapters.PhoneConnectRuleAdapter;
import cc.winboll.studio.contacts.beans.MainServiceBean;
import cc.winboll.studio.contacts.beans.PhoneConnectRuleModel;
import cc.winboll.studio.contacts.beans.RingTongBean; import cc.winboll.studio.contacts.beans.RingTongBean;
import cc.winboll.studio.contacts.beans.SettingsModel; import cc.winboll.studio.libappbase.IWinBollActivity;
import cc.winboll.studio.contacts.bobulltoon.TomCat; import cc.winboll.studio.libappbase.bean.APPInfo;
import cc.winboll.studio.contacts.dun.Rules;
import cc.winboll.studio.contacts.services.MainService;
import cc.winboll.studio.contacts.views.DuInfoTextView;
import cc.winboll.studio.libaes.winboll.APPInfo;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.winboll.IWinBollActivity;
import com.hjq.toast.ToastUtils; import com.hjq.toast.ToastUtils;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.List;
import cc.winboll.studio.contacts.App;
public class SettingsActivity extends AppCompatActivity implements IWinBollActivity { public class SettingsActivity extends AppCompatActivity implements IWinBollActivity {
@@ -48,25 +33,11 @@ public class SettingsActivity extends AppCompatActivity implements IWinBollActiv
Toolbar mToolbar; Toolbar mToolbar;
Switch swSilent; Switch swSilent;
SeekBar msbVolume;
TextView mtvVolume;
int mnStreamMaxVolume;
int mnStreamVolume;
Switch mswMainService;
static DuInfoTextView _DuInfoTextView;
// 云盾防御层数量 @Override
EditText etDunTotalCount; public APPInfo getAppInfo() {
// 防御层恢复时间间隔(秒钟) return null;
EditText etDunResumeSecondCount; }
// 每次恢复防御层数
EditText etDunResumeCount;
// 是否启用云盾
Switch swIsEnableDun;
private RecyclerView recyclerView;
private PhoneConnectRuleAdapter adapter;
private List<PhoneConnectRuleModel> ruleList;
@Override @Override
public AppCompatActivity getActivity() { public AppCompatActivity getActivity() {
@@ -78,6 +49,21 @@ public class SettingsActivity extends AppCompatActivity implements IWinBollActiv
return TAG; return TAG;
} }
@Override
public Toolbar initToolBar() {
return findViewById(R.id.activitymainToolbar1);
}
@Override
public boolean isAddWinBollToolBar() {
return true;
}
@Override
public boolean isEnableDisplayHomeAsUp() {
return false;
}
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@@ -86,136 +72,11 @@ public class SettingsActivity extends AppCompatActivity implements IWinBollActiv
// 初始化工具栏 // 初始化工具栏
mToolbar = findViewById(R.id.activitymainToolbar1); mToolbar = findViewById(R.id.activitymainToolbar1);
setSupportActionBar(mToolbar); setSupportActionBar(mToolbar);
// 显示后退按钮 if (isEnableDisplayHomeAsUp()) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true); // 显示后退按钮
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
getSupportActionBar().setSubtitle(getTag()); getSupportActionBar().setSubtitle(getTag());
mswMainService = findViewById(R.id.sw_mainservice);
MainServiceBean mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class);
mswMainService.setChecked(mMainServiceBean.isEnable());
mswMainService.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View arg0) {
LogUtils.d(TAG, "mswMainService onClick");
// TODO: Implement this method
if (mswMainService.isChecked()) {
//ToastUtils.show("Is Checked");
MainService.startMainServiceAndSaveStatus(SettingsActivity.this);
} else {
//ToastUtils.show("Not Checked");
MainService.stopMainServiceAndSaveStatus(SettingsActivity.this);
}
}
});
msbVolume = findViewById(R.id.bellvolume);
mtvVolume = findViewById(R.id.tv_volume);
final AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
// 设置SeekBar的最大值为系统铃声音量的最大刻度
mnStreamMaxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_RING);
msbVolume.setMax(mnStreamMaxVolume);
// 获取当前铃声音量并设置为SeekBar的初始进度
mnStreamVolume = audioManager.getStreamVolume(AudioManager.STREAM_RING);
msbVolume.setProgress(mnStreamVolume);
updateStreamVolumeTextView();
msbVolume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
// 设置铃声音量
audioManager.setStreamVolume(AudioManager.STREAM_RING, progress, 0);
RingTongBean bean = RingTongBean.loadBean(SettingsActivity.this, RingTongBean.class);
if (bean == null) {
bean = new RingTongBean();
}
bean.setStreamVolume(progress);
RingTongBean.saveBean(SettingsActivity.this, bean);
mnStreamVolume = progress;
updateStreamVolumeTextView();
//Toast.makeText(SettingsActivity.this, "音量设置为: " + progress, Toast.LENGTH_SHORT).show();
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
// 当开始拖动SeekBar时的操作
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
// 当停止拖动SeekBar时的操作
}
});
recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
ruleList = Rules.getInstance(this).getPhoneBlacRuleBeanList();
adapter = new PhoneConnectRuleAdapter(this, ruleList);
recyclerView.setAdapter(adapter);
// 设置参数云盾
_DuInfoTextView = findViewById(R.id.tv_DunInfo);
etDunTotalCount = findViewById(R.id.et_DunTotalCount);
etDunResumeSecondCount = findViewById(R.id.et_DunResumeSecondCount);
etDunResumeCount = findViewById(R.id.et_DunResumeCount);
swIsEnableDun = findViewById(R.id.sw_IsEnableDun);
SettingsModel settingsModel = Rules.getInstance(this).getSettingsModel();
etDunTotalCount.setText(Integer.toString(settingsModel.getDunTotalCount()));
etDunResumeSecondCount.setText(Integer.toString(settingsModel.getDunResumeSecondCount()));
etDunResumeCount.setText(Integer.toString(settingsModel.getDunResumeCount()));
swIsEnableDun.setChecked(settingsModel.isEnableDun());
boolean isEnableDun = settingsModel.isEnableDun();
etDunTotalCount.setEnabled(!isEnableDun);
etDunResumeSecondCount.setEnabled(!isEnableDun);
etDunResumeCount.setEnabled(!isEnableDun);
}
public static void notifyDunInfoUpdate() {
if (_DuInfoTextView != null) {
_DuInfoTextView.notifyInfoUpdate();
}
}
public void onSW_IsEnableDun(View view) {
LogUtils.d(TAG, "onSW_IsEnableDun");
boolean isEnableDun = swIsEnableDun.isChecked();
etDunTotalCount.setEnabled(!isEnableDun);
etDunResumeSecondCount.setEnabled(!isEnableDun);
etDunResumeCount.setEnabled(!isEnableDun);
SettingsModel settingsModel = Rules.getInstance(this).getSettingsModel();
if (isEnableDun) {
settingsModel.setDunTotalCount(Integer.parseInt(etDunTotalCount.getText().toString()));
settingsModel.setDunResumeSecondCount(Integer.parseInt(etDunResumeSecondCount.getText().toString()));
settingsModel.setDunResumeCount(Integer.parseInt(etDunResumeCount.getText().toString()));
}
settingsModel.setIsEnableDun(isEnableDun);
Rules.getInstance(this).saveDun();
Rules.getInstance(this).reload();
}
void updateStreamVolumeTextView() {
mtvVolume.setText(String.format("%d/%d", mnStreamVolume, mnStreamMaxVolume));
}
public void onUnitTest(View view) {
Intent intent = new Intent(this, UnitTestActivity.class);
startActivity(intent);
}
public void onAddNewConnectionRule(View view) {
Rules.getInstance(this).getPhoneBlacRuleBeanList().add(new PhoneConnectRuleModel());
Rules.getInstance(this).saveRules();
adapter.notifyDataSetChanged();
} }
public void onDefaultPhone(View view) { public void onDefaultPhone(View view) {
@@ -233,38 +94,6 @@ public class SettingsActivity extends AppCompatActivity implements IWinBollActiv
} }
} }
public void onDownloadBoBullToon(View view) {
final TomCat tomCat = TomCat.getInstance(this);
new Thread(new Runnable() {
@Override
public void run() {
if (tomCat.downloadBoBullToon()) {
ToastUtils.show("BoBullToon downlaod OK!");
MainService.restartMainService(SettingsActivity.this);
Rules.getInstance(SettingsActivity.this).reload();
}
}
}).start();
}
public void onSearchBoBullToonPhone(View view) {
TomCat tomCat = TomCat.getInstance(this);
EditText etPhone = findViewById(R.id.activitysettingsEditText1);
String phone = etPhone.getText().toString().trim();
if (tomCat.loadPhoneBoBullToon()) {
if (tomCat.isPhoneBoBullToon(phone)) {
ToastUtils.show("It is a BoBullToon Phone!");
} else {
ToastUtils.show("Not in BoBullToon.");
}
} else {
ToastUtils.show("没有下载 BoBullToon。");
}
}
private void askForDrawOverlay() { private void askForDrawOverlay() {
AlertDialog alertDialog = new AlertDialog.Builder(this) AlertDialog alertDialog = new AlertDialog.Builder(this)
.setTitle("允许显示悬浮框") .setTitle("允许显示悬浮框")
@@ -311,8 +140,4 @@ public class SettingsActivity extends AppCompatActivity implements IWinBollActiv
} }
} }
} }
public void onAbout(View view) {
App.getWinBollActivityManager().startWinBollActivity(this, AboutActivity.class);
}
} }

View File

@@ -1,94 +0,0 @@
package cc.winboll.studio.contacts.activities;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import cc.winboll.studio.contacts.R;
import cc.winboll.studio.contacts.dun.Rules;
import cc.winboll.studio.contacts.utils.IntUtils;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.LogView;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/03/02 16:07:04
*/
public class UnitTestActivity extends Activity {
public static final String TAG = "UnitTestActivity";
LogView logView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_unittest);
logView = findViewById(R.id.logview);
logView.start();
}
public void onTestPhone(View view) {
// 开始测试数据
EditText etPhone = findViewById(R.id.phone_et);
Rules rules = Rules.getInstance(this);
String phone = etPhone.getText().toString().trim();
LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone)));
}
public void onTestMain(View view) {
LogUtils.d(TAG, "IntUtils.unittest_getIntInRange();");
IntUtils.unittest_getIntInRange();
Rules rules = Rules.getInstance(this);
// 如果没有规则就添加测试规则
if (rules.getPhoneBlacRuleBeanList().size() == 0) {
// 手机号码允许
// 中国手机号码正则表达式以1开头第二位可以是3、4、5、6、7、8、9后面跟9位数字
String regex = "^1[3-9]\\d{9}$";
rules.add(regex, true, true);
// 指定区号号码允许
regex = "^0660\\d+$";
rules.add(regex, true, true);
// 指定区号号码允许
regex = "^020\\d+$";
rules.add(regex, true, true);
// 添加默认拒接规则
regex = ".*";
rules.add(regex, false, true);
// 保存规则到文件
rules.saveRules();
}
// 开始测试数据
String phone = "16769764848";
LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone)));
phone = "16856582777";
LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone)));
phone = "17519703124";
LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone)));
phone = "0205658955";
LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone)));
phone = "0108965253";
LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone)));
phone = "+8616769764848";
LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone)));
phone = "4005816769764848";
LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone)));
phone = "95566";
LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone)));
}
}

View File

@@ -1,60 +0,0 @@
package cc.winboll.studio.contacts.activities;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/03/31 15:16:45
* @Describe 应用窗口基类
*/
import android.app.Activity;
import android.os.Bundle;
import android.view.MenuItem;
import androidx.appcompat.app.AppCompatActivity;
import cc.winboll.studio.libaes.beans.AESThemeBean;
import cc.winboll.studio.libaes.utils.AESThemeUtil;
import cc.winboll.studio.libappbase.winboll.IWinBollActivity;
public class WinBollActivity extends AppCompatActivity implements IWinBollActivity {
public static final String TAG = "WinBollActivity";
protected volatile AESThemeBean.ThemeType mThemeType;
@Override
public Activity getActivity() {
return this;
}
@Override
public String getTag() {
return TAG;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
mThemeType = getThemeType();
setThemeStyle();
super.onCreate(savedInstanceState);
}
AESThemeBean.ThemeType getThemeType() {
/*SharedPreferences sharedPreferences = getSharedPreferences(
SHAREDPREFERENCES_NAME, MODE_PRIVATE);
return AESThemeBean.ThemeType.values()[((sharedPreferences.getInt(DRAWER_THEME_TYPE, AESThemeBean.ThemeType.DEFAULT.ordinal())))];
*/
return AESThemeBean.getThemeStyleType(AESThemeUtil.getThemeTypeID(getApplicationContext()));
}
void setThemeStyle() {
//setTheme(AESThemeBean.getThemeStyle(getThemeType()));
setTheme(AESThemeUtil.getThemeTypeID(getApplicationContext()));
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
}

View File

@@ -1,93 +0,0 @@
package cc.winboll.studio.contacts.adapters;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/26 13:09:32
* @Describe CallLogAdapter
*/
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import cc.winboll.studio.contacts.R;
import cc.winboll.studio.contacts.beans.CallLogModel;
import cc.winboll.studio.contacts.utils.ContactUtils;
import cc.winboll.studio.libaes.views.AOHPCTCSeekBar;
import com.hjq.toast.ToastUtils;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Locale;
public class CallLogAdapter extends RecyclerView.Adapter<CallLogAdapter.CallLogViewHolder> {
public static final String TAG = "CallLogAdapter";
private List<CallLogModel> callLogList;
ContactUtils mContactUtils;
Context mContext;
public CallLogAdapter(Context context, List<CallLogModel> callLogList) {
mContext = context;
this.mContactUtils = ContactUtils.getInstance(mContext);
this.callLogList = callLogList;
}
@NonNull
@Override
public CallLogViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_call_log, parent, false);
return new CallLogViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull CallLogViewHolder holder, int position) {
final CallLogModel callLog = callLogList.get(position);
holder.phoneNumber.setText(callLog.getPhoneNumber() + "" + mContactUtils.getContactsName(callLog.getPhoneNumber()));
holder.callStatus.setText(callLog.getCallStatus());
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
holder.callDate.setText(dateFormat.format(callLog.getCallDate()));
// 初始化拉动后拨号控件
holder.dialAOHPCTCSeekBar.setThumb(holder.itemView.getContext().getDrawable(R.drawable.ic_call));
holder.dialAOHPCTCSeekBar.setBlurRightDP(80);
holder.dialAOHPCTCSeekBar.setThumbOffset(0);
holder.dialAOHPCTCSeekBar.setOnOHPCListener(
new AOHPCTCSeekBar.OnOHPCListener(){
@Override
public void onOHPCommit() {
String phoneNumber = callLog.getPhoneNumber().replaceAll("\\s", "");
ToastUtils.show(phoneNumber);
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(android.net.Uri.parse("tel:" + phoneNumber));
// 添加 FLAG_ACTIVITY_NEW_TASK 标志
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
holder.itemView.getContext().startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return callLogList.size();
}
public class CallLogViewHolder extends RecyclerView.ViewHolder {
TextView phoneNumber, callStatus, callDate;
Button dialButton;
AOHPCTCSeekBar dialAOHPCTCSeekBar;
public CallLogViewHolder(@NonNull View itemView) {
super(itemView);
phoneNumber = itemView.findViewById(R.id.phone_number);
callStatus = itemView.findViewById(R.id.call_status);
callDate = itemView.findViewById(R.id.call_date);
dialAOHPCTCSeekBar = itemView.findViewById(R.id.aohpctcseekbar_dial);
}
}
}

View File

@@ -1,84 +0,0 @@
package cc.winboll.studio.contacts.adapters;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/26 13:35:44
* @Describe ContactAdapter
*/
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import cc.winboll.studio.contacts.R;
import cc.winboll.studio.contacts.beans.ContactModel;
import com.hjq.toast.ToastUtils;
import java.util.List;
import cc.winboll.studio.libaes.views.AOHPCTCSeekBar;
public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContactViewHolder> {
public static final String TAG = "ContactAdapter";
private static final int REQUEST_CALL_PHONE = 1;
private List<ContactModel> contactList;
public ContactAdapter(List<ContactModel> contactList) {
this.contactList = contactList;
}
@NonNull
@Override
public ContactViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_contact, parent, false);
return new ContactViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ContactViewHolder holder, int position) {
final ContactModel contact = contactList.get(position);
holder.contactName.setText(contact.getName());
holder.contactNumber.setText(contact.getNumber());
// 初始化拉动后拨号控件
holder.dialAOHPCTCSeekBar.setThumb(holder.itemView.getContext().getDrawable(R.drawable.ic_call));
holder.dialAOHPCTCSeekBar.setBlurRightDP(80);
holder.dialAOHPCTCSeekBar.setThumbOffset(0);
holder.dialAOHPCTCSeekBar.setOnOHPCListener(
new AOHPCTCSeekBar.OnOHPCListener(){
@Override
public void onOHPCommit() {
String phoneNumber = contact.getNumber().replaceAll("\\s", "");
ToastUtils.show(phoneNumber);
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(android.net.Uri.parse("tel:" + phoneNumber));
// 添加 FLAG_ACTIVITY_NEW_TASK 标志
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
holder.itemView.getContext().startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return contactList.size();
}
public class ContactViewHolder extends RecyclerView.ViewHolder {
TextView contactName;
TextView contactNumber;
AOHPCTCSeekBar dialAOHPCTCSeekBar;
public ContactViewHolder(@NonNull View itemView) {
super(itemView);
contactName = itemView.findViewById(R.id.contact_name);
contactNumber = itemView.findViewById(R.id.contact_number);
dialAOHPCTCSeekBar = itemView.findViewById(R.id.aohpctcseekbar_dial);
}
}
}

View File

@@ -0,0 +1,42 @@
package cc.winboll.studio.contacts.adapters;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/20 13:33:04
* @Describe MyPagerAdapter
*/
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import cc.winboll.studio.contacts.fragments.CallFragment;
import cc.winboll.studio.contacts.fragments.ContactsFragment;
import cc.winboll.studio.contacts.fragments.LogFragment;
public class MyPagerAdapter extends FragmentPagerAdapter {
public static final String TAG = "MyPagerAdapter";
private static final int PAGE_COUNT = 3;
public MyPagerAdapter(@NonNull FragmentManager fm) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
@NonNull
@Override
public Fragment getItem(int position) {
if(position == 1) {
return ContactsFragment.newInstance(position);
} else if(position == 2) {
return LogFragment.newInstance(position);
} else {
return CallFragment.newInstance(position);
}
}
@Override
public int getCount() {
return PAGE_COUNT;
}
}

View File

@@ -1,247 +0,0 @@
package cc.winboll.studio.contacts.adapters;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/03/02 17:27:41
* @Describe PhoneConnectRuleAdapter
*/
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import cc.winboll.studio.contacts.R;
import cc.winboll.studio.contacts.beans.PhoneConnectRuleModel;
import cc.winboll.studio.contacts.dun.Rules;
import cc.winboll.studio.contacts.views.LeftScrollView;
import cc.winboll.studio.libappbase.dialogs.YesNoAlertDialog;
import com.hjq.toast.ToastUtils;
import java.util.ArrayList;
import java.util.List;
public class PhoneConnectRuleAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public static final String TAG = "PhoneConnectRuleAdapter";
private static final int VIEW_TYPE_SIMPLE = 0;
private static final int VIEW_TYPE_EDIT = 1;
private Context context;
private List<PhoneConnectRuleModel> ruleList;
public PhoneConnectRuleAdapter(Context context, List<PhoneConnectRuleModel> ruleList) {
this.context = context;
this.ruleList = ruleList;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
if (viewType == VIEW_TYPE_SIMPLE) {
View view = inflater.inflate(R.layout.view_phone_connect_rule_simple, parent, false);
return new SimpleViewHolder(parent, view);
} else {
View view = inflater.inflate(R.layout.view_phone_connect_rule, parent, false);
return new EditViewHolder(parent, view);
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) {
final PhoneConnectRuleModel model = ruleList.get(position);
if (holder instanceof SimpleViewHolder) {
final SimpleViewHolder simpleViewHolder = (SimpleViewHolder) holder;
String szView = model.getRuleText().trim().equals("") ?"[NULL]": model.getRuleText();
simpleViewHolder.tvRuleText.setText(szView);
simpleViewHolder.scrollView.setOnActionListener(new LeftScrollView.OnActionListener(){
@Override
public void onUp() {
ArrayList<PhoneConnectRuleModel> list = Rules.getInstance(context).getPhoneBlacRuleBeanList();
if (position > 0) {
ToastUtils.show("onUp");
simpleViewHolder.scrollView.smoothScrollTo(0, 0);
// PhoneConnectRuleModel newBean = new PhoneConnectRuleModel();
// newBean.setRuleText(list.get(position).getRuleText());
// newBean.setIsAllowConnection(list.get(position).isAllowConnection());
// newBean.setIsEnable(list.get(position).isEnable());
// newBean.setIsSimpleView(list.get(position).isSimpleView());
list.add(position - 1, list.get(position));
list.remove(position + 1);
Rules.getInstance(context).saveRules();
notifyDataSetChanged();
}
}
@Override
public void onDown() {
ArrayList<PhoneConnectRuleModel> list = Rules.getInstance(context).getPhoneBlacRuleBeanList();
if (position < list.size() - 1) {
ToastUtils.show("onDown");
simpleViewHolder.scrollView.smoothScrollTo(0, 0);
// PhoneConnectRuleModel newBean = new PhoneConnectRuleModel();
// newBean.setRuleText(list.get(position).getRuleText());
// newBean.setIsAllowConnection(list.get(position).isAllowConnection());
// newBean.setIsEnable(list.get(position).isEnable());
// newBean.setIsSimpleView(list.get(position).isSimpleView());
list.add(position + 2, list.get(position));
list.remove(position);
Rules.getInstance(context).saveRules();
notifyDataSetChanged();
}
}
@Override
public void onEdit() {
simpleViewHolder.scrollView.smoothScrollTo(0, 0);
model.setIsSimpleView(false);
notifyDataSetChanged();
//notifyItemChanged(position);
}
@Override
public void onDelete() {
YesNoAlertDialog.show(simpleViewHolder.scrollView.getContext(), "删除确认", "是否删除该通话规则?", new YesNoAlertDialog.OnDialogResultListener(){
@Override
public void onYes() {
simpleViewHolder.scrollView.smoothScrollTo(0, 0);
model.setIsSimpleView(true);
ArrayList<PhoneConnectRuleModel> list = Rules.getInstance(context).getPhoneBlacRuleBeanList();
list.remove(position);
Rules.getInstance(context).saveRules();
notifyDataSetChanged();
//notifyItemChanged(position);
}
@Override
public void onNo() {
}
});
}
});
// simpleViewHolder.editButton.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// model.setIsSimpleView(false);
// notifyItemChanged(position);
// }
// });
// simpleViewHolder.deleteButton.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// model.setIsSimpleView(false);
// ArrayList<PhoneConnectRuleModel> list = Rules.getInstance(context).getPhoneBlacRuleBeanList();
// list.remove(position);
// Rules.getInstance(context).saveRules();
// notifyItemChanged(position);
// }
// });
// // 触摸事件处理
// simpleViewHolder.contentLayout.setOnTouchListener(new View.OnTouchListener() {
// @Override
// public boolean onTouch(View v, MotionEvent event) {
// switch (event.getAction()) {
// case MotionEvent.ACTION_DOWN:
// simpleViewHolder.startX = event.getX();
// simpleViewHolder.isSwiping = true;
// break;
// case MotionEvent.ACTION_MOVE:
// if (simpleViewHolder.isSwiping) {
// float deltaX = simpleViewHolder.startX - event.getX();
// if (deltaX > 0) { // 左滑
// float translationX = Math.max(-simpleViewHolder.actionLayout.getWidth(), -deltaX);
// simpleViewHolder.contentLayout.setTranslationX(translationX);
// simpleViewHolder.actionLayout.setVisibility(View.VISIBLE);
// }
// }
// break;
// case MotionEvent.ACTION_UP:
// simpleViewHolder.isSwiping = false;
// if (simpleViewHolder.contentLayout.getTranslationX() < -simpleViewHolder.actionLayout.getWidth() / 2) {
// // 保持按钮显示
// simpleViewHolder.contentLayout.setTranslationX(-actionLayout.getWidth());
// } else {
// // 恢复原状
// simpleViewHolder.contentLayout.animate().translationX(0).setDuration(200).start();
// simpleViewHolder.actionLayout.setVisibility(View.INVISIBLE);
// }
// break;
// }
// return true;
// }
// });
} else if (holder instanceof EditViewHolder) {
final EditViewHolder editViewHolder = (EditViewHolder) holder;
editViewHolder.editText.setText(model.getRuleText());
editViewHolder.checkBoxAllow.setChecked(model.isAllowConnection());
editViewHolder.checkBoxEnable.setChecked(model.isEnable());
editViewHolder.buttonConfirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
model.setRuleText(editViewHolder.editText.getText().toString());
model.setIsAllowConnection(editViewHolder.checkBoxAllow.isChecked());
model.setIsEnable(editViewHolder.checkBoxEnable.isChecked());
model.setIsSimpleView(true);
Rules.getInstance(context).saveRules();
notifyItemChanged(position);
Toast.makeText(context, "保存成功", Toast.LENGTH_SHORT).show();
}
});
}
}
@Override
public int getItemCount() {
return ruleList.size();
}
@Override
public int getItemViewType(int position) {
PhoneConnectRuleModel model = ruleList.get(position);
// 这里可以根据模型的状态来决定视图类型,简单起见,假设点击按钮后进入编辑视图
return model.isSimpleView() ? VIEW_TYPE_SIMPLE : VIEW_TYPE_EDIT;
}
static class SimpleViewHolder extends RecyclerView.ViewHolder {
private final LeftScrollView scrollView;
private final TextView tvRuleText;
public SimpleViewHolder(@NonNull ViewGroup parent, @NonNull View itemView) {
super(itemView);
scrollView = itemView.findViewById(R.id.scrollView);
//tvRuleText = itemView.findViewById(R.id.ruletext_tv);
tvRuleText = new TextView(itemView.getContext());
scrollView.setContentWidth(parent.getWidth());
//scrollView.setContentWidth(600);
scrollView.addContentLayout(tvRuleText);
}
}
static class EditViewHolder extends RecyclerView.ViewHolder {
EditText editText;
CheckBox checkBoxAllow;
CheckBox checkBoxEnable;
Button buttonConfirm;
public EditViewHolder(@NonNull ViewGroup parent, @NonNull View itemView) {
super(itemView);
editText = itemView.findViewById(R.id.edit_text);
checkBoxAllow = itemView.findViewById(R.id.checkbox_allow);
checkBoxEnable = itemView.findViewById(R.id.checkbox_enable);
buttonConfirm = itemView.findViewById(R.id.button_confirm);
}
}
}

View File

@@ -1,36 +0,0 @@
package cc.winboll.studio.contacts.beans;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/26 13:10:57
* @Describe CallLogModel
*/
import java.util.Date;
public class CallLogModel {
public static final String TAG = "CallLogModel";
private String phoneNumber;
private String callStatus;
private Date callDate;
public CallLogModel(String phoneNumber, String callStatus, Date callDate) {
this.phoneNumber = phoneNumber.replaceAll("\\s", "");
this.callStatus = callStatus;
this.callDate = callDate;
}
public String getPhoneNumber() {
return phoneNumber;
}
public String getCallStatus() {
return callStatus;
}
public Date getCallDate() {
return callDate;
}
}

View File

@@ -1,64 +0,0 @@
package cc.winboll.studio.contacts.beans;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/26 13:37:00
* @Describe ContactModel
*/
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
public class ContactModel {
public static final String TAG = "ContactModel";
private String name;
private String number;
private String pinyin;
public ContactModel(String name, String number) {
this.name = name;
this.number = number.replaceAll("\\s", "");
this.pinyin = convertToPinyin(name);
}
private String convertToPinyin(String chinese) {
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
StringBuilder pinyin = new StringBuilder();
for (int i = 0; i < chinese.length(); i++) {
char ch = chinese.charAt(i);
if (Character.toString(ch).matches("[\\u4e00-\\u9fa5]")) {
try {
String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(ch, format);
if (pinyinArray != null) {
pinyin.append(pinyinArray[0]);
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace();
}
} else {
pinyin.append(ch);
}
}
return pinyin.toString();
}
public String getName() {
return name;
}
public String getNumber() {
return number;
}
public String getPinyin() {
return pinyin;
}
}

View File

@@ -10,35 +10,21 @@ import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean; import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException; import java.io.IOException;
public class PhoneConnectRuleModel extends BaseBean { public class PhoneBlackRuleBean extends BaseBean {
public static final String TAG = "PhoneConnectRuleModel"; public static final String TAG = "PhoneBlackRuleBean";
String ruleText; String ruleText;
boolean isAllowConnection;
boolean isEnable; boolean isEnable;
boolean isSimpleView;
public PhoneBlackRuleBean() {
public PhoneConnectRuleModel() {
this.ruleText = ""; this.ruleText = "";
this.isAllowConnection = false;
this.isEnable = false; this.isEnable = false;
this.isSimpleView = true;
} }
public PhoneConnectRuleModel(String ruleText, boolean isAllowConnection, boolean isEnable) { public PhoneBlackRuleBean(String ruleText, boolean isEnable) {
this.ruleText = ruleText; this.ruleText = ruleText;
this.isAllowConnection = isAllowConnection;
this.isEnable = isEnable; this.isEnable = isEnable;
this.isSimpleView = true;
}
public void setIsSimpleView(boolean isSimpleView) {
this.isSimpleView = isSimpleView;
}
public boolean isSimpleView() {
return isSimpleView;
} }
public void setRuleText(String ruleText) { public void setRuleText(String ruleText) {
@@ -49,14 +35,6 @@ public class PhoneConnectRuleModel extends BaseBean {
return ruleText; return ruleText;
} }
public void setIsAllowConnection(boolean isAllowConnection) {
this.isAllowConnection = isAllowConnection;
}
public boolean isAllowConnection() {
return isAllowConnection;
}
public void setIsEnable(boolean isEnable) { public void setIsEnable(boolean isEnable) {
this.isEnable = isEnable; this.isEnable = isEnable;
} }
@@ -65,19 +43,17 @@ public class PhoneConnectRuleModel extends BaseBean {
return isEnable; return isEnable;
} }
@Override @Override
public String getName() { public String getName() {
return PhoneConnectRuleModel.class.getName(); return PhoneBlackRuleBean.class.getName();
} }
@Override @Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter); super.writeThisToJsonWriter(jsonWriter);
jsonWriter.name("ruleText").value(getRuleText()); jsonWriter.name("ruleText").value(getRuleText());
jsonWriter.name("isAllowConnection").value(isAllowConnection());
jsonWriter.name("isEnable").value(isEnable()); jsonWriter.name("isEnable").value(isEnable());
} }
@Override @Override
@@ -85,8 +61,6 @@ public class PhoneConnectRuleModel extends BaseBean {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
if (name.equals("ruleText")) { if (name.equals("ruleText")) {
setRuleText(jsonReader.nextString()); setRuleText(jsonReader.nextString());
} else if (name.equals("isAllowConnection")) {
setIsAllowConnection(jsonReader.nextBoolean());
} else if (name.equals("isEnable")) { } else if (name.equals("isEnable")) {
setIsEnable(jsonReader.nextBoolean()); setIsEnable(jsonReader.nextBoolean());
} else { } else {
@@ -109,6 +83,6 @@ public class PhoneConnectRuleModel extends BaseBean {
jsonReader.endObject(); jsonReader.endObject();
return this; return this;
} }
} }

View File

@@ -12,26 +12,26 @@ import android.media.AudioManager;
import android.util.JsonReader; import android.util.JsonReader;
public class RingTongBean extends BaseBean { public class RingTongBean extends BaseBean {
public static final String TAG = "AudioRingTongBean"; public static final String TAG = "AudioRingTongBean";
// 铃声音量 // 模式
int streamVolume; int ringerMode;
public RingTongBean() { public RingTongBean() {
this.streamVolume = 100; this.ringerMode = AudioManager.RINGER_MODE_NORMAL;
} }
public RingTongBean(int streamVolume) { public RingTongBean(int ringerMode) {
this.streamVolume = streamVolume; this.ringerMode = ringerMode;
} }
public void setStreamVolume(int streamVolume) { public void setRingerMode(int ringerMode) {
this.streamVolume = streamVolume; this.ringerMode = ringerMode;
} }
public int getStreamVolume() { public int getRingerMode() {
return streamVolume; return ringerMode;
} }
@Override @Override
@@ -42,15 +42,15 @@ public class RingTongBean extends BaseBean {
@Override @Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter); super.writeThisToJsonWriter(jsonWriter);
jsonWriter.name("streamVolume").value(getStreamVolume()); jsonWriter.name("ringerMode").value(getRingerMode());
} }
@Override @Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
if (name.equals("streamVolume")) { if (name.equals("ringerMode")) {
setStreamVolume(jsonReader.nextInt()); setRingerMode(jsonReader.nextInt());
} else { } else {
return false; return false;
} }

View File

@@ -1,141 +0,0 @@
package cc.winboll.studio.contacts.beans;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/03/02 19:51:40
* @Describe SettingsModel
*/
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException;
import cc.winboll.studio.contacts.utils.IntUtils;
public class SettingsModel extends BaseBean {
public static final String TAG = "SettingsModel";
public static final int MAX_INTRANGE = 666666;
public static final int MIN_INTRANGE = 1;
// 云盾防御层数量
int dunTotalCount;
// 当前云盾防御层
int dunCurrentCount;
// 防御层恢复时间间隔(秒钟)
int dunResumeSecondCount;
// 每次恢复防御层数
int dunResumeCount;
// 是否启用云盾
boolean isEnableDun;
public SettingsModel() {
this.dunTotalCount = 6;
this.dunCurrentCount = 6;
this.dunResumeSecondCount = 60;
this.dunResumeCount = 1;
this.isEnableDun = false;
}
public SettingsModel(int dunTotalCount, int dunCurrentCount, int dunResumeSecondCount, int dunResumeCount, boolean isEnableDun) {
this.dunTotalCount = getSettingsModelRangeInt(dunTotalCount);
this.dunCurrentCount = getSettingsModelRangeInt(dunCurrentCount);
this.dunResumeSecondCount = getSettingsModelRangeInt(dunResumeSecondCount);
this.dunResumeCount = getSettingsModelRangeInt(dunResumeCount);
this.isEnableDun = isEnableDun;
}
public void setDunTotalCount(int dunTotalCount) {
this.dunTotalCount = getSettingsModelRangeInt(dunTotalCount);
}
public int getDunTotalCount() {
return dunTotalCount;
}
public void setDunCurrentCount(int dunCurrentCount) {
this.dunCurrentCount = getSettingsModelRangeInt(dunCurrentCount);
}
public int getDunCurrentCount() {
return dunCurrentCount;
}
public void setDunResumeSecondCount(int dunResumeSecondCount) {
this.dunResumeSecondCount = getSettingsModelRangeInt(dunResumeSecondCount);
}
public int getDunResumeSecondCount() {
return dunResumeSecondCount;
}
public void setDunResumeCount(int dunResumeCount) {
this.dunResumeCount = getSettingsModelRangeInt(dunResumeCount);
}
public int getDunResumeCount() {
return dunResumeCount;
}
public void setIsEnableDun(boolean isEnableDun) {
this.isEnableDun = isEnableDun;
}
public boolean isEnableDun() {
return isEnableDun;
}
int getSettingsModelRangeInt(int origin) {
return IntUtils.getIntInRange(origin, MIN_INTRANGE, MAX_INTRANGE);
}
@Override
public String getName() {
return SettingsModel.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
jsonWriter.name("dunTotalCount").value(getDunTotalCount());
jsonWriter.name("dunCurrentCount").value(getDunCurrentCount());
jsonWriter.name("dunResumeSecondCount").value(getDunResumeSecondCount());
jsonWriter.name("dunResumeCount").value(getDunResumeCount());
jsonWriter.name("isEnableDun").value(isEnableDun());
}
@Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
if (name.equals("dunTotalCount")) {
setDunTotalCount(getSettingsModelRangeInt(jsonReader.nextInt()));
} else if (name.equals("dunCurrentCount")) {
setDunCurrentCount(getSettingsModelRangeInt(jsonReader.nextInt()));
} else if (name.equals("dunResumeSecondCount")) {
setDunResumeSecondCount(getSettingsModelRangeInt(jsonReader.nextInt()));
} else if (name.equals("dunResumeCount")) {
setDunResumeCount(getSettingsModelRangeInt(jsonReader.nextInt()));
} else if (name.equals("isEnableDun")) {
setIsEnableDun(jsonReader.nextBoolean());
} else {
return false;
}
}
return true;
}
@Override
public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException {
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String name = jsonReader.nextName();
if (!initObjectsFromJsonReader(jsonReader, name)) {
jsonReader.skipValue();
}
}
// 结束 JSON 对象
jsonReader.endObject();
return this;
}
}

View File

@@ -1,178 +0,0 @@
package cc.winboll.studio.contacts.bobulltoon;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/03/02 13:47:48
* @Describe 汤姆猫管家 :使用 BoBullToon 项目,对通讯地址进行筛选判断的好朋友。
*/
import android.content.Context;
import cc.winboll.studio.libappbase.LogUtils;
import com.hjq.toast.ToastUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class TomCat {
public static final String TAG = "TomCat";
List<String> listPhoneBoBullToon = new ArrayList<String>();
static volatile TomCat _TomCat;
Context mContext;
TomCat(Context context) {
mContext = context;
}
public static synchronized TomCat getInstance(Context context) {
if (_TomCat == null) {
_TomCat = new TomCat(context);
}
return _TomCat;
}
void downloadAndExtractZip(String zipUrl, String destinationFolder) throws IOException {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(zipUrl)
.build();
try {
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
// 下载 ZIP 文件到临时位置
File tempZipFile = File.createTempFile("temp", ".zip");
try {
InputStream inputStream = response.body().byteStream();
FileOutputStream outputStream = new FileOutputStream(tempZipFile);
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
} catch (Exception e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
// 解压 ZIP 文件到指定文件夹
try {
ZipInputStream zipInputStream = new ZipInputStream(Files.newInputStream(tempZipFile.toPath()));
ZipEntry zipEntry;
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
Path targetFilePath = Paths.get(destinationFolder, zipEntry.getName());
if (zipEntry.isDirectory()) {
Files.createDirectories(targetFilePath);
} else {
Files.createDirectories(targetFilePath.getParent());
try (FileOutputStream fos = new FileOutputStream(targetFilePath.toFile())) {
byte[] buffer = new byte[1024];
int len;
while ((len = zipInputStream.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
}
}
zipInputStream.closeEntry();
}
} catch (Exception e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
// 删除临时 ZIP 文件
tempZipFile.delete();
LogUtils.d(TAG, "已更新 BoBullToon 数据");
} catch (Exception e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
}
public boolean downloadBoBullToon() {
String zipUrl = "http://10.8.0.12:3000/Studio/BoBullToon/archive/main.zip"; // 替换为实际的 ZIP 文件 URL
String destinationFolder = getWorkingFolder().getPath(); // 替换为实际的目标文件夹路径
try {
// 删除旧文件
File fOldFolder = new File(destinationFolder);
if (fOldFolder.exists()) {
deleteFolderRecursive(fOldFolder);
fOldFolder.mkdirs();
LogUtils.d(TAG, "已清空 BoBullToon 数据");
}
// 更新新文件
downloadAndExtractZip(zipUrl, destinationFolder);
LogUtils.d(TAG, "ZIP 文件下载并解压成功。");
return true;
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
return false;
}
// 递归删除文件夹及其内容的方法
public static void deleteFolderRecursive(File file) {
// 判断是否为文件夹
if (file.isDirectory()) {
// 列出文件夹中的所有文件和子文件夹
File[] files = file.listFiles();
if (files != null) {
// 遍历并递归删除每个文件和子文件夹
for (File f : files) {
deleteFolderRecursive(f);
}
}
}
// 删除文件或空文件夹
file.delete();
}
File getWorkingFolder() {
return mContext.getExternalFilesDir(TAG);
}
public boolean loadPhoneBoBullToon() {
listPhoneBoBullToon.clear();
File fBoBullToon = new File(getWorkingFolder(), "bobulltoon");
if (fBoBullToon.exists()) {
LogUtils.d(TAG, String.format("getWorkingFolder() %s", getWorkingFolder()));
for (File userFolder : fBoBullToon.listFiles()) {
if (userFolder.isDirectory()) {
for (File recordFile : userFolder.listFiles()) {
listPhoneBoBullToon.add(recordFile.getName());
}
}
}
for (int i = 0; i < listPhoneBoBullToon.size(); i++) {
LogUtils.d(TAG, String.format("listPhoneBoBullToon add : %s", listPhoneBoBullToon.get(i)));
}
return true;
} else {
LogUtils.d(TAG, "fBoBullToon not exists。");
}
return false;
}
public boolean isPhoneBoBullToon(String phone) {
for (int i = 0; i < listPhoneBoBullToon.size(); i++) {
LogUtils.d(TAG, String.format("isPhoneBoBullToon(...) get(i) phone : %s", listPhoneBoBullToon.get(i)));
if (listPhoneBoBullToon.get(i).equals(phone)) {
return true;
}
}
return false;
}
}

View File

@@ -5,36 +5,25 @@ package cc.winboll.studio.contacts.dun;
* @Date 2025/02/21 06:15:10 * @Date 2025/02/21 06:15:10
* @Describe 云盾防御规则 * @Describe 云盾防御规则
*/ */
import android.content.Context; import cc.winboll.studio.contacts.beans.PhoneBlackRuleBean;
import cc.winboll.studio.contacts.activities.SettingsActivity;
import cc.winboll.studio.contacts.beans.PhoneConnectRuleModel;
import cc.winboll.studio.contacts.beans.SettingsModel;
import cc.winboll.studio.contacts.services.MainService;
import cc.winboll.studio.contacts.utils.ContactUtils;
import cc.winboll.studio.contacts.utils.IntUtils;
import cc.winboll.studio.contacts.utils.RegexPPiUtils;
import cc.winboll.studio.libappbase.LogUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import android.content.Context;
public class Rules { public class Rules {
public static final String TAG = "Rules"; public static final String TAG = "Rules";
ArrayList<PhoneConnectRuleModel> _PhoneConnectRuleModelList; ArrayList<PhoneBlackRuleBean> _PhoneBlacRuleBeanList;
static volatile Rules _Rules; static volatile Rules _Rules;
Context mContext; Context mContext;
SettingsModel mSettingsModel;
Timer mDunResumeTimer;
Rules(Context context) { Rules(Context context) {
mContext = context; mContext = context;
_PhoneConnectRuleModelList = new ArrayList<PhoneConnectRuleModel>(); _PhoneBlacRuleBeanList = new ArrayList<PhoneBlackRuleBean>();
reload(); PhoneBlackRuleBean.loadBeanList(mContext, _PhoneBlacRuleBeanList, PhoneBlackRuleBean.class);
}
}
public static synchronized Rules getInstance(Context context) { public static synchronized Rules getInstance(Context context) {
if (_Rules == null) { if (_Rules == null) {
_Rules = new Rules(context); _Rules = new Rules(context);
@@ -42,168 +31,46 @@ public class Rules {
return _Rules; return _Rules;
} }
public void reload() {
LogUtils.d(TAG, "reload()");
loadRules();
loadDun();
setDunResumTimer();
}
public void setDunResumTimer() {
if (mDunResumeTimer != null) {
mDunResumeTimer.cancel();
}
// 盾牌恢复定时器
mDunResumeTimer = new Timer();
int ss = IntUtils.getIntInRange(mSettingsModel.getDunResumeSecondCount() * 1000, SettingsModel.MIN_INTRANGE, SettingsModel.MAX_INTRANGE);
mDunResumeTimer.schedule(new TimerTask() {
@Override
public void run() {
if (mSettingsModel.getDunCurrentCount() != mSettingsModel.getDunTotalCount()) {
LogUtils.d(TAG, String.format("当前防御值为%d最大防御值为%d", mSettingsModel.getDunCurrentCount(), mSettingsModel.getDunTotalCount()));
int newDunCount = mSettingsModel.getDunCurrentCount() + mSettingsModel.getDunResumeCount();
// 设置盾值在[0DunTotalCount]之内其他值一律重置为 DunTotalCount。
newDunCount = (newDunCount > mSettingsModel.getDunTotalCount()) ?mSettingsModel.getDunTotalCount(): newDunCount;
mSettingsModel.setDunCurrentCount(newDunCount);
LogUtils.d(TAG, String.format("设置防御值为%d", newDunCount));
saveDun();
SettingsActivity.notifyDunInfoUpdate();
}
}
}, 1000, ss);
}
public void loadRules() {
_PhoneConnectRuleModelList.clear();
PhoneConnectRuleModel.loadBeanList(mContext, _PhoneConnectRuleModelList, PhoneConnectRuleModel.class);
}
public void saveRules() {
LogUtils.d(TAG, String.format("saveRules()"));
PhoneConnectRuleModel.saveBeanList(mContext, _PhoneConnectRuleModelList, PhoneConnectRuleModel.class);
}
public void loadDun() {
mSettingsModel = SettingsModel.loadBean(mContext, SettingsModel.class);
if (mSettingsModel == null) {
mSettingsModel = new SettingsModel();
SettingsModel.saveBean(mContext, mSettingsModel);
}
}
public void saveDun() {
LogUtils.d(TAG, String.format("saveDun()"));
SettingsModel.saveBean(mContext, mSettingsModel);
}
public boolean isAllowed(String phoneNumber) { public boolean isAllowed(String phoneNumber) {
// 没有启用云盾,默认允许接通任何电话 // 黑名单拒接
if (!mSettingsModel.isEnableDun()) { for (int i = 0; i < _PhoneBlacRuleBeanList.size(); i++) {
LogUtils.d(TAG, String.format("没有启用云盾默认允许接通任何电话。isAllowed(...) return true")); if (_PhoneBlacRuleBeanList.get(i).isEnable()) {
String regex = _PhoneBlacRuleBeanList.get(i).getRuleText();
if (Pattern.matches(regex, phoneNumber)) {
return false;
}
}
}
// 手机号码允许
// 中国手机号码正则表达式以1开头第二位可以是3、4、5、6、7、8、9后面跟9位数字
String regex = "^1[3-9]\\d{9}$";
if (Pattern.matches(regex, phoneNumber)) {
return true;
}
// 指定区号号码允许
regex = "^0660\\d+$";
if (Pattern.matches(regex, phoneNumber)) {
return true;
}
// 指定区号号码允许
regex = "^020\\d+$";
if (Pattern.matches(regex, phoneNumber)) {
return true; return true;
} }
// // 其他拒接
// 以下是云盾防御体系 return false;
boolean isDefend = false; // 盾牌是否生效
boolean isConnect = true; // 防御结果是否连接
// 如果盾值小于1则解除防御
if (!isDefend && mSettingsModel.getDunCurrentCount() < 1) {
// 盾层为1以下防御解除
LogUtils.d(TAG, "盾层为1以下防御解除");
isDefend = true;
isConnect = true;
LogUtils.d(TAG, String.format("isDefend == %s\nisConnect == %s", isDefend, isConnect));
}
// 正则运算预防针
if (!isDefend && !RegexPPiUtils.isPPiOK(phoneNumber)) {
LogUtils.d(TAG, "正则运算预防针生效。");
isDefend = true;
isConnect = false;
LogUtils.d(TAG, String.format("isDefend == %s\nisConnect == %s", isDefend, isConnect));
}
// 查询通讯录是否有该联系人
boolean isPhoneInContacts = ContactUtils.getInstance(mContext).isPhoneInContacts(mContext, phoneNumber);
if (!isDefend) {
if (isPhoneInContacts) {
LogUtils.d(TAG, String.format("Phone %s is in contacts.", phoneNumber));
isDefend = true;
isConnect = true;
LogUtils.d(TAG, String.format("isDefend == %s\nisConnect == %s", isDefend, isConnect));
} else {
LogUtils.d(TAG, String.format("Phone %s is not in contacts.", phoneNumber));
}
}
// 检验拨不通号码群
if (!isDefend && MainService.isPhoneInBoBullToon(phoneNumber)) {
LogUtils.d(TAG, String.format("PhoneNumber %s\n Is In BoBullToon", phoneNumber));
isDefend = true;
isConnect = false;
LogUtils.d(TAG, String.format("isDefend == %s\nisConnect == %s", isDefend, isConnect));
}
// 正则匹配规则名单校验
if (!isDefend) {
for (int i = 0; i < _PhoneConnectRuleModelList.size(); i++) {
if (_PhoneConnectRuleModelList.get(i).isEnable()) {
String regex = _PhoneConnectRuleModelList.get(i).getRuleText();
if (Pattern.matches(regex, phoneNumber)) {
LogUtils.d(TAG, String.format("Phone Number [%s] is matched by rule : %s", phoneNumber, _PhoneConnectRuleModelList.get(i)));
isDefend = true;
isConnect = _PhoneConnectRuleModelList.get(i).isAllowConnection();
LogUtils.d(TAG, String.format("isDefend == %s\nisConnect == %s", isDefend, isConnect));
break;
}
}
}
}
if (isConnect) {
// 如果防御结果为连接,则恢复防御盾牌最大值层数
mSettingsModel.setDunCurrentCount(mSettingsModel.getDunTotalCount());
LogUtils.d(TAG, String.format("防御结果为连接,恢复防御盾牌最大值层数 %d", mSettingsModel.getDunTotalCount()));
saveDun();
SettingsActivity.notifyDunInfoUpdate();
} else if (isDefend) {
// 如果触发了以上某个防御模块,
// 就减少防御盾牌层数。
// 每校验一次规则云盾防御层数减1
// 当云盾防御层数为0时再次进行以下程序段则恢复满值防御。
int newDunCount = mSettingsModel.getDunCurrentCount() - 1;
LogUtils.d(TAG, String.format("新的防御层数预计为 %d", newDunCount));
// 保证盾值在[0DunTotalCount]之内其他值一律重置为 DunTotalCount。
if (newDunCount < 0 || newDunCount > mSettingsModel.getDunTotalCount()) {
mSettingsModel.setDunCurrentCount(mSettingsModel.getDunTotalCount());
LogUtils.d(TAG, String.format("盾值不在[0%d]区间,恢复防御最大值%d", mSettingsModel.getDunTotalCount(), mSettingsModel.getDunTotalCount()));
} else {
mSettingsModel.setDunCurrentCount(newDunCount);
LogUtils.d(TAG, String.format("设置防御层数为 %d", newDunCount));
}
saveDun();
SettingsActivity.notifyDunInfoUpdate();
}
// 返回校验结果
LogUtils.d(TAG, String.format("返回校验结果 isConnect == %s", isConnect));
return isConnect;
} }
public void add(String szPhoneConnectRule, boolean isAllowConnection, boolean isEnable) { public void add(String phoneRuleBlack, boolean isEnable) {
_PhoneConnectRuleModelList.add(new PhoneConnectRuleModel(szPhoneConnectRule, isAllowConnection, isEnable)); _PhoneBlacRuleBeanList.add(new PhoneBlackRuleBean(phoneRuleBlack, isEnable));
PhoneBlackRuleBean.saveBeanList(mContext, _PhoneBlacRuleBeanList, PhoneBlackRuleBean.class);
} }
public ArrayList<PhoneConnectRuleModel> getPhoneBlacRuleBeanList() { public ArrayList<PhoneBlackRuleBean> getPhoneBlacRuleBeanList() {
return _PhoneConnectRuleModelList; return _PhoneBlacRuleBeanList;
}
public SettingsModel getSettingsModel() {
return mSettingsModel;
} }
} }

View File

@@ -0,0 +1,51 @@
package cc.winboll.studio.contacts.fragments;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/20 12:57:00
* @Describe 拨号
*/
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import cc.winboll.studio.contacts.R;
import cc.winboll.studio.libappbase.LogView;
import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
import android.widget.TextView;
public class CallFragment extends Fragment {
public static final String TAG = "CallFragment";
private static final String ARG_PAGE = "ARG_PAGE";
private int mPage;
public static CallFragment newInstance(int page) {
Bundle args = new Bundle();
args.putInt(ARG_PAGE, page);
CallFragment fragment = new CallFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments()!= null) {
mPage = getArguments().getInt(ARG_PAGE);
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_call, container, false);
TextView textView = view.findViewById(R.id.page_text);
textView.setText("这是第 " + mPage + "");
return view;
}
}

View File

@@ -1,164 +0,0 @@
package cc.winboll.studio.contacts.fragments;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/20 12:57:00
* @Describe 拨号
*/
import android.Manifest;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.provider.CallLog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import cc.winboll.studio.contacts.R;
import cc.winboll.studio.contacts.adapters.CallLogAdapter;
import cc.winboll.studio.contacts.beans.CallLogModel;
import com.hjq.toast.ToastUtils;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class CallLogFragment extends Fragment {
public static final String TAG = "CallFragment";
static volatile CallLogFragment _CallLogFragment;
public static final int MSG_UPDATE = 1; // 添加消息常量
private static final String ARG_PAGE = "ARG_PAGE";
private int mPage;
private static final int REQUEST_READ_CALL_LOG = 1;
private RecyclerView recyclerView;
private CallLogAdapter callLogAdapter;
private List<CallLogModel> callLogList = new ArrayList<>();
// 添加Handler
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
if (msg.what == MSG_UPDATE) {
readCallLog(); // 接收到消息时更新通话记录
}
}
};
CallLogFragment() {
super();
}
public static CallLogFragment newInstance(int page) {
Bundle args = new Bundle();
args.putInt(ARG_PAGE, page);
CallLogFragment fragment = new CallLogFragment();
fragment.setArguments(args);
_CallLogFragment = fragment;
return fragment;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_call_log, container, false);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mPage = getArguments().getInt(ARG_PAGE);
}
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
recyclerView = view.findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
callLogAdapter = new CallLogAdapter(getContext(), callLogList);
recyclerView.setAdapter(callLogAdapter);
if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(requireActivity(), new String[]{Manifest.permission.READ_CALL_LOG}, REQUEST_READ_CALL_LOG);
} else {
mHandler.sendEmptyMessage(MSG_UPDATE); // 通过Handler触发更新
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_READ_CALL_LOG) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mHandler.sendEmptyMessage(MSG_UPDATE); // 通过Handler触发更新
}
}
}
private void readCallLog() {
callLogList.clear(); // 清空原有数据
Cursor cursor = requireContext().getContentResolver().query(
CallLog.Calls.CONTENT_URI,
null,
null,
null,
CallLog.Calls.DATE + " DESC");
if (cursor != null) {
while (cursor.moveToNext()) {
String phoneNumber = cursor.getString(cursor.getColumnIndex(CallLog.Calls.NUMBER));
int callType = cursor.getInt(cursor.getColumnIndex(CallLog.Calls.TYPE));
long callDateLong = cursor.getLong(cursor.getColumnIndex(CallLog.Calls.DATE));
Date callDate = new Date(callDateLong);
String callStatus = getCallStatus(callType);
callLogList.add(new CallLogModel(phoneNumber, callStatus, callDate));
}
cursor.close();
callLogAdapter.notifyDataSetChanged();
}
}
private String getCallStatus(int callType) {
switch (callType) {
case CallLog.Calls.OUTGOING_TYPE:
return "Outgoing";
case CallLog.Calls.INCOMING_TYPE:
return "Incoming";
case CallLog.Calls.MISSED_TYPE:
return "Missed";
default:
return "Unknown";
}
}
@Override
public void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null); // 清理Handler防止内存泄漏
}
public void triggerUpdate() {
mHandler.sendEmptyMessage(MSG_UPDATE);
}
public static void updateCallLogFragment() {
if (_CallLogFragment != null) {
_CallLogFragment.triggerUpdate();
}
}
}

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