diff --git a/.gitignore b/.gitignore index 994a6c7..bcc1909 100644 --- a/.gitignore +++ b/.gitignore @@ -101,5 +101,6 @@ lint-results.html ## WinBoLL 衍生应用, ## 外派类型类库应用需要注释掉以下部分,以便部署通用类库编译配置。 ## APPBase,AES需要上传以下两种配置。 -#/settings.gradle -#/gradle.properties +## OriginMaster 仓库合并各类分支需要忽略的文件修改 +/settings.gradle +/gradle.properties diff --git a/aes/.gitignore b/aes/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/aes/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/aes/README.md b/aes/README.md new file mode 100644 index 0000000..1606637 --- /dev/null +++ b/aes/README.md @@ -0,0 +1,36 @@ +# AES +[![](https://jitpack.io/v/ZhanGSKen/AES.svg)](https://jitpack.io/#ZhanGSKen/AES) + +#### 介绍 +WinBoLL AndroidX 可视化元素类库。 + +#### 软件架构 +适配安卓应用 [AIDE Pro] 的 Gradle 编译结构。 +也适配安卓应用 [AndroidIDE] 的 Gradle 编译结构。 + + +#### Gradle 编译说明 +调试版编译命令 :gradle assembleBetaDebug +阶段版编译命令 :bash .winboll/bashPublishAPKAddTag.sh aes +阶段版类库发布命令 :git pull &&bash .winboll/bashPublishLIBAddTag.sh libaes + +#### 使用说明 + +#### 参与贡献 + +1. Fork 本仓库 +2. 新建 Feat_xxx 分支 +3. 提交代码 : ZhanGSKen(ZhanGSKen) +4. 新建 Pull Request + + +#### 特技 + +1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md +2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) +3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 +4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 +5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) +6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) + +#### 参考文档 diff --git a/aes/app_update_description.txt b/aes/app_update_description.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/aes/app_update_description.txt @@ -0,0 +1 @@ + diff --git a/aes/build.gradle b/aes/build.gradle new file mode 100644 index 0000000..899f105 --- /dev/null +++ b/aes/build.gradle @@ -0,0 +1,48 @@ +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 { + // 适配MIUI12 + compileSdkVersion 30 + buildToolsVersion "30.0.3" + + defaultConfig { + applicationId "cc.winboll.studio.aes" + minSdkVersion 21 + targetSdkVersion 30 + versionCode 1 + // versionName 更新后需要手动设置 + // 项目模块目录的 build.gradle 文件的 stageCount=0 + // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" + versionName "15.15" + if(true) { + versionName = genVersionName("${versionName}") + } + } + + // 米盟 SDK + packagingOptions { + doNotStrip "*/*/libmimo_1011.so" + } +} + +dependencies { + api project(':libaes') + api fileTree(dir: 'libs', include: ['*.jar']) +} diff --git a/aes/build.properties b/aes/build.properties new file mode 100644 index 0000000..7007fb4 --- /dev/null +++ b/aes/build.properties @@ -0,0 +1,8 @@ +#Created by .winboll/winboll_app_build.gradle +#Tue Jan 13 03:37:56 HKT 2026 +stageCount=2 +libraryProject=libaes +baseVersion=15.15 +publishVersion=15.15.1 +buildCount=0 +baseBetaVersion=15.15.2 diff --git a/aes/proguard-rules.pro b/aes/proguard-rules.pro new file mode 100644 index 0000000..a18de74 --- /dev/null +++ b/aes/proguard-rules.pro @@ -0,0 +1,137 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in C:\tools\adt-bundle-windows-x86_64-20131030\sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# ============================== 基础通用规则 ============================== +# 保留系统组件 +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgentHelper +-keep public class * extends android.preference.Preference + +# 保留 WinBoLL 核心包及子类(合并简化规则) +-keep class cc.winboll.studio.** { *; } +-keepclassmembers class cc.winboll.studio.** { *; } + +# 保留所有类中的 public static final String TAG 字段(便于日志定位) +-keepclassmembers class * { + public static final java.lang.String TAG; +} + +# 保留序列化类(避免Parcelable/Gson解析异常) +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} +-keepclassmembers class * implements java.io.Serializable { + static final long serialVersionUID; + private static final java.io.ObjectStreamField[] serialPersistentFields; + private void writeObject(java.io.ObjectOutputStream); + private void readObject(java.io.ObjectInputStream); + java.lang.Object writeReplace(); + java.lang.Object readResolve(); +} + +# 保留 R 文件(避免资源ID混淆) +-keepclassmembers class **.R$* { + public static ; +} + +# 保留 native 方法(避免JNI调用失败) +-keepclasseswithmembernames class * { + native ; +} + +# 保留注解和泛型(避免反射/序列化异常) +-keepattributes *Annotation* +-keepattributes Signature + +# 屏蔽 Java 8+ 警告(适配 Java 7 语法) +-dontwarn java.lang.invoke.* +-dontwarn android.support.v8.renderscript.* +-dontwarn java.util.function.** + +# ============================== 第三方框架专项规则 ============================== +# OkHttp 4.4.1(米盟广告请求依赖,完善Lambda兼容) +-keep class okhttp3.** { *; } +-keep interface okhttp3.** { *; } +-keep class okhttp3.internal.** { *; } +-keep class okio.** { *; } +-dontwarn okhttp3.internal.platform.** +-dontwarn okio.** + +# Glide 4.9.0(米盟广告图片加载依赖) +-keep public class * implements com.bumptech.glide.module.GlideModule +-keep public class * extends com.bumptech.glide.module.AppGlideModule +-keep public enum com.bumptech.glide.load.ImageHeaderParser$ImageType { + **[] $VALUES; + public *; +} +-keepclassmembers class * implements com.bumptech.glide.module.AppGlideModule { + (); +} +-dontwarn com.bumptech.glide.** + +# Gson 2.8.5(米盟广告数据序列化依赖) +-keep class com.google.gson.** { *; } +-keep interface com.google.gson.** { *; } +-keepclassmembers class * { + @com.google.gson.annotations.SerializedName ; +} + +# 米盟 SDK(核心广告组件,完整保留避免加载失败) +-keep class com.miui.zeus.** { *; } +-keep interface com.miui.zeus.** { *; } +# 保留米盟日志字段(便于广告加载失败排查) +-keepclassmembers class com.miui.zeus.mimo.sdk.** { + public static final java.lang.String TAG; +} + +# RecyclerView 1.0.0(米盟广告布局渲染依赖) +-keep class androidx.recyclerview.** { *; } +-keep interface androidx.recyclerview.** { *; } +-keepclassmembers class androidx.recyclerview.widget.RecyclerView$Adapter { + public *; +} + +# 其他第三方框架(按引入依赖保留,无则可删除) +# XXPermissions 18.63 +-keep class com.hjq.permissions.** { *; } +-keep interface com.hjq.permissions.** { *; } + +# ZXing 二维码(核心解析组件) +-keep class com.google.zxing.** { *; } +-keep class com.journeyapps.zxing.** { *; } + +# Jsoup HTML解析 +-keep class org.jsoup.** { *; } + +# Pinyin4j 拼音搜索 +-keep class net.sourceforge.pinyin4j.** { *; } + +# JSch SSH组件 +-keep class com.jcraft.jsch.** { *; } + +# AndroidX 基础组件 +-keep class androidx.appcompat.** { *; } +-keep interface androidx.appcompat.** { *; } + +# ============================== 优化与调试配置 ============================== +# 优化级别(平衡混淆效果与性能) +-optimizationpasses 5 +-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/* + +# 调试辅助(保留行号便于崩溃定位) +-verbose +-dontpreverify +-dontusemixedcaseclassnames +-keepattributes SourceFile,LineNumberTable + diff --git a/aes/src/beta/AndroidManifest.xml b/aes/src/beta/AndroidManifest.xml new file mode 100644 index 0000000..ee78d9f --- /dev/null +++ b/aes/src/beta/AndroidManifest.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/aes/src/beta/res/values/strings.xml b/aes/src/beta/res/values/strings.xml new file mode 100644 index 0000000..6f287f2 --- /dev/null +++ b/aes/src/beta/res/values/strings.xml @@ -0,0 +1,6 @@ + + + + + AES+ + diff --git a/aes/src/main/AndroidManifest.xml b/aes/src/main/AndroidManifest.xml new file mode 100644 index 0000000..c0ca77d --- /dev/null +++ b/aes/src/main/AndroidManifest.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aes/src/main/java/cc/winboll/studio/aes/AboutActivity.java b/aes/src/main/java/cc/winboll/studio/aes/AboutActivity.java new file mode 100644 index 0000000..a824a62 --- /dev/null +++ b/aes/src/main/java/cc/winboll/studio/aes/AboutActivity.java @@ -0,0 +1,59 @@ +package cc.winboll.studio.aes; + +import android.app.Activity; +import android.os.Bundle; +import android.view.View; +import android.widget.Toolbar; +import cc.winboll.studio.aes.R; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.models.APPInfo; +import cc.winboll.studio.libappbase.views.AboutView; + +/** + * @Author 豆包&ZhanGSKen + * @Date 2026/01/11 15:16 + * @Describe 应用介绍窗口 + */ +public class AboutActivity extends Activity { + + public static final String TAG = "AboutActivity"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_about); + + // 设置工具栏 + Toolbar toolbar = findViewById(R.id.toolbar); + setActionBar(toolbar); + getActionBar().setSubtitle(TAG); + getActionBar().setDisplayHomeAsUpEnabled(true); + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); // 点击导航栏返回按钮,触发 finish() + } + }); + + AboutView aboutView = findViewById(R.id.aboutview); + aboutView.setAPPInfo(genDefaultAppInfo()); + } + + private APPInfo genDefaultAppInfo() { + LogUtils.d(TAG, "genDefaultAppInfo() 调用"); + String branchName = "aes"; + APPInfo appInfo = new APPInfo(); + appInfo.setAppName(getString(R.string.app_name)); + appInfo.setAppIcon(R.drawable.ic_winboll); + appInfo.setAppDescription(getString(R.string.app_description)); + appInfo.setAppGitName("AES"); + appInfo.setAppGitOwner("Studio"); + appInfo.setAppGitAPPBranch(branchName); + appInfo.setAppGitAPPSubProjectFolder(branchName); + appInfo.setAppHomePage("https://www.winboll.cc/apks/index.php?project=AES"); + appInfo.setAppAPKName("AES"); + appInfo.setAppAPKFolderName("AES"); + LogUtils.d(TAG, "genDefaultAppInfo: 应用信息已生成"); + return appInfo; + } +} diff --git a/aes/src/main/java/cc/winboll/studio/aes/App.java b/aes/src/main/java/cc/winboll/studio/aes/App.java new file mode 100644 index 0000000..f6816f7 --- /dev/null +++ b/aes/src/main/java/cc/winboll/studio/aes/App.java @@ -0,0 +1,34 @@ +package cc.winboll.studio.aes; + +/** + * @Author ZhanGSKen + * @Date 2024/06/13 19:03:58 + * @Describe AES应用类 + */ +import android.view.Gravity; +import cc.winboll.studio.libaes.utils.WinBoLLActivityManager; +import cc.winboll.studio.libappbase.GlobalApplication; +import cc.winboll.studio.libappbase.ToastUtils; + + +public class App extends GlobalApplication { + + public static final String TAG = "App"; + + @Override + public void onCreate() { + super.onCreate(); + setIsDebugging(BuildConfig.DEBUG); + //setIsDebugging(false); + WinBoLLActivityManager.init(this); + + // 初始化 Toast 框架 + ToastUtils.init(this); + } + + @Override + public void onTerminate() { + super.onTerminate(); + ToastUtils.release(); + } +} diff --git a/aes/src/main/java/cc/winboll/studio/aes/MainActivity.java b/aes/src/main/java/cc/winboll/studio/aes/MainActivity.java new file mode 100644 index 0000000..5360023 --- /dev/null +++ b/aes/src/main/java/cc/winboll/studio/aes/MainActivity.java @@ -0,0 +1,200 @@ +package cc.winboll.studio.aes; + +/** + * @Author ZhanGSKen + * @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.dialogs.LocalFileSelectDialog; +import cc.winboll.studio.libaes.dialogs.StoragePathDialog; +import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; +import cc.winboll.studio.libaes.models.DrawerMenuBean; +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.libaes.utils.WinBoLLActivityManager; +import cc.winboll.studio.libappbase.LogUtils; +import com.a4455jkjh.colorpicker.ColorPickerDialog; +import java.util.ArrayList; + +public class MainActivity extends DrawerFragmentActivity implements IWinBoLLActivity { + + + public static final String TAG = "MainActivity"; + + TestAButtonFragment mTestAButtonFragment; + TestViewPageFragment mTestViewPageFragment; + + @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 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 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_main, menu); +// if(App.isDebugging()) { +// getMenuInflater().inflate(cc.winboll.studio.libaes.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_testactivitymanager) { + WinBoLLActivityManager.getInstance().startWinBoLLActivity(this, TestActivityManagerActivity.class); + //ToastUtils.show("item_testactivitymanager"); + } 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_settings) { + Intent intent = new Intent(this, SettingsActivity.class); + startActivity(intent); + } else if (nItemId == R.id.item_about) { + Intent intent = new Intent(this, AboutActivity.class); + startActivity(intent); + } + + + return super.onOptionsItemSelected(item); + } + + +} diff --git a/aes/src/main/java/cc/winboll/studio/aes/SettingsActivity.java b/aes/src/main/java/cc/winboll/studio/aes/SettingsActivity.java new file mode 100644 index 0000000..1767c02 --- /dev/null +++ b/aes/src/main/java/cc/winboll/studio/aes/SettingsActivity.java @@ -0,0 +1,39 @@ +package cc.winboll.studio.aes; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import cc.winboll.studio.libaes.views.ADsControlView; + +/** + * @Author ZhanGSKen&豆包大模型 + * @Date 2025/11/26 18:01 + * @Describe SettingsActivity + */ +public class SettingsActivity extends Activity { + + public static final String TAG = "SettingsActivity"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_settings); + ADsControlView adsControlView = (ADsControlView) findViewById(R.id.ads_control_view); + +// adsControlView.setOnAdsModeSelectedListener(new ADsControlView.OnAdsModeSelectedListener() { +// @Override +// public void onModeSelected(ADsMode selectedMode) { +// if (selectedMode == ADsMode.STANDALONE) { +// // 处理单机模式逻辑(如释放米盟资源) +// ToastUtils.show("STANDALONE"); +// } else if (selectedMode == ADsMode.MIMO_SDK) { +// // 处理米盟SDK模式逻辑(如初始化SDK) +// ToastUtils.show("MIMO_SDK"); +// } +// } +// }); + } + +} diff --git a/aes/src/main/java/cc/winboll/studio/aes/TestActivityManagerActivity.java b/aes/src/main/java/cc/winboll/studio/aes/TestActivityManagerActivity.java new file mode 100644 index 0000000..71d114d --- /dev/null +++ b/aes/src/main/java/cc/winboll/studio/aes/TestActivityManagerActivity.java @@ -0,0 +1,33 @@ +package cc.winboll.studio.aes; + +import android.app.Activity; +import android.os.Bundle; +import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; + +/** + * @Author ZhanGSKen&豆包大模型 + * @Date 2025/09/28 21:07 + * @Describe 窗口管理类测试窗口 + */ +public class TestActivityManagerActivity extends WinBoLLActivity implements IWinBoLLActivity { + + public static final String TAG = "TestActivityManagerActivity"; + + @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_testactivitymanager); + + } + +} diff --git a/aes/src/main/java/cc/winboll/studio/aes/WinBoLLActivity.java b/aes/src/main/java/cc/winboll/studio/aes/WinBoLLActivity.java new file mode 100644 index 0000000..76005db --- /dev/null +++ b/aes/src/main/java/cc/winboll/studio/aes/WinBoLLActivity.java @@ -0,0 +1,60 @@ +package cc.winboll.studio.aes; + +/** + * @Author ZhanGSKen&豆包大模型 + * @Date 2025/09/29 00:11 + * @Describe WinBoLL 窗口基础类 + */ +import android.app.Activity; +import android.os.Bundle; +import android.view.MenuItem; +import androidx.appcompat.app.AppCompatActivity; +import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; +import cc.winboll.studio.libaes.utils.WinBoLLActivityManager; +import cc.winboll.studio.libappbase.LogUtils; + +public class WinBoLLActivity extends AppCompatActivity implements IWinBoLLActivity { + + public static final String TAG = "WinBoLLActivity"; + + @Override + public Activity getActivity() { + return this; + } + + @Override + public String getTag() { + return TAG; + } + + @Override + protected void onResume() { + super.onResume(); + LogUtils.d(TAG, String.format("onResume %s", getTag())); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + /*if (item.getItemId() == R.id.item_log) { + WinBoLLActivityManager.getInstance().startLogActivity(this); + return true; + } else if (item.getItemId() == R.id.item_home) { + startActivity(new Intent(this, MainActivity.class)); + return true; + }*/ + // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。 + return super.onOptionsItemSelected(item); + } + + @Override + protected void onPostCreate(Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + WinBoLLActivityManager.getInstance().add(this); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + WinBoLLActivityManager.getInstance().registeRemove(this); + } +} diff --git a/aes/src/main/res/drawable/bg_frame.xml b/aes/src/main/res/drawable/bg_frame.xml new file mode 100644 index 0000000..75b2b94 --- /dev/null +++ b/aes/src/main/res/drawable/bg_frame.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + diff --git a/aes/src/main/res/layout/activity_about.xml b/aes/src/main/res/layout/activity_about.xml new file mode 100644 index 0000000..bfd02eb --- /dev/null +++ b/aes/src/main/res/layout/activity_about.xml @@ -0,0 +1,21 @@ + + + + + + + + + diff --git a/aes/src/main/res/layout/activity_settings.xml b/aes/src/main/res/layout/activity_settings.xml new file mode 100644 index 0000000..c8d3432 --- /dev/null +++ b/aes/src/main/res/layout/activity_settings.xml @@ -0,0 +1,17 @@ + + + + + + + diff --git a/aes/src/main/res/layout/activity_testactivitymanager.xml b/aes/src/main/res/layout/activity_testactivitymanager.xml new file mode 100644 index 0000000..e030ebb --- /dev/null +++ b/aes/src/main/res/layout/activity_testactivitymanager.xml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/aes/src/main/res/menu/toolbar_main.xml b/aes/src/main/res/menu/toolbar_main.xml new file mode 100644 index 0000000..b87657a --- /dev/null +++ b/aes/src/main/res/menu/toolbar_main.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + diff --git a/aes/src/main/res/values/colors.xml b/aes/src/main/res/values/colors.xml new file mode 100644 index 0000000..87d3836 --- /dev/null +++ b/aes/src/main/res/values/colors.xml @@ -0,0 +1,7 @@ + + + #FF00B322 + #FF005C12 + #FF8DFFA2 + #FFFFFB8D + diff --git a/aes/src/main/res/values/strings.xml b/aes/src/main/res/values/strings.xml new file mode 100644 index 0000000..664f43a --- /dev/null +++ b/aes/src/main/res/values/strings.xml @@ -0,0 +1,7 @@ + + + + AES + WinBoLL AndroidX 可视化元素类库。 + + diff --git a/aes/src/main/res/values/styles.xml b/aes/src/main/res/values/styles.xml new file mode 100644 index 0000000..1da88ba --- /dev/null +++ b/aes/src/main/res/values/styles.xml @@ -0,0 +1,5 @@ + + + + diff --git a/aes/src/main/res/xml/network_security_config.xml b/aes/src/main/res/xml/network_security_config.xml new file mode 100644 index 0000000..ee39aa4 --- /dev/null +++ b/aes/src/main/res/xml/network_security_config.xml @@ -0,0 +1,6 @@ + + + + winboll.cc + + diff --git a/aes/src/stage/AndroidManifest.xml b/aes/src/stage/AndroidManifest.xml new file mode 100644 index 0000000..ee78d9f --- /dev/null +++ b/aes/src/stage/AndroidManifest.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/aes/src/stage/res/values/strings.xml b/aes/src/stage/res/values/strings.xml new file mode 100644 index 0000000..ace0c41 --- /dev/null +++ b/aes/src/stage/res/values/strings.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/gradle.properties b/gradle.properties deleted file mode 100644 index 74b1f76..0000000 --- a/gradle.properties +++ /dev/null @@ -1,21 +0,0 @@ -# Project-wide Gradle settings. -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx2048m -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true -# AndroidX package structure to make it clearer which packages are bundled with the -# Android operating system, and which are packaged with your app"s APK -# https://developer.android.com/topic/libraries/support-library/androidx-rn -android.useAndroidX=true -# Automatically convert third-party libraries to use AndroidX -android.enableJetifier=true -# 保持与旧版Gradle插件的兼容 -android.disableAutomaticComponentCreation=true diff --git a/libaes/.gitignore b/libaes/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/libaes/.gitignore @@ -0,0 +1 @@ +/build diff --git a/libaes/build.gradle b/libaes/build.gradle new file mode 100644 index 0000000..881bae7 --- /dev/null +++ b/libaes/build.gradle @@ -0,0 +1,71 @@ +apply plugin: 'com.android.library' +apply plugin: 'maven-publish' +apply from: '../.winboll/winboll_lib_build.gradle' +apply from: '../.winboll/winboll_lint_build.gradle' + +android { + // 适配MIUI12 + compileSdkVersion 30 + buildToolsVersion "30.0.3" + + defaultConfig { + minSdkVersion 21 + targetSdkVersion 30 + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + // 米盟 SDK + packagingOptions { + doNotStrip "*/*/libmimo_1011.so" + } +} + +dependencies { + // 权限请求框架:https://github.com/getActivity/XXPermissions + api 'com.github.getActivity:XXPermissions:18.63' + // 下拉控件 + api 'com.baoyz.pullrefreshlayout:library:1.2.0' + // 拼音搜索 + // https://mvnrepository.com/artifact/com.github.open-android/pinyin4j + api 'com.github.open-android:pinyin4j:2.5.0' + // SSH + api 'com.jcraft:jsch:0.1.55' + // Html 解析 + api 'org.jsoup:jsoup:1.13.1' + // 二维码类库 + api 'com.google.zxing:core:3.4.1' + api 'com.journeyapps:zxing-android-embedded:3.6.0' + // 应用介绍页类库 + api 'io.github.medyo:android-about-page:2.0.0' + // 网络连接类库 + 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 'com.miui.zeus:mimo-ad-sdk:5.3.+'//请使用最新版sdk + //注意:以下5个库必须要引入 + //implementation 'androidx.appcompat:appcompat:1.4.1' + api 'androidx.recyclerview:recyclerview:1.0.0' + api 'com.google.code.gson:gson:2.8.5' + api 'com.github.bumptech.glide:glide:4.9.0' + //annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0' + + // WinBoLL库 nexus.winboll.cc 地址 + api 'cc.winboll.studio:libappbase:15.15.3' + // 备用库 jitpack.io 地址 + //api 'com.github.ZhanGSKen:APPBase:appbase-v15.15.3' + + api fileTree(dir: 'libs', include: ['*.jar']) +} diff --git a/libaes/build.properties b/libaes/build.properties new file mode 100644 index 0000000..3da4b01 --- /dev/null +++ b/libaes/build.properties @@ -0,0 +1,8 @@ +#Created by .winboll/winboll_app_build.gradle +#Tue Jan 13 03:37:01 HKT 2026 +stageCount=2 +libraryProject=libaes +baseVersion=15.15 +publishVersion=15.15.1 +buildCount=0 +baseBetaVersion=15.15.2 diff --git a/libaes/libs/colorpicker-20180319.jar b/libaes/libs/colorpicker-20180319.jar new file mode 100644 index 0000000..b010a12 Binary files /dev/null and b/libaes/libs/colorpicker-20180319.jar differ diff --git a/libaes/proguard-rules.pro b/libaes/proguard-rules.pro new file mode 100644 index 0000000..536058a --- /dev/null +++ b/libaes/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in C:/tools/adt-bundle-windows-x86_64-20131030/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# 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 *; +#} diff --git a/libaes/src/main/AndroidManifest.xml b/libaes/src/main/AndroidManifest.xml new file mode 100644 index 0000000..d4325dc --- /dev/null +++ b/libaes/src/main/AndroidManifest.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/DrawerMenuDataAdapter.java b/libaes/src/main/java/cc/winboll/studio/libaes/DrawerMenuDataAdapter.java new file mode 100644 index 0000000..a9e7bf6 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/DrawerMenuDataAdapter.java @@ -0,0 +1,207 @@ +package cc.winboll.studio.libaes; + +import android.content.Context; +import android.util.SparseArray; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; +import java.util.ArrayList; + +public abstract class DrawerMenuDataAdapter extends BaseAdapter { + + private ArrayList mData; + private int mLayoutResource; //布局id + + + public DrawerMenuDataAdapter() { + } + + public DrawerMenuDataAdapter(ArrayList mData, int mLayoutRes) { + this.mData = mData; + this.mLayoutResource = mLayoutRes; + } + + @Override + public int getCount() { + return mData != null ? mData.size() : 0; + } + + @Override + public T getItem(int position) { + return mData.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + ViewHolder viewHolder = ViewHolder.bind(parent.getContext(), convertView, parent, mLayoutResource + , position); + bindView(viewHolder, getItem(position)); + return viewHolder.getItemView(); + } + + public abstract void bindView(ViewHolder holder, T obj); + + // 添加数据项 + // + public void add(T item) { + if (mData == null) { + mData = new ArrayList<>(); + } + mData.add(item); + notifyDataSetChanged(); + } + + // 添加数据项在指定位置 + // + public void add(int position, T item) { + if (mData == null) { + mData = new ArrayList<>(); + } + mData.add(position, item); + notifyDataSetChanged(); + } + + // 删除数据项 + // + public void remove(T item) { + if (mData != null) { + mData.remove(item); + } + notifyDataSetChanged(); + } + + // 删除指定位置数据项 + // + public void remove(int position) { + if (mData != null) { + mData.remove(position); + } + notifyDataSetChanged(); + } + + // 清理所有数据项 + // + public void clear() { + if (mData != null) { + mData.clear(); + } + notifyDataSetChanged(); + } + + + public static class ViewHolder { + + // 存储在 ListView 的 item 中的 View + SparseArray mSparseArrayView; + // 存放convertView + View mViewItem; + // 游标 + int mnPosition; + Context mContext; + + //构造方法 + // + private ViewHolder(Context context, ViewGroup parent, int layoutResource) { + mSparseArrayView = new SparseArray<>(); + this.mContext = context; + View convertView = LayoutInflater.from(context).inflate(layoutResource, parent, false); + convertView.setTag(this); + mViewItem = convertView; + } + + //绑定 ViewHolder 与数据项 + // + public static ViewHolder bind(Context context, View convertView, ViewGroup parent, + int layoutResource, int position) { + ViewHolder viewHolder; + if (convertView == null) { + viewHolder = new ViewHolder(context, parent, layoutResource); + } else { + viewHolder = (ViewHolder) convertView.getTag(); + viewHolder.mViewItem = convertView; + } + viewHolder.mnPosition = position; + return viewHolder; + } + + @SuppressWarnings("unchecked") + public T getView(int id) { + T t = (T) mSparseArrayView.get(id); + if (t == null) { + t = (T) mViewItem.findViewById(id); + mSparseArrayView.put(id, t); + } + return t; + } + + + + // 获取当前条目 + // + public View getItemView() { + return mViewItem; + } + + + // 获取条目位置 + // + public int getItemPosition() { + return mnPosition; + } + + + // 设置文字 + // + public ViewHolder setText(int id, CharSequence text) { + View view = getView(id); + if (view instanceof TextView) { + ((TextView) view).setText(text); + } + return this; + } + + + // 设置图片 + // + public ViewHolder setImageResource(int id, int drawableResource) { + View view = getView(id); + if (view instanceof ImageView) { + ((ImageView) view).setImageResource(drawableResource); + } else { + view.setBackgroundResource(drawableResource); + } + return this; + } + + // 设置点击监听 + // + public ViewHolder setOnClickListener(int id, View.OnClickListener listener) { + getView(id).setOnClickListener(listener); + return this; + } + + // 设置可见 + // + public ViewHolder setVisibility(int id, int visible) { + getView(id).setVisibility(visible); + return this; + } + + // 设置标签 + // + public ViewHolder setTag(int id, Object obj) { + getView(id).setTag(obj); + return this; + } + + } + +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/ImagePagerAdapter.java b/libaes/src/main/java/cc/winboll/studio/libaes/ImagePagerAdapter.java new file mode 100644 index 0000000..488eb8f --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/ImagePagerAdapter.java @@ -0,0 +1,75 @@ +package cc.winboll.studio.libaes; + +import android.view.View; +import android.view.ViewGroup; +import androidx.viewpager.widget.PagerAdapter; +import java.util.List; + +public class ImagePagerAdapter extends PagerAdapter { + + /* + * 四个必须重写的方法,否则会报错 + * + */ + + private List views; + + //构造方法,拿到views + public ImagePagerAdapter(List views) { + this.views = views; + } + + //以下四个是重写的方法 + // 获取要滑动的控件的数量,在这里我们以滑动的广告栏为例,那么这里就应该是展示的广告图片的ImageView数量 + @Override + public int getCount() { + // TODO Auto-generated method stub + return this.views.size(); + } + + + // 来判断显示的是否是同一张图片,这里我们将两个参数相比较返回即可 + @Override + public boolean isViewFromObject(View arg0, Object arg1) { + // TODO Auto-generated method stub + return arg0 == arg1; + } + + + /** + * position是在viewPager中显示图片的下标 + * 把对应的图片放到对应的位置就好了 + * instantiateItem和destroyItem是对应的 + * 一个是创建item,一个是销毁item + * 当要显示的图片可以进行缓存的时候,会调用instantiateItem()进行显示图片的初始化, + * 我们将要显示的ImageView加入到ViewGroup中,然后作为返回值返回即可 + * + * ViewPager 是扩展于 ViewGroup,container参数是当前的ViewPager对象, + * 所有的item都会被加入到ViewPager中, + * position就是 每个item对应的下标 + */ + @Override + public Object instantiateItem(ViewGroup container, int position) { + container.addView(views.get(position)); + return views.get(position); + } + + //如果出现IllegalStateException: The specified child already has a parent. 这样的错误:则可替换为以下的try catch 代码 + /*try{ +     if(views.get(position).getParent()==null){ +   container.addView(views.get(position)); +     }else{ + ((ViewGroup)views.get(position).getParent()).removeView(views.get(position)); + container.addView(views.get(position)); + } + }catch(Exception e){ + e.printStackTrace(); + }*/ + + // PagerAdapter只缓存5张要显示的图片,如果滑动的图片超出了缓存的范围,就会调用destroyItem(),将图片销毁 + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + container.removeView(views.get(position)); + } +} + diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java new file mode 100644 index 0000000..430e4fd --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/activitys/DrawerFragmentActivity.java @@ -0,0 +1,400 @@ +package cc.winboll.studio.libaes.activitys; + +/** + * @Author ZhanGSKen + * @Date 2024/06/13 18:58:54 + * @Describe 可以加入Fragment的有抽屉的活动窗口抽象类 + */ +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView; +import androidx.appcompat.app.ActionBarDrawerToggle; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.drawerlayout.widget.DrawerLayout; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; +import cc.winboll.studio.libaes.DrawerMenuDataAdapter; +import cc.winboll.studio.libaes.R; +import cc.winboll.studio.libaes.models.AESThemeBean; +import cc.winboll.studio.libaes.models.DrawerMenuBean; +import cc.winboll.studio.libaes.utils.AESThemeUtil; +import cc.winboll.studio.libaes.utils.DevelopUtils; +import cc.winboll.studio.libaes.views.ADrawerMenuListView; +import cc.winboll.studio.libaes.views.ADsBannerView; +import cc.winboll.studio.libappbase.GlobalApplication; +import cc.winboll.studio.libappbase.LogUtils; +import com.baoyz.widget.PullRefreshLayout; +import java.util.ArrayList; + +public abstract class DrawerFragmentActivity extends AppCompatActivity implements AdapterView.OnItemClickListener { + + public static final String TAG = "DrawerFragmentActivity"; + + static final String SHAREDPREFERENCES_NAME = "SHAREDPREFERENCES_NAME"; + static final String DRAWER_THEME_TYPE = "DRAWER_THEME_TYPE"; + + //protected Context mContext; + ActivityType mActivityType; + ActionBarDrawerToggle mActionBarDrawerToggle; + DrawerLayout mDrawerLayout; + PullRefreshLayout mPullRefreshLayout; + ADrawerMenuListView mADrawerMenuListView; + DrawerMenuDataAdapter mDrawerMenuDataAdapter; + boolean mIsDrawerOpened = false; + boolean mIsDrawerOpening = false; + boolean mIsDrawerClosing = false; + + protected Toolbar mToolbar; + public enum ActivityType { Main, Secondary } + protected volatile AESThemeBean.ThemeType mThemeType; + protected ArrayList malDrawerMenuItem; + abstract protected ActivityType initActivityType(); + //abstract protected View initContentView(LayoutInflater inflater, ViewGroup rootView); + + @Override + protected void onCreate(Bundle savedInstanceState) { + //mContext = this; + mThemeType = getThemeType(); + setThemeStyle(); + super.onCreate(savedInstanceState); + mActivityType = initActivityType(); + initRootView(); + LogUtils.d(TAG, "onCreate end."); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + // 修复:释放广告资源,避免内存泄漏 + ADsBannerView adsBannerView = findViewById(R.id.adsbanner); + if (adsBannerView != null) { + adsBannerView.releaseAdResources(); + } + } + + /*@Override + public Intent getIntent() { + // TODO: Implement this method + return super.getIntent(); + } + + public Context getContext() { + return this.mContext; + }*/ + + @Override + public MenuInflater getMenuInflater() { + // TODO: Implement this method + return super.getMenuInflater(); + } + + /*public void setSubtitle(CharSequence context) { + // TODO: Implement this method + getSupportActionBar().setSubtitle(context); + }*/ + + @Override + public void recreate() { + super.recreate(); + } + + /*@Override + public boolean moveTaskToBack(boolean nonRoot) { + return super.moveTaskToBack(nonRoot); + }*/ + + @Override + public void startActivity(Intent intent) { + super.startActivity(intent); + } + + @Override + public void startActivityForResult(Intent intent, int requestCode, Bundle options) { + super.startActivityForResult(intent, requestCode, options); + } + + /*@Override + public FragmentManager getSupportFragmentManager() { + return super.getSupportFragmentManager(); + } + + public void setSubtitle(int resId) { + // TODO: Implement this method + getSupportActionBar().setSubtitle(resId); + } + + public void setTitle(CharSequence context) { + // TODO: Implement this method + getSupportActionBar().setTitle(context); + } + + public void setTitle(int resId) { + // TODO: Implement this method + getSupportActionBar().setTitle(resId); + }*/ + + @Override + public SharedPreferences getSharedPreferences(String name, int mode) { + return super.getSharedPreferences(name, mode); + } + + @Override + public Context getApplicationContext() { + // TODO: Implement this method + return super.getApplicationContext(); + } + + @Override + public void onBackPressed() { + super.onBackPressed(); + } + + void setThemeStyle() { + //setTheme(AESThemeBean.getThemeStyle(getThemeType())); + setTheme(AESThemeUtil.getThemeTypeID(getApplicationContext())); + } + + boolean checkThemeStyleChange() { + return mThemeType != getThemeType(); + } + + AESThemeBean.ThemeType getThemeType() { + /*SharedPreferences sharedPreferences = getSharedPreferences( + SHAREDPREFERENCES_NAME, MODE_PRIVATE); + return AESThemeBean.ThemeType.values()[((sharedPreferences.getInt(DRAWER_THEME_TYPE, AESThemeBean.ThemeType.DEFAULT.ordinal())))]; + */ + return AESThemeBean.getThemeStyleType(AESThemeUtil.getThemeTypeID(getApplicationContext())); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (AESThemeUtil.onAppThemeItemSelected(this, item)) { + recreate(); + } if (DevelopUtils.onDevelopItemSelected(this, item)) { + LogUtils.d(TAG, String.format("onOptionsItemSelected item.getItemId() %d ", item.getItemId())); + } else { + return super.onOptionsItemSelected(item); + } + + return true; + } + + @Override + protected void onResume() { + super.onResume(); + if (checkThemeStyleChange()) { + recreate(); + } + + ADsBannerView adsBannerView = findViewById(R.id.adsbanner); + if (adsBannerView != null) { + adsBannerView.resumeADs(DrawerFragmentActivity.this); + } + } + + void initRootView() { + setContentView(R.layout.activity_drawerfragment); + + mToolbar = findViewById(R.id.activitydrawerfragmentASupportToolbar1); + setSupportActionBar(mToolbar); + + if (mActivityType == ActivityType.Main) { + initMainRootView(); + } else if (mActivityType == ActivityType.Secondary) { + initSecondaryRootView(); + } + } + + void initMainRootView() { + mDrawerLayout = findViewById(R.id.activitydrawerfragmentDrawerLayout1); + mADrawerMenuListView = findViewById(R.id.activitydrawerfragmentDrawerMenuListView1); + mPullRefreshLayout = findViewById(R.id.activitydrawerfragmentPullRefreshLayout1); + + mPullRefreshLayout.setOnRefreshListener(new PullRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + //LogUtils.d(TAG, "onRefresh"); + reinitDrawerMenuItemList(malDrawerMenuItem); + mDrawerMenuDataAdapter.notifyDataSetChanged(); + mPullRefreshLayout.setRefreshing(false); + } + }); + + malDrawerMenuItem = new ArrayList(); + + mDrawerMenuDataAdapter = new DrawerMenuDataAdapter(malDrawerMenuItem, R.layout.listview_drawermenu) { + @Override + public void bindView(ViewHolder holder, DrawerMenuBean obj) { + holder.setImageResource(R.id.listviewdrawermenuImageView1, obj.getIconId()); + holder.setText(R.id.listviewdrawermenuTextView1, obj.getIconName()); + } + }; + mADrawerMenuListView.setAdapter(mDrawerMenuDataAdapter); + mADrawerMenuListView.setOnItemClickListener(this); + + mActionBarDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, mToolbar, R.string.lib_name, R.string.lib_name) { + @Override + public void onDrawerOpened(View drawerView) {//完全打开时触发 + super.onDrawerOpened(drawerView); + mIsDrawerOpened = true; + mIsDrawerOpening = false; + //Toast.makeText(MainActivity.this,"onDrawerOpened",Toast.LENGTH_SHORT).show(); + } + + @Override + public void onDrawerClosed(View drawerView) {//完全关闭时触发 + super.onDrawerClosed(drawerView); + mIsDrawerOpened = false; + mIsDrawerClosing = false; + //Toast.makeText(MainActivity.this,"onDrawerClosed",Toast.LENGTH_SHORT).show(); + } + + /** + * 当抽屉被滑动的时候调用此方法 + * slideOffset表示 滑动的幅度(0-1) + */ + @Override + public void onDrawerSlide(View drawerView, float slideOffset) { + super.onDrawerSlide(drawerView, slideOffset); + } + + /** + * 当抽屉滑动状态改变的时候被调用 + * 状态值是STATE_IDLE(闲置--0), STATE_DRAGGING(拖拽的--1), STATE_SETTLING(固定--2)中之一。 + *具体状态可以慢慢调试 + */ + @Override + public void onDrawerStateChanged(int newState) { + super.onDrawerStateChanged(newState); + } + }; + + //设置显示旋转菜单 + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + //通过下面这句实现toolbar和Drawer的联动:如果没有这行代码,箭头是不会随着侧滑菜单的开关而变换的(或者没有箭头), + // 可以尝试一下,不影响正常侧滑 + mActionBarDrawerToggle.syncState(); + mDrawerLayout.setDrawerListener(mActionBarDrawerToggle); + + //去掉侧滑的默认图标(动画箭头图标),也可以选择不去, + //不去的话把这一行注释掉或者改成true,然后把toolbar.setNavigationIcon注释掉就行了 + //mActionBarDrawerToggle.setDrawerIndicatorEnabled(false); + mToolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mIsDrawerOpened || mIsDrawerOpening) { + mIsDrawerClosing = true; + mIsDrawerOpening = false; + mDrawerLayout.closeDrawer(mPullRefreshLayout); + return; + } + if (!mIsDrawerOpened || mIsDrawerClosing) { + mIsDrawerOpening = true; + mIsDrawerClosing = false; + mDrawerLayout.openDrawer(mPullRefreshLayout); + return; + } + } + }); + + initDrawerMenuItemList(malDrawerMenuItem); + } + + void initSecondaryRootView() { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + mToolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + //LogUtils.d(TAG, "onClick " + Integer.toString(v.getId())); + finish(); + } + }); + } + + public int removeFragment(T fragment) { + FragmentManager fragmentManager = getSupportFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + fragmentTransaction.remove(fragment); + fragmentTransaction.commit(); + return fragmentManager.getFragments().size() - 1; + } + + public int addFragment(T fragment) { + FragmentManager fragmentManager = getSupportFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + fragmentTransaction.add(R.id.activitydrawerfragmentFrameLayout1, fragment); + fragmentTransaction.commit(); + return fragmentManager.getFragments().size() - 1; + } + + public void showFragment(T fragment) { + FragmentManager fragmentManager = getSupportFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + for (int i = 0; i < fragmentManager.getFragments().size(); i++) { + if (fragmentManager.getFragments().get(i).equals(fragment)) { + fragmentTransaction.show(fragmentManager.getFragments().get(i)); + } else { + fragmentTransaction.hide(fragmentManager.getFragments().get(i)); + } + } + fragmentTransaction.commit(); + } + + public void showFragment(int nPosition) { + FragmentManager fragmentManager = getSupportFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + for (int i = 0; i < fragmentManager.getFragments().size(); i++) { + if (i == nPosition) { + fragmentTransaction.show(fragmentManager.getFragments().get(i)); + } else { + fragmentTransaction.hide(fragmentManager.getFragments().get(i)); + } + } + fragmentTransaction.commit(); + } + + protected void initDrawerMenuItemList(ArrayList listDrawerMenu) { + + } + + protected void reinitDrawerMenuItemList(ArrayList listDrawerMenu) { + + } + + public void notifyDrawerMenuDataChanged() { + mDrawerMenuDataAdapter.notifyDataSetChanged(); + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + mDrawerLayout.closeDrawer(mPullRefreshLayout); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + if (mActivityType == ActivityType.Main) { + // 主题菜单 + AESThemeUtil.inflateMenu(this, menu); + // 调试工具菜单 + if (GlobalApplication.isDebugging()) { + DevelopUtils.inflateMenu(this, menu); + } + // 应用信息菜单 + getMenuInflater().inflate(R.menu.toolbar_drawerbase, menu); + } + return super.onCreateOptionsMenu(menu); + } + + @Override + protected void onActivityResult(int who, int targetFragment, Intent requestCode) { + super.onActivityResult(who, targetFragment, requestCode); + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/dialogs/LocalFileSelectDialog.java b/libaes/src/main/java/cc/winboll/studio/libaes/dialogs/LocalFileSelectDialog.java new file mode 100644 index 0000000..c181865 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/dialogs/LocalFileSelectDialog.java @@ -0,0 +1,204 @@ +package cc.winboll.studio.libaes.dialogs; + +import android.content.Context; +import android.content.DialogInterface; +import android.widget.TextView; +import android.widget.Toast; +import androidx.appcompat.app.AlertDialog; +import cc.winboll.studio.libappbase.LogUtils; +import java.io.File; +import java.lang.reflect.Field; +import java.text.Collator; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +public class LocalFileSelectDialog { + + public static final String TAG = LocalFileSelectDialog.class.getSimpleName(); + + File mfCurrentPath = new File("/storage/emulated/0"); + String mszResultPath = "/storage/emulated/0"; + OKClickListener mOKClickListener; + + Context mContext; + + public LocalFileSelectDialog(Context context) { + mContext = context; + } + + public void open() { + LogUtils.d(TAG, "call open()"); + String[] szlist = getChildFileList(mfCurrentPath); + if (szlist != null) { + showSingleChoiceDialog(szlist, 0); + } + } + + int yourChoice; + protected void showSingleChoiceDialog(final String[] szItems, final int nChoice) { + LogUtils.d(TAG, "call showSingleChoiceDialog(...)"); + yourChoice = nChoice; + AlertDialog.Builder builder = new AlertDialog.Builder(mContext); + String sz = mfCurrentPath.getPath(); + + builder.setTitle(sz); + //builder.setCancelable(false); + builder.setSingleChoiceItems(szItems, nChoice, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + yourChoice = which; + } + }); + // 确定按钮 + builder.setPositiveButton("确定", + new DialogInterface.OnClickListener() { + + @Override + public void onClick( + DialogInterface dialog, + int which) { + mszResultPath = mfCurrentPath.getPath() + File.separator + szItems[yourChoice]; + //Toast.makeText(mContext, mszResultPath, Toast.LENGTH_SHORT).show(); + mOKClickListener.onOKClick(mszResultPath); + } + }); + // 下一层文件按钮 + builder.setNegativeButton(">>>", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + File file = new File(mfCurrentPath.getPath() + File.separator + szItems[yourChoice]); + String[] szlist = getChildFileList(file); + if (szlist != null) { + mfCurrentPath = new File(mfCurrentPath.getPath() + File.separator + szItems[yourChoice]); + + showSingleChoiceDialog(szlist, 0); + + } else { + Toast.makeText(mContext, "这是一个最低的目录", Toast.LENGTH_SHORT).show(); + String[] szlistOld = getChildFileList(mfCurrentPath); + showSingleChoiceDialog(szlistOld, yourChoice); + } + + } + }); + // 上一层文件按钮 + builder.setNeutralButton("<<<", + new DialogInterface.OnClickListener() {// 添加返回按钮 + + @Override + public void onClick( + DialogInterface dialog, + int which) {// 响应事件 + + String[] szlist = getChildFileList(mfCurrentPath.getParentFile()); + if (szlist != null) { + mfCurrentPath = mfCurrentPath.getParentFile(); + + showSingleChoiceDialog(szlist, 0); + + } else { + Toast.makeText(mContext, "这是一个最高的目录", Toast.LENGTH_SHORT).show(); + String[] szlistOld = getChildFileList(mfCurrentPath); + showSingleChoiceDialog(szlistOld, yourChoice); + } + + } + }); + AlertDialog dialog = builder.create(); + dialog.show(); + + // 反射原理修改对话框元素 + // + //需要在show()方法之后才能修改 + //修改“确认”、“取消”按钮的字体大小 + //dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextSize(16); + //dialog.getButton(DialogInterface.BUTTON_NEGATIVE).setTextSize(16); + //dialog.getButton(DialogInterface.BUTTON_NEUTRAL).setTextSize(16); + try { + Field mAlert = AlertDialog.class.getDeclaredField("mAlert"); + mAlert.setAccessible(true); + Object mAlertController = mAlert.get(dialog); + + //通过反射修改title字体大小和颜色 + Field mTitle = mAlertController.getClass().getDeclaredField("mTitleView"); + mTitle.setAccessible(true); + TextView mTitleView = (TextView) mTitle.get(mAlertController); + //mTitleView.setTextSize(16); + //mTitleView.setTextColor(Color.RED); + mTitleView.setSingleLine(false); + + //通过反射修改message字体大小和颜色 + //Field mMessage = mAlertController.getClass().getDeclaredField("mMessageView"); + //mMessage.setAccessible(true); + //TextView mMessageView = (TextView) mMessage.get(mAlertController); + //mMessageView.setTextSize(16); + //mMessageView.setTextColor(Color.GREEN); + } catch (IllegalAccessException e) { + LogUtils.d(TAG, "IllegalAccessException : " + e.getMessage()); + } catch (NoSuchFieldException e) { + LogUtils.d(TAG, "NoSuchFieldException : " + e.getMessage()); + } + } + + public void setOnOKClickListener(OKClickListener listener) { + mOKClickListener = listener; + } + + public interface OKClickListener { + void onOKClick(String szResultPath); + } + + // 读取文件夹子目录 + // + // "/storage/emulated/0"以上 + // 和没有子目录的f参数返回空列表 + protected String[] getChildFileList(File file) { + ArrayList szlistFiles = new ArrayList(); + if (!file.getPath().equals("/storage/emulated")) { + File[] fileList = file.listFiles(); + if (fileList != null) { + for (File fileItem : fileList) { + if (fileItem.getName().charAt(0) != '.') { + if (fileItem.isDirectory()) { + szlistFiles.add(fileItem.getName()); + } + } + } + } + } + Collections.sort(szlistFiles, new SortChineseName(true)); + + if (szlistFiles.size() > 0) { + return szlistFiles.toArray(new String[szlistFiles.size()]); + } else { + return null; + } + } + + private class SortChineseName implements Comparator { + private boolean mIsA2Z = true; + public SortChineseName(boolean isA2Z) { + mIsA2Z = isA2Z; + } + Collator cmp = Collator.getInstance(java.util.Locale.CHINA); + @Override + public int compare(String o1, String o2) { + if (mIsA2Z) { + if (cmp.compare(o1, o2) > 0) { + return 1; + } else if (cmp.compare(o1, o2) < 0) { + return -1; + } + } else { + if (cmp.compare(o1, o2) > 0) { + return -1; + } else if (cmp.compare(o1, o2) < 0) { + return 1; + } + } + return 0; + } + } + +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/dialogs/StoragePathDialog.java b/libaes/src/main/java/cc/winboll/studio/libaes/dialogs/StoragePathDialog.java new file mode 100644 index 0000000..2870a0f --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/dialogs/StoragePathDialog.java @@ -0,0 +1,57 @@ +package cc.winboll.studio.libaes.dialogs; + +import android.app.Dialog; +import android.view.Gravity; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import cc.winboll.studio.libaes.R; +import cc.winboll.studio.libaes.utils.ScreenUtil; + +public class StoragePathDialog extends Dialog { + + public static final String TAG = "StoragePathDialog"; + View.OnClickListener mOnOKClickListener; + + public StoragePathDialog(android.content.Context context) { + super(context); + + } + + public StoragePathDialog(android.content.Context context, int themeResId) { + super(context, (themeResId == 0) ? cc.winboll.studio.libaes.R.style.NormalDialogStyle: themeResId); + // 加载默认布局 + View view = View.inflate(context, R.layout.dialog_storagepath, null); + setContentView(view); + // 添加按键点击监听 + view.findViewById(R.id.dialogstoragepathButton1).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (mOnOKClickListener != null) { + mOnOKClickListener.onClick(view); + } + } + }); + // 使得点击对话框外部不消失对话框 + setCanceledOnTouchOutside(false); + // 设置对话框大小 + ScreenUtil.ScreenSize ss = ScreenUtil.getScreenSize(context); + view.setMinimumHeight((int) (ss.getHeightPixels() * 0.23f)); + Window dialogWindow = getWindow(); + WindowManager.LayoutParams lp = dialogWindow.getAttributes(); + lp.width = (int) (ss.getWidthPixels() * 0.75f); + lp.height = WindowManager.LayoutParams.WRAP_CONTENT; + lp.gravity = Gravity.CENTER; + dialogWindow.setAttributes(lp); + + } + + protected StoragePathDialog(android.content.Context context, boolean cancelable, android.content.DialogInterface.OnCancelListener cancelListener) { + super(context, cancelable, cancelListener); + } + + public void setOnOKClickListener(View.OnClickListener listener) { + mOnOKClickListener = listener; + } + +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/dialogs/YesNoAlertDialog.java b/libaes/src/main/java/cc/winboll/studio/libaes/dialogs/YesNoAlertDialog.java new file mode 100644 index 0000000..f176daa --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/dialogs/YesNoAlertDialog.java @@ -0,0 +1,60 @@ +package cc.winboll.studio.libaes.dialogs; + +/** + * @Author ZhanGSKen + * @Date 2025/03/28 17:40:47 + * @Date 2024/08/12 14:46:25 + * @Describe 询问用户确定与否的选择框 + */ +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; + +public class YesNoAlertDialog { + + public static final String TAG = "YesNoAlertDialog"; + + public static void show(Context context, String szTitle, String szMessage, final OnDialogResultListener listener) { + AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder( + context); + + // set title + alertDialogBuilder.setTitle(szTitle); + + // set dialog message + alertDialogBuilder + .setMessage(szMessage) + .setCancelable(true) + .setOnCancelListener(new DialogInterface.OnCancelListener(){ + @Override + public void onCancel(DialogInterface dialog) { + listener.onNo(); + } + }) + .setPositiveButton("YES", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // if this button is clicked, close + // current activity + listener.onYes(); + } + }) + .setNegativeButton("NO", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // if this button is clicked, just close + // the dialog box and do nothing + dialog.cancel(); + } + }); + + // create alert dialog + AlertDialog alertDialog = alertDialogBuilder.create(); + + // show it + alertDialog.show(); + } + + public interface OnDialogResultListener { + abstract void onYes(); + abstract void onNo(); + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/enums/ADsMode.java b/libaes/src/main/java/cc/winboll/studio/libaes/enums/ADsMode.java new file mode 100644 index 0000000..a43743c --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/enums/ADsMode.java @@ -0,0 +1,32 @@ +package cc.winboll.studio.libaes.enums; + +/** + * @Author ZhanGSKen&豆包大模型 + * @Date 2025/11/26 17:49 + * @Describe 广告控制模式枚举 + */ +public enum ADsMode { + STANDALONE("单机模式"), // 单机模式(默认) + MIMO_SDK("米盟广告SDK支持模式"), // 米盟广告SDK模式 + STORE_QRCODE("云宝物语模式"); // 米盟广告SDK模式 + + private final String modeName; + + ADsMode(String modeName) { + this.modeName = modeName; + } + + public String getModeName() { + return modeName; + } + + // 根据保存的字符串值解析枚举(SP读取时使用) + public static ADsMode fromValue(String value) { + if (value == null) return STANDALONE; + try { + return ADsMode.valueOf(value); + } catch (IllegalArgumentException e) { + return STANDALONE; + } + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/enums/PrivacyAgreeStatus.java b/libaes/src/main/java/cc/winboll/studio/libaes/enums/PrivacyAgreeStatus.java new file mode 100644 index 0000000..fe9e133 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/enums/PrivacyAgreeStatus.java @@ -0,0 +1,67 @@ +package cc.winboll.studio.libaes.enums; + +/** + * @Author ZhanGSKen&豆包大模型 + * @Date 2025/11/27 12:35 + * @Describe 隐私协议签约状态枚举 + * 对应值:0-拒绝,1-赞同,2-未签约(默认) + */ +public enum PrivacyAgreeStatus { + REJECTED(0, "拒绝"), // 0: 拒绝隐私协议 + AGREED(1, "赞同"), // 1: 赞同隐私协议 + UN_SIGNED(2, "未签约"); // 2: 未签约(初始默认状态) + + private final int statusCode; // 对应存储的int值 + private final String statusDesc; // 状态描述(可选,便于日志/UI显示) + + // Java 7 枚举构造方法(必须private) + private PrivacyAgreeStatus(int statusCode, String statusDesc) { + this.statusCode = statusCode; + this.statusDesc = statusDesc; + } + + /** + * 根据int值获取枚举(SP读取时使用,兼容Java 7) + * @param code 存储的int值(0/1/2) + * @return 对应枚举,默认返回UN_SIGNED(未签约) + */ + public static PrivacyAgreeStatus fromCode(int code) { + // Java 7 不支持switch(String),用if-else兼容 + if (code == REJECTED.statusCode) { + return REJECTED; + } else if (code == AGREED.statusCode) { + return AGREED; + } else { + return UN_SIGNED; // 默认未签约 + } + } + + /** + * 根据SP存储的字符串值获取枚举(兼容原逻辑中String类型存储) + * @param codeStr 存储的字符串值("0"/"1"/"2") + * @return 对应枚举,默认返回UN_SIGNED(未签约) + */ + public static PrivacyAgreeStatus fromString(String codeStr) { + if (codeStr == null) { + return UN_SIGNED; + } + try { + int code = Integer.parseInt(codeStr); + return fromCode(code); + } catch (NumberFormatException e) { + // 字符串格式异常时,默认返回未签约 + return UN_SIGNED; + } + } + + // 获取状态码(用于存储到SP) + public int getStatusCode() { + return statusCode; + } + + // 获取状态描述(用于日志/UI显示,可选) + public String getStatusDesc() { + return statusDesc; + } +} + diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/interfaces/IWinBoLLActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/interfaces/IWinBoLLActivity.java new file mode 100644 index 0000000..aa4805b --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/interfaces/IWinBoLLActivity.java @@ -0,0 +1,18 @@ +package cc.winboll.studio.libaes.interfaces; + +/** + * @Author ZhanGSKen + * @Date 2025/05/10 09:34 + * @Describe WinBoLL 窗口操作接口 + */ + import android.app.Activity; + +public abstract interface IWinBoLLActivity { + + public static final String TAG = "IWinBoLLActivity"; + + public static final String ACTION_BIND = IWinBoLLActivity.class.getName() + ".ACTION_BIND"; + + public Activity getActivity(); + public String getTag(); +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/models/AESThemeBean.java b/libaes/src/main/java/cc/winboll/studio/libaes/models/AESThemeBean.java new file mode 100644 index 0000000..dd4d8d8 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/models/AESThemeBean.java @@ -0,0 +1,143 @@ +package cc.winboll.studio.libaes.models; + +/** + * @Author ZhanGSKen + * @Date 2024/06/14 02:42:57 + * @Describe 主题元素项目类 + */ +import android.util.JsonReader; +import android.util.JsonWriter; +import cc.winboll.studio.libaes.R; +import cc.winboll.studio.libappbase.BaseBean; +import java.io.IOException; + +public class AESThemeBean extends BaseBean { + + public static final String TAG = "AESThemeBean"; + + public enum ThemeType { + AES("默认主题"), + DEPTH("深奥主题"), + SKY("天空主题"), + GOLDEN("辉煌主题"), + BEARING("智芋主题"), + MEMOR("梦箩主题"), + TAO("黑白主题"); + + private String name; + + // 枚举构造函数 + ThemeType(String name) { + this.name = name; + } + + // 将字符串转换为枚举 + public static ThemeType fromString(String themeTypeStr) { + return ThemeType.valueOf(themeTypeStr.toUpperCase()); // 注意这里用了toUpperCase(),确保匹配时不区分大小写 + } + + // 获取枚举的名称 + public String getName() { + return name; + } + } + + // 保存当前主题 + int currentThemeStyleID = getThemeStyleID(ThemeType.AES); + + public AESThemeBean() { + } + + public AESThemeBean(int currentThemeStyleID) { + this.currentThemeStyleID = currentThemeStyleID; + } + + public void setCurrentThemeTypeID(int currentThemeTypeID) { + this.currentThemeStyleID = currentThemeTypeID; + } + + public int getCurrentThemeTypeID() { + return this.currentThemeStyleID; + } + + @Override + public String getName() { + return AESThemeBean.class.getName(); + } + + @Override + public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { + super.writeThisToJsonWriter(jsonWriter); + AESThemeBean bean = this; + jsonWriter.name("currentThemeTypeID").value(bean.getCurrentThemeTypeID()); + } + + @Override + public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { + if(super.initObjectsFromJsonReader(jsonReader, name)) { return true; } + else{ + if (name.equals("currentThemeTypeID")) { + setCurrentThemeTypeID(jsonReader.nextInt()); + } 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; + } + + public static int getThemeStyleID(ThemeType themeType) { + int themeStyleID = R.style.AESTheme; + if (AESThemeBean.ThemeType.DEPTH == themeType) { + themeStyleID = R.style.DepthAESTheme; + } else if (AESThemeBean.ThemeType.SKY == themeType) { + themeStyleID = R.style.SkyAESTheme; + } else if (AESThemeBean.ThemeType.GOLDEN == themeType) { + themeStyleID = R.style.GoldenAESTheme; + } else if (AESThemeBean.ThemeType.BEARING == themeType) { + themeStyleID = R.style.BearingAESTheme; + } else if (AESThemeBean.ThemeType.MEMOR == themeType) { + themeStyleID = R.style.MemorAESTheme; + } else if (AESThemeBean.ThemeType.TAO == themeType) { + themeStyleID = R.style.TaoAESTheme; + } else if (AESThemeBean.ThemeType.AES == themeType) { + themeStyleID = R.style.AESTheme; + } + //LogUtils.d(TAG, "themeStyleID " + Integer.toString(themeStyleID)); + return themeStyleID; + } + + public static AESThemeBean.ThemeType getThemeStyleType(int nThemeStyleID) { + AESThemeBean.ThemeType themeStyle = AESThemeBean.ThemeType.AES; + if (R.style.DepthAESTheme == nThemeStyleID) { + themeStyle = AESThemeBean.ThemeType.DEPTH ; + } else if (R.style.SkyAESTheme == nThemeStyleID) { + themeStyle = AESThemeBean.ThemeType.SKY ; + } else if (R.style.GoldenAESTheme == nThemeStyleID) { + themeStyle = AESThemeBean.ThemeType.GOLDEN ; + } else if (R.style.BearingAESTheme == nThemeStyleID) { + themeStyle = AESThemeBean.ThemeType.BEARING ; + } else if (R.style.MemorAESTheme == nThemeStyleID) { + themeStyle = AESThemeBean.ThemeType.MEMOR ; + } else if (R.style.TaoAESTheme == nThemeStyleID) { + themeStyle = AESThemeBean.ThemeType.TAO ; + } else if (R.style.AESTheme == nThemeStyleID) { + themeStyle = AESThemeBean.ThemeType.AES; + } + //LogUtils.d(TAG, "themeStyle " + Integer.toString(themeStyle.ordinal())); + return themeStyle; + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/models/APPInfo.java b/libaes/src/main/java/cc/winboll/studio/libaes/models/APPInfo.java new file mode 100644 index 0000000..cf097e0 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/models/APPInfo.java @@ -0,0 +1,169 @@ +package cc.winboll.studio.libaes.models; + +/** + * @Author ZhanGSKen + * @Date 2025/01/20 14:19:02 + * @Describe 应用信息类 + */ +import cc.winboll.studio.libaes.R; +import java.io.Serializable; + +public class APPInfo implements Serializable { + + public static final String TAG = "APPInfo"; + + // 应用名称 + String appName; + // 应用图标 + int appIcon; + // 应用描述 + String appDescription; + // 应用Git仓库地址 + String appGitName; + // 应用Git仓库拥有者 + String appGitOwner; + // 应用Git仓库分支 + String appGitAPPBranch; + // 应用Git仓库子项目文件夹 + String appGitAPPSubProjectFolder; + // 应用主页 + String appHomePage; + // 应用包名称 + String appAPKName; + // 应用包存储文件夹名称 + String appAPKFolderName; + // 是否添加调试工具 + boolean isAddDebugTools; + + public APPInfo(String appName, int appIcon, String appDescription, String appGitName, String appGitOwner, String appGitAPPBranch, String appGitAPPSubProjectFolder, String appHomePage, String appAPKName, String appAPKFolderName) { + this.appName = appName; + this.appIcon = appIcon; + this.appDescription = appDescription; + this.appGitName = appGitName; + this.appGitOwner = appGitOwner; + this.appGitAPPBranch = appGitAPPBranch; + this.appGitAPPSubProjectFolder = appGitAPPSubProjectFolder; + this.appHomePage = appHomePage; + this.appAPKName = appAPKName; + this.appAPKFolderName = appAPKFolderName; + this.isAddDebugTools = false; + } + + public APPInfo(String appName, int appIcon, String appDescription, String appGitName, String appGitOwner, String appGitAPPBranch, String appGitAPPSubProjectFolder, String appHomePage, String appAPKName, String appAPKFolderName, boolean isAddDebugTools) { + this.appName = appName; + this.appIcon = appIcon; + this.appDescription = appDescription; + this.appGitName = appGitName; + this.appGitOwner = appGitOwner; + this.appGitAPPBranch = appGitAPPBranch; + this.appGitAPPSubProjectFolder = appGitAPPSubProjectFolder; + this.appHomePage = appHomePage; + this.appAPKName = appAPKName; + this.appAPKFolderName = appAPKFolderName; + this.isAddDebugTools = isAddDebugTools; + } + + public APPInfo() { + String szBranchName = "app"; + this.appName = "APP"; + this.appIcon = R.drawable.ic_launcher; + this.appDescription = "APP Description"; + this.appGitName = "APP"; + this.appGitOwner = "Studio"; + this.appGitAPPBranch = szBranchName; + this.appGitAPPSubProjectFolder = szBranchName; + this.appHomePage = "https://www.winboll.cc/studio/details.php?app=APP"; + this.appAPKName = "APP"; + this.appAPKFolderName = "APP"; + this.isAddDebugTools = false; + } + + public void setIsAddDebugTools(boolean isAddDebugTools) { + this.isAddDebugTools = isAddDebugTools; + } + + public boolean isAddDebugTools() { + return isAddDebugTools; + } + + public void setAppGitOwner(String appGitOwner) { + this.appGitOwner = appGitOwner; + } + + public String getAppGitOwner() { + return appGitOwner; + } + + public void setAppGitAPPBranch(String appGitAPPBranch) { + this.appGitAPPBranch = appGitAPPBranch; + } + + public String getAppGitAPPBranch() { + return appGitAPPBranch; + } + + public void setAppGitAPPSubProjectFolder(String appGitAPPSubProjectFolder) { + this.appGitAPPSubProjectFolder = appGitAPPSubProjectFolder; + } + + public String getAppGitAPPSubProjectFolder() { + return appGitAPPSubProjectFolder; + } + + public void setAppIcon(int appIcon) { + this.appIcon = appIcon; + } + + public int getAppIcon() { + return appIcon; + } + + public void setAppDescription(String appDescription) { + this.appDescription = appDescription; + } + + public String getAppDescription() { + return appDescription; + } + + public void setAppAPKFolderName(String appAPKFolderName) { + this.appAPKFolderName = appAPKFolderName; + } + + public String getAppAPKFolderName() { + return appAPKFolderName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getAppName() { + return appName; + } + + public void setAppGitName(String appGitName) { + this.appGitName = appGitName; + } + + public String getAppGitName() { + return appGitName; + } + + public void setAppHomePage(String appHomePage) { + this.appHomePage = appHomePage; + } + + public String getAppHomePage() { + return appHomePage; + } + + public void setAppAPKName(String appAPKName) { + this.appAPKName = appAPKName; + } + + public String getAppAPKName() { + return appAPKName; + } +} + diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/models/DrawerMenuBean.java b/libaes/src/main/java/cc/winboll/studio/libaes/models/DrawerMenuBean.java new file mode 100644 index 0000000..662d4d4 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/models/DrawerMenuBean.java @@ -0,0 +1,35 @@ +package cc.winboll.studio.libaes.models; + +/** + * @Author ZhanGSKen + * @Date 2024/06/14 01:53:34 + * @Describe 抽屉菜单项目类 + */ +public class DrawerMenuBean { + + public static final String TAG = "DrawerMenuBean"; + + private int iconId; + private String iconName; + + public DrawerMenuBean(int iconId, String iconName) { + this.iconId = iconId; + this.iconName = iconName; + } + + public int getIconId() { + return iconId; + } + + public String getIconName() { + return iconName; + } + + public void setIconId(int iconId) { + this.iconId = iconId; + } + + public void setIconName(String iconName) { + this.iconName = iconName; + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/models/WinBoLLClientServiceBean.java b/libaes/src/main/java/cc/winboll/studio/libaes/models/WinBoLLClientServiceBean.java new file mode 100644 index 0000000..dcd112b --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/models/WinBoLLClientServiceBean.java @@ -0,0 +1,78 @@ +package cc.winboll.studio.libaes.models; + +/** + * @Author ZhanGSKen + * @Date 2025/05/03 19:16 + */ +import android.content.Context; +import android.util.JsonReader; +import android.util.JsonWriter; +import cc.winboll.studio.libappbase.BaseBean; +import java.io.IOException; + +public class WinBoLLClientServiceBean extends BaseBean { + + public static final String TAG = "WinBoLLClientServiceBean"; + + // 服务是否正在使用中 + boolean isEnable; + + public WinBoLLClientServiceBean() { + this.isEnable = false; + } + + public WinBoLLClientServiceBean(boolean isEnable) { + this.isEnable = isEnable; + } + + public void setIsEnable(boolean isEnable) { + this.isEnable = isEnable; + } + + public boolean isEnable() { + return isEnable; + } + + + @Override + public String getName() { + return WinBoLLClientServiceBean.class.getName(); + } + + @Override + public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { + super.writeThisToJsonWriter(jsonWriter); + WinBoLLClientServiceBean bean = this; + //jsonWriter.name("logLevel").value(bean.getLogLevel().ordinal()); + } + + @Override + public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { + if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { +// if (name.equals("logLevel")) { +// setLogLevel(LogUtils.LOG_LEVEL.values()[jsonReader.nextInt()]); +// } 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; + } + + public static WinBoLLClientServiceBean loadWinBoLLClientServiceBean(Context context) { + return new WinBoLLClientServiceBean(); + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/unittests/SecondaryLibraryActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/SecondaryLibraryActivity.java new file mode 100644 index 0000000..2373d6a --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/SecondaryLibraryActivity.java @@ -0,0 +1,62 @@ +package cc.winboll.studio.libaes.unittests; + +import android.app.Activity; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.Toast; +import cc.winboll.studio.libaes.R; +import cc.winboll.studio.libaes.activitys.DrawerFragmentActivity; +import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; + +/** + * @Author ZhanGSKen + * @Date 2024/06/15 00:58:10 + * @Describe 第二级窗口 + */ +public class SecondaryLibraryActivity extends DrawerFragmentActivity implements IWinBoLLActivity { + + public static final String TAG = "SecondaryLibraryActivity"; + + SecondaryLibraryFragment mSecondaryLibraryFragment; + + @Override + public Activity getActivity() { + return this; + } + + @Override + public String getTag() { + return null; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (mSecondaryLibraryFragment == null) { + mSecondaryLibraryFragment = new SecondaryLibraryFragment(); + addFragment(mSecondaryLibraryFragment); + } + showFragment(mSecondaryLibraryFragment); + } + + @Override + public DrawerFragmentActivity.ActivityType initActivityType() { + return DrawerFragmentActivity.ActivityType.Secondary; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.toolbar_secondarylibrary, menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int nItemId = item.getItemId(); + if (nItemId == R.id.item_test) { + Toast.makeText(getApplicationContext(), "item_test", Toast.LENGTH_SHORT).show(); + } + return super.onOptionsItemSelected(item); + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/unittests/SecondaryLibraryFragment.java b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/SecondaryLibraryFragment.java new file mode 100644 index 0000000..c0ddc14 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/SecondaryLibraryFragment.java @@ -0,0 +1,25 @@ +package cc.winboll.studio.libaes.unittests; + +/** + * @Author ZhanGSKen + * @Date 2024/07/16 02:36:34 + * @Describe SecondaryLibraryFragment + */ +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import androidx.fragment.app.Fragment; +import cc.winboll.studio.libaes.R; + +public class SecondaryLibraryFragment extends Fragment { + + public static final String TAG = "SecondaryLibraryFragment"; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_secondarylibrary, container, false); + + return view; + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestAButtonFragment.java b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestAButtonFragment.java new file mode 100644 index 0000000..ce837aa --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestAButtonFragment.java @@ -0,0 +1,37 @@ +package cc.winboll.studio.libaes.unittests; + +/** + * @Author ZhanGSKen + * @Date 2024/07/16 01:27:50 + * @Describe TestAButtonFragment + */ +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import androidx.fragment.app.Fragment; +import cc.winboll.studio.libaes.R; +import cc.winboll.studio.libaes.views.AButton; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.ToastUtils; + +public class TestAButtonFragment extends Fragment { + + public static final String TAG = "TestAButtonFragment"; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_abutton, container, false); + AButton aButton = view.findViewById(R.id.fragmentabuttonAButton1); + aButton.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View view) { + LogUtils.d(TAG, "onClick"); + ToastUtils.show("AButton"); + } + + }); + return view; + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestASupportToolbarActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestASupportToolbarActivity.java new file mode 100644 index 0000000..6fa37b6 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestASupportToolbarActivity.java @@ -0,0 +1,42 @@ +package cc.winboll.studio.libaes.unittests; + +/** + * @Author ZhanGSKen + * @Date 2024/07/16 01:14:00 + * @Describe TestASupportToolbarActivity + */ +import android.app.Activity; +import android.os.Bundle; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import cc.winboll.studio.libaes.R; +import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; +import cc.winboll.studio.libaes.utils.AESThemeUtil; + +public class TestASupportToolbarActivity extends AppCompatActivity implements IWinBoLLActivity { + + public static final String TAG = "TestASupportToolbarActivity"; + + @Override + public Activity getActivity() { + return this; + } + + @Override + public String getTag() { + return TAG; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + AESThemeUtil.applyAppTheme(this); + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_testasupporttoolbar); + Toolbar toolbar = findViewById(R.id.activitytestasupporttoolbarASupportToolbar1); + setSupportActionBar(toolbar); + getSupportActionBar().setTitle(TAG); + + } + + +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestAToolbarActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestAToolbarActivity.java new file mode 100644 index 0000000..bba25fc --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestAToolbarActivity.java @@ -0,0 +1,28 @@ +package cc.winboll.studio.libaes.unittests; + +/** + * @Author ZhanGSKen + * @Date 2024/07/16 01:16:07 + * @Describe TestAToolbarActivity + */ +import android.app.Activity; +import android.os.Bundle; +import android.widget.Toolbar; +import cc.winboll.studio.libaes.R; +import cc.winboll.studio.libaes.utils.AESThemeUtil; + +public class TestAToolbarActivity extends Activity { + + public static final String TAG = "TestAToolbarActivity"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + AESThemeUtil.applyAppTheme(this); + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_testatoolbar); + Toolbar toolbar = findViewById(R.id.activitytestatoolbarAToolbar1); + setActionBar(toolbar); + getActionBar().setTitle(TAG); + } + +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestDrawerFragmentActivity.java b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestDrawerFragmentActivity.java new file mode 100644 index 0000000..ab4fc2b --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestDrawerFragmentActivity.java @@ -0,0 +1,124 @@ +package cc.winboll.studio.libaes.unittests; + +/** + * @Author ZhanGSKen + * @Date 2024/06/30 15:00:51 + */ +import android.app.Activity; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.Toast; +import androidx.fragment.app.Fragment; +import cc.winboll.studio.libaes.R; +import cc.winboll.studio.libaes.activitys.DrawerFragmentActivity; +import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; +import cc.winboll.studio.libaes.models.DrawerMenuBean; +import cc.winboll.studio.libappbase.LogUtils; +import java.util.ArrayList; + +public class TestDrawerFragmentActivity extends DrawerFragmentActivity implements IWinBoLLActivity { + + @Override + public Activity getActivity() { + return this; + } + + @Override + public String getTag() { + return null; + } + + public static final String TAG = "TestDrawerFragmentActivity"; + + TestFragment1 mTestFragment1; + TestFragment2 mTestFragment2; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mTestFragment1 = new TestFragment1(); + addFragment(mTestFragment1); + mTestFragment2 = new TestFragment2(); + addFragment(mTestFragment2); + showFragment(0); + } + + @Override + protected DrawerFragmentActivity.ActivityType initActivityType() { + return DrawerFragmentActivity.ActivityType.Main; + } + + @Override + public void initDrawerMenuItemList(ArrayList listDrawerMenu) { + super.initDrawerMenuItemList(listDrawerMenu); + LogUtils.d(TAG, "initDrawerMenuItemList"); + //listDrawerMenu.clear(); + // 添加抽屉菜单项 + listDrawerMenu.add(new DrawerMenuBean(R.drawable.ic_launcher, TestFragment1.TAG)); + listDrawerMenu.add(new DrawerMenuBean(R.drawable.ic_launcher, TestFragment2.TAG)); + notifyDrawerMenuDataChanged(); + } + + @Override + public void reinitDrawerMenuItemList(ArrayList listDrawerMenu) { + super.reinitDrawerMenuItemList(listDrawerMenu); + LogUtils.d(TAG, "reinitDrawerMenuItemList"); + //listDrawerMenu.clear(); + // 添加抽屉菜单项 + listDrawerMenu.add(new DrawerMenuBean(R.drawable.ic_launcher, TestFragment1.TAG)); + listDrawerMenu.add(new DrawerMenuBean(R.drawable.ic_launcher, TestFragment2.TAG)); + notifyDrawerMenuDataChanged(); + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + super.onItemClick(parent, view, position, id); + switch (position) { + case 0 : { + Toast.makeText(getApplicationContext(), "0", Toast.LENGTH_SHORT).show(); + //LogUtils.d(TAG, "MenuItem 1"); + showFragment(mTestFragment1); + break; + } + case 1 : { + //LogUtils.d(TAG, "MenuItem 2"); + showFragment(mTestFragment2); + break; + } + + } + } + + public static class TestFragment1 extends Fragment { + + public static final String TAG = "TestFragment1"; + + View mView; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + mView = inflater.inflate(R.layout.fragment_test1, container, false); + + return mView; + } + + } + + public static class TestFragment2 extends Fragment { + + public static final String TAG = "TestFragment2"; + + View mView; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + mView = inflater.inflate(R.layout.fragment_test2, container, false); + + return mView; + } + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestViewPageFragment.java b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestViewPageFragment.java new file mode 100644 index 0000000..1d922fa --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/unittests/TestViewPageFragment.java @@ -0,0 +1,226 @@ +package cc.winboll.studio.libaes.unittests; + +/** + * @Author ZhanGSKen + * @Date 2024/07/16 01:35:56 + * @Describe TestViewPageFragment + */ +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import androidx.fragment.app.Fragment; +import androidx.viewpager.widget.ViewPager; +import cc.winboll.studio.libaes.ImagePagerAdapter; +import cc.winboll.studio.libaes.R; +import cc.winboll.studio.libaes.views.AOHPCTCSeekBar; +import cc.winboll.studio.libappbase.LogView; +import cc.winboll.studio.libappbase.ToastUtils; +import java.util.ArrayList; +import java.util.List; + +public class TestViewPageFragment extends Fragment implements ViewPager.OnPageChangeListener, View.OnClickListener { + + public static final String TAG = "TestViewPageFragment"; + + Context mContext; + LogView mLogView; + + private ViewPager viewPager; + private List views; //用来存放放进ViewPager里面的布局 + //实例化存储imageView(导航原点)的集合 + ImageView[] imageViews; + private ImagePagerAdapter adapter;//适配器 + private LinearLayout linearLayout;//下标所在在LinearLayout布局里 + private int currentPoint = 0;//当前被选中中页面的下标 + View mView; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + mView = inflater.inflate(R.layout.fragment_viewpage, container, false); + mContext = getActivity(); + + mLogView = mView.findViewById(R.id.logview); + mLogView.start(); + + //viewPager = findViewById(R.id.activitymainViewPager1); + initData(); + initView();//调用初始化视图方法 + initPoint();//调用初始化导航原点的方法 + viewPager.addOnPageChangeListener(this);//滑动事件 + //viewPager.setAdapter(new MyAdapter()); + + // 获取屏幕参数 + //ScreenUtil.ScreenSize ss = ScreenUtil.getScreenSize(MainActivity.this); + //Toast.makeText(getApplication(), Integer.toString(ss.getHeightPixels())+" "+Integer.toString(ss.getWidthPixels()), Toast.LENGTH_SHORT).show(); + + return mView; + } + + //初始化view,即显示的图片 + void initView() { + adapter = new ImagePagerAdapter(views); + viewPager = mView.findViewById(R.id.fragmentviewpageViewPager1); + viewPager.setAdapter(adapter); + linearLayout = mView.findViewById(R.id.fragmentviewpageLinearLayout1); + initPoint();//初始化页面下方的点 + viewPager.setOnPageChangeListener(this); + initAOHPCTCSeekBar(); + initAOHPCTCSeekBar2(); + } + + //初始化所要显示的布局 + void initData() { + ViewPager viewPager = mView.findViewById(R.id.fragmentviewpageViewPager1); + LayoutInflater inflater = LayoutInflater.from(mContext); + View view1 = inflater.inflate(R.layout.viewpage_atickprogressbar, viewPager, false); + View view2 = inflater.inflate(R.layout.viewpage_acard, viewPager, false); + View view3 = inflater.inflate(R.layout.viewpage_aohpctccard, viewPager, false); + View view4 = inflater.inflate(R.layout.viewpage_aohpctcsb, viewPager, false); + + views = new ArrayList<>(); + views.add(view1); + views.add(view2); + views.add(view3); + views.add(view4); + } + + //setTag注释 + /* + //View中的setTag(Onbect)表示给View添加一个格外的数据,以后可以用getTag()将这个数据取出来。来 + 代表这个数据,即实例化 + Tag是标签的bai意识,这里的tag是object类型。所以通常会使用setTag()设置不同的Object子类对象, + 然后使用强制转换getTag()获得对象。 + //可以用在多个Button添加一个监听器,每个Button都设置不同的setTag。 + 这个监听器就通过getTag来分辨是哪个Button 被按下。 + public class Main extends Activity { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + Button button1 = (Button) findViewById(R.id.Button01); + Button button2 = (Button) findViewById(R.id.Button02); + Button button3 = (Button) findViewById(R.id.Button03); + Button button4 = (Button) findViewById(R.id.Button04); + MyListener listener = new MyListener(); + button1.setTag(1); + button1.setOnClickListener(listener); + button2.setTag(2); + button2.setOnClickListener(listener); + button3.setTag(3); + button3.setOnClickListener(listener); + button4.setTag(4); + button4.setOnClickListener(listener); + } + + public class MyListener implements View.OnClickListener { + + @Override + public void onClick(View v) { + int tag = (Integer) v.getTag(); + switch (tag) { + case 1: + System.out.println(“button1 click”); + break; + case 2: + System.out.println(“button2 click”); + break; + case 3: + System.out.println(“button3 click”); + break; + case 4: + System.out.println(“button4 click”); + break; + } + + */ + + private void initPoint() { + + imageViews = new ImageView[5];//实例化5个图片 + for (int i = 0; i < linearLayout.getChildCount(); i++) { + imageViews[i] = (ImageView) linearLayout.getChildAt(i); + imageViews[i].setImageResource(R.drawable.ic_arrow_left_right_bold); + imageViews[i].setOnClickListener(this);//点击导航点,即可跳转 + imageViews[i].setTag(i);//重复利用实例化的对象 + } + currentPoint = 0;//默认第一个坐标 + imageViews[currentPoint].setImageResource(R.drawable.ic_arrow_up_circle_outline); + } + + //OnPageChangeListener接口要实现的三个方法 + /* onPageScrollStateChanged(int state) + 此方法是在状态改变的时候调用,其中state这个参数有三种状态: + SCROLL_STATE_DRAGGING(1)表示用户手指“按在屏幕上并且开始拖动”的状态 + (手指按下但是还没有拖动的时候还不是这个状态,只有按下并且手指开始拖动后log才打出。) + SCROLL_STATE_IDLE(0)滑动动画做完的状态。 + SCROLL_STATE_SETTLING(2)在“手指离开屏幕”的状态。*/ + @Override + public void onPageScrollStateChanged(int state) { + + } + /* onPageScrolled(int position, float positionOffset, int positionOffsetPixels) + 当页面在滑动的时候会调用此方法,在滑动被停止之前,此方法回一直得到调用。其中三个参数的含义分别为: + + position :当前页面,即你点击滑动的页面(从A滑B,则是A页面的position。 + positionOffset:当前页面偏移的百分比 + positionOffsetPixels:当前页面偏移的像素位置*/ + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + + } + /* onPageSelected(int position) + 此方法是页面滑动完后得到调用,position是你当前选中的页面的Position(位置编号) + (从A滑动到B,就是B的position)*/ + public void onPageSelected(int position) { + + ImageView preView = imageViews[currentPoint]; + preView.setImageResource(R.drawable.ic_arrow_left_right_bold); + ImageView currView = imageViews[position]; + currView.setImageResource(R.drawable.ic_arrow_up_circle_outline); + currentPoint = position; + } + + //小圆点点击事件 + @Override + public void onClick(View v) { + // TODO Auto-generated method stub + //通过getTag(),可以判断是哪个控件 + int i = (Integer) v.getTag(); + viewPager.setCurrentItem(i);//直接跳转到某一个页面的情况 + } + + void initAOHPCTCSeekBar() { + AOHPCTCSeekBar seekbar = views.get(3).findViewById(R.id.fragmentviewpageAOHPCTCSeekBar1); + seekbar.setThumb(mContext.getDrawable(R.drawable.ic_launcher)); + //seekbar.setThumbOffset(200); + //seekbar.setThumbOffset(1); + seekbar.setBlurRightDP(50); + seekbar.setOnOHPCListener(new AOHPCTCSeekBar.OnOHPCListener() { + + @Override + public void onOHPCommit() { + ToastUtils.show("onOHPCommit"); + } + }); + } + + void initAOHPCTCSeekBar2() { + AOHPCTCSeekBar seekbar = views.get(3).findViewById(R.id.fragmentviewpageAOHPCTCSeekBar2); + seekbar.setThumb(mContext.getDrawable(R.drawable.ic_call)); + //seekbar.setThumbOffset(200); + //seekbar.setThumbOffset(1); + seekbar.setBlurRightDP(50); + seekbar.setOnOHPCListener(new AOHPCTCSeekBar.OnOHPCListener() { + + @Override + public void onOHPCommit() { + ToastUtils.show("onOHPCommit 2"); + } + }); + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/utils/AESThemeUtil.java b/libaes/src/main/java/cc/winboll/studio/libaes/utils/AESThemeUtil.java new file mode 100644 index 0000000..b4e7548 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/utils/AESThemeUtil.java @@ -0,0 +1,211 @@ +package cc.winboll.studio.libaes.utils; + +/** + * @Author ZhanGSKen + * @Date 2024/11/29 22:52:09 + * @Describe AES 主题工具集 + */ +import android.app.Activity; +import android.content.Context; +import android.view.Menu; +import android.view.MenuItem; +import androidx.appcompat.app.AppCompatActivity; +import cc.winboll.studio.libaes.R; +import cc.winboll.studio.libaes.activitys.DrawerFragmentActivity; +import cc.winboll.studio.libaes.models.AESThemeBean; + +public class AESThemeUtil { + + public static final String TAG = "AESThemeUtil"; + + static final String SHAREDPREFERENCES_NAME = "SHAREDPREFERENCES_NAME"; + static final String DRAWER_THEME_TYPE = "DRAWER_THEME_TYPE"; + + protected volatile AESThemeBean.ThemeType mThemeType; + + public static int getThemeTypeID(T context) { + AESThemeBean bean = AESThemeBean.loadBean(context, AESThemeBean.class); + return bean == null ? AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.AES): bean.getCurrentThemeTypeID(); + } + + public static void saveThemeStyleID(T context, int nThemeTypeID) { + AESThemeBean bean = new AESThemeBean(nThemeTypeID); + AESThemeBean.saveBean(context, bean); + } + + public static void applyAppTheme(T activity) { + activity.setTheme(getThemeTypeID(activity)); + } + + public static void applyAppCompatTheme(T activity) { + activity.setTheme(getThemeTypeID(activity)); + } + + /*public static void applyWinBoLLTheme(T activity) { + activity.setTheme(getThemeTypeID(activity.getApplicationContext())); + }*/ + + public static void applyAppTheme(Activity activity, AESThemeBean.ThemeType themeType) { + activity.setTheme(AESThemeBean.getThemeStyleID(themeType)); + } + + public static void applyAppCompatTheme(Activity activity, AESThemeBean.ThemeType themeType) { + activity.setTheme(AESThemeBean.getThemeStyleID(themeType)); + } + + /*public static void applyWinBoLLTheme(Activity activity, AESThemeBean.ThemeType themeType) { + activity.setTheme(AESThemeBean.getThemeStyleID(themeType)); + }*/ + + public static void inflateMenu(T activity, Menu menu) { + activity.getMenuInflater().inflate(R.menu.toolbar_apptheme, menu); + } + + public static void inflateCompatMenu(T activity, Menu menu) { + activity.getMenuInflater().inflate(R.menu.toolbar_apptheme, menu); + } + + /*public static void inflateWinBoLLMenu(T activity, Menu menu) { + activity.getMenuInflater().inflate(R.menu.toolbar_apptheme, menu); + }*/ + + public static boolean onAppThemeItemSelected(T activity, MenuItem item) { + int nThemeStyleID; + if (R.id.item_depththeme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.DEPTH); + saveThemeStyleID(activity, nThemeStyleID); + return true; + } else if (R.id.item_skytheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.SKY); + saveThemeStyleID(activity, nThemeStyleID); + return true; + } else if (R.id.item_goldentheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.GOLDEN); + saveThemeStyleID(activity, nThemeStyleID); + return true; + } else if (R.id.item_bearingtheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.BEARING); + saveThemeStyleID(activity, nThemeStyleID); + return true; + } else if (R.id.item_memortheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.MEMOR); + saveThemeStyleID(activity, nThemeStyleID); + return true; + } else if (R.id.item_taotheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.TAO); + saveThemeStyleID(activity, nThemeStyleID); + return true; + } else if (R.id.item_defaulttheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.AES); + saveThemeStyleID(activity, nThemeStyleID); + return true; + } + + return false; + } + + public static boolean onAppCompatThemeItemSelected(T activity, MenuItem item) { + int nThemeStyleID; + if (R.id.item_depththeme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.DEPTH); + saveThemeStyleID(activity, nThemeStyleID); + return true; + } else if (R.id.item_skytheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.SKY); + saveThemeStyleID(activity, nThemeStyleID); + return true; + } else if (R.id.item_goldentheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.GOLDEN); + saveThemeStyleID(activity, nThemeStyleID); + return true; + } else if (R.id.item_bearingtheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.BEARING); + saveThemeStyleID(activity, nThemeStyleID); + return true; + } else if (R.id.item_memortheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.MEMOR); + saveThemeStyleID(activity, nThemeStyleID); + return true; + } else if (R.id.item_taotheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.TAO); + saveThemeStyleID(activity, nThemeStyleID); + return true; + } else if (R.id.item_defaulttheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.AES); + saveThemeStyleID(activity, nThemeStyleID); + return true; + } + + return false; + } + + public static boolean onWinBoLLThemeItemSelected(T activity, MenuItem item) { + int nThemeStyleID; + if (R.id.item_depththeme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.DEPTH); + saveThemeStyleID(activity.getApplicationContext(), nThemeStyleID); + return true; + } else if (R.id.item_skytheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.SKY); + saveThemeStyleID(activity.getApplicationContext(), nThemeStyleID); + return true; + } else if (R.id.item_goldentheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.GOLDEN); + saveThemeStyleID(activity.getApplicationContext(), nThemeStyleID); + return true; + } else if (R.id.item_bearingtheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.BEARING); + saveThemeStyleID(activity.getApplicationContext(), nThemeStyleID); + return true; + } else if (R.id.item_memortheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.MEMOR); + saveThemeStyleID(activity.getApplicationContext(), nThemeStyleID); + return true; + } else if (R.id.item_taotheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.TAO); + saveThemeStyleID(activity.getApplicationContext(), nThemeStyleID); + return true; + } else if (R.id.item_defaulttheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.AES); + saveThemeStyleID(activity.getApplicationContext(), nThemeStyleID); + return true; + } + + return false; + } + + public static boolean onWinBoLLThemeItemSelected(T activity, MenuItem item) { + int nThemeStyleID; + if (R.id.item_depththeme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.DEPTH); + saveThemeStyleID(activity.getApplicationContext(), nThemeStyleID); + return true; + } else if (R.id.item_skytheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.SKY); + saveThemeStyleID(activity.getApplicationContext(), nThemeStyleID); + return true; + } else if (R.id.item_goldentheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.GOLDEN); + saveThemeStyleID(activity.getApplicationContext(), nThemeStyleID); + return true; + } else if (R.id.item_bearingtheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.BEARING); + saveThemeStyleID(activity.getApplicationContext(), nThemeStyleID); + return true; + } else if (R.id.item_memortheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.MEMOR); + saveThemeStyleID(activity.getApplicationContext(), nThemeStyleID); + return true; + } else if (R.id.item_taotheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.TAO); + saveThemeStyleID(activity.getApplicationContext(), nThemeStyleID); + return true; + } else if (R.id.item_defaulttheme == item.getItemId()) { + nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.AES); + saveThemeStyleID(activity.getApplicationContext(), nThemeStyleID); + return true; + } + + return false; + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/utils/AppVersionUtils.java b/libaes/src/main/java/cc/winboll/studio/libaes/utils/AppVersionUtils.java new file mode 100644 index 0000000..e4ac66b --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/utils/AppVersionUtils.java @@ -0,0 +1,162 @@ +package cc.winboll.studio.libaes.utils; + + +/** + * @Author ZhanGSKen + * @Date 2024/08/12 14:45:35 + * @Describe 应用版本工具集 + */ +import cc.winboll.studio.libappbase.LogUtils; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class AppVersionUtils { + + public static final String TAG = "AppVersionUtils"; + + // + // 检查新版本是否成立 + // szCurrentCode : 当前版本应用包名 + // szNextCode : 新版本应用包名 + // 返回 :情况1:当前版本是发布版 + // 返回 true (新版本 > 当前版本) + // 情况1:当前版本是Beta版 + // true 新版本 == 当前版本 + // + public static boolean isHasNewVersion2(String szCurrentName, String szNextName) { + LogUtils.d(TAG, String.format("isHasNewVersion2\nszCurrentName : %s\nszNextName : %s", szCurrentName, szNextName)); + //szCurrentName = "AES_6.2.0-beta0_3234.apk"; + //szNextName = "AES_6.1.12.apk"; + //szCurrentName = "AES_6.2.0-beta0_3234.apk"; + //szNextName = "AES_6.2.0.apk"; + //szCurrentName = "AES_6.2.0-beta0_3234.apk"; + //szNextName = "AES_6.2.2.apk"; + //szCurrentName = "AES_6.2.0-beta0_3234.apk"; + //szNextName = "AES_6.2.0.apk"; + //szCurrentName = "AES_6.1.0.apk"; + //szNextName = "AES_6.2.0.apk"; + //LogUtils.d(TAG, "szCurrentName : " + szCurrentName); + //LogUtils.d(TAG, "szNextName : " + szNextName); + + //boolean isVersionNewer = false; + //if(szCurrentName.equals(szNextName)) { + // isVersionNewer = false; + //} else { + //ToastUtils.show("szCurrent : " + szCurrent + "\nszNext : " + szNext); + //int nApk = szNextName.lastIndexOf(".apk"); + //ToastUtils.show("nApk : " + Integer.toString(nApk)); + //String szNextNoApkName = szNextName.substring(0, nApk); + //ToastUtils.show("szNextNoApkName : " + szNextNoApkName); + //String szCurrentNoApkName = szCurrentName.substring(0, szNextNoApkName.length()); + //ToastUtils.show("szCurrentNoApkName : " + szCurrentNoApkName); + //String str1 = "3.4.50"; + //String str2 = "3.3.60"; + //String str1 = getCodeInPackageName(szCurrentName); + //String str2 = getCodeInPackageName(szNextName); + //String str1 = getCodeInPackageName(szNextName); + //String str2 = getCodeInPackageName(szCurrentName); + //Boolean isVersionNewer2 = checkNewVersion(str1,str2); + //ToastUtils.show("isVersionNewer2 : " + Boolean.toString(isVersionNewer2)); + //ToastUtils.show(checkNewVersion(getCodeInPackageName(szCurrentName), getCodeInPackageName(szNextName))); + //return checkNewVersion(getCodeInPackageName(szCurrentName), getCodeInPackageName(szNextName)); + //} + //return isVersionNewer; + if (checkNewVersion(getCodeInPackageName(szCurrentName), getCodeInPackageName(szNextName))) { + // 比 AES_6.2.0.apk 版本大,如 AES_6.2.1.apk。 + // 比 AES_6.2.0-beta0_3234.apk 大,如 AES_6.2.1.apk。 + //LogUtils.d(TAG, "App newer stage version is released. Release name : " + szNextName); + return true; + } + if (szCurrentName.matches(".*_\\d+\\.\\d+\\.\\d+-beta.*\\.apk")) { + String szCurrentReleasePackageName = getReleasePackageName(szCurrentName); + //LogUtils.d(TAG, "szCurrentReleasePackageName : " + szCurrentReleasePackageName); + if (szCurrentReleasePackageName.equals(szNextName)) { + // 与 AES_6.2.0-beta0_3234.apk 版本相同,如 AES_6.2.0.apk。 + //LogUtils.d(TAG, "App stage version is released. Release name : " + szNextName); + return true; + } + } + //LogUtils.d(TAG, "App version is the newest. "); + return false; + } + + public static boolean isHasNewStageReleaseVersion(String szCurrentName, String szNextName) { + LogUtils.d(TAG, String.format("isHasNewStageReleaseVersion\nszCurrentName : %s\nszNextName : %s", szCurrentName, szNextName)); + //szCurrentName = "AES_6.2.12.apk"; + //szNextName = "AES_6.3.12.apk"; + if (checkNewVersion(getCodeInPackageName(szCurrentName), getCodeInPackageName(szNextName))) { + // 比 AES_6.2.0.apk 版本大,如 AES_6.2.1.apk。 + //LogUtils.d(TAG, "App newer stage version is released. Release name : " + szNextName); + return true; + } + return false; + } + + // + // 检查新版本是否成立 + // szCurrentCode : 当前版本 + // szNextCode : 新版本 + // 返回 :true 新版本 > 当前版本 + // + public static Boolean checkNewVersion(String szCurrentCode, String szNextCode) { + if (szCurrentCode == null || szCurrentCode.equals("") || szNextCode == null || szNextCode.equals("")) { + LogUtils.d(TAG, String.format("checkNewVersion unexpected parameters:\nszCurrentCode : %s\nszNextCode : %s", szCurrentCode, szNextCode)); + return false; + } + boolean isNew = false; + String[] appVersionCurrent = szCurrentCode.split("\\."); + String[] appVersionNext = szNextCode.split("\\."); + //根据位数最短的判断 + int lim = appVersionCurrent.length > appVersionNext.length ? appVersionNext.length : appVersionCurrent.length; + //根据位数循环判断各个版本 + for (int i = 0; i < lim; i++) { + if (Integer.parseInt(appVersionNext[i]) > Integer.parseInt(appVersionCurrent[i])) { + isNew = true; + return isNew; + } else if (Integer.parseInt(appVersionNext[i]) == Integer.parseInt(appVersionCurrent[i])) { + continue ; + } else { + isNew = false; + return isNew; + } + } + return isNew; + } + + // + // 截取应用包名称版本号信息 + // 如 :AppUtils_7.0.4-beta1_0120.apk 版本号为 7.0.4 + // 如 :AppUtils_7.0.4.apk 版本号为 7.0.4 + // + public static String getCodeInPackageName(String apkName) { + LogUtils.d(TAG, String.format("getCodeInPackageName apkName : %s", apkName)); + //String apkName = "AppUtils_7.0.0.apk"; + Pattern pattern = Pattern.compile("\\d+\\.\\d+\\.\\d+"); + Matcher matcher = pattern.matcher(apkName); + if (matcher.find()) { + String version = matcher.group(); + LogUtils.d(TAG, String.format("version is %s", version)); + return version; + //System.out.println("Version number: " + version); // 输出:7.0.0 + } + LogUtils.d(TAG, String.format("No result.")); + return ""; + } + + // + // 根据Beta版名称生成发布版应用包名称 + // 如 AppUtils_7.0.4-beta1_0120.apk + // 发布版名称就为AppUtils_7.0.4.apk + // + public static String getReleasePackageName(String szBetaPackageName) { + //String szBetaPackageName = "AppUtils_7.0.4-beta1_0120.apk"; + Pattern pattern = Pattern.compile(".*\\d+\\.\\d+\\.\\d+"); + Matcher matcher = pattern.matcher(szBetaPackageName); + if (matcher.find()) { + String szReleasePackageName = matcher.group(); + return szReleasePackageName + ".apk"; + //System.out.println("Version number: " + version); // 输出:7.0.0 + } + return ""; + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/utils/DevelopUtils.java b/libaes/src/main/java/cc/winboll/studio/libaes/utils/DevelopUtils.java new file mode 100644 index 0000000..377afc3 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/utils/DevelopUtils.java @@ -0,0 +1,35 @@ +package cc.winboll.studio.libaes.utils; + +import android.app.Activity; +import android.view.Menu; +import android.view.MenuItem; +import cc.winboll.studio.libaes.R; +import cc.winboll.studio.libappbase.LogActivity; + +/** + * @Author ZhanGSKen&豆包大模型 + * @Date 2025/12/07 13:31 + * @Describe 应用开发工具类 + */ +public class DevelopUtils { + + public static final String TAG = "DevelopUtils"; + + public static void inflateMenu(T activity, Menu menu) { + activity.getMenuInflater().inflate(R.menu.toolbar_appdebug, menu); + } + + public static boolean onDevelopItemSelected(T activity, MenuItem item) { + if (R.id.item_testappcrash == item.getItemId()) { + for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) { + activity.getString(i); + } + } else if (R.id.item_log == item.getItemId()) { + //ToastUtils.show("Test"); + LogActivity.startLogActivity(activity); + } else { + return false; + } + return true; + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/utils/MimoUtils.java b/libaes/src/main/java/cc/winboll/studio/libaes/utils/MimoUtils.java new file mode 100644 index 0000000..2c07337 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/utils/MimoUtils.java @@ -0,0 +1,33 @@ +package cc.winboll.studio.libaes.utils; + +import android.content.Context; +import android.util.DisplayMetrics; + +/** + * @Author ZhanGSKen&豆包大模型 + * @Date 2025/11/18 15:23 + * @Describe 米盟 MimoUtils + */ +public final class MimoUtils { + public static final String TAG = "Utils"; + + public static int dpToPx(Context context, float dp) { + DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); + return (int) (dp * displayMetrics.density + 0.5f); + } + + public static int pxToDp(Context context, float px) { + DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); + return (int) (px / displayMetrics.density + 0.5f); + } + + public static int pxToSp(Context context, float pxValue) { + DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); + return (int) (pxValue / displayMetrics.scaledDensity + 0.5f); + } + + public static int spToPx(Context context, float spValue) { + DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); + return (int) (spValue * displayMetrics.scaledDensity + 0.5f); + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/utils/MyActivityLifecycleCallbacks.java b/libaes/src/main/java/cc/winboll/studio/libaes/utils/MyActivityLifecycleCallbacks.java new file mode 100644 index 0000000..d32928d --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/utils/MyActivityLifecycleCallbacks.java @@ -0,0 +1,97 @@ +package cc.winboll.studio.libaes.utils; + +/** + * @Author ZhanGSKen + * @Date 2025/03/25 04:29:19 + */ +import android.app.Activity; +import android.app.Application; +import android.content.Intent; +import android.os.Bundle; +import cc.winboll.studio.libappbase.LogUtils; + +public class MyActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks { + + public static final String TAG = "MyActivityLifecycleCallbacks"; + + public String mInfo = ""; + + public MyActivityLifecycleCallbacks() { + + } + + void createActivityeInfo(Activity activity) { + StringBuilder sb = new StringBuilder(); + Intent receivedIntent = activity.getIntent(); + sb.append("\nCallingActivity : \n"); + if (activity.getCallingActivity() != null) { + sb.append(activity.getCallingActivity().getPackageName()); + } + sb.append("\nReceived Intent Package : \n"); + sb.append(receivedIntent.getPackage()); + + Bundle extras = receivedIntent.getExtras(); + if (extras != null) { + for (String key : extras.keySet()) { + sb.append("\nIntentInfo"); + sb.append("\n键: "); + sb.append(key); + sb.append(", 值: "); + sb.append(extras.get(key)); + //Log.d("IntentInfo", "键: " + key + ", 值: " + extras.get(key)); + } + } + mInfo = sb.toString(); + //Log.d("IntentInfo", "发送Intent的应用包名: " + senderPackage); + } + + public void showActivityeInfo() { + //ToastUtils.show("ActivityeInfo : " + mInfo); + LogUtils.d(TAG, "ActivityeInfo : " + mInfo); + } + + @Override + public void onActivityCreated(Activity activity, Bundle savedInstanceState) { + // 在这里可以做一些初始化相关的操作,例如记录Activity的创建时间等 + //System.out.println(activity.getLocalClassName() + " was created"); + LogUtils.d(TAG, activity.getLocalClassName() + " was created"); + createActivityeInfo(activity); + } + + @Override + public void onActivityStarted(Activity activity) { + //System.out.println(activity.getLocalClassName() + " was started"); + LogUtils.d(TAG, activity.getLocalClassName() + " was started"); + //createActivityeInfo(activity); + } + + @Override + public void onActivityResumed(Activity activity) { + //System.out.println(activity.getLocalClassName() + " was resumed"); + LogUtils.d(TAG, activity.getLocalClassName() + " was resumed"); + //createActivityeInfo(activity); + } + + @Override + public void onActivityPaused(Activity activity) { + //System.out.println(activity.getLocalClassName() + " was paused"); + LogUtils.d(TAG, activity.getLocalClassName() + " was paused"); + } + + @Override + public void onActivityStopped(Activity activity) { + //System.out.println(activity.getLocalClassName() + " was stopped"); + LogUtils.d(TAG, activity.getLocalClassName() + " was stopped"); + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle outState) { + // 可以在这里添加保存状态的自定义逻辑 + } + + @Override + public void onActivityDestroyed(Activity activity) { + //System.out.println(activity.getLocalClassName() + " was destroyed"); + LogUtils.d(TAG, activity.getLocalClassName() + " was destroyed"); + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/utils/PrefUtils.java b/libaes/src/main/java/cc/winboll/studio/libaes/utils/PrefUtils.java new file mode 100644 index 0000000..751a9e5 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/utils/PrefUtils.java @@ -0,0 +1,33 @@ +package cc.winboll.studio.libaes.utils; + +import android.content.Context; +import android.content.SharedPreferences; + +/** + * @Author ZhanGSKen&豆包大模型 + * @Date 2025/11/13 06:50 + * @Describe 应用变量保存工具 + */ + +public class PrefUtils { + + public static final String TAG = "PrefUtils"; + + // + // 保存字符串到SharedPreferences的函数 + // + public static void saveString(Context context, String key, String value) { + SharedPreferences sharedPreferences = context.getSharedPreferences("myPrefs", Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putString(key, value); + editor.apply(); + } + + // + // 从SharedPreferences读取字符串的函数 + // + public static String getString(Context context, String key, String defaultValue) { + SharedPreferences sharedPreferences = context.getSharedPreferences("myPrefs", Context.MODE_PRIVATE); + return sharedPreferences.getString(key, defaultValue); + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/utils/ScreenUtil.java b/libaes/src/main/java/cc/winboll/studio/libaes/utils/ScreenUtil.java new file mode 100644 index 0000000..20399ea --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/utils/ScreenUtil.java @@ -0,0 +1,64 @@ +package cc.winboll.studio.libaes.utils; + +import android.content.Context; +import android.util.DisplayMetrics; +import android.view.WindowManager; + +public class ScreenUtil { + + // 分辨率宽度和高度计量类 + // + public static class ScreenSize { + int widthPixels; + int heightPixels; + + public ScreenSize(int widthPixels, int heightPixels) { + this.widthPixels = widthPixels; + this.heightPixels = heightPixels; + } + + public void setWidthPixels(int widthPixels) { + this.widthPixels = widthPixels; + } + + public int getWidthPixels() { + return widthPixels; + } + + public void setHeightPixels(int heightPixels) { + this.heightPixels = heightPixels; + } + + public int getHeightPixels() { + return heightPixels; + } + } + + // 获取屏幕分辨率宽度和高度 + // + public static ScreenSize getScreenSize(Context mContext) { + WindowManager manager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); + DisplayMetrics dm = new DisplayMetrics(); + manager.getDefaultDisplay().getMetrics(dm); + return new ScreenSize(dm.widthPixels, dm.heightPixels); + } + + // 获取屏幕宽度 + // + public static int getScreenWidth(Context mContext) { + WindowManager manager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); + DisplayMetrics dm = new DisplayMetrics(); + manager.getDefaultDisplay().getMetrics(dm); + return dm.widthPixels; + } + + // 获取屏幕高度 + // + public static int getScreenHeight(Context mContext) { + WindowManager manager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); + DisplayMetrics dm = new DisplayMetrics(); + manager.getDefaultDisplay().getMetrics(dm); + return dm.heightPixels; + } + +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/utils/WebUtils.java b/libaes/src/main/java/cc/winboll/studio/libaes/utils/WebUtils.java new file mode 100644 index 0000000..94d8502 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/utils/WebUtils.java @@ -0,0 +1,102 @@ +package cc.winboll.studio.libaes.utils; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.widget.Toast; + +import cc.winboll.studio.libappbase.LogUtils; + +/** + * @Author 豆包&ZhanGSKen + * @Date 2026/01/05 15:45 + * @LastEditTime 2026/01/05 19:30:00 HKT + * @Describe 网页工具集(优化:新增合法性校验+浏览器可用性检查+链接格式自动修复) + */ +public class WebUtils { + + public static final String TAG = "WebUtils"; + + /** + * 唤起系统默认浏览器打开指定网站 + * @param context 上下文对象(建议使用 ApplicationContext 避免内存泄漏) + * @param url 目标 URL(支持自动修复格式错误) + */ + public static void openUrlInBrowser(Context context, String url) { + // 1. 空指针与合法性校验 + if (context == null) { + LogUtils.e(TAG, "openUrlInBrowser: Context is null"); + return; + } + if (url == null || url.trim().isEmpty()) { + LogUtils.e(TAG, "openUrlInBrowser: Url is null or empty"); + showToast(context, "链接不能为空"); + return; + } + + // 2. 链接格式自动修复(核心新增:处理多斜杠、补全协议头) + String fixedUrl = fixUrlFormat(url.trim()); + LogUtils.d(TAG, "openUrlInBrowser: Fixed url from [" + url + "] to [" + fixedUrl + "]"); + + // 3. 构建隐式意图 + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(fixedUrl)); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 新任务栈启动 + + // 4. 检查浏览器可用性 + if (intent.resolveActivity(context.getPackageManager()) != null) { + try { + context.startActivity(intent); + } catch (Exception e) { + LogUtils.e(TAG, "openUrlInBrowser: Start activity failed", e); + showToast(context, "打开浏览器失败,请手动复制链接"); + } + } else { + LogUtils.e(TAG, "openUrlInBrowser: No browser app found"); + showToast(context, "未找到可用的浏览器应用"); + } + } + + /** + * 工具方法:修复 URL 格式错误 + * 1. 补全 http/https 协议头 + * 2. 处理协议头后的多斜杠问题(如 https://mmec//path → https://mmec/path) + * @param originalUrl 原始 URL + * @return 修复后的 URL + */ + private static String fixUrlFormat(String originalUrl) { + String url = originalUrl; + + // 步骤1:补全协议头(优先 https) + if (!url.startsWith("http://") && !url.startsWith("https://")) { + url = "https://" + url; + } + + // 步骤2:修复协议头后的多斜杠问题 + // 匹配 https:// 或 http:// 后的任意数量斜杠,替换为单斜杠 + url = url.replaceAll("(?<=https?://)[/]+", "/"); + + return url; + } + + /** + * 工具方法:显示 Toast 提示(确保在主线程执行) + */ + private static void showToast(final Context context, final String message) { + if (context == null || message == null) { + return; + } + if (Looper.myLooper() == Looper.getMainLooper()) { + Toast.makeText(context.getApplicationContext(), message, Toast.LENGTH_SHORT).show(); + } else { + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + Toast.makeText(context.getApplicationContext(), message, Toast.LENGTH_SHORT).show(); + } + }); + } + } +} + diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/utils/WinBoLLActivityManager.java b/libaes/src/main/java/cc/winboll/studio/libaes/utils/WinBoLLActivityManager.java new file mode 100644 index 0000000..c95d302 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/utils/WinBoLLActivityManager.java @@ -0,0 +1,292 @@ +package cc.winboll.studio.libaes.utils; + +/** + * @Author ZhanGSKen + * @Date 2025/05/10 10:02 + * @Describe 应用活动窗口管理器 + * 参考 : + * android 类似微信小程序多任务窗口 及 设置 TaskDescription 修改 icon 和 label + * https://blog.csdn.net/qq_29364417/article/details/109379915?app_version=6.4.2&code=app_1562916241&csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22109379915%22%2C%22source%22%3A%22weixin_38986226%22%7D&uLinkId=usr1mkqgl919blen&utm_source=app + */ +import android.app.Activity; +import android.app.ActivityManager; +import android.content.Context; +import android.content.Intent; +import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; +import cc.winboll.studio.libappbase.GlobalApplication; +import cc.winboll.studio.libappbase.LogActivity; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.ToastUtils; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +public class WinBoLLActivityManager { + + public static final String TAG = "WinBoLLActivityManager"; + + public static final String EXTRA_TAG = "EXTRA_TAG"; + + + public enum WinBoLLUI_TYPE { Aplication, Service } + + GlobalApplication mGlobalApplication; + volatile static WinBoLLActivityManager _mIWinBoLLActivityManager; + Map mActivityListMap; + + volatile static WinBoLLUI_TYPE _WinBoLLUI_TYPE = WinBoLLUI_TYPE.Service; + public static void setWinBoLLUI_TYPE(WinBoLLUI_TYPE winBoLLUI_TYPE) { + _WinBoLLUI_TYPE = winBoLLUI_TYPE; + } + + public static WinBoLLUI_TYPE getWinBoLLUI_TYPE() { + return _WinBoLLUI_TYPE; + } + + WinBoLLActivityManager(GlobalApplication application) { + mGlobalApplication = application; + mActivityListMap = new HashMap(); + } + + public static WinBoLLActivityManager getInstance() { + return _mIWinBoLLActivityManager; + } + + public static synchronized void init(T application) { + if (_mIWinBoLLActivityManager == null) { + _mIWinBoLLActivityManager = new WinBoLLActivityManager(application); + } + } + + /** + * 把Activity添加到管理中 + */ + public void add(T activity) { + if (isActivityActive(activity.getTag())) { + LogUtils.d(TAG, String.format("add(...) %s is active.", activity.getTag())); + } else { + mActivityListMap.put(activity.getTag(), activity); + LogUtils.d(TAG, String.format("Add activity : %s\n_mapActivityList.size() : %d", activity.getTag(), mActivityListMap.size())); + } + } + + // + // activity: 为 null 时, + // intent.putExtra 函数 "tag" 参数为 tag + // activity: 不为 null 时, + // intent.putExtra 函数 "tag" 参数为 activity.getTag() + // + public void startWinBoLLActivity(Context context, Class clazz) { + // 如果窗口已存在就重启窗口 + if (!resumeActivity(clazz)) { + // 新建一个任务窗口 + Intent intent = new Intent(context, clazz); + //打开多任务窗口 flags + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); + intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + //intent.putExtra("tag", tag); + context.startActivity(intent); + } + } + + public void startWinBoLLActivity(Context context, Intent intent, Class clazz) { + // 如果窗口已存在就重启窗口 + if (!resumeActivity(clazz)) { + // 新建一个任务窗口 + //Intent intent = new Intent(context, clazz); + //打开多任务窗口 flags + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); + intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + //intent.putExtra("tag", tag); + context.startActivity(intent); + } + } + + public void startLogActivity(Context context) { + // 如果窗口已存在就重启窗口 + //if (!resumeActivity(LogActivity.class)) { + // 新建一个任务窗口 + Intent intent = new Intent(context, LogActivity.class); + //打开多任务窗口 flags + // Define the bounds. +// Rect bounds = new Rect(0, 0, 800, 200); +// // Set the bounds as an activity option. +// ActivityOptions options = ActivityOptions.makeBasic(); +// options.setLaunchBounds(bounds); + intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); + intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + + //intent.putExtra(EXTRA_TAG, tag); + + //context.startActivity(intent, options.toBundle()); + context.startActivity(intent); + //} + } + + // + // 判断 tag 绑定的 Activity 是否已经创建 + // + public boolean isActivityActive(String tag) { + return mActivityListMap.get(tag) != null; + } + + Activity getActivityByTag(String tag) { + return (mActivityListMap.get(tag) == null) ?null: mActivityListMap.get(tag).getActivity(); + } + + + // + // 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台 + // + public boolean resumeActivity(Class clazz) { + try { + Activity activity = getActivityByTag(clazz.newInstance().getTag()); + if (activity != null) { + return resumeActivity(activity); + } + } catch (InstantiationException | IllegalAccessException e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + return false; + } + + // + // 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台 + // + public boolean resumeActivity(String tag) { + Activity activity = getActivityByTag(tag); + if (activity != null) { + return resumeActivity(activity); + } + return false; + } + + // + // 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台 + // + public boolean resumeActivity(Activity activity) { + ActivityManager am = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE); + //返回启动它的根任务(home 或者 MainActivity) + //Intent intent = new Intent(mContext, activity.getClass()); + //TaskStackBuilder stackBuilder = TaskStackBuilder.create(mContext); + //stackBuilder.addNextIntentWithParentStack(intent); + //stackBuilder.startActivities(); + am.moveTaskToFront(activity.getTaskId(), ActivityManager.MOVE_TASK_NO_USER_ACTION); + //ToastUtils.show("resumeActivity"); + return true; + } + + + /** + * 结束所有 Activity + */ + public void finishAll() { + try { + //ToastUtils.show(String.format("finishAll() size : %d", _mIWinBoLLActivityList.size())); + for (int i = mActivityListMap.size() - 1; i > -1; i--) { + IWinBoLLActivity iWinBoLLActivity = mActivityListMap.get(i); + ToastUtils.show("finishAll() activity"); + if (iWinBoLLActivity != null && iWinBoLLActivity.getActivity() != null && !iWinBoLLActivity.getActivity().isFinishing() && !iWinBoLLActivity.getActivity().isDestroyed()) { + //ToastUtils.show("activity != null ..."); + if (getWinBoLLUI_TYPE() == WinBoLLUI_TYPE.Service) { + // 结束窗口和最近任务栏, 建议前台服务类应用使用,可以方便用户再次调用 UI 操作。 + iWinBoLLActivity.getActivity().finishAndRemoveTask(); + //ToastUtils.show("finishAll() activity.finishAndRemoveTask();"); + } else if (getWinBoLLUI_TYPE() == WinBoLLUI_TYPE.Aplication) { + // 结束窗口保留最近任务栏,建议前台服务类应用使用,可以保持应用的系统自觉性。 + iWinBoLLActivity.getActivity().finish(); + //ToastUtils.show("finishAll() activity.finish();"); + } else { + ToastUtils.show("WinBollApplication.WinBollUI_TYPE error."); + } + } + } + } catch (Exception e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + } + + /** + * 结束指定Activity + */ + public void finish(T iWinBoLLActivity) { + try { + if (iWinBoLLActivity != null && iWinBoLLActivity.getActivity() != null && !iWinBoLLActivity.getActivity().isFinishing() && !iWinBoLLActivity.getActivity().isDestroyed()) { + //根据tag 移除 MyActivity + //String tag= activity.getTag(); + //_mIWinBoLLActivityList.remove(tag); + //ToastUtils.show("remove"); + //ToastUtils.show("_mIWinBoLLActivityArrayMap.size() " + Integer.toString(_mIWinBoLLActivityArrayMap.size())); + + // 窗口回调规则: + // [] 当前窗口位置 >> 调度出的窗口位置 + // ★:[0] 1 2 3 4 >> 1 + // ★:0 1 [2] 3 4 >> 1 + // ★:0 1 2 [3] 4 >> 2 + // ★:0 1 2 3 [4] >> 3 + // ★:[0] >> 直接关闭当前窗口 + Activity preActivity = getPreActivity(iWinBoLLActivity); + iWinBoLLActivity.getActivity().finish(); + if (preActivity != null) { + resumeActivity(preActivity); + } + } + + } catch (Exception e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + } + + Activity getPreActivity(IWinBoLLActivity iWinBoLLActivity) { + try { + boolean bingo = false; + IWinBoLLActivity preIWinBoLLActivity = null; + for (Map.Entry entity : mActivityListMap.entrySet()) { + if (entity.getKey().equals(iWinBoLLActivity.getTag())) { + bingo = true; + LogUtils.d(TAG, "bingo"); + break; + } + preIWinBoLLActivity = entity.getValue(); + } + + if (bingo) { + return preIWinBoLLActivity.getActivity(); + } + } catch (Exception e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + + return null; + } + + public boolean registeRemove(T iWinBoLLActivity) { + IWinBoLLActivity iWinBoLLActivityTest = mActivityListMap.get(iWinBoLLActivity.getTag()); + if (iWinBoLLActivityTest != null) { + mActivityListMap.remove(iWinBoLLActivity.getTag()); + return true; + } + return false; + } + + public void printAvtivityListInfo() { + if (!mActivityListMap.isEmpty()) { + StringBuilder sb = new StringBuilder("Map entries : " + Integer.toString(mActivityListMap.size())); + Iterator> iterator = mActivityListMap.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + sb.append("\nKey: " + entry.getKey() + ", \nValue: " + entry.getValue().getTag()); + //ToastUtils.show("\nKey: " + entry.getKey() + ", Value: " + entry.getValue().getTag()); + } + sb.append("\nMap entries end."); + LogUtils.d(TAG, sb.toString()); + } else { + LogUtils.d(TAG, "The map is empty."); + } + } +} + diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/views/AButton.java b/libaes/src/main/java/cc/winboll/studio/libaes/views/AButton.java new file mode 100644 index 0000000..5c9c111 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/views/AButton.java @@ -0,0 +1,28 @@ +package cc.winboll.studio.libaes.views; + +/** + * @Author ZhanGSKen + * @Date 2024/07/16 01:41:22 + * @Describe AButton + */ +import android.content.Context; +import android.util.AttributeSet; +import cc.winboll.studio.libaes.R; + +public class AButton extends android.widget.Button { + + public static final String TAG = "AButton"; + + public AButton(Context context) { + super(context); + } + + public AButton(Context context, AttributeSet attrs) { + super(context, attrs); + setBackground(context.getDrawable(R.drawable.btn_style)); + } + + public AButton(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/views/ACard.java b/libaes/src/main/java/cc/winboll/studio/libaes/views/ACard.java new file mode 100644 index 0000000..4f627f8 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/views/ACard.java @@ -0,0 +1,45 @@ +package cc.winboll.studio.libaes.views; + +/** + * @Author ZhanGSKen + * @Date 2024/07/16 01:44:27 + * @Describe ACard + */ +import android.content.Context; +import android.util.AttributeSet; +import android.widget.LinearLayout; +import cc.winboll.studio.libaes.R; + +public class ACard extends LinearLayout { + + public static final String TAG = "ACard"; + + public ACard(Context context) { + super(context); + } + + public ACard(Context context, AttributeSet attrs) { + super(context, attrs); + setPadding(0 + 0 + 2 + 1, 0 + 0 + 2 + 1, 0 + 1 + 3 + 1, 0 + 2 + 3 + 1); + + // 获得TypedArray + //TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AToolbar); + // 获得attrs.xml里面的属性值,格式为:名称_属性名,后面是默认值 + //int colorBackgroud = a.getColor(R.styleable.ACard_backgroudColor, context.getColor(R.color.colorACardBackgroung)); + //int centerColor = a.getColor(R.styleable.AToolbar_centerColor, context.getColor(R.color.colorAToolbarCenterColor)); + //int endColor = a.getColor(R.styleable.AToolbar_endColor, context.getColor(R.color.colorAToolbarEndColor)); + //float tSize = a.getDimension(R.styleable.CustomView_tSize, 35); + //p.setColor(tColor); + //p.setTextSize(tSize); + //Drawable drawable = context.getDrawable(R.drawable.frame_atoolbar); + + setBackground(context.getDrawable(R.drawable.acard_frame_main)); + + // 返回一个绑定资源结束的信号给资源 + //a.recycle(); + } + + public ACard(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/views/ADrawerMenuListView.java b/libaes/src/main/java/cc/winboll/studio/libaes/views/ADrawerMenuListView.java new file mode 100644 index 0000000..2f4e889 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/views/ADrawerMenuListView.java @@ -0,0 +1,19 @@ +package cc.winboll.studio.libaes.views; + +/** + * @Author ZhanGSKen + * @Date 2023/05/30 11:30:07 + */ +import android.content.Context; +import android.util.AttributeSet; +import android.widget.ListView; + +public class ADrawerMenuListView extends ListView { + + public static final String TAG = "ADrawerMenuListView"; + + public ADrawerMenuListView(Context context, AttributeSet attrs) { + super(context, attrs); + } + +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/views/ADsBannerView.java b/libaes/src/main/java/cc/winboll/studio/libaes/views/ADsBannerView.java new file mode 100644 index 0000000..89eb74f --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/views/ADsBannerView.java @@ -0,0 +1,491 @@ +package cc.winboll.studio.libaes.views; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Handler; +import android.os.Looper; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import cc.winboll.studio.libaes.R; +import cc.winboll.studio.libaes.enums.ADsMode; +import cc.winboll.studio.libaes.utils.MimoUtils; +import cc.winboll.studio.libappbase.GlobalApplication; +import cc.winboll.studio.libappbase.LogUtils; +import com.miui.zeus.mimo.sdk.ADParams; +import com.miui.zeus.mimo.sdk.BannerAd; +import com.miui.zeus.mimo.sdk.MimoCustomController; +import com.miui.zeus.mimo.sdk.MimoLocation; +import com.miui.zeus.mimo.sdk.MimoSdk; +import java.util.ArrayList; +import java.util.List; + +/** + * @Author ZhanGSKen&豆包大模型 + * @Date 2025/11/18 14:41 + * @Describe WinBoLL 横幅广告类 + */ +public class ADsBannerView extends LinearLayout { + + public static final String TAG = "ADsBannerView"; + + + private String BANNER_POS_ID = "802e356f1726f9ff39c69308bfd6f06a"; + private String BANNER_POS_ID_WINBOLL_BETA = "d129ee5a263911f981a6dc7a9802e3e7"; + private String BANNER_POS_ID_WINBOLL = "4ec30efdb32271765b9a4efac902828b"; + + /* + private String BANNER_POS_ID = "802e356f1726f9ff39c69308bfd6f06a"; + private String BANNER_POS_ID_WINBOLL_BETA = "802e356f1726f9ff39c69308bfd6f06a"; + private String BANNER_POS_ID_WINBOLL = "802e356f1726f9ff39c69308bfd6f06a"; + */ + + Context mContext; + View mMianView; + SharedPreferences mSharedPreferences; + ViewGroup mContainer; + BannerAd mBannerAd; + List mAllBanners = new ArrayList<>(); + // 新增:主线程Handler,确保广告操作在主线程执行 + private Handler mMainHandler; + + public ADsBannerView(Context context) { + super(context); + initView(context); + } + + public ADsBannerView(Context context, AttributeSet attrs) { + super(context, attrs); + initView(context); + } + + public ADsBannerView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initView(context); + } + + public ADsBannerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + initView(context); + } + + void initView(Context context) { + this.mContext = context; + initMimoSdk(this.mContext); + + // 初始化主线程Handler(关键:确保广告操作在主线程执行) + mMainHandler = new Handler(Looper.getMainLooper()); + + this.mMianView = inflate(this.mContext, R.layout.view_adsbanner, null); + mContainer = this.mMianView.findViewById(R.id.ads_container); + addView(this.mMianView); + } + + public void resumeADs(final Activity activity) { + // 没有设置米盟广告支持就退出 + if (ADsControlView.getAdsModeFromStatic(this.mContext) != ADsMode.MIMO_SDK) { + // 2. 释放之前的广告资源 + if (mBannerAd != null) { + mBannerAd.destroy(); + } + return; + } + + // 修复:优化广告请求逻辑(添加生命周期判断 + 主线程执行) + if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) { + if (ADsControlView.getAdsModeFromStatic(this.mContext) == ADsMode.MIMO_SDK) { + LogUtils.i(TAG, "已设置播放米盟广告,正在播放..."); + mMainHandler.postDelayed(new Runnable() { + @Override + public void run() { + // 再次校验生命周期,避免延迟执行时Activity已销毁 + if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) { + fetchAd(activity); + } + } + }, 1000); // 延迟1秒请求广告,提升页面加载体验 + } + } + } + + /** + * 释放广告资源(关键:避免内存泄漏和空Context调用) + */ + public void releaseAdResources() { + // 没有设置米盟广告支持就退出 + if (ADsControlView.getAdsModeFromStatic(this.mContext) != ADsMode.MIMO_SDK) { + return; + } + + LogUtils.d(TAG, "releaseAdResources()"); + + // 移除Handler回调 + if (mMainHandler != null) { + mMainHandler.removeCallbacksAndMessages(null); + } + + // 销毁所有广告实例 + if (mAllBanners != null && !mAllBanners.isEmpty()) { + for (BannerAd ad : mAllBanners) { + if (ad != null) { + ad.destroy(); + } + } + mAllBanners.clear(); + } + // 置空当前广告引用 + mBannerAd = null; + // 移除广告容器中的视图 + if (mContainer != null) { + mContainer.removeAllViews(); + } + } + + /** + * 显示广告(核心修复:传递安全的Context + 生命周期校验) + */ + private void showAd(final Activity activity) { + // 没有设置米盟广告支持就退出 + if (ADsControlView.getAdsModeFromStatic(this.mContext) != ADsMode.MIMO_SDK) { + return; + } + + LogUtils.d(TAG, "showAd()"); + // 1. 生命周期校验:避免Activity已销毁时操作UI + if (activity == null || activity.isFinishing() || activity.isDestroyed()) { + LogUtils.e(TAG, "showAd: Activity is finishing or destroyed"); + return; + } + // 2. 非空校验:广告实例和容器 + if (mBannerAd == null || mContainer == null) { + LogUtils.e(TAG, "showAd: BannerAd or Container is null"); + return; + } + // 3. 创建广告容器(使用ApplicationContext避免内存泄漏) + final FrameLayout container = new FrameLayout(activity.getApplicationContext()); + container.setPadding(0, 0, 0, MimoUtils.dpToPx(activity, 10)); + mContainer.addView(container, new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.WRAP_CONTENT + )); + +// if (mIsBiddingWin) { +// mBannerAd.setPrice(getPrice()); +// } + // 4. 显示广告:传递ApplicationContext,避免Activity Context失效 + mBannerAd.showAd(activity, container, new BannerAd.BannerInteractionListener() { + @Override + public void onAdClick() { + LogUtils.d(TAG, "onAdClick"); + } + + @Override + public void onAdShow() { + LogUtils.d(TAG, "onAdShow"); + } + + @Override + public void onAdDismiss() { + LogUtils.d(TAG, "onAdDismiss"); + // 修复:移除容器时校验Activity状态 + if (activity != null && !activity.isFinishing() && !activity.isDestroyed() && mContainer != null) { + mContainer.removeView(container); + } + } + + @Override + public void onRenderSuccess() { + LogUtils.d(TAG, "onRenderSuccess"); + } + + @Override + public void onRenderFail(int code, String msg) { + LogUtils.e(TAG, "onRenderFail errorCode " + code + " errorMsg " + msg); + // 修复:渲染失败时移除容器 + if (activity != null && !activity.isFinishing() && !activity.isDestroyed() && mContainer != null) { + mContainer.removeView(container); + } + } + }); + } + + /** + * 请求广告(核心修复:Context安全校验 + 异常捕获 + 资源管理) + */ + private void fetchAd(final Activity activity) { + // 没有设置米盟广告支持就退出 + if (ADsControlView.getAdsModeFromStatic(this.mContext) != ADsMode.MIMO_SDK) { + return; + } + + LogUtils.d(TAG, "fetchAd()"); + // 1. 双重校验:Activity未销毁 + Context非空 + if (activity == null || activity.isFinishing() || activity.isDestroyed() || activity.getApplicationContext() == null) { + LogUtils.e(TAG, "fetchAd: Invalid Context or Activity state"); + return; + } + // 2. 释放之前的广告资源,避免内存泄漏 + if (mBannerAd != null) { + mBannerAd.destroy(); + } + // 3. 初始化广告(使用ApplicationContext,避免Activity Context失效) + try { + mBannerAd = new BannerAd(); + mAllBanners.add(mBannerAd); + } catch (Exception e) { + LogUtils.e(TAG, "fetchAd: Init BannerAd failed", e); + return; + } + // 4. 设置下载监听 + mBannerAd.setDownLoadListener(new BannerAd.BannerDownloadListener() { + @Override + public void onDownloadStarted() { + LogUtils.d(TAG, "onDownloadStarted"); + } + + @Override + public void onDownloadPaused() { + LogUtils.d(TAG, "onDownloadPaused"); + } + + @Override + public void onDownloadFailed(int errorCode) { + String msg = "onDownloadFailed, errorCode = " + errorCode; + LogUtils.d(TAG, msg); + //ToastUtils.show(msg); + } + + @Override + public void onDownloadFinished() { + LogUtils.d(TAG, "onDownloadFinished"); + } + + @Override + public void onDownloadProgressUpdated(int progress) { + LogUtils.d(TAG, "onDownloadProgressUpdated " + progress + "%"); + } + + @Override + public void onInstallFailed(int errorCode) { + LogUtils.d(TAG, "onInstallFailed, errorCode = " + errorCode); + } + + @Override + public void onInstallStart() { + LogUtils.d(TAG, "onInstallStart"); + } + + @Override + public void onInstallSuccess() { + LogUtils.d(TAG, "onInstallSuccess"); + } + + @Override + public void onDownloadCancel() { + LogUtils.d(TAG, "onDownloadCancel"); + } + }); + + // 5. 构建广告参数并请求 + String currentAD_ID = getAD_ID(); + LogUtils.d(TAG, String.format("currentAD_ID = %s", currentAD_ID)); + ADParams params = new ADParams.Builder().setUpId(currentAD_ID).build(); + mBannerAd.loadAd(params, new BannerAd.BannerLoadListener() { + @Override + public void onBannerAdLoadSuccess() { + LogUtils.d(TAG, "onBannerAdLoadSuccess()"); + // 修复:广告加载成功后校验Activity状态 + if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) { + showAd(activity); + //ToastUtils.show("showAd()"); + } + } + + @Override + public void onAdLoadFailed(int errorCode, String errorMsg) { + String msg = "onAdLoadFailed: errorCode = " + errorCode + ", errorMsg = " + errorMsg; + LogUtils.d(TAG, msg); + removeAllBanners(); + } + }); + } + + void removeAllBanners() { + // 没有设置米盟广告支持就退出 + if (ADsControlView.getAdsModeFromStatic(this.mContext) != ADsMode.MIMO_SDK) { + return; + } + + // 修复:加载失败时移除当前广告实例 + if (mAllBanners.contains(mBannerAd)) { + mAllBanners.remove(mBannerAd); + } + mBannerAd.destroy(); + mBannerAd = null; + } + + /** + * 根据当前秒数获取广告ID(原逻辑保留) + */ + private String getAD_ID() { + long currentSecond = System.currentTimeMillis() / 1000; + return (currentSecond % 2 == 0) ? BANNER_POS_ID : + (GlobalApplication.isDebugging() ? BANNER_POS_ID_WINBOLL_BETA : BANNER_POS_ID_WINBOLL); + } + + /** + * 获取广告价格(原逻辑保留,添加空指针校验) + */ +// private long getPrice() { +// if (mBannerAd == null) { +// return 0; +// } +// Map map = mBannerAd.getMediaExtraInfo(); +// if (map == null || map.isEmpty() || !map.containsKey("price")) { +// LogUtils.w(TAG, "getPrice: media extra info is null or no price key"); +// return 0; +// } +// Object priceObj = map.get("price"); +// if (priceObj instanceof Long) { +// return (Long) priceObj; +// } else if (priceObj instanceof Integer) { +// return ((Integer) priceObj).longValue(); +// } else { +// LogUtils.e(TAG, "getPrice: price type is invalid"); +// return 0; +// } +// } + + /** + * 显示隐私协议弹窗(原逻辑保留,优化Context使用) + */ +// private void showPrivacy() { +// // 校验Activity状态,避免弹窗泄露 +// if (getActivity() == null || getActivity().isFinishing() || getActivity().isDestroyed()) { +// return; +// } +// ADsMode adsMode = ADsControlView.getAdsModeFromStatic(this.mContext); +// if (adsMode == ADsMode.STANDALONE) { +// ADsControlView.updateAdsModeByStatic(this.mContext, ADsMode.STANDALONE); +// LogUtils.i(TAG, "单机模式,广告已处于不可用状态..."); +// Toast.makeText(getActivity().getApplicationContext(), "单机模式,广告已处于不可用状态...", Toast.LENGTH_SHORT).show(); +// return; +// } else if (adsMode == ADsMode.MIMO_SDK) { +// ADsControlView.updateAdsModeByStatic(this.mContext, ADsMode.MIMO_SDK); +// LogUtils.i(TAG, "米盟广告SDK支持模式,现在初始化SDK..."); +// initMimoSdk(); +// return; +// } +// else { +// LogUtils.i(TAG, "开始弹出隐私协议..."); +// AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); +// builder.setTitle("用户须知"); +// builder.setMessage("小米广告SDK隐私政策: https://dev.mi.com/distribute/doc/details?pId=1688, 请复制到浏览器查看"); +// builder.setIcon(R.drawable.ic_launcher); +// builder.setCancelable(false); // 点击对话框以外的区域不消失 +// builder.setPositiveButton("同意", new DialogInterface.OnClickListener() { +// @Override +// public void onClick(DialogInterface dialog, int which) { +// getSharedPreferences().edit() +// .putString(PRIVACY_VALUE, String.valueOf(1)) +// .apply(); +// initMimoSdk(); +// dialog.dismiss(); +// } +// }); +// builder.setNegativeButton("拒绝", new DialogInterface.OnClickListener() { +// @Override +// public void onClick(DialogInterface dialog, int which) { +// getSharedPreferences().edit() +// .putString(PRIVACY_VALUE, String.valueOf(0)) +// .apply(); +// dialog.dismiss(); +// } +// }); +// AlertDialog dialog = builder.create(); +// +// // 配置弹窗位置(底部全屏) +// Window window = dialog.getWindow(); +// if (window != null) { +// window.setGravity(Gravity.BOTTOM); +// WindowManager m = getActivity().getWindowManager(); +// Display d = m.getDefaultDisplay(); +// WindowManager.LayoutParams p = window.getAttributes(); +// p.width = d.getWidth(); +// window.setAttributes(p); +// } +// dialog.show(); +// } +// } + + /** + * 初始化米盟SDK(核心修复:传递ApplicationContext + 异常捕获) + */ + private void initMimoSdk(Context context) { + // 1. 安全获取ApplicationContext,避免Activity Context失效 + Context appContext = context.getApplicationContext(); + if (appContext == null) { + LogUtils.e(TAG, "initMimoSdk: ApplicationContext is null"); + return; + } + // 2. 初始化SDK,捕获异常避免崩溃 + try { + MimoSdk.init(appContext, new MimoCustomController() { + @Override + public boolean isCanUseLocation() { + return true; + } + + @Override + public MimoLocation getMimoLocation() { + return null; + } + + @Override + public boolean isCanUseWifiState() { + return true; + } + + @Override + public boolean alist() { + return true; + } + }, new MimoSdk.InitCallback() { + @Override + public void success() { + LogUtils.d(TAG, "MimoSdk init success"); + } + + @Override + public void fail(int code, String msg) { + LogUtils.e(TAG, "MimoSdk init fail, code=" + code + ",msg=" + msg); + } + }); + MimoSdk.setDebugOn(true); + } catch (Exception e) { + LogUtils.e(TAG, "initMimoSdk: init failed", e); + } + } + + + /** + * 获取SharedPreferences实例(原逻辑保留,添加空指针校验) + */ +// SharedPreferences getSharedPreferences() { +//// if (mSharedPreferences == null) { +//// // 修复:使用ApplicationContext获取SharedPreferences,避免Activity Context泄露 +//// Context appContext = getActivity().getApplicationContext(); +//// if (appContext != null) { +//// mSharedPreferences = appContext.getSharedPreferences(PRIVACY_FILE, Context.MODE_PRIVATE); +//// } else { +//// LogUtils.e(TAG, "getSharedPreferences: ApplicationContext is null"); +//// // 降级方案:若ApplicationContext为空,使用Activity Context(仅作兼容) +//// mSharedPreferences = getActivity().getSharedPreferences(PRIVACY_FILE, Context.MODE_PRIVATE); +//// } +//// } +// return mSharedPreferences; +// } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/views/ADsControlView.java b/libaes/src/main/java/cc/winboll/studio/libaes/views/ADsControlView.java new file mode 100644 index 0000000..c24efca --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/views/ADsControlView.java @@ -0,0 +1,633 @@ +package cc.winboll.studio.libaes.views; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.text.Html; +import android.util.AttributeSet; +import android.view.Display; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.PopupMenu; +import android.widget.PopupWindow; +import android.widget.RadioButton; +import android.widget.RadioGroup; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; +import androidx.appcompat.app.AlertDialog; +import cc.winboll.studio.libaes.R; +import cc.winboll.studio.libaes.enums.ADsMode; +import cc.winboll.studio.libaes.enums.PrivacyAgreeStatus; +import cc.winboll.studio.libaes.utils.WebUtils; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.ToastUtils; +import com.miui.zeus.mimo.sdk.MimoCustomController; +import com.miui.zeus.mimo.sdk.MimoLocation; +import com.miui.zeus.mimo.sdk.MimoSdk; +import java.lang.reflect.Field; + +/** + * @Author ZhanGSKen&豆包大模型 + * @Date 2025/11/26 17:51 + * @LastEditTime 2026/01/08 11:00:00 HKT + * @Describe 广告模式控制控件(Java 7 兼容,云宝物语模式) + * 核心修改:将PopupMenu锚点绑定到view_popmenu_anchor_point控件,菜单精准显示在锚点位置 + */ +public class ADsControlView extends LinearLayout { + public static final String TAG = "ADsControlView"; + + // SP存储配置 + private static final String SP_NAME = "ads_control_config"; + private static final String KEY_SELECTED_MODE = "selected_ads_mode"; + ADsMode mADsMode; + private static final String PRIVACY_VALUE = "privacy_value"; + PrivacyAgreeStatus mPrivacyAgreeStatus; + + // Handler消息标识 + private static final int MSG_UPDATE_MODE = 1001; + + // 控件引用 + private RadioGroup rgADsMode; + private RadioButton rbStandalone; + private RadioButton rbMimoSDK; + private RadioButton rbStoreQrcode; + private RelativeLayout rlWinbollStore; + private ImageView ivWinbollStoreQrcode; + // 新增:锚点控件引用 + private TextView viewPopmenuAnchorPoint; + + // 外部监听、SP实例、Handler实例 + private OnAdsModeSelectedListener listener; + private SharedPreferences sharedPreferences; + private InternalHandler mHandler; + private Context mContext; + + // 静态列表:存储所有已创建的控件实例 + private static final java.util.List sControlViews = new java.util.ArrayList(); + + // 常量定义 + private static final String WECHAT_STORE_URL = "https://store.weixin.qq.com/shop/b/XhrPkZgoeHo4zug"; + private static final int MENU_ITEM_OPEN_STORE = 1001; + + // 构造方法(Java 7 兼容) + public ADsControlView(Context context) { + super(context); + initView(context); + } + + public ADsControlView(Context context, AttributeSet attrs) { + super(context, attrs); + initView(context); + } + + @SuppressWarnings("deprecation") + public ADsControlView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initView(context); + } + + public void setPrivacyAgreeStatus(PrivacyAgreeStatus privacyAgreeStatus) { + this.mPrivacyAgreeStatus = privacyAgreeStatus; + sharedPreferences.edit().putString(PRIVACY_VALUE, this.mPrivacyAgreeStatus.name()).apply(); + } + + public PrivacyAgreeStatus getPrivacyAgreeStatus() { + String privacyAgreeStatusStr = sharedPreferences.getString(PRIVACY_VALUE, PrivacyAgreeStatus.UN_SIGNED.name()); + PrivacyAgreeStatus privacyAgreeStatus = PrivacyAgreeStatus.fromString(privacyAgreeStatusStr); + return privacyAgreeStatus; + } + + public void setADsMode(ADsMode mADsMode) { + this.mADsMode = mADsMode; + sharedPreferences.edit().putString(KEY_SELECTED_MODE, this.mADsMode.name()).apply(); + updateStoreQrcodeLayoutVisibility(mADsMode); + } + + public ADsMode getADsMode() { + String savedModeStr = sharedPreferences.getString(KEY_SELECTED_MODE, ADsMode.STANDALONE.name()); + mADsMode = ADsMode.fromValue(savedModeStr); + return mADsMode; + } + + /** + * 初始化视图、SP、Handler + */ + private void initView(final Context context) { + this.mContext = context; + + // 加载布局 + LayoutInflater.from(context).inflate(R.layout.view_adscontrol, this, true); + + // 初始化SP + sharedPreferences = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); + + // 绑定控件 + rgADsMode = (RadioGroup) findViewById(R.id.rg_ads_mode); + rbStandalone = (RadioButton) findViewById(R.id.rb_standalone); + rbMimoSDK = (RadioButton) findViewById(R.id.rb_mimo_sdk); + rbStoreQrcode = (RadioButton) findViewById(R.id.rb_store_qrcode); + rlWinbollStore = (RelativeLayout) findViewById(R.id.rl_winboll_store); + ivWinbollStoreQrcode = (ImageView) findViewById(R.id.iv_winboll_store); + // 绑定锚点控件 + viewPopmenuAnchorPoint = (TextView) findViewById(R.id.view_popmenu_anchor_point); + + // 初始化Handler + mHandler = new InternalHandler(Looper.getMainLooper()); + + // 核心修改:初始化图片的点击和长按事件(锚点改为view_popmenu_anchor_point) + initImageViewClickAndLongClick(); + + // 注册控件实例 + registerControlView(this); + + // 从SP读取初始模式 + setSelectedMode(getADsMode()); + + // 单选组选择事件监听 + rgADsMode.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(RadioGroup group, int checkedId) { + if (checkedId == R.id.rb_standalone) { + setADsMode(ADsMode.STANDALONE); + if (listener != null) listener.onModeSelected(ADsMode.STANDALONE); + } else if (checkedId == R.id.rb_mimo_sdk) { + handlePrivacyLogic((Activity) context, PrivacyAgreeStatus.UN_SIGNED, new OnPrivacyChangeListener() { + @Override + public void onAgreePrivacy() { + setADsMode(ADsMode.MIMO_SDK); + if (listener != null) listener.onModeSelected(ADsMode.MIMO_SDK); + } + + @Override + public void onDisagreePrivacy() { + setADsMode(ADsMode.STANDALONE); + setSelectedMode(ADsMode.STANDALONE); + if (listener != null) listener.onModeSelected(ADsMode.STANDALONE); + } + }); + } else if (checkedId == R.id.rb_store_qrcode) { + setADsMode(ADsMode.STORE_QRCODE); + if (listener != null) listener.onModeSelected(ADsMode.STORE_QRCODE); + } + } + }); + } + + /** + * 初始化图片的点击和长按事件 + * 核心:将PopupMenu锚点绑定到view_popmenu_anchor_point控件 + */ + private void initImageViewClickAndLongClick() { + if (ivWinbollStoreQrcode == null || viewPopmenuAnchorPoint == null) { + LogUtils.e(TAG, "initImageViewClickAndLongClick: 控件引用为空"); + return; + } + + // 1. 点击事件:简化为提示信息 + ivWinbollStoreQrcode.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + ToastUtils.show("长按图片可打开微信小店"); + LogUtils.d(TAG, "图片点击:提示用户长按打开微信小店"); + } + }); + + // 2. 长按事件:锚点改为view_popmenu_anchor_point + ivWinbollStoreQrcode.setOnLongClickListener(new OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + // 计算锚点控件的屏幕坐标(用于菜单位置微调) + int[] anchorLocation = new int[2]; + viewPopmenuAnchorPoint.getLocationOnScreen(anchorLocation); + final int anchorX = anchorLocation[0]; + final int anchorY = anchorLocation[1]; + + // 创建PopupMenu,锚点绑定到view_popmenu_anchor_point + PopupMenu popupMenu = new PopupMenu(mContext, viewPopmenuAnchorPoint); + // 设置菜单重力:相对锚点居中显示 + popupMenu.setGravity(Gravity.CENTER); + + Menu menu = popupMenu.getMenu(); + menu.add(Menu.NONE, MENU_ITEM_OPEN_STORE, Menu.NONE, "打开微信小店"); + + // 设置菜单点击事件 + popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + if (item.getItemId() == MENU_ITEM_OPEN_STORE) { + WebUtils.openUrlInBrowser(mContext, WECHAT_STORE_URL); + return true; + } + return false; + } + }); + + try { + // 反射获取PopupWindow,微调菜单位置(可选) + Field popupField = PopupMenu.class.getDeclaredField("mPopup"); + popupField.setAccessible(true); + Object popupObject = popupField.get(popupMenu); + if (popupObject instanceof PopupWindow) { + final PopupWindow popupWindow = (PopupWindow) popupObject; + popupWindow.setAnimationStyle(0); // 关闭默认动画 + + // 延迟微调菜单位置(确保布局测量完成) + new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { + @Override + public void run() { + int menuX = anchorX + viewPopmenuAnchorPoint.getWidth() / 2 - popupWindow.getWidth() / 2; + int menuY = anchorY + viewPopmenuAnchorPoint.getHeight() / 2 - popupWindow.getHeight() / 2; + if (!popupWindow.isShowing()) { + popupWindow.showAtLocation(viewPopmenuAnchorPoint, Gravity.NO_GRAVITY, menuX, menuY); + } + } + }, 30); + } + } catch (NoSuchFieldException | IllegalAccessException e) { + LogUtils.e(TAG, "反射获取PopupWindow失败", e); + } + + // 显示菜单 + popupMenu.show(); + LogUtils.d(TAG, "长按图片,菜单锚点为view_popmenu_anchor_point"); + return true; + } + }); + + // 设置控件可交互标识 + ivWinbollStoreQrcode.setClickable(true); + ivWinbollStoreQrcode.setFocusable(true); + ivWinbollStoreQrcode.setLongClickable(true); + viewPopmenuAnchorPoint.setClickable(false); // 锚点控件不可点击 + viewPopmenuAnchorPoint.setLongClickable(false); + } + + /** + * 从ImageView中提取Bitmap(保留方法,无实际调用) + */ + private Bitmap getBitmapFromImageView(ImageView imageView) { + Drawable drawable = imageView.getDrawable(); + if (drawable instanceof BitmapDrawable) { + return ((BitmapDrawable) drawable).getBitmap(); + } + return null; + } + + /** + * 压缩Bitmap(备用方法,无实际调用) + */ + private Bitmap compressBitmapBySize(Bitmap src, int maxWidth, int maxHeight) { + if (src == null) return null; + int width = src.getWidth(); + int height = src.getHeight(); + float scale = Math.min((float) maxWidth / width, (float) maxHeight / height); + int newWidth = (int) (width * scale); + int newHeight = (int) (height * scale); + return Bitmap.createScaledBitmap(src, newWidth, newHeight, true); + } + + /** + * 计算Bitmap采样率(备用方法,无实际调用) + */ + private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { + final int height = options.outHeight; + final int width = options.outWidth; + int inSampleSize = 1; + if (height > reqHeight || width > reqWidth) { + final int halfHeight = height / 2; + final int halfWidth = width / 2; + while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { + inSampleSize *= 2; + } + } + return inSampleSize; + } + + /** + * 从ImageView反射获取资源ID(备用方法,无实际调用) + */ + private int getResIdFromImageView(ImageView imageView) { + try { + Field field = ImageView.class.getDeclaredField("mSrcResource"); + field.setAccessible(true); + return field.getInt(imageView); + } catch (NoSuchFieldException | IllegalAccessException e) { + LogUtils.e(TAG, "getResIdFromImageView: 反射失败", e); + return 0; + } + } + + /** + * 更新二维码布局显示状态 + */ + private void updateStoreQrcodeLayoutVisibility(ADsMode mode) { + if (rlWinbollStore == null) return; + rlWinbollStore.setVisibility(mode == ADsMode.STORE_QRCODE ? View.VISIBLE : View.GONE); + } + + /** + * 清理SP中的隐私协议状态 + */ + public static void cleanPrivacyStatus(Context context) { + if (context == null) { + LogUtils.e(TAG, "cleanPrivacyStatus: Context is null"); + return; + } + SharedPreferences sp = getPrivacySharedPreferences(context); + sp.edit().remove(PRIVACY_VALUE).apply(); + LogUtils.i(TAG, "隐私协议状态清理成功"); + ToastUtils.show("隐私协议状态已清理"); + } + + /** + * 获取隐私协议SP实例 + */ + private static SharedPreferences getPrivacySharedPreferences(Context context) { + Context appContext = context.getApplicationContext(); + if (appContext != null) { + return appContext.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); + } + return context.getSharedPreferences(PRIVACY_VALUE, Context.MODE_PRIVATE); + } + + /** + * 处理隐私协议逻辑 + */ + private static void handlePrivacyLogic(final Activity activity, PrivacyAgreeStatus privacyAgreeStatus, final OnPrivacyChangeListener onPrivacyChangeListener) { + if (privacyAgreeStatus == PrivacyAgreeStatus.REJECTED) { + Toast.makeText(activity.getApplicationContext(), "已拒绝隐私协议,广告已处于不可用状态", Toast.LENGTH_SHORT).show(); + return; + } else if (privacyAgreeStatus == PrivacyAgreeStatus.AGREED) { + initMimoSdkStatic(activity.getApplicationContext()); + return; + } else { + AlertDialog dialog = createPrivacyDialog(activity, onPrivacyChangeListener); + Window window = dialog.getWindow(); + if (window != null) { + window.setGravity(Gravity.BOTTOM); + WindowManager m = activity.getWindowManager(); + Display d = m.getDefaultDisplay(); + WindowManager.LayoutParams p = window.getAttributes(); + p.width = d.getWidth(); + window.setAttributes(p); + } + dialog.show(); + } + } + + /** + * 初始化米盟SDK + */ + private static void initMimoSdkStatic(Context appContext) { + if (appContext == null) return; + try { + MimoSdk.init(appContext, new MimoCustomController() { + @Override + public boolean isCanUseLocation() { + return true; + } + + @Override + public MimoLocation getMimoLocation() { + return null; + } + + @Override + public boolean isCanUseWifiState() { + return true; + } + + @Override + public boolean alist() { + return true; + } + }, new MimoSdk.InitCallback() { + @Override + public void success() { + LogUtils.d(TAG, "米盟SDK初始化成功"); + } + + @Override + public void fail(int code, String msg) { + LogUtils.e(TAG, "米盟SDK初始化失败:" + code + ", " + msg); + } + }); + MimoSdk.setDebugOn(true); + } catch (Exception e) { + LogUtils.e(TAG, "米盟SDK初始化异常", e); + } + } + + /** + * 静态方法:更新SP中的模式 + */ + public static void updateAdsModeByStatic(Context context, ADsMode mode) { + if (context == null || mode == null) return; + SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); + sp.edit().putString(KEY_SELECTED_MODE, mode.name()).apply(); + InternalHandler.sendUpdateModeMessage(mode); + } + + /** + * 静态方法:读取SP中的模式 + */ + public static ADsMode getAdsModeFromStatic(Context context) { + if (context == null) return ADsMode.STANDALONE; + SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); + String savedModeStr = sp.getString(KEY_SELECTED_MODE, ADsMode.STANDALONE.name()); + return ADsMode.fromValue(savedModeStr); + } + + /** + * 注册控件实例 + */ + private static void registerControlView(ADsControlView view) { + synchronized (sControlViews) { + if (!sControlViews.contains(view)) { + sControlViews.add(view); + } + } + } + + /** + * 移除控件实例 + */ + private static void unregisterControlView(ADsControlView view) { + synchronized (sControlViews) { + sControlViews.remove(view); + } + } + + /** + * 设置选中模式 + */ + private void setSelectedMode(final ADsMode mode) { + final ADsMode mode2 = (mode == null) ? ADsMode.STANDALONE : mode; + if (Looper.myLooper() == Looper.getMainLooper()) { + if (mode2 == ADsMode.STANDALONE) { + rbStandalone.setChecked(true); + } else if (mode2 == ADsMode.MIMO_SDK) { + rbMimoSDK.setChecked(true); + } else if (mode2 == ADsMode.STORE_QRCODE) { + rbStoreQrcode.setChecked(true); + } + updateStoreQrcodeLayoutVisibility(mode2); + } else { + mHandler.post(new Runnable() { + @Override + public void run() { + setSelectedMode(mode2); + } + }); + } + } + + /** + * 获取选中模式 + */ + public ADsMode getSelectedMode() { + int checkedId = rgADsMode.getCheckedRadioButtonId(); + if (checkedId == R.id.rb_mimo_sdk) { + return ADsMode.MIMO_SDK; + } else if (checkedId == R.id.rb_store_qrcode) { + return ADsMode.STORE_QRCODE; + } else { + return ADsMode.STANDALONE; + } + } + + /** + * 设置外部监听 + */ + public void setOnAdsModeSelectedListener(OnAdsModeSelectedListener listener) { + this.listener = listener; + } + + /** + * 内部Handler类 + */ + private static class InternalHandler extends Handler { + static volatile InternalHandler _InternalHandler; + + public InternalHandler(Looper looper) { + super(looper); + _InternalHandler = this; + } + + public static void sendUpdateModeMessage(ADsMode mode) { + if (mode == null || _InternalHandler == null) return; + Message msg = _InternalHandler.obtainMessage(); + msg.what = MSG_UPDATE_MODE; + msg.obj = mode; + _InternalHandler.sendMessage(msg); + } + + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + if (msg.what == MSG_UPDATE_MODE) { + ADsMode mode = (ADsMode) msg.obj; + if (mode == null) return; + synchronized (sControlViews) { + for (ADsControlView view : sControlViews) { + if (view != null && view.isShown() && view.isAttachedToWindow()) { + view.setSelectedMode(mode); + view.updateStoreQrcodeLayoutVisibility(mode); + } + } + } + } + } + } + + /** + * 生命周期:控件销毁 + */ + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (mHandler != null) { + mHandler.removeCallbacksAndMessages(null); + } + unregisterControlView(this); + } + + /** + * 外部监听接口 + */ + public interface OnAdsModeSelectedListener { + void onModeSelected(ADsMode selectedMode); + } + + /** + * 隐私协议监听接口 + */ + public interface OnPrivacyChangeListener { + void onAgreePrivacy(); + void onDisagreePrivacy(); + } + + /** + * 创建隐私协议对话框 + */ + private static AlertDialog createPrivacyDialog(final Activity activity, final OnPrivacyChangeListener onPrivacyChangeListener) { + View dialogView = LayoutInflater.from(activity).inflate(R.layout.dialog_privacy_agreement, null); + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setView(dialogView).setCancelable(false); + final AlertDialog dialog = builder.create(); + + final TextView tvPrivacyUrl = (TextView) dialogView.findViewById(R.id.tv_privacy_url); + Button btnAgree = (Button) dialogView.findViewById(R.id.btn_agree); + Button btnDisagree = (Button) dialogView.findViewById(R.id.btn_disagree); + + tvPrivacyUrl.setText(Html.fromHtml("" + tvPrivacyUrl.getText().toString() + "")); + tvPrivacyUrl.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + String url = tvPrivacyUrl.getText().toString().trim(); + ToastUtils.show("隐私协议链接:" + url); + } + }); + tvPrivacyUrl.setClickable(true); + tvPrivacyUrl.setFocusable(true); + + btnAgree.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (onPrivacyChangeListener != null) { + onPrivacyChangeListener.onAgreePrivacy(); + } + dialog.dismiss(); + } + }); + + btnDisagree.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (onPrivacyChangeListener != null) { + onPrivacyChangeListener.onDisagreePrivacy(); + } + dialog.dismiss(); + } + }); + + return dialog; + } +} + diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/views/AOHPCTCSeekBar.java b/libaes/src/main/java/cc/winboll/studio/libaes/views/AOHPCTCSeekBar.java new file mode 100644 index 0000000..432fbde --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/views/AOHPCTCSeekBar.java @@ -0,0 +1,108 @@ +package cc.winboll.studio.libaes.views; + +/** + * @Author ZhanGSKen + * @Date 2024/07/16 01:46:30 + * @Describe AOneHundredPercantClickToCommitSeekBar + */ +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.widget.SeekBar; +import cc.winboll.studio.libappbase.LogUtils; + +public class AOHPCTCSeekBar extends SeekBar { + + public static final String TAG = "AOHPCTCSeekBar"; + + volatile int thumbWidth = 1; + volatile int progressBarWidth = 1; + // 设置按钮模糊右边边缘像素 + volatile int blurRightDP = 1; + // 是否从起点拉动的标志 + volatile boolean isStartSeek = false; + + // 外部接口对象,确定事件提交会调用该对象的方法 + OnOHPCListener mOnOHPCListener; + + + public void setBlurRightDP(int blurRight) { + this.blurRightDP = blurRight; + } + + public void setOnOHPCListener(OnOHPCListener listener) { + mOnOHPCListener = listener; + } + + public interface OnOHPCListener { + abstract void onOHPCommit(); + } + + public AOHPCTCSeekBar(Context context) { + super(context); + initView(context); + } + + public AOHPCTCSeekBar(Context context, AttributeSet attrs) { + super(context, attrs); + initView(context); + } + + public AOHPCTCSeekBar(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initView(context); + } + + void initView(Context context) { + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (thumbWidth + blurRightDP > event.getX() && event.getX() > 0) { + getParent().requestDisallowInterceptTouchEvent(true); + isStartSeek = true; + } + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + if (isStartSeek) { + super.dispatchTouchEvent(event); + } + } else if (event.getAction() == MotionEvent.ACTION_UP + || event.getAction() == MotionEvent.ACTION_CANCEL) { + getParent().requestDisallowInterceptTouchEvent(false); + if (getProgress() == progressBarWidth) { + mOnOHPCListener.onOHPCommit(); + } + // 重置控件状态 + setProgress(0); + isStartSeek = false; + } + return true; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int width = MeasureSpec.getSize(widthMeasureSpec); + //int height = MeasureSpec.getSize(heightMeasureSpec); + //LogUtils.d(TAG, String.format("width %d height %d", width, height)); + + // 获取SeekBar的图标宽度 + Drawable thumbDrawable = getThumb(); + if (thumbDrawable != null) { + // 获取图标宽度 + thumbWidth = thumbDrawable.getIntrinsicWidth(); + } + + // 获取进度条宽度 + progressBarWidth = width; + + //LogUtils.d(TAG, String.format("thumbWidth %d progressBarWidth %d", thumbWidth, progressBarWidth)); + + // 设置图标位置 + setThumbOffset(0); + // 设置进度条刻度 + setMax(progressBarWidth); + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/views/AOHPCTSCard.java b/libaes/src/main/java/cc/winboll/studio/libaes/views/AOHPCTSCard.java new file mode 100644 index 0000000..a7120ea --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/views/AOHPCTSCard.java @@ -0,0 +1,43 @@ +package cc.winboll.studio.libaes.views; + +/** + * @Author ZhanGSKen + * @Date 2024/07/16 01:49:23 + * @Describe AOneHundredPercantClickToStartCard + */ +import android.content.Context; +import android.util.AttributeSet; + +public class AOHPCTSCard extends ACard { + + public static final String TAG = "AOHPCTSCard"; + + public AOHPCTSCard(Context context) { + super(context); + } + + public AOHPCTSCard(Context context, AttributeSet attrs) { + super(context, attrs); + //setPadding(0 + 0 + 2 + 1, 0 + 0 + 2 + 1, 0 + 1 + 3 + 1, 0 + 2 + 3 + 1); + + // 获得TypedArray + //TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AToolbar); + // 获得attrs.xml里面的属性值,格式为:名称_属性名,后面是默认值 + //int colorBackgroud = a.getColor(R.styleable.ACard_backgroudColor, context.getColor(R.color.colorACardBackgroung)); + //int centerColor = a.getColor(R.styleable.AToolbar_centerColor, context.getColor(R.color.colorAToolbarCenterColor)); + //int endColor = a.getColor(R.styleable.AToolbar_endColor, context.getColor(R.color.colorAToolbarEndColor)); + //float tSize = a.getDimension(R.styleable.CustomView_tSize, 35); + //p.setColor(tColor); + //p.setTextSize(tSize); + //Drawable drawable = context.getDrawable(R.drawable.frame_atoolbar); + + //setBackground(context.getDrawable(R.drawable.acard_frame_main)); + + // 返回一个绑定资源结束的信号给资源 + //a.recycle(); + } + + public AOHPCTSCard(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/views/ASupportToolbar.java b/libaes/src/main/java/cc/winboll/studio/libaes/views/ASupportToolbar.java new file mode 100644 index 0000000..c384919 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/views/ASupportToolbar.java @@ -0,0 +1,89 @@ +package cc.winboll.studio.libaes.views; + +/** + * @Author ZhanGSKen + * @Date 2024/07/16 01:54:40 + * @Describe ASupportToolbar + */ +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.LayerDrawable; +import android.util.AttributeSet; +import androidx.appcompat.widget.Toolbar; +import cc.winboll.studio.libaes.R; +import android.graphics.drawable.Drawable; +import androidx.core.content.ContextCompat; +import android.graphics.PorterDuff; + +public class ASupportToolbar extends Toolbar { + + public static final String TAG = "ASupportToolbar"; + + int mTitleTextColor; + int mStartColor; + int mCenterColor; + int mEndColor; + LayerDrawable ld; + GradientDrawable[] array = new GradientDrawable[3]; + //private GradientDrawable gradientDrawable; + + public ASupportToolbar(Context context) { + super(context); + } + + public ASupportToolbar(Context context, AttributeSet attrs) { + super(context, attrs); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ASupportToolbar, R.attr.aSupportToolbar, 0); + mTitleTextColor = a.getColor(R.styleable.ASupportToolbar_attrASupportToolbarTitleTextColor, Color.GREEN); + mStartColor = a.getColor(R.styleable.ASupportToolbar_attrASupportToolbarStartColor, Color.BLUE); + mCenterColor = a.getColor(R.styleable.ASupportToolbar_attrASupportToolbarCenterColor, Color.RED); + mEndColor = a.getColor(R.styleable.ASupportToolbar_attrASupportToolbarEndColor, Color.YELLOW); + // 返回一个绑定资源结束的信号给资源 + a.recycle(); + notifyColorChange(); + } + + void notifyColorChange() { + // 工具栏描边 + int nStroke = 5; + + //分别为开始颜色,中间夜色,结束颜色 + int colors0[] = { mEndColor , mCenterColor, mStartColor}; + GradientDrawable gradientDrawable0; + array[2] = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, colors0); + gradientDrawable0 = array[2]; + gradientDrawable0.setShape(GradientDrawable.RECTANGLE); + gradientDrawable0.setColors(colors0); //添加颜色组 + gradientDrawable0.setGradientType(GradientDrawable.LINEAR_GRADIENT);//设置线性渐变 + gradientDrawable0.setCornerRadius(20); + + int colors1[] = { mCenterColor , mCenterColor, mCenterColor }; + GradientDrawable gradientDrawable1; + array[1] = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, colors1); + gradientDrawable1 = array[1]; + gradientDrawable1.setShape(GradientDrawable.RECTANGLE); + gradientDrawable1.setColors(colors1); //添加颜色组 + gradientDrawable1.setGradientType(GradientDrawable.LINEAR_GRADIENT);//设置线性渐变 + gradientDrawable1.setCornerRadius(20); + + int colors2[] = { mEndColor, mCenterColor, mStartColor }; + GradientDrawable gradientDrawable2; + array[0] = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, colors2); + gradientDrawable2 = array[0]; + gradientDrawable2.setShape(GradientDrawable.RECTANGLE); + gradientDrawable2.setColors(colors2); //添加颜色组 + gradientDrawable2.setGradientType(GradientDrawable.LINEAR_GRADIENT);//设置线性渐变 + gradientDrawable2.setCornerRadius(20); + + ld = new LayerDrawable(array); //参数为上面的Drawable数组 + ld.setLayerInset(2, nStroke * 2, nStroke * 2, getWidth() + nStroke * 2, getHeight() + nStroke * 2); + ld.setLayerInset(1, nStroke, nStroke, getWidth() + nStroke, getHeight() + nStroke); + ld.setLayerInset(0, 0, 0, getWidth(), getHeight()); + + setBackgroundDrawable(ld); + setTitleTextColor(mTitleTextColor); + setSubtitleTextColor(mTitleTextColor); + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/views/ATickProgressBar.java b/libaes/src/main/java/cc/winboll/studio/libaes/views/ATickProgressBar.java new file mode 100644 index 0000000..ddba22b --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/views/ATickProgressBar.java @@ -0,0 +1,55 @@ +package cc.winboll.studio.libaes.views; + +/** + * @Author ZhanGSKen + * @Date 2024/07/16 01:56:38 + * @Describe ATickProgressBar + */ +import android.content.Context; +import android.os.Handler; +import android.util.AttributeSet; +import android.widget.ProgressBar; + +public class ATickProgressBar extends ProgressBar { + + public static final String TAG = "ATickProgressBar"; + + int mnStepDistantce = 100 / 10; + int mnProgress = 0; + + public ATickProgressBar(Context context) { + super(context); + + } + + public ATickProgressBar(Context context, AttributeSet attrs) { + super(context, attrs); + setProgress(50); + } + + public int stepOnTick(int nStepDistantce) { + if (mnProgress < 100) { + int nProgressOld = mnProgress; + mnProgress += nStepDistantce; + new Handler().postDelayed(new Runnable(){ + + @Override + public void run() { + ; + } + }, 1000); + return nProgressOld; + } else { + return mnProgress; + } + } + + /*@Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int nWidthSize = MeasureSpec.getSize(widthMeasureSpec); + int nHeightSize = MeasureSpec.getSize(heightMeasureSpec); + + setMeasuredDimension(nWidthSize, nHeightSize); + }*/ +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/views/AToolbar.java b/libaes/src/main/java/cc/winboll/studio/libaes/views/AToolbar.java new file mode 100644 index 0000000..39b9249 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/views/AToolbar.java @@ -0,0 +1,92 @@ +package cc.winboll.studio.libaes.views; + +/** + * @Author ZhanGSKen + * @Date 2024/07/16 01:58:01 + * @Describe AToolbar + */ +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.LayerDrawable; +import android.util.AttributeSet; +import android.widget.Toolbar; +import cc.winboll.studio.libaes.R; + +public class AToolbar extends Toolbar { + + public static final String TAG = "AToolbar"; + + int mTitleTextColor; + int mStartColor; + int mCenterColor; + int mEndColor; + LayerDrawable ld; + GradientDrawable[] array = new GradientDrawable[3]; + + public AToolbar(Context context) { + super(context); + } + + public AToolbar(Context context, AttributeSet attrs) { + super(context, attrs); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AToolbar, R.attr.aToolbar, 0); + mTitleTextColor = a.getColor(R.styleable.AToolbar_attrAToolbarTitleTextColor, Color.GREEN); + mStartColor = a.getColor(R.styleable.AToolbar_attrAToolbarStartColor, Color.BLUE); + mCenterColor = a.getColor(R.styleable.AToolbar_attrAToolbarCenterColor, Color.RED); + mEndColor = a.getColor(R.styleable.AToolbar_attrAToolbarEndColor, Color.YELLOW); + // 返回一个绑定资源结束的信号给资源 + a.recycle(); + + notifyColorChange(); + } + + public AToolbar(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + void notifyColorChange() { + // 工具栏描边 + int nStroke = 5; + + //分别为开始颜色,中间夜色,结束颜色 + int colors0[] = { mEndColor , mCenterColor, mStartColor}; + GradientDrawable gradientDrawable0; + array[2] = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, colors0); + gradientDrawable0 = array[2]; + gradientDrawable0.setShape(GradientDrawable.RECTANGLE); + gradientDrawable0.setColors(colors0); //添加颜色组 + gradientDrawable0.setGradientType(GradientDrawable.LINEAR_GRADIENT);//设置线性渐变 + gradientDrawable0.setCornerRadius(20); + + int colors1[] = { mCenterColor , mCenterColor, mCenterColor }; + GradientDrawable gradientDrawable1; + array[1] = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, colors1); + gradientDrawable1 = array[1]; + gradientDrawable1.setShape(GradientDrawable.RECTANGLE); + gradientDrawable1.setColors(colors1); //添加颜色组 + gradientDrawable1.setGradientType(GradientDrawable.LINEAR_GRADIENT);//设置线性渐变 + gradientDrawable1.setCornerRadius(20); + + int colors2[] = { mEndColor, mCenterColor, mStartColor }; + GradientDrawable gradientDrawable2; + array[0] = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, colors2); + gradientDrawable2 = array[0]; + gradientDrawable2.setShape(GradientDrawable.RECTANGLE); + gradientDrawable2.setColors(colors2); //添加颜色组 + gradientDrawable2.setGradientType(GradientDrawable.LINEAR_GRADIENT);//设置线性渐变 + gradientDrawable2.setCornerRadius(20); + + + ld = new LayerDrawable(array); //参数为上面的Drawable数组 + ld.setLayerInset(2, nStroke * 2, nStroke * 2, getWidth() + nStroke * 2, getHeight() + nStroke * 2); + ld.setLayerInset(1, nStroke, nStroke, getWidth() + nStroke, getHeight() + nStroke); + ld.setLayerInset(0, 0, 0, getWidth(), getHeight()); + + setBackgroundDrawable(ld); + setTitleTextColor(mTitleTextColor); + setSubtitleTextColor(mTitleTextColor); + } +} diff --git a/libaes/src/main/java/cc/winboll/studio/libaes/views/AboutView.java b/libaes/src/main/java/cc/winboll/studio/libaes/views/AboutView.java new file mode 100644 index 0000000..9f5ed56 --- /dev/null +++ b/libaes/src/main/java/cc/winboll/studio/libaes/views/AboutView.java @@ -0,0 +1,379 @@ +package cc.winboll.studio.libaes.views; + +/** + * @Author ZhanGSKen + * @Date 2025/03/24 15:08:52 + * @Describe WinBoLL应用介绍视图 + */ +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.res.TypedArray; +import android.net.Uri; +import android.os.Message; +import android.util.AttributeSet; +import android.view.View; +import android.widget.EditText; +import android.widget.LinearLayout; +import cc.winboll.studio.libaes.R; +import cc.winboll.studio.libaes.dialogs.YesNoAlertDialog; +import cc.winboll.studio.libaes.models.APPInfo; +import cc.winboll.studio.libaes.utils.AppVersionUtils; +import cc.winboll.studio.libaes.utils.PrefUtils; +import cc.winboll.studio.libaes.utils.WinBoLLActivityManager; +import cc.winboll.studio.libappbase.GlobalApplication; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.ToastUtils; +import java.io.IOException; +import mehdi.sakout.aboutpage.AboutPage; +import mehdi.sakout.aboutpage.Element; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Credentials; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +public class AboutView extends LinearLayout { + + public static final String TAG = "AboutView"; + + public static final int MSG_APPUPDATE_CHECKED = 0; + + static Context _mContext; + APPInfo mAPPInfo; + + //WinBoLLServiceStatusView mWinBoLLServiceStatusView; + OnRequestDevUserInfoAutofillListener mOnRequestDevUserInfoAutofillListener; + String mszAppName = ""; + String mszAppAPKFolderName = ""; + String mszAppAPKName = ""; + String mszAppGitName = ""; + String mszAppVersionName = ""; + String mszCurrentAppPackageName = ""; + boolean mIsAddDebugTools; + volatile String mszNewestAppPackageName = ""; + String mszAppDescription = ""; + String mszHomePage = ""; + String mszGitea = ""; + int mnAppIcon = 0; + String mszWinBoLLServerHost; + String mszReleaseAPKName; + EditText metDevUserName; + EditText metDevUserPassword; + + public AboutView(Context context, APPInfo appInfo) { + super(context); + _mContext = context; + + setAPPInfo(appInfo); + initView(context); + } + + public AboutView(Context context, AttributeSet attrs) { + super(context, attrs); + _mContext = context; + + initView(context, attrs); + } + + public void setAPPInfo(APPInfo appInfo) { + mAPPInfo = appInfo; + } + + APPInfo createAppInfo(Context context, AttributeSet attrs) { + APPInfo appInfo = new APPInfo(); + TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.AboutView); + appInfo.setAppName(typedArray.getString(R.styleable.AboutView_app_name)); + appInfo.setAppAPKFolderName(typedArray.getString(R.styleable.AboutView_app_apkfoldername)); + appInfo.setAppAPKName(typedArray.getString(R.styleable.AboutView_app_apkname)); + appInfo.setAppGitName(typedArray.getString(R.styleable.AboutView_app_gitname)); + appInfo.setAppGitOwner(typedArray.getString(R.styleable.AboutView_app_gitowner)); + appInfo.setAppGitAPPBranch(typedArray.getString(R.styleable.AboutView_app_gitappbranch)); + appInfo.setAppGitAPPSubProjectFolder(typedArray.getString(R.styleable.AboutView_app_gitappsubprojectfolder)); + appInfo.setAppDescription(typedArray.getString(R.styleable.AboutView_appdescription)); + appInfo.setAppIcon(typedArray.getResourceId(R.styleable.AboutView_appicon, R.drawable.ic_winboll)); + appInfo.setIsAddDebugTools(typedArray.getBoolean(R.styleable.AboutView_is_adddebugtools, false)); + // 返回一个绑定资源结束的信号给资源 + typedArray.recycle(); + return appInfo; + } + + void initView(Context context) { + mszAppName = mAPPInfo.getAppName(); + mszAppAPKFolderName = mAPPInfo.getAppAPKFolderName(); + mszAppAPKName = mAPPInfo.getAppAPKName(); + mszAppGitName = mAPPInfo.getAppGitName(); + mszAppDescription = mAPPInfo.getAppDescription(); + mnAppIcon = mAPPInfo.getAppIcon(); + + mszWinBoLLServerHost = GlobalApplication.isDebugging() ? "https://yun-preivew.winboll.cc": "https://yun.winboll.cc"; + + try { + mszAppVersionName = _mContext.getPackageManager().getPackageInfo(_mContext.getPackageName(), 0).versionName; + } catch (PackageManager.NameNotFoundException e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + mszCurrentAppPackageName = mszAppAPKName + "_" + mszAppVersionName + ".apk"; + mszHomePage = mAPPInfo.getAppHomePage(); + //mszHomePage = mszWinBoLLServerHost + "/studio/details.php?app=" + mszAppAPKFolderName; + if (mAPPInfo.getAppGitAPPBranch().equals("")) { + mszGitea = "https://gitea.winboll.cc/" + mAPPInfo.getAppGitOwner() + "/" + mszAppGitName; + } else { + mszGitea = "https://gitea.winboll.cc/" + mAPPInfo.getAppGitOwner() + "/" + mszAppGitName + "/src/branch/" + mAPPInfo.getAppGitAPPBranch() + "/" + mAPPInfo.getAppGitAPPSubProjectFolder(); + } + + addView(createAboutPage()); + + // 初始化标题栏 + //setSubtitle(getContext().getString(R.string.text_about)); + +// LinearLayout llMain = findViewById(R.id.viewaboutLinearLayout1); +// llMain.addView(createAboutPage()); + + // 就读取正式版应用包版本号,设置 Release 应用包文件名 + String szReleaseAppVersionName = ""; + try { + //LogUtils.d(TAG, String.format("mContext.getPackageName() %s", mContext.getPackageName())); + String szSubBetaSuffix = subBetaSuffix(_mContext.getPackageName()); + //LogUtils.d(TAG, String.format("szSubBetaSuffix : %s", szSubBetaSuffix)); + szReleaseAppVersionName = _mContext.getPackageManager().getPackageInfo(szSubBetaSuffix, 0).versionName; + } catch (PackageManager.NameNotFoundException e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + mszReleaseAPKName = mszAppAPKName + "_" + szReleaseAppVersionName + ".apk"; + + } + + void initView(Context context, AttributeSet attrs) { + mAPPInfo = createAppInfo(context, attrs); + initView(context); + } + + public static String subBetaSuffix(String input) { + if (input.endsWith(".beta")) { + return input.substring(0, input.length() - ".beta".length()); + } + return input; + } + + android.os.Handler mHandler = new android.os.Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what) { + case MSG_APPUPDATE_CHECKED : { + /*//检查当前应用包文件名是否是测试版,如果是就忽略检查 + if(mszCurrentAppPackageName.matches(".*_\\d+\\.\\d+\\.\\d+-beta.*\\.apk")) { + ToastUtils.show("APP is the beta Version. Version check ignore."); + return; + }*/ + +// if (!AppVersionUtils.isHasNewStageReleaseVersion(mszReleaseAPKName, mszNewestAppPackageName)) { +// ToastUtils.delayedShow("Current app is the newest.", 5000); +// } + if (!AppVersionUtils.isHasNewVersion2(mszCurrentAppPackageName, mszNewestAppPackageName)) { + ToastUtils.show("Current app is the newest."); + } else { + String szMsg = "Current app is :\n[ " + mszCurrentAppPackageName + + " ]\nThe last app is :\n[ " + mszNewestAppPackageName + + " ]\nIs download the last app?"; + YesNoAlertDialog.show(_mContext, "Application Update Prompt", szMsg, mIsDownlaodUpdateListener); + } + break; + } + } + } + }; + + protected View createAboutPage() { + // 定义 GitWeb 按钮 + // + Element elementGitWeb = new Element(_mContext.getString(R.string.gitea_home), R.drawable.ic_winboll); + elementGitWeb.setOnClickListener(mGitWebOnClickListener); + // 定义检查更新按钮 + // + /*Element elementAppUpdate = new Element(_mContext.getString(R.string.app_update), R.drawable.ic_winboll); + elementAppUpdate.setOnClickListener(mAppUpdateOnClickListener); + */ + + String szAppInfo = ""; + try { + szAppInfo = mszAppName + " " + + _mContext.getPackageManager().getPackageInfo(_mContext.getPackageName(), 0).versionName + + "\n" + mszAppDescription; + } catch (PackageManager.NameNotFoundException e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + AboutPage aboutPage = new AboutPage(_mContext); + aboutPage.setDescription(szAppInfo) + //.isRTL(false) + //.setCustomFont(String) // or Typeface + .setImage(mnAppIcon) + //.addItem(versionElement) + //.addItem(adsElement) + //.addGroup("Connect with us") + .addEmail("WinBoLLStudio") + .addWebsite(mszHomePage) + .addItem(elementGitWeb); + //.addItem(elementAppUpdate); + //.addFacebook("the.medy") + //.addTwitter("medyo80") + //.addYoutube("UCdPQtdWIsg7_pi4mrRu46vA") + //.addPlayStore("com.ideashower.readitlater.pro") + //.addGitHub("medyo") + //.addInstagram("medyo80") + //.create(); + + /*if (mAPPInfo.isAddDebugTools()) { + // 定义应用调试按钮 + // + Element elementAppMode; + if (GlobalApplication.isDebugging()) { + elementAppMode = new Element(_mContext.getString(R.string.app_normal), R.drawable.ic_winboll); + elementAppMode.setOnClickListener(mAppNormalOnClickListener); + } else { + elementAppMode = new Element(_mContext.getString(R.string.app_debug), R.drawable.ic_winboll); + elementAppMode.setOnClickListener(mAppDebugOnClickListener); + } + aboutPage.addItem(elementAppMode); + }*/ + + return aboutPage.create(); + } + + View.OnClickListener mAppDebugOnClickListener = new View.OnClickListener(){ + @Override + public void onClick(View view) { + //ToastUtils.show("mAppDebugOnClickListener"); + setApp2DebugMode(_mContext); + } + }; + + View.OnClickListener mAppNormalOnClickListener = new View.OnClickListener(){ + @Override + public void onClick(View view) { + //ToastUtils.show("mAppNormalOnClickListener"); + setApp2NormalMode(_mContext); + } + }; + + public static void setApp2DebugMode(Context context) { + Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()); + if (intent != null) { + //intent.setAction(cc.winboll.studio.libapputils.intent.action.DEBUGVIEW); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + GlobalApplication.setIsDebugging(true); + GlobalApplication.saveDebugStatus((GlobalApplication)_mContext.getApplicationContext()); + + WinBoLLActivityManager.getInstance().finishAll(); + context.startActivity(intent); + } + } + + public static void setApp2NormalMode(Context context) { + Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()); + if (intent != null) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + GlobalApplication.setIsDebugging(false); + GlobalApplication.saveDebugStatus((GlobalApplication)_mContext.getApplicationContext()); + + WinBoLLActivityManager.getInstance().finishAll(); + context.startActivity(intent); + } + } + + View.OnClickListener mGitWebOnClickListener = new View.OnClickListener(){ + @Override + public void onClick(View view) { + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(mszGitea)); + _mContext.startActivity(browserIntent); + } + }; + + View.OnClickListener mAppUpdateOnClickListener = new View.OnClickListener(){ + @Override + public void onClick(View view) { + ToastUtils.show("Start app update checking."); + new Thread(new Runnable() { + @Override + public void run() { + String szUrl = mszWinBoLLServerHost + "/studio/details.php?app=" + mszAppAPKFolderName; + // 构建包含认证信息的请求 + String credential = ""; + if (GlobalApplication.isDebugging()) { + credential = Credentials.basic(metDevUserName.getText().toString(), metDevUserPassword.getText().toString()); + PrefUtils.saveString(_mContext, "metDevUserName", metDevUserName.getText().toString()); + PrefUtils.saveString(_mContext, "metDevUserPassword", metDevUserPassword.getText().toString()); + } else { + String username = "WinBoLL"; + String password = "WinBoLLPowerByZhanGSKen"; + credential = Credentials.basic(username, password); + } + + Request request = new Request.Builder() + .url(szUrl) + .header("Accept", "text/plain") // 设置正确的Content-Type头 + .header("Authorization", credential) + .build(); + OkHttpClient client = new OkHttpClient(); + Call call = client.newCall(request); + call.enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + // 处理网络请求失败 + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + if (!response.isSuccessful()) { + LogUtils.d(TAG, "Unexpected code " + response, Thread.currentThread().getStackTrace()); + return; + } + + try { + // 读取响应体作为字符串,注意这里可能需要解码 + String text = response.body().string(); + org.jsoup.nodes.Document doc = org.jsoup.Jsoup.parse(text); + LogUtils.v(TAG, doc.text()); + + // 使用id选择器找到具有特定id的元素 + org.jsoup.nodes.Element elementWithId = doc.select("#LastRelease").first(); // 获取第一个匹配的元素 + + // 提取并打印元素的文本内容 + mszNewestAppPackageName = elementWithId.text(); + //ToastUtils.delayedShow(text + "\n" + mszNewestAppPackageName, 5000); + + mHandler.sendMessage(mHandler.obtainMessage(MSG_APPUPDATE_CHECKED)); + } catch (Exception e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + } + }); + } + }).start(); + } + }; + + YesNoAlertDialog.OnDialogResultListener mIsDownlaodUpdateListener = new YesNoAlertDialog.OnDialogResultListener() { + @Override + public void onYes() { + String szUrl = mszWinBoLLServerHost + "/studio/download.php?appname=" + mszAppAPKFolderName + "&apkname=" + mszNewestAppPackageName; + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(szUrl)); + _mContext.startActivity(browserIntent); + } + + @Override + public void onNo() { + } + }; + + public interface OnRequestDevUserInfoAutofillListener { + void requestAutofill(EditText etDevUserName, EditText etDevUserPassword); + } + + public void setOnRequestDevUserInfoAutofillListener(OnRequestDevUserInfoAutofillListener l) { + mOnRequestDevUserInfoAutofillListener = l; + } +} diff --git a/libaes/src/main/res/anim/normal_dialog_enter_center.xml b/libaes/src/main/res/anim/normal_dialog_enter_center.xml new file mode 100644 index 0000000..7a6ac10 --- /dev/null +++ b/libaes/src/main/res/anim/normal_dialog_enter_center.xml @@ -0,0 +1,35 @@ + + + + + + + + diff --git a/libaes/src/main/res/anim/normal_dialog_enter_corner.xml b/libaes/src/main/res/anim/normal_dialog_enter_corner.xml new file mode 100644 index 0000000..edfc076 --- /dev/null +++ b/libaes/src/main/res/anim/normal_dialog_enter_corner.xml @@ -0,0 +1,15 @@ + + + + diff --git a/libaes/src/main/res/anim/normal_dialog_exit_center.xml b/libaes/src/main/res/anim/normal_dialog_exit_center.xml new file mode 100644 index 0000000..4d69f65 --- /dev/null +++ b/libaes/src/main/res/anim/normal_dialog_exit_center.xml @@ -0,0 +1,35 @@ + + + + + + + + diff --git a/libaes/src/main/res/anim/normal_dialog_exit_corner.xml b/libaes/src/main/res/anim/normal_dialog_exit_corner.xml new file mode 100644 index 0000000..4b9d1fc --- /dev/null +++ b/libaes/src/main/res/anim/normal_dialog_exit_corner.xml @@ -0,0 +1,14 @@ + + + + diff --git a/libaes/src/main/res/drawable/acard_frame_main.xml b/libaes/src/main/res/drawable/acard_frame_main.xml new file mode 100644 index 0000000..f8780ff --- /dev/null +++ b/libaes/src/main/res/drawable/acard_frame_main.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libaes/src/main/res/drawable/atoolbar_frame.xml b/libaes/src/main/res/drawable/atoolbar_frame.xml new file mode 100644 index 0000000..280f018 --- /dev/null +++ b/libaes/src/main/res/drawable/atoolbar_frame.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libaes/src/main/res/drawable/bg_shadow.xml b/libaes/src/main/res/drawable/bg_shadow.xml new file mode 100644 index 0000000..6d3d898 --- /dev/null +++ b/libaes/src/main/res/drawable/bg_shadow.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + diff --git a/libaes/src/main/res/drawable/btn_style.xml b/libaes/src/main/res/drawable/btn_style.xml new file mode 100644 index 0000000..7c6bb83 --- /dev/null +++ b/libaes/src/main/res/drawable/btn_style.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/libaes/src/main/res/drawable/default_shape.xml b/libaes/src/main/res/drawable/default_shape.xml new file mode 100644 index 0000000..8a405ca --- /dev/null +++ b/libaes/src/main/res/drawable/default_shape.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + diff --git a/libaes/src/main/res/drawable/ic_arrow_left_right_bold.xml b/libaes/src/main/res/drawable/ic_arrow_left_right_bold.xml new file mode 100644 index 0000000..8d6dc41 --- /dev/null +++ b/libaes/src/main/res/drawable/ic_arrow_left_right_bold.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/libaes/src/main/res/drawable/ic_arrow_up_circle_outline.xml b/libaes/src/main/res/drawable/ic_arrow_up_circle_outline.xml new file mode 100644 index 0000000..38c794a --- /dev/null +++ b/libaes/src/main/res/drawable/ic_arrow_up_circle_outline.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/libaes/src/main/res/drawable/ic_call.xml b/libaes/src/main/res/drawable/ic_call.xml new file mode 100644 index 0000000..c5802bb --- /dev/null +++ b/libaes/src/main/res/drawable/ic_call.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/libaes/src/main/res/drawable/ic_dev_connected.xml b/libaes/src/main/res/drawable/ic_dev_connected.xml new file mode 100644 index 0000000..1fb2f26 --- /dev/null +++ b/libaes/src/main/res/drawable/ic_dev_connected.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/libaes/src/main/res/drawable/ic_dev_disconnected.xml b/libaes/src/main/res/drawable/ic_dev_disconnected.xml new file mode 100644 index 0000000..4267975 --- /dev/null +++ b/libaes/src/main/res/drawable/ic_dev_disconnected.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/libaes/src/main/res/drawable/ic_email.xml b/libaes/src/main/res/drawable/ic_email.xml new file mode 100644 index 0000000..d526b26 --- /dev/null +++ b/libaes/src/main/res/drawable/ic_email.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/libaes/src/main/res/drawable/ic_email_alert.xml b/libaes/src/main/res/drawable/ic_email_alert.xml new file mode 100644 index 0000000..f3ed613 --- /dev/null +++ b/libaes/src/main/res/drawable/ic_email_alert.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/libaes/src/main/res/drawable/ic_launcher.xml b/libaes/src/main/res/drawable/ic_launcher.xml new file mode 100644 index 0000000..f269b7e --- /dev/null +++ b/libaes/src/main/res/drawable/ic_launcher.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/libaes/src/main/res/drawable/ic_launcher_background.xml b/libaes/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..9486190 --- /dev/null +++ b/libaes/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libaes/src/main/res/drawable/ic_launcher_foreground.xml b/libaes/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..872b04e --- /dev/null +++ b/libaes/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,10 @@ + + + + diff --git a/libaes/src/main/res/drawable/ic_winboll.xml b/libaes/src/main/res/drawable/ic_winboll.xml new file mode 100644 index 0000000..f269b7e --- /dev/null +++ b/libaes/src/main/res/drawable/ic_winboll.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/libaes/src/main/res/drawable/ic_winboll_store.png b/libaes/src/main/res/drawable/ic_winboll_store.png new file mode 100644 index 0000000..e8bb856 Binary files /dev/null and b/libaes/src/main/res/drawable/ic_winboll_store.png differ diff --git a/libaes/src/main/res/drawable/ic_winbollbeta.xml b/libaes/src/main/res/drawable/ic_winbollbeta.xml new file mode 100644 index 0000000..f4876a0 --- /dev/null +++ b/libaes/src/main/res/drawable/ic_winbollbeta.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/libaes/src/main/res/drawable/ohpcts_frame.xml b/libaes/src/main/res/drawable/ohpcts_frame.xml new file mode 100644 index 0000000..caf8c6d --- /dev/null +++ b/libaes/src/main/res/drawable/ohpcts_frame.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libaes/src/main/res/drawable/pressed_shape.xml b/libaes/src/main/res/drawable/pressed_shape.xml new file mode 100644 index 0000000..ed448af --- /dev/null +++ b/libaes/src/main/res/drawable/pressed_shape.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + diff --git a/libaes/src/main/res/drawable/shape_gradient.xml b/libaes/src/main/res/drawable/shape_gradient.xml new file mode 100644 index 0000000..c164fe9 --- /dev/null +++ b/libaes/src/main/res/drawable/shape_gradient.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/libaes/src/main/res/drawable/toast_frame.xml b/libaes/src/main/res/drawable/toast_frame.xml new file mode 100644 index 0000000..c4b8f8a --- /dev/null +++ b/libaes/src/main/res/drawable/toast_frame.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/libaes/src/main/res/drawable/view_border.xml b/libaes/src/main/res/drawable/view_border.xml new file mode 100644 index 0000000..58b374a --- /dev/null +++ b/libaes/src/main/res/drawable/view_border.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/libaes/src/main/res/drawable/winboll_help.xml b/libaes/src/main/res/drawable/winboll_help.xml new file mode 100644 index 0000000..564175f --- /dev/null +++ b/libaes/src/main/res/drawable/winboll_help.xml @@ -0,0 +1,27 @@ + + + + + diff --git a/libaes/src/main/res/drawable/winboll_logo.xml b/libaes/src/main/res/drawable/winboll_logo.xml new file mode 100644 index 0000000..ea28987 --- /dev/null +++ b/libaes/src/main/res/drawable/winboll_logo.xml @@ -0,0 +1,48 @@ + + + + + + + + diff --git a/libaes/src/main/res/drawable/winboll_point.xml b/libaes/src/main/res/drawable/winboll_point.xml new file mode 100644 index 0000000..48028cc --- /dev/null +++ b/libaes/src/main/res/drawable/winboll_point.xml @@ -0,0 +1,20 @@ + + + + diff --git a/libaes/src/main/res/layout/activity_about.xml b/libaes/src/main/res/layout/activity_about.xml new file mode 100644 index 0000000..7d2a2ca --- /dev/null +++ b/libaes/src/main/res/layout/activity_about.xml @@ -0,0 +1,21 @@ + + + + + + + + diff --git a/libaes/src/main/res/layout/activity_drawer.xml b/libaes/src/main/res/layout/activity_drawer.xml new file mode 100644 index 0000000..cd1723d --- /dev/null +++ b/libaes/src/main/res/layout/activity_drawer.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/libaes/src/main/res/layout/activity_drawerfragment.xml b/libaes/src/main/res/layout/activity_drawerfragment.xml new file mode 100644 index 0000000..22ce6ef --- /dev/null +++ b/libaes/src/main/res/layout/activity_drawerfragment.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libaes/src/main/res/layout/activity_secondarylibrary.xml b/libaes/src/main/res/layout/activity_secondarylibrary.xml new file mode 100644 index 0000000..bf0f2d8 --- /dev/null +++ b/libaes/src/main/res/layout/activity_secondarylibrary.xml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/libaes/src/main/res/layout/activity_test_aboutfragment.xml b/libaes/src/main/res/layout/activity_test_aboutfragment.xml new file mode 100644 index 0000000..6476c15 --- /dev/null +++ b/libaes/src/main/res/layout/activity_test_aboutfragment.xml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/libaes/src/main/res/layout/activity_testasupporttoolbar.xml b/libaes/src/main/res/layout/activity_testasupporttoolbar.xml new file mode 100644 index 0000000..a92a8ca --- /dev/null +++ b/libaes/src/main/res/layout/activity_testasupporttoolbar.xml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/libaes/src/main/res/layout/activity_testatoolbar.xml b/libaes/src/main/res/layout/activity_testatoolbar.xml new file mode 100644 index 0000000..a30473e --- /dev/null +++ b/libaes/src/main/res/layout/activity_testatoolbar.xml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/libaes/src/main/res/layout/dialog_privacy_agreement.xml b/libaes/src/main/res/layout/dialog_privacy_agreement.xml new file mode 100644 index 0000000..ebe6fe2 --- /dev/null +++ b/libaes/src/main/res/layout/dialog_privacy_agreement.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + +