Compare commits

..

4 Commits

Author SHA1 Message Date
ZhanGSKen
03e21ab81c <mymessagemanager>APK 4.1.15 release Publish. 2025-02-25 20:51:01 +08:00
ZhanGSKen
ac72132969 添加电话号码前面有+号的检测兼容。 2025-02-25 20:50:03 +08:00
ZhanGSKen
cedb5f521b <mymessagemanager>APK 4.1.14 release Publish. 2025-02-25 20:25:31 +08:00
ZhanGSKen
396df6713c 添加单元测试模块,增加电话号码是否是数字的检测。 2025-02-25 20:19:54 +08:00
861 changed files with 46198 additions and 17779 deletions

1
.gitignore vendored
View File

@@ -96,7 +96,6 @@ local.properties
## 忽略模块应用编译配置
/settings.gradle
/gradle.properties
## 忽略 srv 纠结问题
/srv/

3
.gitmodules vendored
View File

@@ -1,3 +1,6 @@
[submodule "winboll-x"]
path = winboll-x
url = https://gitea.winboll.cc/Studio/WinBollX.git
[submodule "libjc/jcc/libs"]
path = libjc/jcc/libs
url = https://gitea.winboll.cc/Studio/APP_libjc_jcc_libs.git

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

210
LICENSE
View File

@@ -1,201 +1,73 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Copyright 2024 ZhanGSKen
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

131
README.md
View File

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

View File

@@ -19,7 +19,7 @@ def genVersionName(def versionName){
android {
compileSdkVersion 32
buildToolsVersion "32.0.0"
buildToolsVersion "33.0.3"
defaultConfig {
applicationId "cc.winboll.studio.aes"
@@ -29,7 +29,7 @@ android {
// versionName 更新后需要手动设置
// 项目模块目录的 build.gradle 文件的 stageCount=0
// Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
versionName "15.8"
versionName "7.6"
if(true) {
versionName = genVersionName("${versionName}")
}
@@ -41,9 +41,29 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
}
dependencies {
api project(':libaes')
//api 'cc.winboll.studio:winboll-shared:1.6.5'
api 'io.github.medyo:android-about-page:2.0.0'
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 'androidx.appcompat:appcompat:1.0.0'
api 'androidx.fragment:fragment:1.0.0'
api 'com.google.android.material:material:1.0.0'
api 'cc.winboll.studio:libapputils:9.2.1'
api 'cc.winboll.studio:libappbase:1.0.3'
api fileTree(dir: 'libs', include: ['*.jar'])
}

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Tue May 13 11:22:23 HKT 2025
stageCount=1
#Sun Jan 19 04:58:59 GMT 2025
stageCount=3
libraryProject=libaes
baseVersion=15.8
publishVersion=15.8.0
buildCount=0
baseBetaVersion=15.8.1
baseVersion=7.6
publishVersion=7.6.2
buildCount=4
baseBetaVersion=7.6.3

View File

@@ -8,10 +8,9 @@
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/MyAESTheme"
android:theme="@style/WinBoll.SupportThemeNoActionBar"
android:requestLegacyExternalStorage="true"
android:supportsRtl="true"
android:networkSecurityConfig="@xml/network_security_config">
android:supportsRtl="true">
<activity
android:name=".MainActivity"
@@ -31,8 +30,6 @@
android:name="android.max_aspect"
android:value="4.0"/>
<activity android:name=".AboutActivity"/>
</application>
</manifest>

View File

@@ -1,93 +0,0 @@
package cc.winboll.studio.aes;
/**
* @Author ZhanGSKen<zhangsken@188.com>
* @Date 2025/03/24 23:52:29
* @Describe AES应用介绍窗口
*/
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
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 AppCompatActivity 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 = "aes";
APPInfo appInfo = new APPInfo();
appInfo.setAppName("AES");
appInfo.setAppIcon(cc.winboll.studio.libaes.R.drawable.ic_winboll);
appInfo.setAppDescription("AES Description");
appInfo.setAppGitName("APP");
appInfo.setAppGitOwner("Studio");
appInfo.setAppGitAPPBranch(szBranchName);
appInfo.setAppGitAPPSubProjectFolder(szBranchName);
appInfo.setAppHomePage("https://www.winboll.cc/studio/details.php?app=AES");
appInfo.setAppAPKName("AES");
appInfo.setAppAPKFolderName("AES");
//appInfo.setIsAddDebugTools(false);
appInfo.setIsAddDebugTools(BuildConfig.DEBUG);
return new AboutView(mContext, appInfo);
}
}

View File

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

View File

@@ -1,197 +1,16 @@
package cc.winboll.studio.aes;
/**
* @Author ZhanGSKen<zhangsken@188.com>
* @Author ZhanGSKen@QQ.COM
* @Date 2024/06/13 19:05:52
* @Describe 应用主窗口
*/
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Toast;
import cc.winboll.studio.aes.R;
import cc.winboll.studio.libaes.activitys.DrawerFragmentActivity;
import cc.winboll.studio.libaes.beans.DrawerMenuBean;
import cc.winboll.studio.libaes.dialogs.LocalFileSelectDialog;
import cc.winboll.studio.libaes.dialogs.StoragePathDialog;
import cc.winboll.studio.libaes.unittests.SecondaryLibraryActivity;
import cc.winboll.studio.libaes.unittests.TestAButtonFragment;
import cc.winboll.studio.libaes.unittests.TestASupportToolbarActivity;
import cc.winboll.studio.libaes.unittests.TestAToolbarActivity;
import cc.winboll.studio.libaes.unittests.TestDrawerFragmentActivity;
import cc.winboll.studio.libaes.unittests.TestViewPageFragment;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity;
import com.a4455jkjh.colorpicker.ColorPickerDialog;
import com.hjq.toast.ToastUtils;
import java.util.ArrayList;
import cc.winboll.studio.libaes.unittests.LibraryActivity;
public class MainActivity extends DrawerFragmentActivity implements IWinBoLLActivity {
public static final String TAG = "MainActivity";
TestAButtonFragment mTestAButtonFragment;
TestViewPageFragment mTestViewPageFragment;
public class MainActivity extends LibraryActivity {
public static final String TAG = "MainActivity";
@Override
public Activity getActivity() {
return this;
}
@Override
public String getTag() {
return TAG;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (mTestAButtonFragment == null) {
mTestAButtonFragment = new TestAButtonFragment();
addFragment(mTestAButtonFragment);
}
showFragment(mTestAButtonFragment);
//setSubtitle(TAG);
//ToastUtils.show("onCreate");
}
@Override
public void initDrawerMenuItemList(ArrayList<DrawerMenuBean> listDrawerMenu) {
super.initDrawerMenuItemList(listDrawerMenu);
LogUtils.d(TAG, "initDrawerMenuItemList");
//listDrawerMenu.clear();
// 添加抽屉菜单项
listDrawerMenu.add(new DrawerMenuBean(R.drawable.ic_launcher, TestAButtonFragment.TAG));
listDrawerMenu.add(new DrawerMenuBean(R.drawable.ic_launcher, TestViewPageFragment.TAG));
notifyDrawerMenuDataChanged();
}
@Override
public void reinitDrawerMenuItemList(ArrayList<DrawerMenuBean> listDrawerMenu) {
super.reinitDrawerMenuItemList(listDrawerMenu);
LogUtils.d(TAG, "reinitDrawerMenuItemList");
//listDrawerMenu.clear();
// 添加抽屉菜单项
listDrawerMenu.add(new DrawerMenuBean(R.drawable.ic_launcher, TestAButtonFragment.TAG));
listDrawerMenu.add(new DrawerMenuBean(R.drawable.ic_launcher, TestViewPageFragment.TAG));
notifyDrawerMenuDataChanged();
}
@Override
public DrawerFragmentActivity.ActivityType initActivityType() {
return DrawerFragmentActivity.ActivityType.Main;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar_library, menu);
if(App.isDebuging()) {
getMenuInflater().inflate(cc.winboll.studio.libapputils.R.menu.toolbar_studio_debug, menu);
}
return super.onCreateOptionsMenu(menu);
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
super.onItemClick(parent, view, position, id);
switch (position) {
case 0 : {
if (mTestAButtonFragment == null) {
mTestAButtonFragment = new TestAButtonFragment();
addFragment(mTestAButtonFragment);
}
showFragment(mTestAButtonFragment);
break;
}
case 1 : {
if (mTestViewPageFragment == null) {
mTestViewPageFragment = new TestViewPageFragment();
addFragment(mTestViewPageFragment);
}
showFragment(mTestViewPageFragment);
break;
}
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int nItemId = item.getItemId();
// if (item.getItemId() == R.id.item_log) {
// WinBoLLActivityManager.getInstance(this).startWinBoLLActivity(getApplicationContext(), LogActivity.class);
// } else
if (nItemId == R.id.item_atoast) {
Toast.makeText(getApplication(), "item_testatoast", Toast.LENGTH_SHORT).show();
} else if (nItemId == R.id.item_atoolbar) {
Intent intent = new Intent(this, TestAToolbarActivity.class);
startActivity(intent);
} else if (nItemId == R.id.item_asupporttoolbar) {
Intent intent = new Intent(this, TestASupportToolbarActivity.class);
startActivity(intent);
} else if (nItemId == R.id.item_colordialog) {
ColorPickerDialog dlg = new ColorPickerDialog(this, getResources().getColor(R.color.colorPrimary));
dlg.setOnColorChangedListener(new com.a4455jkjh.colorpicker.view.OnColorChangedListener() {
@Override
public void beforeColorChanged() {
}
@Override
public void onColorChanged(int color) {
}
@Override
public void afterColorChanged() {
}
});
dlg.show();
} else if (nItemId == R.id.item_dialogstoragepath) {
final StoragePathDialog dialog = new StoragePathDialog(this, 0);
dialog.setOnOKClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
dialog.show();
} else if (nItemId == R.id.item_localfileselectdialog) {
final LocalFileSelectDialog dialog = new LocalFileSelectDialog(this);
dialog.setOnOKClickListener(new LocalFileSelectDialog.OKClickListener() {
@Override
public void onOKClick(String sz) {
Toast.makeText(getApplication(), sz, Toast.LENGTH_SHORT).show();
//dialog.dismiss();
}
});
dialog.open();
} else if (nItemId == R.id.item_secondarylibraryactivity) {
Intent intent = new Intent(this, SecondaryLibraryActivity.class);
startActivity(intent);
} else if (nItemId == R.id.item_drawerfragmentactivity) {
Intent intent = new Intent(this, TestDrawerFragmentActivity.class);
startActivity(intent);
}
else if (nItemId == R.id.item_about) {
Intent intent = new Intent(this, AboutActivity.class);
startActivity(intent);
return true;
}
return super.onOptionsItemSelected(item);
}
}

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#FF00B322</color>
<color name="colorPrimaryDark">#FF005C12</color>
<color name="colorAccent">#FF8DFFA2</color>
<color name="colorText">#FFFFFB8D</color>
</resources>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="MyAESTheme" parent="AESTheme">
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
</style>
</resources>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">winboll.cc</domain>
</domain-config>
</network-security-config>

View File

@@ -1 +0,0 @@
/build

View File

@@ -1,72 +0,0 @@
apply plugin: 'com.android.application'
apply from: '../.winboll/winboll_app_build.gradle'
apply from: '../.winboll/winboll_lint_build.gradle'
def genVersionName(def versionName){
// 检查编译标志位配置
assert (winbollBuildProps['stageCount'] != null)
assert (winbollBuildProps['baseVersion'] != null)
// 保存基础版本号
winbollBuildProps.setProperty("baseVersion", "${versionName}");
//保存编译标志配置
FileOutputStream fos = new FileOutputStream(winbollBuildPropsFile)
winbollBuildProps.store(fos, "${winbollBuildPropsDesc}");
fos.close();
// 返回编译版本号
return "${versionName}." + winbollBuildProps['stageCount']
}
android {
compileSdkVersion 32
buildToolsVersion "32.0.0"
defaultConfig {
applicationId "cc.winboll.studio.androiddemo"
minSdkVersion 24
targetSdkVersion 29
versionCode 1
// versionName 更新后需要手动设置
// .winboll/winbollBuildProps.properties 文件的 stageCount=0
// Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
versionName "15.0"
if(true) {
versionName = genVersionName("${versionName}")
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
api fileTree(dir: 'libs', include: ['*.jar'])
// Android 类库
//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:animated-vector-drawable:28.0.0"
}
// https://mvnrepository.com/artifact/com.android.support/support-compat
api 'com.android.support:support-compat:28.0.0' // 保留原有依赖(可选)
// https://mvnrepository.com/artifact/com.android.support/support-v4
api 'com.android.support:support-v4:28.0.0'
// https://mvnrepository.com/artifact/com.android.support/support-media-compat
api 'com.android.support:support-media-compat:28.0.0'
// https://mvnrepository.com/artifact/com.android.support/support-core-utils
api 'com.android.support:support-core-utils:28.0.0'
// https://mvnrepository.com/artifact/com.android.support/support-core-ui
api 'com.android.support:support-core-ui:28.0.0'
// https://mvnrepository.com/artifact/com.android.support/support-fragment
api 'com.android.support:support-fragment:28.0.0'
// https://mvnrepository.com/artifact/com.android.support/recyclerview-v7
api 'com.android.support:recyclerview-v7:28.0.0'
api 'cc.winboll.studio:libapputils:15.2.2'
api 'cc.winboll.studio:libappbase:15.2.2'
}

View File

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

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Android Demo +</string>
</resources>

View File

@@ -1,334 +0,0 @@
package cc.winboll.studio.androiddemo;
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.res.Resources;
import android.graphics.Typeface;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import cc.winboll.studio.libappbase.GlobalApplication;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.Thread.UncaughtExceptionHandler;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
public class App extends GlobalApplication {
private static Handler MAIN_HANDLER = new Handler(Looper.getMainLooper());
@Override
public void onCreate() {
super.onCreate();
//CrashHandler.getInstance().registerGlobal(this);
//CrashHandler.getInstance().registerPart(this);
}
public static void write(InputStream input, OutputStream output) throws IOException {
byte[] buf = new byte[1024 * 8];
int len;
while ((len = input.read(buf)) != -1) {
output.write(buf, 0, len);
}
}
public static void write(File file, byte[] data) throws IOException {
File parent = file.getParentFile();
if (parent != null && !parent.exists()) parent.mkdirs();
ByteArrayInputStream input = new ByteArrayInputStream(data);
FileOutputStream output = new FileOutputStream(file);
try {
write(input, output);
} finally {
closeIO(input, output);
}
}
public static String toString(InputStream input) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
write(input, output);
try {
return output.toString("UTF-8");
} finally {
closeIO(input, output);
}
}
public static void closeIO(Closeable... closeables) {
for (Closeable closeable : closeables) {
try {
if (closeable != null) closeable.close();
} catch (IOException ignored) {}
}
}
public static class CrashHandler {
public static final UncaughtExceptionHandler DEFAULT_UNCAUGHT_EXCEPTION_HANDLER = Thread.getDefaultUncaughtExceptionHandler();
private static CrashHandler sInstance;
private PartCrashHandler mPartCrashHandler;
public static CrashHandler getInstance() {
if (sInstance == null) {
sInstance = new CrashHandler();
}
return sInstance;
}
public void registerGlobal(Context context) {
registerGlobal(context, null);
}
public void registerGlobal(Context context, String crashDir) {
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandlerImpl(context.getApplicationContext(), crashDir));
}
public void unregister() {
Thread.setDefaultUncaughtExceptionHandler(DEFAULT_UNCAUGHT_EXCEPTION_HANDLER);
}
public void registerPart(Context context) {
unregisterPart(context);
mPartCrashHandler = new PartCrashHandler(context.getApplicationContext());
MAIN_HANDLER.postAtFrontOfQueue(mPartCrashHandler);
}
public void unregisterPart(Context context) {
if (mPartCrashHandler != null) {
mPartCrashHandler.isRunning.set(false);
mPartCrashHandler = null;
}
}
private static class PartCrashHandler implements Runnable {
private final Context mContext;
public AtomicBoolean isRunning = new AtomicBoolean(true);
public PartCrashHandler(Context context) {
this.mContext = context;
}
@Override
public void run() {
while (isRunning.get()) {
try {
Looper.loop();
} catch (final Throwable e) {
e.printStackTrace();
if (isRunning.get()) {
MAIN_HANDLER.post(new Runnable(){
@Override
public void run() {
Toast.makeText(mContext, e.toString(), Toast.LENGTH_LONG).show();
}
});
} else {
if (e instanceof RuntimeException) {
throw (RuntimeException)e;
} else {
throw new RuntimeException(e);
}
}
}
}
}
}
private static class UncaughtExceptionHandlerImpl implements UncaughtExceptionHandler {
private static DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy_MM_dd-HH_mm_ss");
private final Context mContext;
private final File mCrashDir;
public UncaughtExceptionHandlerImpl(Context context, String crashDir) {
this.mContext = context;
this.mCrashDir = TextUtils.isEmpty(crashDir) ? new File(mContext.getExternalCacheDir(), "crash") : new File(crashDir);
}
@Override
public void uncaughtException(Thread thread, Throwable throwable) {
try {
String log = buildLog(throwable);
writeLog(log);
try {
Intent intent = new Intent(mContext, CrashActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_TEXT, log);
mContext.startActivity(intent);
} catch (Throwable e) {
e.printStackTrace();
writeLog(e.toString());
}
throwable.printStackTrace();
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
} catch (Throwable e) {
if (DEFAULT_UNCAUGHT_EXCEPTION_HANDLER != null) DEFAULT_UNCAUGHT_EXCEPTION_HANDLER.uncaughtException(thread, throwable);
}
}
private String buildLog(Throwable throwable) {
String time = DATE_FORMAT.format(new Date());
String versionName = "unknown";
long versionCode = 0;
try {
PackageInfo packageInfo = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0);
versionName = packageInfo.versionName;
versionCode = Build.VERSION.SDK_INT >= 28 ? packageInfo.getLongVersionCode() : packageInfo.versionCode;
} catch (Throwable ignored) {}
LinkedHashMap<String, String> head = new LinkedHashMap<String, String>();
head.put("Time Of Crash", time);
head.put("Device", String.format("%s, %s", Build.MANUFACTURER, Build.MODEL));
head.put("Android Version", String.format("%s (%d)", Build.VERSION.RELEASE, Build.VERSION.SDK_INT));
head.put("App Version", String.format("%s (%d)", versionName, versionCode));
head.put("Kernel", getKernel());
head.put("Support Abis", Build.VERSION.SDK_INT >= 21 && Build.SUPPORTED_ABIS != null ? Arrays.toString(Build.SUPPORTED_ABIS): "unknown");
head.put("Fingerprint", Build.FINGERPRINT);
StringBuilder builder = new StringBuilder();
for (String key : head.keySet()) {
if (builder.length() != 0) builder.append("\n");
builder.append(key);
builder.append(" : ");
builder.append(head.get(key));
}
builder.append("\n\n");
builder.append(Log.getStackTraceString(throwable));
return builder.toString();
}
private void writeLog(String log) {
String time = DATE_FORMAT.format(new Date());
File file = new File(mCrashDir, "crash_" + time + ".txt");
try {
write(file, log.getBytes("UTF-8"));
} catch (Throwable e) {
e.printStackTrace();
}
}
private static String getKernel() {
try {
return App.toString(new FileInputStream("/proc/version")).trim();
} catch (Throwable e) {
return e.getMessage();
}
}
}
}
public static final class CrashActivity extends Activity {
private String mLog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(android.R.style.Theme_DeviceDefault);
setTitle("App Crash");
mLog = getIntent().getStringExtra(Intent.EXTRA_TEXT);
ScrollView contentView = new ScrollView(this);
contentView.setFillViewport(true);
HorizontalScrollView horizontalScrollView = new HorizontalScrollView(this);
TextView textView = new TextView(this);
int padding = dp2px(16);
textView.setPadding(padding, padding, padding, padding);
textView.setText(mLog);
textView.setTextIsSelectable(true);
textView.setTypeface(Typeface.DEFAULT);
textView.setLinksClickable(true);
horizontalScrollView.addView(textView);
contentView.addView(horizontalScrollView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
setContentView(contentView);
}
private void restart() {
Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName());
if (intent != null) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
finish();
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
}
private static int dp2px(float dpValue) {
final float scale = Resources.getSystem().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, android.R.id.copy, 0, android.R.string.copy)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.copy:
ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
cm.setPrimaryClip(ClipData.newPlainText(getPackageName(), mLog));
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
restart();
}
}
}

View File

@@ -1,25 +0,0 @@
package cc.winboll.studio.androiddemo;
import android.app.Activity;
import android.os.Bundle;
import cc.winboll.studio.libappbase.LogView;
public class MainActivity extends Activity {
LogView mLogView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLogView = findViewById(R.id.logview);
mLogView.start();
}
@Override
protected void onResume() {
super.onResume();
mLogView.start();
}
}

View File

@@ -1,37 +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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:gravity="center_vertical|center_horizontal"
android:layout_weight="1.0">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Android Demo"
android:textAppearance="?android:attr/textAppearanceLarge"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0">
<cc.winboll.studio.libappbase.LogView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Text"
android:id="@+id/logview"/>
</LinearLayout>
</LinearLayout>

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="@android:style/Theme.Material.Light.DarkActionBar">
<item name="android:colorPrimary">@color/colorPrimary</item>
<item name="android:colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="android:colorAccent">@color/colorAccent</item>
<item name="android:navigationBarColor">?android:colorPrimary</item>
</style>
</resources>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#009688</color>
<color name="colorPrimaryDark">#00796B</color>
<color name="colorAccent">#FF9800</color>
</resources>

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Android Demo</string>
</resources>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="@android:style/Theme.Holo.Light.DarkActionBar">
</style>
</resources>

View File

@@ -1 +0,0 @@
/build

View File

@@ -1,73 +0,0 @@
apply plugin: 'com.android.application'
apply from: '../.winboll/winboll_app_build.gradle'
apply from: '../.winboll/winboll_lint_build.gradle'
def genVersionName(def versionName){
// 检查编译标志位配置
assert (winbollBuildProps['stageCount'] != null)
assert (winbollBuildProps['baseVersion'] != null)
// 保存基础版本号
winbollBuildProps.setProperty("baseVersion", "${versionName}");
//保存编译标志配置
FileOutputStream fos = new FileOutputStream(winbollBuildPropsFile)
winbollBuildProps.store(fos, "${winbollBuildPropsDesc}");
fos.close();
// 返回编译版本号
return "${versionName}." + winbollBuildProps['stageCount']
}
android {
compileSdkVersion 32
buildToolsVersion "32.0.0"
defaultConfig {
applicationId "cc.winboll.studio.androidxdemo"
minSdkVersion 24
targetSdkVersion 29
versionCode 1
// versionName 更新后需要手动设置
// .winboll/winbollBuildProps.properties 文件的 stageCount=0
// Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
versionName "15.0"
if(true) {
versionName = genVersionName("${versionName}")
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
api fileTree(dir: 'libs', include: ['*.jar'])
// 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.journeyapps:zxing-android-embedded:3.6.0'
// 应用介绍页类库
api 'io.github.medyo:android-about-page:2.0.0'
// 吐司类库
api 'com.github.getActivity:ToastUtils:10.5'
// 网络连接类库
api 'com.squareup.okhttp3:okhttp:4.4.1'
// AndroidX 类库
api 'androidx.appcompat:appcompat:1.1.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.6'
api 'cc.winboll.studio:libapputils:15.2.2'
api 'cc.winboll.studio:libappbase:15.2.2'
}

View File

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

View File

@@ -1,21 +0,0 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

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

View File

@@ -1,37 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="cc.winboll.studio.androidxdemo">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:theme="@style/MyAppTheme"
android:resizeableActivity="true"
android:name=".App">
<activity
android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<meta-data
android:name="android.max_aspect"
android:value="4.0"/>
<activity android:name=".GlobalApplication$CrashActivity"/>
</application>
</manifest>

View File

@@ -1,345 +0,0 @@
package cc.winboll.studio.androidxdemo;
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.res.Resources;
import android.graphics.Typeface;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import cc.winboll.studio.androidxdemo.R;
import cc.winboll.studio.libappbase.GlobalApplication;
import com.hjq.toast.ToastUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.Thread.UncaughtExceptionHandler;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
public class App extends GlobalApplication {
private static Handler MAIN_HANDLER = new Handler(Looper.getMainLooper());
@Override
public void 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().registerPart(this);
}
public static void write(InputStream input, OutputStream output) throws IOException {
byte[] buf = new byte[1024 * 8];
int len;
while ((len = input.read(buf)) != -1) {
output.write(buf, 0, len);
}
}
public static void write(File file, byte[] data) throws IOException {
File parent = file.getParentFile();
if (parent != null && !parent.exists()) parent.mkdirs();
ByteArrayInputStream input = new ByteArrayInputStream(data);
FileOutputStream output = new FileOutputStream(file);
try {
write(input, output);
} finally {
closeIO(input, output);
}
}
public static String toString(InputStream input) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
write(input, output);
try {
return output.toString("UTF-8");
} finally {
closeIO(input, output);
}
}
public static void closeIO(Closeable... closeables) {
for (Closeable closeable : closeables) {
try {
if (closeable != null) closeable.close();
} catch (IOException ignored) {}
}
}
public static class CrashHandler {
public static final UncaughtExceptionHandler DEFAULT_UNCAUGHT_EXCEPTION_HANDLER = Thread.getDefaultUncaughtExceptionHandler();
private static CrashHandler sInstance;
private PartCrashHandler mPartCrashHandler;
public static CrashHandler getInstance() {
if (sInstance == null) {
sInstance = new CrashHandler();
}
return sInstance;
}
public void registerGlobal(Context context) {
registerGlobal(context, null);
}
public void registerGlobal(Context context, String crashDir) {
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandlerImpl(context.getApplicationContext(), crashDir));
}
public void unregister() {
Thread.setDefaultUncaughtExceptionHandler(DEFAULT_UNCAUGHT_EXCEPTION_HANDLER);
}
public void registerPart(Context context) {
unregisterPart(context);
mPartCrashHandler = new PartCrashHandler(context.getApplicationContext());
MAIN_HANDLER.postAtFrontOfQueue(mPartCrashHandler);
}
public void unregisterPart(Context context) {
if (mPartCrashHandler != null) {
mPartCrashHandler.isRunning.set(false);
mPartCrashHandler = null;
}
}
private static class PartCrashHandler implements Runnable {
private final Context mContext;
public AtomicBoolean isRunning = new AtomicBoolean(true);
public PartCrashHandler(Context context) {
this.mContext = context;
}
@Override
public void run() {
while (isRunning.get()) {
try {
Looper.loop();
} catch (final Throwable e) {
e.printStackTrace();
if (isRunning.get()) {
MAIN_HANDLER.post(new Runnable(){
@Override
public void run() {
Toast.makeText(mContext, e.toString(), Toast.LENGTH_LONG).show();
}
});
} else {
if (e instanceof RuntimeException) {
throw (RuntimeException)e;
} else {
throw new RuntimeException(e);
}
}
}
}
}
}
private static class UncaughtExceptionHandlerImpl implements UncaughtExceptionHandler {
private static DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy_MM_dd-HH_mm_ss");
private final Context mContext;
private final File mCrashDir;
public UncaughtExceptionHandlerImpl(Context context, String crashDir) {
this.mContext = context;
this.mCrashDir = TextUtils.isEmpty(crashDir) ? new File(mContext.getExternalCacheDir(), "crash") : new File(crashDir);
}
@Override
public void uncaughtException(Thread thread, Throwable throwable) {
try {
String log = buildLog(throwable);
writeLog(log);
try {
Intent intent = new Intent(mContext, CrashActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_TEXT, log);
mContext.startActivity(intent);
} catch (Throwable e) {
e.printStackTrace();
writeLog(e.toString());
}
throwable.printStackTrace();
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
} catch (Throwable e) {
if (DEFAULT_UNCAUGHT_EXCEPTION_HANDLER != null) DEFAULT_UNCAUGHT_EXCEPTION_HANDLER.uncaughtException(thread, throwable);
}
}
private String buildLog(Throwable throwable) {
String time = DATE_FORMAT.format(new Date());
String versionName = "unknown";
long versionCode = 0;
try {
PackageInfo packageInfo = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0);
versionName = packageInfo.versionName;
versionCode = Build.VERSION.SDK_INT >= 28 ? packageInfo.getLongVersionCode() : packageInfo.versionCode;
} catch (Throwable ignored) {}
LinkedHashMap<String, String> head = new LinkedHashMap<String, String>();
head.put("Time Of Crash", time);
head.put("Device", String.format("%s, %s", Build.MANUFACTURER, Build.MODEL));
head.put("Android Version", String.format("%s (%d)", Build.VERSION.RELEASE, Build.VERSION.SDK_INT));
head.put("App Version", String.format("%s (%d)", versionName, versionCode));
head.put("Kernel", getKernel());
head.put("Support Abis", Build.VERSION.SDK_INT >= 21 && Build.SUPPORTED_ABIS != null ? Arrays.toString(Build.SUPPORTED_ABIS): "unknown");
head.put("Fingerprint", Build.FINGERPRINT);
StringBuilder builder = new StringBuilder();
for (String key : head.keySet()) {
if (builder.length() != 0) builder.append("\n");
builder.append(key);
builder.append(" : ");
builder.append(head.get(key));
}
builder.append("\n\n");
builder.append(Log.getStackTraceString(throwable));
return builder.toString();
}
private void writeLog(String log) {
String time = DATE_FORMAT.format(new Date());
File file = new File(mCrashDir, "crash_" + time + ".txt");
try {
write(file, log.getBytes("UTF-8"));
} catch (Throwable e) {
e.printStackTrace();
}
}
private static String getKernel() {
try {
return App.toString(new FileInputStream("/proc/version")).trim();
} catch (Throwable e) {
return e.getMessage();
}
}
}
}
public static final class CrashActivity extends Activity {
private String mLog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(android.R.style.Theme_DeviceDefault);
setTitle("App Crash");
mLog = getIntent().getStringExtra(Intent.EXTRA_TEXT);
ScrollView contentView = new ScrollView(this);
contentView.setFillViewport(true);
HorizontalScrollView horizontalScrollView = new HorizontalScrollView(this);
TextView textView = new TextView(this);
int padding = dp2px(16);
textView.setPadding(padding, padding, padding, padding);
textView.setText(mLog);
textView.setTextIsSelectable(true);
textView.setTypeface(Typeface.DEFAULT);
textView.setLinksClickable(true);
horizontalScrollView.addView(textView);
contentView.addView(horizontalScrollView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
setContentView(contentView);
}
private void restart() {
Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName());
if (intent != null) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
finish();
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
}
private static int dp2px(float dpValue) {
final float scale = Resources.getSystem().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, android.R.id.copy, 0, android.R.string.copy)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.copy:
ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
cm.setPrimaryClip(ClipData.newPlainText(getPackageName(), mLog));
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
restart();
}
}
}

View File

@@ -1,31 +0,0 @@
package cc.winboll.studio.androidxdemo;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libappbase.LogView;
import com.hjq.toast.ToastUtils;
public class MainActivity extends AppCompatActivity {
LogView mLogView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar=(Toolbar)findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mLogView = findViewById(R.id.logview);
ToastUtils.show("onCreate");
}
@Override
protected void onResume() {
super.onResume();
mLogView.start();
}
}

View File

@@ -1,51 +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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0"
android:gravity="center_vertical|center_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="AndroidX Demo"
android:textAppearance="?android:attr/textAppearanceLarge"/>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0">
<cc.winboll.studio.libappbase.LogView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/logview"/>
</LinearLayout>
</LinearLayout>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#009688</color>
<color name="colorPrimaryDark">#00796B</color>
<color name="colorAccent">#FF9800</color>
</resources>

View File

@@ -1,4 +0,0 @@
<resources>
<string name="app_name">AndroidX Demo</string>
</resources>

View File

@@ -1,11 +0,0 @@
<resources>
<!-- Base application theme. -->
<style name="MyAppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>

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

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Contacts+</string>
<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,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

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

View File

@@ -4,10 +4,7 @@
<color name="colorPrimary">#FF196ABC</color>
<color name="colorPrimaryDark">#FF002B57</color>
<color name="colorAccent">#FF80BFFF</color>
<color name="blue">#FF379AFF</color>
<color name="green">#FF69E551</color>
<color name="red">#FFE55151</color>
<color name="white">#FFFFFFFF</color>
<color name="lightgray">#FFE0E0E0</color>
<color name="colorToastFrame">#FFA9A9A9</color>
<color name="colorToastShadow">#FF000000</color>
<color name="colorToastBackgroung">#FFFFFFFF</color>
</resources>

View File

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

View File

@@ -1,6 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Put flavor specific strings here -->
</resources>

View File

@@ -18,19 +18,18 @@ def genVersionName(def versionName){
}
android {
compileSdkVersion 32
buildToolsVersion "32.0.0"
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "cc.winboll.studio.appbase"
minSdkVersion 24
targetSdkVersion 30
minSdkVersion 26
targetSdkVersion 29
versionCode 1
// versionName 更新后需要手动设置
// .winboll/winbollBuildProps.properties 文件的 stageCount=0
// Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
versionName "15.7"
versionName "2.0"
if(true) {
versionName = genVersionName("${versionName}")
}
@@ -46,5 +45,5 @@ android {
dependencies {
api project(':libappbase')
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
#Sun May 11 19:36:35 GMT 2025
stageCount=7
#Tue Feb 25 16:51:17 HKT 2025
stageCount=3
libraryProject=libappbase
baseVersion=15.7
publishVersion=15.7.6
buildCount=15
baseBetaVersion=15.7.7
baseVersion=2.0
publishVersion=2.0.2
buildCount=0
baseBetaVersion=2.0.3

View File

@@ -5,18 +5,15 @@
<application
android:name=".App"
android:icon="@drawable/ic_miapp"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/MyAPPBaseTheme"
android:resizeableActivity="true"
android:process=":App">
android:theme="@style/AppTheme"
android:resizeableActivity="true">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:exported="true"
android:resizeableActivity="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation">
android:exported="true">
<intent-filter>
@@ -32,22 +29,10 @@
</activity>
<activity
android:name=".activities.NewActivity"
android:label="NewActivity"
android:exported="true"
android:resizeableActivity="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"/>
<activity android:name=".activities.New2Activity"
android:label="New2Activity"
android:exported="true"
android:resizeableActivity="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"/>
<activity android:name=".GlobalApplication$CrashActivity"/>
<service
android:name=".MyTileService"
android:exported="true"
android:label="@string/tileservice_name"
android:icon="@drawable/ic_launcher"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
@@ -64,39 +49,24 @@
android:name=".services.MainService"
android:exported="true"/>
<service
android:name="cc.winboll.studio.appbase.services.TestDemoBindService"
android:exported="true"/>
<service
android:name="cc.winboll.studio.appbase.services.TestDemoService"
android:exported="true"/>
<service android:name=".services.AssistantService"/>
<receiver android:name="cc.winboll.studio.appbase.receivers.MainReceiver"
android:exported="true">
<receiver android:name="cc.winboll.studio.appbase.receivers.MainReceiver">
<intent-filter>
<action android:name="cc.winboll.studio.appbase.receivers.MainReceiver"/>
</intent-filter>
</receiver>
<receiver
android:name=".widgets.APPNewsWidget"
android:name=".widgets.SOSWidget"
android:exported="true">
<intent-filter>
<action android:name="cc.winboll.studio.appbase.widgets.APPNewsWidget.ACTION_WAKEUP_SERVICE"/>
<action android:name="cc.winboll.studio.appbase.widgets.APPNewsWidget.ACTION_RELOAD_REPORT"/>
<action android:name="cc.winboll.studio.appbase.widgets.SOSWidget.ACTION_WAKEUP_SERVICE"/>
<action android:name="cc.winboll.studio.appbase.widgets.SOSWidget.ACTION_RELOAD_REPORT"/>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
<meta-data
@@ -105,14 +75,13 @@
</receiver>
<receiver android:name=".receivers.APPNewsWidgetClickListener"
android:exported="true">
<receiver android:name=".widgets.SOSWidgetClickListener">
<intent-filter>
<action android:name="cc.winboll.studio.appbase.receivers.APPNewsWidgetClickListener.ACTION_PRE"/>
<action android:name="cc.winboll.studio.appbase.widgets.SOSWidgetClickListener.ACTION_PRE"/>
<action android:name="cc.winboll.studio.appbase.receivers.APPNewsWidgetClickListener.ACTION_NEXT"/>
<action android:name="cc.winboll.studio.appbase.widgets.SOSWidgetClickListener.ACTION_NEXT"/>
</intent-filter>

View File

@@ -1,27 +1,27 @@
package cc.winboll.studio.appbase;
/**
* @Author ZhanGSKen<zhangsken@188.com>
* @Author ZhanGSKen@QQ.COM
* @Date 2025/01/05 09:54:42
* @Describe APPbase 应用类
*/
import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.SOSCSBroadcastReceiver;
import android.content.IntentFilter;
import cc.winboll.studio.libappbase.sos.SOSCenterServiceReceiver;
import cc.winboll.studio.libappbase.sos.SOS;
public class App extends GlobalApplication {
public static final String TAG = "App";
SOSCenterServiceReceiver mSOSCenterServiceReceiver;
SOSCSBroadcastReceiver mSOSCSBroadcastReceiver;
@Override
public void onCreate() {
super.onCreate();
mSOSCenterServiceReceiver = new SOSCenterServiceReceiver();
GlobalApplication.setIsDebuging(this, BuildConfig.DEBUG);
mSOSCSBroadcastReceiver = new SOSCSBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(SOS.ACTION_SOS);
registerReceiver(mSOSCenterServiceReceiver, intentFilter);
intentFilter.addAction(SOSCSBroadcastReceiver.ACTION_SOS);
registerReceiver(mSOSCSBroadcastReceiver, intentFilter);
}
}

View File

@@ -1,45 +1,28 @@
package cc.winboll.studio.appbase;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.CheckBox;
import android.widget.Toolbar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.appbase.R;
import cc.winboll.studio.appbase.activities.NewActivity;
import cc.winboll.studio.appbase.activities.WinBoLLActivity;
import cc.winboll.studio.appbase.services.MainService;
import cc.winboll.studio.appbase.services.TestDemoBindService;
import cc.winboll.studio.appbase.services.TestDemoService;
import cc.winboll.studio.libappbase.CrashHandler;
import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.GlobalCrashActivity;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.LogView;
import cc.winboll.studio.libappbase.sos.SOS;
import cc.winboll.studio.libappbase.utils.ToastUtils;
import cc.winboll.studio.libappbase.SOS;
import cc.winboll.studio.libappbase.SimpleOperateSignalCenterService;
import cc.winboll.studio.libappbase.bean.APPSOSBean;
import cc.winboll.studio.libappbase.services.TestService;
import cc.winboll.studio.libappbase.widgets.StatusWidget;
import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity;
import com.hjq.toast.ToastUtils;
public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
public class MainActivity extends AppCompatActivity {
public static final String TAG = "MainActivity";
@Override
public Activity getActivity() {
return this;
}
@Override
public String getTag() {
return TAG;
}
Toolbar mToolbar;
LogView mLogView;
@Override
@@ -48,26 +31,14 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
ToastUtils.show("onCreate");
setContentView(R.layout.activity_main);
mToolbar = findViewById(R.id.toolbar);
setActionBar(mToolbar);
Toolbar toolbar = findViewById(R.id.activitymainToolbar1);
setSupportActionBar(toolbar);
CheckBox cbIsDebugMode = findViewById(R.id.activitymainCheckBox1);
cbIsDebugMode.setChecked(GlobalApplication.isDebuging());
mLogView = findViewById(R.id.logview);
mLogView.start();
}
mLogView = findViewById(R.id.activitymainLogView1);
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar_main, menu);
getMenuInflater().inflate(R.menu.toolbar_appbase, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// 在switch语句中处理每个ID并在处理完后返回true未处理的情况返回false。
return super.onOptionsItemSelected(item);
if (GlobalApplication.isDebuging()) { mLogView.start(); }
}
@Override
@@ -78,16 +49,15 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
sendBroadcast(intentAPPWidget);
}
public void onSwitchDebugMode(View view) {
boolean isDebuging = ((CheckBox)view).isChecked();
GlobalApplication.setIsDebuging(isDebuging);
GlobalApplication.saveDebugStatus();
@Override
protected void onResume() {
LogUtils.d(TAG, "onResume");
super.onResume();
mLogView.start();
}
public void onPreviewGlobalCrashActivity(View view) {
Intent intent = new Intent(this, GlobalCrashActivity.class);
intent.putExtra(CrashHandler.EXTRA_CRASH_INFO, "Demo log...");
startActivity(intent);
public void onSwitchDebugMode(View view) {
GlobalApplication.setIsDebuging(this, ((CheckBox)view).isChecked());
}
public void onStartCenter(View view) {
@@ -98,17 +68,17 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
MainService.stopMainService(this);
}
public void onTestStopMainServiceWithoutSettingEnable(View view) {
LogUtils.d(TAG, "onTestStopMainServiceWithoutSettingEnable");
stopService(new Intent(this, MainService.class));
public void onTestStopWithoutSettingEnable(View view) {
LogUtils.d(TAG, "onTestStopWithoutSettingEnable");
stopService(new Intent(this, SimpleOperateSignalCenterService.class));
}
public void onTestUseComponentStartService(View view) {
LogUtils.d(TAG, "onTestUseComponentStartService");
public void onTestStartWithString(View view) {
LogUtils.d(TAG, "onTestStartWithString");
// 目标服务的包名和类名
String packageName = this.getPackageName();
String serviceClassName = TestDemoService.class.getName();
String serviceClassName = SimpleOperateSignalCenterService.class.getName();
// 构建Intent
Intent intentService = new Intent();
@@ -117,67 +87,30 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
startService(intentService);
}
public void onTestDemoServiceSOS(View view) {
Intent intent = new Intent(this, TestDemoService.class);
public void onSOS(View view) {
Intent intent = new Intent(this, TestService.class);
stopService(intent);
if (App.isDebuging()) {
SOS.sosToAppBaseBeta(this, TestDemoService.class.getName());
} else {
SOS.sosToAppBase(this, TestDemoService.class.getName());
}
SOS.sosWinBollService(this, new APPSOSBean(getPackageName(), TestService.class.getName()));
}
public void onSartTestDemoService(View view) {
Intent intent = new Intent(this, TestDemoService.class);
intent.setAction(TestDemoService.ACTION_ENABLE);
public void onStartTestService(View view) {
Intent intent = new Intent(this, TestService.class);
intent.setAction(SOS.ACTION_SERVICE_ENABLE);
startService(intent);
}
public void onStopTestDemoService(View view) {
Intent intent = new Intent(this, TestDemoService.class);
intent.setAction(TestDemoService.ACTION_DISABLE);
public void onStopTestService(View view) {
Intent intent = new Intent(this, TestService.class);
intent.setAction(SOS.ACTION_SERVICE_DISABLE);
startService(intent);
Intent intentStop = new Intent(this, TestDemoService.class);
Intent intentStop = new Intent(this, TestService.class);
stopService(intentStop);
}
public void onStopTestDemoServiceNoSettings(View view) {
Intent intent = new Intent(this, TestDemoService.class);
public void onStopTestServiceNoSettings(View view) {
Intent intent = new Intent(this, TestService.class);
stopService(intent);
}
public void onSartTestDemoBindService(View view) {
Intent intent = new Intent(this, TestDemoBindService.class);
intent.setAction(TestDemoBindService.ACTION_ENABLE);
startService(intent);
}
public void onStopTestDemoBindService(View view) {
Intent intent = new Intent(this, TestDemoBindService.class);
intent.setAction(TestDemoBindService.ACTION_DISABLE);
startService(intent);
Intent intentStop = new Intent(this, TestDemoBindService.class);
stopService(intentStop);
}
public void onStopTestDemoBindServiceNoSettings(View view) {
Intent intent = new Intent(this, TestDemoBindService.class);
stopService(intent);
}
public void onTestOpenNewActivity(View view) {
GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(this, NewActivity.class);
}
@Override
protected void onResume() {
super.onResume();
mLogView.start();
}
}

View File

@@ -1,13 +1,13 @@
package cc.winboll.studio.appbase;
/**
* @Author ZhanGSKen<zhangsken@188.com>
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/13 19:30:10
*/
import android.content.Context;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
import cc.winboll.studio.appbase.models.MainServiceBean;
import cc.winboll.studio.appbase.beans.MainServiceBean;
import cc.winboll.studio.appbase.services.MainService;
public class MyTileService extends TileService {

View File

@@ -1,82 +0,0 @@
package cc.winboll.studio.appbase.activities;
/**
* @Author ZhanGSKen<zhangsken@188.com>
* @Date 2025/03/25 11:46:40
* @Describe 测试窗口2
*/
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toolbar;
import cc.winboll.studio.appbase.R;
import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity;
public class New2Activity extends WinBoLLActivity implements IWinBoLLActivity {
public static final String TAG = "New2Activity";
Toolbar mToolbar;
//LogView mLogView;
@Override
public Activity getActivity() {
return this;
}
@Override
public String getTag() {
return TAG;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new2);
// mLogView = findViewById(R.id.logview);
// mLogView.start();
mToolbar = findViewById(R.id.toolbar);
setActionBar(mToolbar);
}
@Override
protected void onResume() {
super.onResume();
//mLogView.start();
}
public void onCloseThisActivity(View view) {
GlobalApplication.getWinBoLLActivityManager().finish(this);
}
public void onCloseAllActivity(View view) {
GlobalApplication.getWinBoLLActivityManager().finishAll();
}
public void onNewActivity(View view) {
GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(this, NewActivity.class);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar_main, menu);
getMenuInflater().inflate(R.menu.toolbar_appbase, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == cc.winboll.studio.appbase.R.id.item_log) {
//GlobalApplication.getWinBoLLActivityManager().startLogActivity(this);
return true;
}
// 在switch语句中处理每个ID并在处理完后返回true未处理的情况返回false。
return super.onOptionsItemSelected(item);
}
}

View File

@@ -1,80 +0,0 @@
package cc.winboll.studio.appbase.activities;
/**
* @Author ZhanGSKen<zhangsken@188.com>
* @Date 2025/03/25 05:04:22
*/
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toolbar;
import cc.winboll.studio.appbase.R;
import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity;
public class NewActivity extends WinBoLLActivity implements IWinBoLLActivity {
public static final String TAG = "NewActivity";
Toolbar mToolbar;
//LogView mLogView;
@Override
public Activity getActivity() {
return this;
}
@Override
public String getTag() {
return TAG;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new);
// mLogView = findViewById(R.id.logview);
// mLogView.start();
mToolbar = findViewById(R.id.toolbar);
setActionBar(mToolbar);
}
@Override
protected void onResume() {
super.onResume();
//mLogView.start();
}
public void onCloseThisActivity(View view) {
GlobalApplication.getWinBoLLActivityManager().finish(this);
}
public void onCloseAllActivity(View view) {
GlobalApplication.getWinBoLLActivityManager().finishAll();
}
public void onNew2Activity(View view) {
GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(this, New2Activity.class);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar_main, menu);
getMenuInflater().inflate(R.menu.toolbar_appbase, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == cc.winboll.studio.appbase.R.id.item_log) {
//GlobalApplication.getWinBoLLActivityManager().startLogActivity(this);
return true;
}
// 在switch语句中处理每个ID并在处理完后返回true未处理的情况返回false。
return super.onOptionsItemSelected(item);
}
}

View File

@@ -1,24 +0,0 @@
package cc.winboll.studio.appbase.activities;
/**
* @Author ZhanGSKen<zhangsken@188.com>
* @Date 2025/05/10 09:48
* @Describe WinBoLL 窗口基础类
*/
import android.app.Activity;
import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity;
public class WinBoLLActivity extends Activity implements IWinBoLLActivity {
public static final String TAG = "WinBoLLActivity";
@Override
public Activity getActivity() {
return this;
}
@Override
public String getTag() {
return TAG;
}
}

View File

@@ -1,7 +1,7 @@
package cc.winboll.studio.contacts.beans;
package cc.winboll.studio.appbase.beans;
/**
* @Author ZhanGSKen<zhangsken@188.com>
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/13 07:06:13
*/
import android.util.JsonReader;

View File

@@ -1,7 +1,7 @@
package cc.winboll.studio.appbase.models;
package cc.winboll.studio.appbase.beans;
/**
* @Author ZhanGSKen<zhangsken@188.com>
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/17 10:05:09
* @Describe APPSOSReportBean
*/
@@ -10,45 +10,45 @@ import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException;
public class WinBollNewsBean extends BaseBean {
public class SOSReportBean extends BaseBean {
public static final String TAG = "WinBollNewsBean";
public static final String TAG = "APPSOSReportBean";
protected String message;
protected String sosReport;
public WinBollNewsBean() {
this.message = "";
public SOSReportBean() {
this.sosReport = "";
}
public WinBollNewsBean(String message) {
this.message = message;
public SOSReportBean(String sosReport) {
this.sosReport = sosReport;
}
public void setMessage(String message) {
this.message = message;
public void setSosReport(String sosReport) {
this.sosReport = sosReport;
}
public String getMessage() {
return message;
public String getSosReport() {
return sosReport;
}
@Override
public String getName() {
return WinBollNewsBean.class.getName();
return SOSReportBean.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
jsonWriter.name("message").value(getMessage());
jsonWriter.name("sosReport").value(getSosReport());
}
@Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
if (name.equals("message")) {
setMessage(jsonReader.nextString());
if (name.equals("sosReport")) {
setSosReport(jsonReader.nextString());
} else {
return false;
}

View File

@@ -1,7 +1,7 @@
package cc.winboll.studio.appbase.handlers;
/**
* @Author ZhanGSKen<zhangsken@188.com>
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/14 03:51:40
*/
import android.os.Handler;

View File

@@ -1,67 +0,0 @@
package cc.winboll.studio.appbase.models;
/**
* @Author ZhanGSKen<zhangsken@188.com>
* @Date 2025/02/13 07:06:13
*/
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException;
public class MainServiceBean extends BaseBean {
public static final String TAG = "MainServiceBean";
boolean isEnable;
public MainServiceBean() {
this.isEnable = false;
}
public void setIsEnable(boolean isEnable) {
this.isEnable = isEnable;
}
public boolean isEnable() {
return isEnable;
}
@Override
public String getName() {
return MainServiceBean.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
jsonWriter.name("isEnable").value(isEnable());
}
@Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
if (name.equals("isEnable")) {
setIsEnable(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,27 +1,24 @@
package cc.winboll.studio.appbase.receivers;
/**
* @Author ZhanGSKen<zhangsken@188.com>
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/13 06:58:04
* @Describe 主要广播接收器
*/
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import cc.winboll.studio.appbase.beans.SOSReportBean;
import cc.winboll.studio.appbase.services.MainService;
import cc.winboll.studio.appbase.widgets.APPNewsWidget;
import cc.winboll.studio.appbase.widgets.SOSWidget;
import cc.winboll.studio.libappbase.AppUtils;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.models.APPModel;
import cc.winboll.studio.libappbase.models.WinBoLLModel;
import cc.winboll.studio.libappbase.models.WinBoLLNewsBean;
import cc.winboll.studio.libappbase.sos.SOS;
import cc.winboll.studio.libappbase.sos.SOSObject;
import cc.winboll.studio.libappbase.utils.ToastUtils;
import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity;
import cc.winboll.studio.libappbase.winboll.WinBoLL;
import cc.winboll.studio.libappbase.SOS;
import cc.winboll.studio.libappbase.bean.APPSOSBean;
import com.hjq.toast.ToastUtils;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
@@ -30,10 +27,12 @@ import java.util.Date;
public class MainReceiver extends BroadcastReceiver {
public static final String TAG = "MainReceiver";
public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
WeakReference<MainService> mwrService;
// 存储电量指示值,
// 用于校验电量消息时的电量变化
static volatile int _mnTheQuantityOfElectricityOld = -1;
static volatile boolean _mIsCharging = false;
public MainReceiver(MainService service) {
mwrService = new WeakReference<MainService>(service);
@@ -44,62 +43,74 @@ public class MainReceiver extends BroadcastReceiver {
String szAction = intent.getAction();
if (szAction.equals(ACTION_BOOT_COMPLETED)) {
ToastUtils.show("ACTION_BOOT_COMPLETED");
} else if (szAction.equals(IWinBoLLActivity.ACTION_BIND)) {
} else if (szAction.equals(SOS.ACTION_BIND)) {
LogUtils.d(TAG, "ACTION_BIND");
LogUtils.d(TAG, String.format("context.getPackageName() %s", context.getPackageName()));
LogUtils.d(TAG, String.format("intent.getAction() %s", intent.getAction()));
String szWinBoLLModel = intent.getStringExtra(WinBoLL.EXTRA_WINBOLLMODEL);
LogUtils.d(TAG, String.format("szAPPModel %s", szWinBoLLModel));
if (szWinBoLLModel != null && !szWinBoLLModel.equals("")) {
try {
WinBoLLModel bean = WinBoLLModel.parseStringToBean(szWinBoLLModel, WinBoLLModel.class);
if (bean != null) {
String szAppPackageName = bean.getAppPackageName();
LogUtils.d(TAG, String.format("szAppPackageName %s", szAppPackageName));
String szAppMainServiveName = bean.getAppMainServiveName();
LogUtils.d(TAG, String.format("szAppMainServiveName %s", szAppMainServiveName));
mwrService.get().bindWinBoLLModelConnection(bean);
String SOS = intent.getStringExtra("SOS");
LogUtils.d(TAG, String.format("SOS %s", SOS));
if (SOS != null && SOS.equals("Service")) {
String szAPPSOSBean = intent.getStringExtra("APPSOSBean");
LogUtils.d(TAG, String.format("szAPPSOSBean %s", szAPPSOSBean));
if (szAPPSOSBean != null && !szAPPSOSBean.equals("")) {
try {
APPSOSBean bean = APPSOSBean.parseStringToBean(szAPPSOSBean, APPSOSBean.class);
if (bean != null) {
String sosPackage = bean.getSosPackage();
LogUtils.d(TAG, String.format("sosPackage %s", sosPackage));
String sosClassName = bean.getSosClassName();
LogUtils.d(TAG, String.format("sosClassName %s", sosClassName));
mwrService.get().bindSOSConnection(bean);
}
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
}
} else if (intent.getAction().equals(SOS.ACTION_SOS)) {
LogUtils.d(TAG, "ACTION_SOS");
String sos = intent.getStringExtra(SOS.EXTRA_OBJECT);
LogUtils.d(TAG, String.format("SOS %s", sos));
if (sos != null && !sos.equals("")) {
SOSObject bean = SOS.parseSOSObject(sos);
if (bean != null) {
String szObjectPackageName = bean.getObjectPackageName();
LogUtils.d(TAG, String.format("szObjectPackageName %s", szObjectPackageName));
String szObjectServiveName = bean.getObjectServiveName();
LogUtils.d(TAG, String.format("szObjectServiveName %s", szObjectServiveName));
LogUtils.d(TAG, String.format("context.getPackageName() %s", context.getPackageName()));
LogUtils.d(TAG, String.format("intent.getAction() %s", intent.getAction()));
String SOS = intent.getStringExtra("SOS");
LogUtils.d(TAG, String.format("SOS %s", SOS));
if (SOS != null && SOS.equals("Service")) {
String szAPPSOSBean = intent.getStringExtra("APPSOSBean");
LogUtils.d(TAG, String.format("szAPPSOSBean %s", szAPPSOSBean));
if (szAPPSOSBean != null && !szAPPSOSBean.equals("")) {
try {
APPSOSBean bean = APPSOSBean.parseStringToBean(szAPPSOSBean, APPSOSBean.class);
if (bean != null) {
String sosPackage = bean.getSosPackage();
LogUtils.d(TAG, String.format("sosPackage %s", sosPackage));
String sosClassName = bean.getSosClassName();
LogUtils.d(TAG, String.format("sosClassName %s", sosClassName));
Intent intentService = new Intent();
intentService.setComponent(new ComponentName(szObjectPackageName, szObjectServiveName));
context.startService(intentService);
Intent intentService = new Intent();
intentService.setComponent(new ComponentName(sosPackage, sosClassName));
context.startService(intentService);
String appName = AppUtils.getAppNameByPackageName(context, szObjectPackageName);
LogUtils.d(TAG, String.format("appName %s", appName));
WinBoLLNewsBean appWinBoLLNewsBean = new WinBoLLNewsBean(appName);
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
String currentTime = sdf.format(new Date());
StringBuilder sbLine = new StringBuilder();
sbLine.append("[");
sbLine.append(currentTime);
sbLine.append("] Power to ");
sbLine.append(appName);
appWinBoLLNewsBean.setMessage(sbLine.toString());
String appName = AppUtils.getAppNameByPackageName(context, sosPackage);
LogUtils.d(TAG, String.format("appName %s", appName));
SOSReportBean appSOSReportBean = new SOSReportBean(appName);
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
String currentTime = sdf.format(new Date());
StringBuilder sbLine = new StringBuilder();
sbLine.append("[");
sbLine.append(currentTime);
sbLine.append("] Power to ");
sbLine.append(appName);
appSOSReportBean.setSosReport(sbLine.toString());
APPNewsWidget.addWinBoLLNewsBean(context, appWinBoLLNewsBean);
Intent intentWidget = new Intent(context, APPNewsWidget.class);
intentWidget.setAction(APPNewsWidget.ACTION_RELOAD_REPORT);
context.sendBroadcast(intentWidget);
SOSWidget.addAPPSOSReportBean(context, appSOSReportBean);
Intent intentWidget = new Intent(context, SOSWidget.class);
intentWidget.setAction(SOSWidget.ACTION_RELOAD_REPORT);
context.sendBroadcast(intentWidget);
}
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
}
}
} else {
ToastUtils.show(szAction);
@@ -112,7 +123,9 @@ public class MainReceiver extends BroadcastReceiver {
IntentFilter filter=new IntentFilter();
filter.addAction(ACTION_BOOT_COMPLETED);
filter.addAction(SOS.ACTION_SOS);
filter.addAction(WinBoLL.ACTION_BIND);
filter.addAction(SOS.ACTION_BIND);
filter.addAction(SOS.ACTION_SERVICE_ENABLE);
filter.addAction(SOS.ACTION_SERVICE_DISABLE);
//filter.addAction(Intent.ACTION_BATTERY_CHANGED);
service.registerReceiver(this, filter);
}

View File

@@ -1,7 +1,7 @@
package cc.winboll.studio.appbase.services;
/**
* @Author ZhanGSKen<zhangsken@188.com>
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/14 03:38:31
* @Describe 守护进程服务
*/
@@ -11,7 +11,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import cc.winboll.studio.appbase.models.MainServiceBean;
import cc.winboll.studio.appbase.beans.MainServiceBean;
import cc.winboll.studio.appbase.services.AssistantService;
import cc.winboll.studio.appbase.services.MainService;
import cc.winboll.studio.libappbase.LogUtils;

View File

@@ -1,7 +1,7 @@
package cc.winboll.studio.appbase.services;
/**
* @Author ZhanGSKen<zhangsken@188.com>
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/13 06:56:41
* @Describe 拨号主服务
* 参考:
@@ -18,15 +18,14 @@ import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import cc.winboll.studio.appbase.MyTileService;
import cc.winboll.studio.appbase.beans.MainServiceBean;
import cc.winboll.studio.appbase.handlers.MainServiceHandler;
import cc.winboll.studio.appbase.models.MainServiceBean;
import cc.winboll.studio.appbase.receivers.MainReceiver;
import cc.winboll.studio.appbase.services.AssistantService;
import cc.winboll.studio.appbase.threads.MainServiceThread;
import cc.winboll.studio.appbase.widgets.APPNewsWidget;
import cc.winboll.studio.appbase.widgets.SOSWidget;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.models.APPModel;
import cc.winboll.studio.libappbase.models.WinBoLLModel;
import cc.winboll.studio.libappbase.bean.APPSOSBean;
import java.util.ArrayList;
public class MainService extends Service {
@@ -46,7 +45,7 @@ public class MainService extends Service {
AssistantService mAssistantService;
boolean isBound = false;
MainReceiver mMainReceiver;
ArrayList<APPConnection> mAPPModelConnectionList;
ArrayList<SOSConnection> mSOSConnectionList;
@Override
public IBinder onBind(Intent intent) {
@@ -61,7 +60,7 @@ public class MainService extends Service {
public void onCreate() {
super.onCreate();
LogUtils.d(TAG, "onCreate()");
mAPPModelConnectionList = new ArrayList<APPConnection>();
mSOSConnectionList = new ArrayList<SOSConnection>();
_mControlCenterService = MainService.this;
isServiceRunning = false;
@@ -102,8 +101,8 @@ public class MainService extends Service {
}
// 启动小部件
Intent intentTimeWidget = new Intent(this, APPNewsWidget.class);
intentTimeWidget.setAction(APPNewsWidget.ACTION_RELOAD_REPORT);
Intent intentTimeWidget = new Intent(this, SOSWidget.class);
intentTimeWidget.setAction(SOSWidget.ACTION_RELOAD_REPORT);
this.sendBroadcast(intentTimeWidget);
startMainServiceThread();
@@ -118,11 +117,21 @@ public class MainService extends Service {
//
void wakeupAndBindAssistant() {
LogUtils.d(TAG, "wakeupAndBindAssistant()");
// if (ServiceUtils.isServiceAlive(getApplicationContext(), AssistantService.class.getName()) == false) {
// startService(new Intent(MainService.this, AssistantService.class));
// //LogUtils.d(TAG, "call wakeupAndBindAssistant() : Binding... AssistantService");
// bindService(new Intent(MainService.this, AssistantService.class), mMyServiceConnection, Context.BIND_IMPORTANT);
// }
Intent intent = new Intent(this, AssistantService.class);
startService(intent);
// 绑定服务的Intent
//Intent intent = new Intent(this, AssistantService.class);
bindService(intent, mMyServiceConnection, Context.BIND_IMPORTANT);
// Intent intent = new Intent(this, AssistantService.class);
// startService(intent);
// LogUtils.d(TAG, "startService(intent)");
// bindService(new Intent(this, AssistantService.class), mMyServiceConnection, Context.BIND_IMPORTANT);
}
// 开启提醒铃声线程
@@ -183,40 +192,40 @@ public class MainService extends Service {
}
}
public void bindWinBoLLModelConnection(WinBoLLModel bean) {
LogUtils.d(TAG, "bindAPPModelConnection(...)");
public void bindSOSConnection(APPSOSBean bean) {
LogUtils.d(TAG, "bindSOSConnection(...)");
// 清理旧的绑定链接
for (int i = mAPPModelConnectionList.size() - 1; i > -1; i--) {
APPConnection item = mAPPModelConnectionList.get(i);
if (item.isBindToAPP(bean)) {
for (int i = mSOSConnectionList.size() - 1; i > -1; i--) {
SOSConnection item = mSOSConnectionList.get(i);
if (item.isBindToAPPSOSBean(bean)) {
LogUtils.d(TAG, "Bind Servive exist.");
unbindService(item);
mAPPModelConnectionList.remove(i);
mSOSConnectionList.remove(i);
}
}
// 绑定服务
APPConnection appConnection = new APPConnection();
SOSConnection sosConnection = new SOSConnection();
Intent intentService = new Intent();
intentService.setComponent(new ComponentName(bean.getAppPackageName(), bean.getAppMainServiveName()));
bindService(intentService, appConnection, Context.BIND_IMPORTANT);
mAPPModelConnectionList.add(appConnection);
intentService.setComponent(new ComponentName(bean.getSosPackage(), bean.getSosClassName()));
bindService(intentService, sosConnection, Context.BIND_IMPORTANT);
mSOSConnectionList.add(sosConnection);
Intent intentWidget = new Intent(this, APPNewsWidget.class);
intentWidget.setAction(APPNewsWidget.ACTION_WAKEUP_SERVICE);
WinBoLLModel appSOSBean = new WinBoLLModel(bean.getAppPackageName(), bean.getAppMainServiveName());
Intent intentWidget = new Intent(this, SOSWidget.class);
intentWidget.setAction(SOSWidget.ACTION_WAKEUP_SERVICE);
APPSOSBean appSOSBean = new APPSOSBean(bean.getSosPackage(), bean.getSosClassName());
intentWidget.putExtra("APPSOSBean", appSOSBean.toString());
sendBroadcast(intentWidget);
}
public class APPConnection implements ServiceConnection {
public class SOSConnection implements ServiceConnection {
ComponentName mComponentName;
boolean isBindToAPP(WinBoLLModel bean) {
boolean isBindToAPPSOSBean(APPSOSBean bean) {
return mComponentName != null
&& mComponentName.getClassName().equals(bean.getAppMainServiveName())
&& mComponentName.getPackageName().equals(bean.getAppPackageName());
&& mComponentName.getClassName().equals(bean.getSosClassName())
&& mComponentName.getPackageName().equals(bean.getSosPackage());
}
@Override
@@ -232,13 +241,13 @@ public class MainService extends Service {
LogUtils.d(TAG, String.format("onServiceDisconnected : \ngetClassName %s\ngetPackageName %s", name.getClassName(), name.getPackageName()));
// 尝试无参数启动一下服务
String appPackage = mComponentName.getPackageName();
LogUtils.d(TAG, String.format("appPackage %s", appPackage));
String appMainServiceClassName = mComponentName.getClassName();
LogUtils.d(TAG, String.format("appMainServiceClassName %s", appMainServiceClassName));
String sosPackage = mComponentName.getPackageName();
LogUtils.d(TAG, String.format("sosPackage %s", sosPackage));
String sosClassName = mComponentName.getClassName();
LogUtils.d(TAG, String.format("sosClassName %s", sosClassName));
Intent intentService = new Intent();
intentService.setComponent(new ComponentName(appPackage, appMainServiceClassName));
intentService.setComponent(new ComponentName(sosPackage, sosClassName));
startService(intentService);
}

View File

@@ -1,179 +0,0 @@
package cc.winboll.studio.appbase.services;
/**
* @Author ZhanGSKen<zhangsken@188.com>
* @Date 2025/03/07 12:45:49
* @Describe 启动时申请绑定到APPBase主服务的服务示例
*/
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import cc.winboll.studio.appbase.App;
import cc.winboll.studio.appbase.models.TestDemoBindServiceBean;
import cc.winboll.studio.appbase.services.TestDemoBindService;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.sos.SOS;
import cc.winboll.studio.libappbase.winboll.WinBoLL;
public class TestDemoBindService extends Service {
public static final String TAG = "TestDemoBindService";
public static final String ACTION_ENABLE = TestDemoBindService.class.getName() + ".ACTION_ENABLE";
public static final String ACTION_DISABLE = TestDemoBindService.class.getName() + ".ACTION_DISABLE";
volatile static TestThread _TestThread;
volatile static boolean _IsRunning;
public synchronized static void setIsRunning(boolean isRunning) {
_IsRunning = isRunning;
}
public static boolean isRunning() {
return _IsRunning;
}
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
public class MyBinder extends Binder {
public TestDemoBindService getService() {
return TestDemoBindService.this;
}
}
@Override
public void onCreate() {
super.onCreate();
LogUtils.d(TAG, "onCreate()");
run();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
LogUtils.d(TAG, "onStartCommand(...)");
TestDemoBindServiceBean bean = TestDemoBindServiceBean.loadBean(this, TestDemoBindServiceBean.class);
if (bean == null) {
bean = new TestDemoBindServiceBean();
}
if (intent.getAction() != null) {
if (intent.getAction().equals(ACTION_ENABLE)) {
bean.setIsEnable(true);
LogUtils.d(TAG, "setIsEnable(true);");
TestDemoBindServiceBean.saveBean(this, bean);
} else if (intent.getAction().equals(ACTION_DISABLE)) {
bean.setIsEnable(false);
LogUtils.d(TAG, "setIsEnable(false);");
TestDemoBindServiceBean.saveBean(this, bean);
}
}
run();
return (bean.isEnable()) ? START_STICKY : super.onStartCommand(intent, flags, startId);
//return super.onStartCommand(intent, flags, startId);
}
void run() {
LogUtils.d(TAG, "run()");
TestDemoBindServiceBean bean = TestDemoBindServiceBean.loadBean(this, TestDemoBindServiceBean.class);
if (bean == null) {
bean = new TestDemoBindServiceBean();
TestDemoBindServiceBean.saveBean(this, bean);
}
if (bean.isEnable()) {
LogUtils.d(TAG, "run() bean.isEnable()");
TestThread.getInstance(this).start();
LogUtils.d(TAG, "_TestThread.start()");
}
}
@Override
public void onDestroy() {
super.onDestroy();
LogUtils.d(TAG, "onDestroy()");
TestDemoBindServiceBean bean = TestDemoBindServiceBean.loadBean(this, TestDemoBindServiceBean.class);
if (bean == null) {
bean = new TestDemoBindServiceBean();
}
TestThread.getInstance(this).setIsExit(true);
// 预防 APPBase 应用重启绑定失效。
// 所以退出时检查本服务是否配置启用,如果启用就发送一个 SOS 信号。
// 这样 APPBase 就会用组件方式启动本服务。
if (bean.isEnable()) {
if (App.isDebuging()) {
SOS.sosToAppBaseBeta(this, TestDemoBindService.class.getName());
} else {
SOS.sosToAppBase(this, TestDemoBindService.class.getName());
}
}
_IsRunning = false;
}
static class TestThread extends Thread {
volatile static TestThread _TestThread;
Context mContext;
volatile boolean isStarted = false;
volatile boolean isExit = false;
TestThread(Context context) {
super();
mContext = context;
}
public static synchronized TestThread getInstance(Context context) {
if (_TestThread != null) {
_TestThread.setIsExit(true);
}
_TestThread = new TestThread(context);
return _TestThread;
}
public synchronized void setIsExit(boolean isExit) {
this.isExit = isExit;
}
public boolean isExit() {
return isExit;
}
@Override
public void run() {
if (isStarted == false) {
isStarted = true;
super.run();
LogUtils.d(TAG, "run() start");
if (App.isDebuging()) {
WinBoLL.bindToAPPBaseBeta(mContext, TestDemoBindService.class.getName());
} else {
WinBoLL.bindToAPPBase(mContext, TestDemoBindService.class.getName());
}
while (!isExit()) {
LogUtils.d(TAG, "run()");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
}
LogUtils.d(TAG, "run() exit");
}
}
}
}

View File

@@ -1,7 +1,7 @@
package cc.winboll.studio.appbase.threads;
/**
* @Author ZhanGSKen<zhangsken@188.com>
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/14 03:46:44
*/
import android.content.Context;

View File

@@ -1,187 +0,0 @@
package cc.winboll.studio.appbase.widgets;
/**
* @Author ZhanGSKen<zhangsken@188.com>
* @Date 2025/02/15 14:41:25
* @Describe TimeWidget
*/
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.widget.RemoteViews;
import cc.winboll.studio.appbase.R;
import cc.winboll.studio.appbase.receivers.APPNewsWidgetClickListener;
import cc.winboll.studio.libappbase.AppUtils;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.models.APPModel;
import cc.winboll.studio.libappbase.models.WinBoLLNewsBean;
import cc.winboll.studio.libappbase.winboll.WinBoLL;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import cc.winboll.studio.libappbase.models.WinBoLLModel;
public class APPNewsWidget extends AppWidgetProvider {
public static final String TAG = "APPNewsWidget";
public static final String ACTION_WAKEUP_SERVICE = APPNewsWidget.class.getName() + ".ACTION_WAKEUP_SERVICE";
public static final String ACTION_RELOAD_REPORT = APPNewsWidget.class.getName() + ".ACTION_RELOAD_REPORT";
volatile static ArrayList<WinBoLLNewsBean> _WinBoLLNewsBeanList;
final static int _MAX_PAGES = 10;
final static int _OnePageLinesCount = 5;
volatile static int _CurrentPageIndex = 0;
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
initWinBoLLNewsBeanList(context);
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
initWinBoLLNewsBeanList(context);
if (intent.getAction().equals(ACTION_RELOAD_REPORT)) {
LogUtils.d(TAG, "ACTION_RELOAD_REPORT");
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, APPNewsWidget.class));
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}else if (intent.getAction().equals(ACTION_WAKEUP_SERVICE)) {
LogUtils.d(TAG, "ACTION_WAKEUP_SERVICE");
String szWinBoLLModel = intent.getStringExtra(WinBoLL.EXTRA_WINBOLLMODEL);
LogUtils.d(TAG, String.format("szWinBoLLModel %s", szWinBoLLModel));
if (szWinBoLLModel != null && !szWinBoLLModel.equals("")) {
try {
WinBoLLModel bean = WinBoLLModel.parseStringToBean(szWinBoLLModel, WinBoLLModel.class);
if (bean != null) {
String szAppPackageName = bean.getAppPackageName();
LogUtils.d(TAG, String.format("szAppPackageName %s", szAppPackageName));
String szAppMainServiveName = bean.getAppMainServiveName();
LogUtils.d(TAG, String.format("szAppMainServiveName %s", szAppMainServiveName));
String appName = AppUtils.getAppNameByPackageName(context, szAppPackageName);
LogUtils.d(TAG, String.format("appName %s", appName));
WinBoLLNewsBean winBollNewsBean = new WinBoLLNewsBean(appName);
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
String currentTime = sdf.format(new Date());
StringBuilder sbLine = new StringBuilder();
sbLine.append("[");
sbLine.append(currentTime);
sbLine.append("] Wake up ");
sbLine.append(appName);
winBollNewsBean.setMessage(sbLine.toString());
addWinBoLLNewsBean(context, winBollNewsBean);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, APPNewsWidget.class));
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
}
}
}
//
// 加入新报告信息
//
public synchronized static void addWinBoLLNewsBean(Context context, WinBoLLNewsBean bean) {
initWinBoLLNewsBeanList(context);
_WinBoLLNewsBeanList.add(0, bean);
// 控制记录总数
while (_WinBoLLNewsBeanList.size() > _MAX_PAGES * _OnePageLinesCount) {
_WinBoLLNewsBeanList.remove(_WinBoLLNewsBeanList.size() - 1);
}
WinBoLLNewsBean.saveBeanList(context, _WinBoLLNewsBeanList, WinBoLLNewsBean.class);
}
synchronized static void initWinBoLLNewsBeanList(Context context) {
if (_WinBoLLNewsBeanList == null) {
_WinBoLLNewsBeanList = new ArrayList<WinBoLLNewsBean>();
WinBoLLNewsBean.loadBeanList(context, _WinBoLLNewsBeanList, WinBoLLNewsBean.class);
}
if (_WinBoLLNewsBeanList == null) {
_WinBoLLNewsBeanList = new ArrayList<WinBoLLNewsBean>();
WinBoLLNewsBean.saveBeanList(context, _WinBoLLNewsBeanList, WinBoLLNewsBean.class);
}
}
private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
LogUtils.d(TAG, "updateAppWidget(...)");
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_news);
//设置按钮点击事件
Intent intentPre = new Intent(context, APPNewsWidgetClickListener.class);
intentPre.setAction(APPNewsWidgetClickListener.ACTION_PRE);
PendingIntent pendingIntentPre = PendingIntent.getBroadcast(context, 0, intentPre, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.widget_button_pre, pendingIntentPre);
Intent intentNext = new Intent(context, APPNewsWidgetClickListener.class);
intentNext.setAction(APPNewsWidgetClickListener.ACTION_NEXT);
PendingIntent pendingIntentNext = PendingIntent.getBroadcast(context, 0, intentNext, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.widget_button_next, pendingIntentNext);
views.setTextViewText(R.id.tv_msg, getPageInfo());
views.setTextViewText(R.id.tv_news, getMessage());
appWidgetManager.updateAppWidget(appWidgetId, views);
}
public static String getMessage() {
ArrayList<String> msgTemp = new ArrayList<String>();
if (_WinBoLLNewsBeanList != null) {
int start = _OnePageLinesCount * _CurrentPageIndex;
start = _WinBoLLNewsBeanList.size() > start ? start : _WinBoLLNewsBeanList.size() - 1;
for (int i = start, j = 0; i < _WinBoLLNewsBeanList.size() && j < _OnePageLinesCount && start > -1; i++, j++) {
msgTemp.add(_WinBoLLNewsBeanList.get(i).getMessage());
}
String message = String.join("\n", msgTemp);
return message;
}
return "";
}
public static void prePage(Context context) {
if (_WinBoLLNewsBeanList != null) {
if (_CurrentPageIndex > 0) {
_CurrentPageIndex = _CurrentPageIndex - 1;
}
Intent intentWidget = new Intent(context, APPNewsWidget.class);
intentWidget.setAction(APPNewsWidget.ACTION_RELOAD_REPORT);
context.sendBroadcast(intentWidget);
}
}
public static void nextPage(Context context) {
if (_WinBoLLNewsBeanList != null) {
if ((_CurrentPageIndex + 1) * _OnePageLinesCount < _WinBoLLNewsBeanList.size()) {
_CurrentPageIndex = _CurrentPageIndex + 1;
}
Intent intentWidget = new Intent(context, APPNewsWidget.class);
intentWidget.setAction(APPNewsWidget.ACTION_RELOAD_REPORT);
context.sendBroadcast(intentWidget);
}
}
String getPageInfo() {
if (_WinBoLLNewsBeanList == null) {
return "0/0";
}
int leftCount = _WinBoLLNewsBeanList.size() % _OnePageLinesCount;
int currentPageCount = _WinBoLLNewsBeanList.size() / _OnePageLinesCount + (leftCount == 0 ?0: 1);
return String.format("%d/%d", _CurrentPageIndex + 1, currentPageCount);
}
}

View File

@@ -1,6 +1,6 @@
package cc.winboll.studio.appbase.widgets;
/**
* @Author ZhanGSKen<zhangsken@188.com>
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/15 14:41:25
* @Describe TimeWidget
*/
@@ -12,33 +12,31 @@ import android.content.Context;
import android.content.Intent;
import android.widget.RemoteViews;
import cc.winboll.studio.appbase.R;
import cc.winboll.studio.appbase.models.WinBollNewsBean;
import cc.winboll.studio.appbase.receivers.APPNewsWidgetClickListener;
import cc.winboll.studio.appbase.beans.SOSReportBean;
import cc.winboll.studio.libappbase.AppUtils;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.sos.APPModel;
import cc.winboll.studio.libappbase.sos.WinBoll;
import cc.winboll.studio.libappbase.bean.APPSOSBean;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
public class APPNewsWidget extends AppWidgetProvider {
public class SOSWidget extends AppWidgetProvider {
public static final String TAG = "APPNewsWidget";
public static final String TAG = "SOSWidget";
public static final String ACTION_WAKEUP_SERVICE = APPNewsWidget.class.getName() + ".ACTION_WAKEUP_SERVICE";
public static final String ACTION_RELOAD_REPORT = APPNewsWidget.class.getName() + ".ACTION_RELOAD_REPORT";
public static final String ACTION_WAKEUP_SERVICE = "cc.winboll.studio.appbase.widgets.SOSWidget.ACTION_WAKEUP_SERVICE";
public static final String ACTION_RELOAD_REPORT = "cc.winboll.studio.appbase.widgets.SOSWidget.ACTION_RELOAD_REPORT";
volatile static ArrayList<WinBollNewsBean> _WinBollNewsBeanList;
volatile static ArrayList<SOSReportBean> _SOSReportBeanList;
final static int _MAX_PAGES = 10;
final static int _OnePageLinesCount = 5;
volatile static int _CurrentPageIndex = 0;
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
initWinBollNewsBeanList(context);
initAPPSOSReportBeanList(context);
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
@@ -47,31 +45,31 @@ public class APPNewsWidget extends AppWidgetProvider {
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
initWinBollNewsBeanList(context);
initAPPSOSReportBeanList(context);
if (intent.getAction().equals(ACTION_RELOAD_REPORT)) {
LogUtils.d(TAG, "ACTION_RELOAD_REPORT");
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, APPNewsWidget.class));
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, SOSWidget.class));
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}else if (intent.getAction().equals(ACTION_WAKEUP_SERVICE)) {
LogUtils.d(TAG, "ACTION_WAKEUP_SERVICE");
String szAPPModel = intent.getStringExtra(WinBoll.EXTRA_APPMODEL);
LogUtils.d(TAG, String.format("szAPPModel %s", szAPPModel));
if (szAPPModel != null && !szAPPModel.equals("")) {
String szAPPSOSBean = intent.getStringExtra("APPSOSBean");
LogUtils.d(TAG, String.format("szAPPSOSBean %s", szAPPSOSBean));
if (szAPPSOSBean != null && !szAPPSOSBean.equals("")) {
try {
APPModel bean = APPModel.parseStringToBean(szAPPModel, APPModel.class);
APPSOSBean bean = APPSOSBean.parseStringToBean(szAPPSOSBean, APPSOSBean.class);
if (bean != null) {
String szAppPackageName = bean.getAppPackageName();
LogUtils.d(TAG, String.format("szAppPackageName %s", szAppPackageName));
String szAppMainServiveName = bean.getAppMainServiveName();
LogUtils.d(TAG, String.format("szAppMainServiveName %s", szAppMainServiveName));
String sosPackage = bean.getSosPackage();
LogUtils.d(TAG, String.format("sosPackage %s", sosPackage));
String sosClassName = bean.getSosClassName();
LogUtils.d(TAG, String.format("sosClassName %s", sosClassName));
String appName = AppUtils.getAppNameByPackageName(context, szAppPackageName);
String appName = AppUtils.getAppNameByPackageName(context, sosPackage);
LogUtils.d(TAG, String.format("appName %s", appName));
WinBollNewsBean winBollNewsBean = new WinBollNewsBean(appName);
SOSReportBean appSOSReportBean = new SOSReportBean(appName);
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
String currentTime = sdf.format(new Date());
StringBuilder sbLine = new StringBuilder();
@@ -79,12 +77,12 @@ public class APPNewsWidget extends AppWidgetProvider {
sbLine.append(currentTime);
sbLine.append("] Wake up ");
sbLine.append(appName);
winBollNewsBean.setMessage(sbLine.toString());
appSOSReportBean.setSosReport(sbLine.toString());
addWinBollNewsBean(context, winBollNewsBean);
addAPPSOSReportBean(context, appSOSReportBean);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, APPNewsWidget.class));
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, SOSWidget.class));
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
@@ -99,53 +97,53 @@ public class APPNewsWidget extends AppWidgetProvider {
//
// 加入新报告信息
//
public synchronized static void addWinBollNewsBean(Context context, WinBollNewsBean bean) {
initWinBollNewsBeanList(context);
_WinBollNewsBeanList.add(0, bean);
public synchronized static void addAPPSOSReportBean(Context context, SOSReportBean bean) {
initAPPSOSReportBeanList(context);
_SOSReportBeanList.add(0, bean);
// 控制记录总数
while (_WinBollNewsBeanList.size() > _MAX_PAGES * _OnePageLinesCount) {
_WinBollNewsBeanList.remove(_WinBollNewsBeanList.size() - 1);
while (_SOSReportBeanList.size() > _MAX_PAGES * _OnePageLinesCount) {
_SOSReportBeanList.remove(_SOSReportBeanList.size() - 1);
}
WinBollNewsBean.saveBeanList(context, _WinBollNewsBeanList, WinBollNewsBean.class);
SOSReportBean.saveBeanList(context, _SOSReportBeanList, SOSReportBean.class);
}
synchronized static void initWinBollNewsBeanList(Context context) {
if (_WinBollNewsBeanList == null) {
_WinBollNewsBeanList = new ArrayList<WinBollNewsBean>();
WinBollNewsBean.loadBeanList(context, _WinBollNewsBeanList, WinBollNewsBean.class);
synchronized static void initAPPSOSReportBeanList(Context context) {
if (_SOSReportBeanList == null) {
_SOSReportBeanList = new ArrayList<SOSReportBean>();
SOSReportBean.loadBeanList(context, _SOSReportBeanList, SOSReportBean.class);
}
if (_WinBollNewsBeanList == null) {
_WinBollNewsBeanList = new ArrayList<WinBollNewsBean>();
WinBollNewsBean.saveBeanList(context, _WinBollNewsBeanList, WinBollNewsBean.class);
if (_SOSReportBeanList == null) {
_SOSReportBeanList = new ArrayList<SOSReportBean>();
SOSReportBean.saveBeanList(context, _SOSReportBeanList, SOSReportBean.class);
}
}
private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
LogUtils.d(TAG, "updateAppWidget(...)");
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_news);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_sos);
//设置按钮点击事件
Intent intentPre = new Intent(context, APPNewsWidgetClickListener.class);
intentPre.setAction(APPNewsWidgetClickListener.ACTION_PRE);
Intent intentPre = new Intent(context, SOSWidgetClickListener.class);
intentPre.setAction(SOSWidgetClickListener.ACTION_PRE);
PendingIntent pendingIntentPre = PendingIntent.getBroadcast(context, 0, intentPre, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.widget_button_pre, pendingIntentPre);
Intent intentNext = new Intent(context, APPNewsWidgetClickListener.class);
intentNext.setAction(APPNewsWidgetClickListener.ACTION_NEXT);
Intent intentNext = new Intent(context, SOSWidgetClickListener.class);
intentNext.setAction(SOSWidgetClickListener.ACTION_NEXT);
PendingIntent pendingIntentNext = PendingIntent.getBroadcast(context, 0, intentNext, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.widget_button_next, pendingIntentNext);
views.setTextViewText(R.id.tv_msg, getPageInfo());
views.setTextViewText(R.id.tv_news, getMessage());
views.setTextViewText(R.id.infoTextView, getPageInfo());
views.setTextViewText(R.id.sosReportTextView, getMessage());
appWidgetManager.updateAppWidget(appWidgetId, views);
}
public static String getMessage() {
ArrayList<String> msgTemp = new ArrayList<String>();
if (_WinBollNewsBeanList != null) {
if (_SOSReportBeanList != null) {
int start = _OnePageLinesCount * _CurrentPageIndex;
start = _WinBollNewsBeanList.size() > start ? start : _WinBollNewsBeanList.size() - 1;
for (int i = start, j = 0; i < _WinBollNewsBeanList.size() && j < _OnePageLinesCount && start > -1; i++, j++) {
msgTemp.add(_WinBollNewsBeanList.get(i).getMessage());
start = _SOSReportBeanList.size() > start ? start : _SOSReportBeanList.size() - 1;
for (int i = start, j = 0; i < _SOSReportBeanList.size() && j < _OnePageLinesCount && start > -1; i++, j++) {
msgTemp.add(_SOSReportBeanList.get(i).getSosReport());
}
String message = String.join("\n", msgTemp);
return message;
@@ -154,33 +152,33 @@ public class APPNewsWidget extends AppWidgetProvider {
}
public static void prePage(Context context) {
if (_WinBollNewsBeanList != null) {
if (_SOSReportBeanList != null) {
if (_CurrentPageIndex > 0) {
_CurrentPageIndex = _CurrentPageIndex - 1;
}
Intent intentWidget = new Intent(context, APPNewsWidget.class);
intentWidget.setAction(APPNewsWidget.ACTION_RELOAD_REPORT);
Intent intentWidget = new Intent(context, SOSWidget.class);
intentWidget.setAction(SOSWidget.ACTION_RELOAD_REPORT);
context.sendBroadcast(intentWidget);
}
}
public static void nextPage(Context context) {
if (_WinBollNewsBeanList != null) {
if ((_CurrentPageIndex + 1) * _OnePageLinesCount < _WinBollNewsBeanList.size()) {
if (_SOSReportBeanList != null) {
if ((_CurrentPageIndex + 1) * _OnePageLinesCount < _SOSReportBeanList.size()) {
_CurrentPageIndex = _CurrentPageIndex + 1;
}
Intent intentWidget = new Intent(context, APPNewsWidget.class);
intentWidget.setAction(APPNewsWidget.ACTION_RELOAD_REPORT);
Intent intentWidget = new Intent(context, SOSWidget.class);
intentWidget.setAction(SOSWidget.ACTION_RELOAD_REPORT);
context.sendBroadcast(intentWidget);
}
}
String getPageInfo() {
if (_WinBollNewsBeanList == null) {
if (_SOSReportBeanList == null) {
return "0/0";
}
int leftCount = _WinBollNewsBeanList.size() % _OnePageLinesCount;
int currentPageCount = _WinBollNewsBeanList.size() / _OnePageLinesCount + (leftCount == 0 ?0: 1);
int leftCount = _SOSReportBeanList.size() % _OnePageLinesCount;
int currentPageCount = _SOSReportBeanList.size() / _OnePageLinesCount + (leftCount == 0 ?0: 1);
return String.format("%d/%d", _CurrentPageIndex + 1, currentPageCount);
}
}

View File

@@ -1,20 +1,20 @@
package cc.winboll.studio.appbase.receivers;
package cc.winboll.studio.appbase.widgets;
/**
* @Author ZhanGSKen<zhangsken@188.com>
* @Date 2025/03/24 07:11:44
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/15 17:20:46
* @Describe WidgetButtonClickListener
*/
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import cc.winboll.studio.appbase.widgets.APPNewsWidget;
import cc.winboll.studio.libappbase.LogUtils;
public class APPNewsWidgetClickListener extends BroadcastReceiver {
public class SOSWidgetClickListener extends BroadcastReceiver {
public static final String TAG = "APPNewsWidgetClickListener";
public static final String ACTION_PRE = APPNewsWidgetClickListener.class.getName() + ".ACTION_PRE";
public static final String ACTION_NEXT = APPNewsWidgetClickListener.class.getName() + ".ACTION_NEXT";
public static final String TAG = "SOSWidgetClickListener";
public static final String ACTION_PRE = "cc.winboll.studio.appbase.widgets.SOSWidgetClickListener.ACTION_PRE";
public static final String ACTION_NEXT = "cc.winboll.studio.appbase.widgets.SOSWidgetClickListener.ACTION_NEXT";
@Override
public void onReceive(Context context, Intent intent) {
@@ -25,10 +25,10 @@ public class APPNewsWidgetClickListener extends BroadcastReceiver {
}
if (action.equals(ACTION_PRE)) {
LogUtils.d(TAG, "ACTION_PRE");
APPNewsWidget.prePage(context);
SOSWidget.prePage(context);
} else if (action.equals(ACTION_NEXT)) {
LogUtils.d(TAG, "ACTION_NEXT");
APPNewsWidget.nextPage(context);
SOSWidget.nextPage(context);
} else {
LogUtils.d(TAG, String.format("action %s", action));
}

View File

@@ -1,43 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<android.widget.Toolbar
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/toolbar"/>
android:id="@+id/activitymainToolbar1"/>
<ScrollView
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0">
android:layout_weight="1.0"
android:gravity="center_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, WinBoll!"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Android版本10的代号是“Q”API级别是29。 Android 10开始谷歌不再公开使用甜品作为版本代号但内部仍保留了大量与“Q”相关的元素。Android 10本身并没有严格对应某个特定的Java版本但在开发Android 10应用时通常可以使用Java 8或更高版本。
Java 8为Android开发带来了诸如Lambda表达式、方法引用等新特性能提高开发效率和代码可读性与Android 10开发适配良好。Java 9及更高版本也可用于Android 10开发能使用一些新的语言特性和API但可能需要注意兼容性和配置问题。"/>
<LinearLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
android:gravity="right|center_vertical">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Debug Mode"
android:layout_weight="1.0"
android:onClick="onSwitchDebugMode"
android:id="@+id/activitymainCheckBox1"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test Application CrashReport"
android:textAllCaps="false"
android:onClick="onTestApplicationCrashReport"/>
</LinearLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="400dp">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0"
android:gravity="center_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, WinBoLL!"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Android版本10的代号是“Q”API级别是29。 Android 10开始谷歌不再公开使用甜品作为版本代号但内部仍保留了大量与“Q”相关的元素。Android 10本身并没有严格对应某个特定的Java版本但在开发Android 10应用时通常可以使用Java 8或更高版本。 Java 8为Android开发带来了诸如Lambda表达式、方法引用等新特性能提高开发效率和代码可读性与Android 10开发适配良好。Java 9及更高版本也可用于Android 10开发能使用一些新的语言特性和API但可能需要注意兼容性和配置问题。"/>
android:layout_height="wrap_content"
android:gravity="right">
<HorizontalScrollView
android:layout_width="match_parent"
@@ -45,177 +70,80 @@
<LinearLayout
android:orientation="horizontal"
android:layout_height="wrap_content"
android:gravity="right|center_vertical"
android:layout_width="wrap_content">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Debug Mode"
android:layout_weight="1.0"
android:onClick="onSwitchDebugMode"
android:id="@+id/activitymainCheckBox1"/>
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test Application CrashReport"
android:text="StartTestService"
android:textAllCaps="false"
android:onClick="onTestApplicationCrashReport"/>
android:onClick="onStartTestService"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PreviewGlobalCrashActivity"
android:text="StopTestService"
android:textAllCaps="false"
android:onClick="onPreviewGlobalCrashActivity"/>
android:onClick="onStopTestService"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StopTestServiceNoSettings"
android:textAllCaps="false"
android:onClick="onStopTestServiceNoSettings"/>
</LinearLayout>
</HorizontalScrollView>
<ScrollView
android:layout_width="match_parent"
android:layout_height="400dp">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StartCenter"
android:textAllCaps="false"
android:onClick="onStartCenter"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StopCenter"
android:textAllCaps="false"
android:onClick="onStopCenter"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TestStopWithoutSettingEnable"
android:textAllCaps="false"
android:onClick="onTestStopWithoutSettingEnable"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StartCenter"
android:textAllCaps="false"
android:onClick="onStartCenter"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TestStartWithString"
android:textAllCaps="false"
android:onClick="onTestStartWithString"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StopCenter"
android:textAllCaps="false"
android:onClick="onStopCenter"/>
</LinearLayout>
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SartTestDemoService"
android:textAllCaps="false"
android:onClick="onSartTestDemoService"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StopTestDemoService"
android:textAllCaps="false"
android:onClick="onStopTestDemoService"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StopTestDemoServiceNoSettings"
android:textAllCaps="false"
android:onClick="onStopTestDemoServiceNoSettings"/>
</LinearLayout>
</HorizontalScrollView>
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SartTestDemoBindService"
android:textAllCaps="false"
android:onClick="onSartTestDemoBindService"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StopTestDemoBindService"
android:textAllCaps="false"
android:onClick="onStopTestDemoBindService"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StopTestDemoBindServiceNoSettings"
android:textAllCaps="false"
android:onClick="onStopTestDemoBindServiceNoSettings"/>
</LinearLayout>
</HorizontalScrollView>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TestStopMainServiceWithoutSettingEnable"
android:textAllCaps="false"
android:onClick="onTestStopMainServiceWithoutSettingEnable"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TestUseComponentStartService"
android:textAllCaps="false"
android:onClick="onTestUseComponentStartService"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TestDemoServiceSOS"
android:textAllCaps="false"
android:onClick="onTestDemoServiceSOS"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TestOpenNewActivity"
android:textAllCaps="false"
android:onClick="onTestOpenNewActivity"/>
</LinearLayout>
</ScrollView>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SOS"
android:textAllCaps="false"
android:onClick="onSOS"/>
</LinearLayout>
</LinearLayout>
</ScrollView>
</ScrollView>
<cc.winboll.studio.libappbase.LogView
android:layout_weight="1.0"
android:layout_height="0dp"
android:layout_width="match_parent"
android:id="@+id/activitymainLogView1"/>
<cc.winboll.studio.libappbase.LogView
android:layout_width="match_parent"
android:layout_height="300dp"
android:id="@+id/logview"/>
</LinearLayout>
</LinearLayout>

View File

@@ -1,43 +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"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="NewActivity"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CloseThisActivity"
android:textAllCaps="false"
android:onClick="onCloseThisActivity"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CloseAllActivity"
android:textAllCaps="false"
android:onClick="onCloseAllActivity"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New2Activity"
android:textAllCaps="false"
android:onClick="onNew2Activity"/>
</LinearLayout>

View File

@@ -1,43 +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"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New2Activity"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CloseThisActivity"
android:textAllCaps="false"
android:onClick="onCloseThisActivity"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CloseAllActivity"
android:textAllCaps="false"
android:onClick="onCloseAllActivity"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="NewActivity"
android:textAllCaps="false"
android:onClick="onNewActivity"/>
</LinearLayout>

View File

@@ -1,51 +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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#FFFFFFFF">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right|center_vertical">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/tv_title"
android:layout_weight="1.0"
android:text="WinBoLLNews"
android:textStyle="bold"
android:textSize="16sp"/>
<Button
android:layout_width="48dp"
android:layout_height="48dp"
android:text="⇦"
android:id="@+id/widget_button_pre"/>
<Button
android:layout_width="48dp"
android:layout_height="48dp"
android:text="⇨"
android:id="@+id/widget_button_next"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tv_msg"/>
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="@+id/tv_news"
android:layout_weight="1.0"/>
</LinearLayout>

View File

@@ -2,43 +2,41 @@
<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="wrap_content"
android:padding="16dp">
<EditText
android:id="@+id/edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入规则文本"/>
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#FFFFFFFF">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right|center_vertical">
android:gravity="right">
<CheckBox
android:id="@+id/checkbox_allow"
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/infoTextView"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="⇦"
android:id="@+id/widget_button_pre"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="允许连接"/>
android:text="⇨"
android:id="@+id/widget_button_next"/>
<CheckBox
android:id="@+id/checkbox_enable"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启用"/>
<Button
android:id="@+id/button_confirm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="确定"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="@+id/sosReportTextView"
android:layout_weight="1.0"/>
</LinearLayout>

View File

@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#FF00B322</color>
<color name="colorPrimaryDark">#FF005C12</color>
<color name="colorAccent">#FF8DFFA2</color>
<color name="colorText">#FFFFFB8D</color>
<color name="colorPrimary">#005800FF</color>
<color name="colorPrimaryDark">#005800FF</color>
<color name="colorAccent">#005800FF</color>
</resources>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">AppBase</string>
<string name="tileservice_name">WinBoLL</string>
<string name="tileservice_name">WinBoll</string>
</resources>

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