Compare commits
	
		
			28 Commits
		
	
	
		
			jc
			...
			autoinstal
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 5e39963eea | |||
|   | 71c7af6a9e | ||
| e9bb789daa | |||
| dbff19e7f4 | |||
|   | 44679d0c8a | ||
| 6656161903 | |||
|   | edc63c750b | ||
| b170085482 | |||
| 6e8ba3394d | |||
| b91fe3c16b | |||
| e30b7acfdb | |||
| 6221555dfe | |||
|   | c60eb29f4f | ||
|   | 3efcf40025 | ||
|   | 27e948b86d | ||
|   | ae4742f3e2 | ||
|   | d3312cbb29 | ||
|   | 58f3778dff | ||
|   | f5e2961445 | ||
|   | e4e9c31f02 | ||
|   | a02a7efe43 | ||
|   | 2220efd009 | ||
|   | 0bc0fdf8c2 | ||
|   | 6b7b07a6fd | ||
|   | 8f3417818d | ||
|   | ca280c7334 | ||
|   | 8172cf7b6f | ||
|   | 8014f4149c | 
							
								
								
									
										16
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -87,19 +87,15 @@ lint/tmp/ | ||||
| # Android Profiling | ||||
| *.hprof | ||||
|  | ||||
| # Custom | ||||
| .androidide | ||||
| # 忽略 Lint 输出文件 | ||||
| lint-results.xml | ||||
| lint-results.html | ||||
| winboll.properties | ||||
| local.properties | ||||
|  | ||||
| ## 忽略 AndroidIDE 临时文件夹 | ||||
| .androidide | ||||
|  | ||||
| ## 忽略模块应用编译配置 | ||||
| /settings.gradle | ||||
| /gradle.properties | ||||
|  | ||||
| ## 忽略 srv 纠结问题 | ||||
| /srv/ | ||||
|  | ||||
| ## 忽略 winboll-x 文件夹 | ||||
| /winboll-x/ | ||||
| /winboll.properties | ||||
| /local.properties | ||||
|   | ||||
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,3 @@ | ||||
| [submodule "libjc/jcc/libs"] | ||||
| 	path = libjc/jcc/libs | ||||
| 	url = https://gitea.winboll.cc/Studio/APP_libjc_jcc_libs.git | ||||
| [submodule "keystore"] | ||||
| 	path = keystore | ||||
| 	url = https://gitea.winboll.cc/Studio/keystore.git | ||||
|   | ||||
| @@ -2,6 +2,11 @@ | ||||
| // | ||||
|  | ||||
| android { | ||||
| 	def winbollProps = new Properties() | ||||
|     def winbollPropsFile = rootProject.file("${winbollFilePath}") | ||||
|     assert(winbollPropsFile.exists()) | ||||
|     winbollProps.load(new FileInputStream(winbollPropsFile)) | ||||
|      | ||||
|     // 读取秘钥配置文件 | ||||
|     // | ||||
|     def keyProps = new Properties() | ||||
| @@ -122,6 +127,7 @@ android { | ||||
|                                     FileOutputStream fos = new FileOutputStream(winbollBuildPropsFile) | ||||
|                                     winbollBuildProps.store(fos, "${winbollBuildPropsDesc}"); | ||||
|                                     fos.close(); | ||||
| 									println "\n\n>>> Project build.properties saved.\n\n"; | ||||
|                                      | ||||
|                                     if(winbollBuildProps['libraryProject'] != "") { | ||||
|                                         // 如果应用 build.properties 文件设置了类库模块项目文件名 | ||||
| @@ -133,14 +139,15 @@ android { | ||||
|                                         java.nio.file.Path targetFilePath = libraryProjectBuildPropsFile.toPath(); | ||||
|                                         // 使用copyTo()方法复制文件,如果目标文件存在会被覆盖,可选参数可以选择不覆盖 | ||||
| 	                                    java.nio.file.Files.copy(sourceFilePath, targetFilePath, java.nio.file.StandardCopyOption.REPLACE_EXISTING); | ||||
| 										 | ||||
| 										println "\n\n>>> Library Project build.properties saved.\n\n"; | ||||
|                                     } | ||||
|                                 } | ||||
|                             } | ||||
|                              | ||||
|                             // 如果正在发布,就拷贝到 WinBoLL 标签管理文件夹 | ||||
|                             // 如果正在发布,就拷贝到 WinBoLL 标签管理文件夹,和处理 Git 仓库管理任务。 | ||||
|                             // | ||||
|                             if((variant.flavorName == "stage"&&variant.buildType.name == "debug") | ||||
|                                 || (variant.flavorName == "stage"&&variant.buildType.name == "release")){ | ||||
|                             if(variant.flavorName == "stage"&&variant.buildType.name == "release"){ | ||||
|                                 // 发布 APK 文件 | ||||
|                                 // | ||||
|                                 // 截取版本号的版本字段为短版本名 | ||||
| @@ -221,6 +228,7 @@ android { | ||||
|                                     } | ||||
|                                      | ||||
|                                     // 提交新的编译标志配置 | ||||
| 									println 'exec bashCommitAppPublishBuildFlagInfoFilePath ...' | ||||
|                                     def resultCommitBuildFlag = exec { | ||||
|                                         commandLine 'bash', '--', "${RootProjectDir}/${bashCommitAppPublishBuildFlagInfoFilePath}", "${RootProjectDir}", "${versionName}", variant.buildType.name , rootProject.name | ||||
|                                     } | ||||
| @@ -228,22 +236,78 @@ android { | ||||
|                                     assert(resultCommitBuildFlag.getExitValue() == 0) | ||||
|                                 } | ||||
|                             } //  if(variant.buildType.name == "release"){ | ||||
|                              | ||||
|                             // 如果公共目录存在就拷贝到公共目录并重命名为app.apk | ||||
|                             // | ||||
|                             File outCommonDir = new File("/sdcard/AppProjects") | ||||
|                             String commandAPKName = "app.apk" | ||||
|                             if(outCommonDir.exists()) { | ||||
|                                 copy{ | ||||
|                                     from file.outputFile | ||||
|                                     into outCommonDir | ||||
|                                     rename { | ||||
|                                         String fileName -> "${commandAPKName}" | ||||
| 							 | ||||
| 							// 如果正在调试发布版,就只生成和输出APK文件,不处理 Git 仓库提交与更新问题。 | ||||
| 							// | ||||
| 					        if(variant.flavorName == "stage"&&variant.buildType.name == "debug"){ | ||||
|                                 // 发布 APK 文件 | ||||
|                                 // | ||||
|                                 // 截取版本号的版本字段为短版本名 | ||||
|                                 String szVersionName = "${versionName}" | ||||
|                                 String[] szlistTemp = szVersionName.split("-") | ||||
|                                 String szShortVersionName = szlistTemp[0] | ||||
|                                 //String szCommonTagAPKName = "${rootProject.name}_" + szShortVersionName + ".apk" | ||||
|                                 String szCommonTagAPKName = project.rootDir.name + "_" + szShortVersionName + ".apk" | ||||
|                                 println "CommonTagAPKName is : " + szCommonTagAPKName | ||||
|                                  | ||||
|                                 //File outTagDir = new File(fWinBoLLStudioDir, "/${rootProject.name}/tag/") | ||||
|                                 File outTagDir = new File(fWinBoLLStudioDir, "/" + project.rootDir.name + "/${variant.buildType.name}/") | ||||
|                                 // 创建目标路径目录 | ||||
|                                 if(!outTagDir.exists()) { | ||||
|                                     outTagDir.mkdirs(); | ||||
|                                     println "Output Folder Created.(Tags) : " + outTagDir.getAbsolutePath() | ||||
|                                 } | ||||
|                                  | ||||
|                                 if(outTagDir.exists()) { | ||||
|                                     File targetAPK = new File(outTagDir, "${szCommonTagAPKName}") | ||||
|                                     if(targetAPK.exists()) { | ||||
|                                         // 标签版本APK文件已经存在,构建拷贝任务停止 | ||||
| 										println '如果是在调试 Stage 版应用包构建,请删除(注:在debug目录)现有的 Stage 应用包('+targetAPK.getAbsolutePath()+')。再编译一次。' | ||||
|                                         assert (!targetAPK.exists()) | ||||
|                                         // 可选择删除并继续输出APK文件 | ||||
|                                         //delete targetAPK | ||||
|                                     } | ||||
|                                     println "Output APK (Common): " + outCommonDir.getAbsolutePath() + "/${commandAPKName}" | ||||
|                                     // 复制一个备份 | ||||
|                                     copy{ | ||||
|                                         from file.outputFile | ||||
|                                         into outTagDir | ||||
|                                         rename { | ||||
|                                             String fileName -> "${outputFileName}" | ||||
|                                         } | ||||
|                                         println "Output APK (Tags): "+ outTagDir.getAbsolutePath() + "/${outputFileName}" | ||||
|                                     } | ||||
|                                     // 复制一个并重命名为短版本名 | ||||
|                                     copy{ | ||||
|                                         from file.outputFile | ||||
|                                         into outTagDir | ||||
|                                         rename { | ||||
|                                             String fileName -> "${szCommonTagAPKName}" | ||||
|                                         } | ||||
|                                         println "Output APK (Tags): "+ outTagDir.getAbsolutePath() + "/${szCommonTagAPKName}" | ||||
|                                     } | ||||
|                                      | ||||
|                                     //不保存编译标志配置 | ||||
|                                 } | ||||
|                             } | ||||
|                              | ||||
|                             // 如果配置了APK额外输出路径,就复制一份拷贝到额外路径。 | ||||
|                             // | ||||
| 							if(winbollProps['ExtraAPKOutputPath'] != null ) { | ||||
|                                 File apkFile = new File(winbollProps['ExtraAPKOutputPath']) | ||||
| 								File outCommonDir = apkFile.getParentFile(); | ||||
|                                 String commandAPKName = apkFile.getName(); | ||||
|                                 if(outCommonDir.exists()) { | ||||
|                                     copy{ | ||||
|                                         from file.outputFile | ||||
|                                         into outCommonDir | ||||
|                                         rename { | ||||
|                                             String fileName -> "${commandAPKName}" | ||||
|                                         } | ||||
|                                         println "Output APK (Common): " + outCommonDir.getAbsolutePath() + "/${commandAPKName}" | ||||
|                                     } | ||||
|                                 } | ||||
| 						    } | ||||
|                              | ||||
|                          | ||||
|                     } | ||||
| 	            }// End of (variant.getAssembleProvider().get().doLast {) | ||||
|   | ||||
							
								
								
									
										20
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								README.md
									
									
									
									
									
								
							| @@ -119,7 +119,7 @@ | ||||
| ## ★. 项目 Android SDK 编译环境设置(可选),local.properties-demo 要复制为 local.properties,并按需要设置 Android SDK 目录。 | ||||
| ## ★. 应用签名密钥 keystore 设置问题。一般调试编译只需用【Termux】cd 进 GenKeyStore 目录执行 $ bash gen_debug_keystore.sh 命令即可完成设置。 | ||||
| ## ☆. 应用 WiBoLL 签名密钥配置问题<非必须考虑>。设置时需要 clone 【keystore】模块源码并拷贝模块目录的 appkey.jks 与 appkey.keystore 到项目根目录即可。 | ||||
| ## ☆. 类库型模块编译环境设置(可选),winboll.properties-demo 要复制为 winboll.properties,并按需要设置 WinBoLL Maven 库登录用户信息。 | ||||
| ## ☆. 类库型模块编译环境设置(可选),winboll.properties-demo 要复制为 winboll.properties,并按需要设置 WinBoLL Maven 库登录用户信息, 和 APK 文件额外输出路径。 | ||||
|  | ||||
|  | ||||
| # ☆类库型项目编译方法 | ||||
| @@ -128,7 +128,8 @@ | ||||
| 设置属性 libraryProject=<类库项目模块文件夹名称> | ||||
| ### 再编译测试项目 | ||||
| $ bash .winboll/bashPublishAPKAddTag.sh <应用项目模块文件夹名称> | ||||
| #### 测试项目编译后,编译器会复制一份 APK 到以下路径:"/sdcard/WinBoLLStudio/APKs/<项目根目录名称>/tag/" 文件夹。 | ||||
| #### 测试项目编译后,编译器会复制一份 APK 到 路径:"/sdcard/WinBoLLStudio/APKs/<项目根目录名称>/tag/" 文件夹。 | ||||
| #### 若是 winboll.properties 文件的 [ExtraAPKOutputPath] 属性设置了路径。编译器也会复制一份 APK 到这个路径。 | ||||
| ### 最后编译类库项目 | ||||
| $ bash .winboll/bashPublishLIBAddTag.sh <类库项目模块文件夹名称> | ||||
| #### 类库模块编译命令执行后,编译器会发布到 WinBoLL Nexus Maven 库:Maven 库地址可以参阅根项目目录配置 build.gradle 文件。 | ||||
| @@ -136,4 +137,17 @@ $ bash .winboll/bashPublishLIBAddTag.sh <类库项目模块文件夹名称> | ||||
| # ☆应用型项目编译方法 | ||||
| ## 直接调用以下命令编译应用型项目 | ||||
| $ bash .winboll/bashPublishAPKAddTag.sh <应用项目模块文件夹名称> | ||||
| #### 应用模块编译命令执行后,编译器会复制一份 APK 到以下路径:"/sdcard/WinBoLLStudio/APKs/<项目根目录名称>/tag/" 文件夹。 | ||||
| #### 应用模块编译命令执行后,编译器会复制一份 APK 到 | ||||
| #### 测试项目编译后,编译器会复制一份 APK 到 路径:"/sdcard/WinBoLLStudio/APKs/<项目根目录名称>/tag/" 文件夹。 | ||||
| #### 若是 winboll.properties 文件的 [ExtraAPKOutputPath] 属性设置了路径。编译器也会复制一份 APK 到这个路径。 | ||||
|  | ||||
| ## ☆应用调试编译方法 | ||||
| 使用以下命令编译调试: | ||||
|  | ||||
| ### Beta调试使用: | ||||
| $ bash gradlew assembleBetaDebug | ||||
|  | ||||
| ### Stage调试使用: | ||||
| $ bash gradlew assembleStageDebug | ||||
|  | ||||
| ### 若是 winboll.properties 文件的 [ExtraAPKOutputPath] 属性设置了路径。编译器也会复制一份 APK 到这个路径。 | ||||
|   | ||||
| @@ -30,7 +30,7 @@ android { | ||||
|         // versionName 更新后需要手动设置  | ||||
|         // .winboll/winbollBuildProps.properties 文件的 stageCount=0 | ||||
|         // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" | ||||
|         versionName "15.9" | ||||
|         versionName "15.10" | ||||
|         if(true) { | ||||
|             versionName = genVersionName("${versionName}") | ||||
|         } | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Sun Aug 31 23:37:38 HKT 2025 | ||||
| stageCount=6 | ||||
| #Sat Sep 27 21:03:20 HKT 2025 | ||||
| stageCount=10 | ||||
| libraryProject=libappbase | ||||
| baseVersion=15.9 | ||||
| publishVersion=15.9.5 | ||||
| baseVersion=15.10 | ||||
| publishVersion=15.10.9 | ||||
| buildCount=0 | ||||
| baseBetaVersion=15.9.6 | ||||
| baseBetaVersion=15.10.10 | ||||
|   | ||||
| @@ -2,7 +2,10 @@ | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" > | ||||
|  | ||||
|     <application> | ||||
|     <application | ||||
| 		tools:replace="android:icon,android:roundIcon" | ||||
|         android:icon="@drawable/ic_winboll_beta" | ||||
|         android:roundIcon="@drawable/ic_winboll_beta"> | ||||
|  | ||||
|         <!-- Put flavor specific code here --> | ||||
|  | ||||
|   | ||||
| @@ -2,17 +2,19 @@ | ||||
| <manifest | ||||
|     xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     package="cc.winboll.studio.appbase"> | ||||
|  | ||||
| 	 | ||||
| 	<!-- 网络权限 --> | ||||
| 	<uses-permission android:name="android.permission.INTERNET" /> | ||||
| 		 | ||||
|     <application | ||||
|         android:name=".App" | ||||
|         android:icon="@drawable/ic_miapp" | ||||
|         android:icon="@drawable/ic_winboll" | ||||
|         android:label="@string/app_name" | ||||
|         android:theme="@style/MyAPPBaseTheme" | ||||
|         android:resizeableActivity="true" | ||||
|         android:process=":App" | ||||
|         android:networkSecurityConfig="@xml/network_security_config"> | ||||
|         android:process=":App"> | ||||
|  | ||||
|         <activity | ||||
| 		<activity | ||||
|             android:name=".MainActivity" | ||||
|             android:label="@string/app_name" | ||||
|             android:exported="true" | ||||
| @@ -25,103 +27,14 @@ | ||||
|  | ||||
|                 <category android:name="android.intent.category.LAUNCHER"/> | ||||
|  | ||||
|                 <action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES"/> | ||||
|  | ||||
|                 <category android:name="android.intent.category.DEFAULT"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </activity> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".activities.NewActivity" | ||||
|             android:label="NewActivity" | ||||
|             android:exported="true" | ||||
|             android:resizeableActivity="true" | ||||
|             android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"/> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".activities.New2Activity" | ||||
|             android:label="New2Activity" | ||||
|             android:exported="true" | ||||
|             android:resizeableActivity="true" | ||||
|             android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"/> | ||||
|  | ||||
|         <service | ||||
|             android:name=".MyTileService" | ||||
|             android:exported="true" | ||||
|             android:label="@string/tileservice_name" | ||||
|             android:icon="@drawable/ic_launcher" | ||||
|             android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="android.service.quicksettings.action.QS_TILE"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </service> | ||||
|  | ||||
|         <service | ||||
|             android:name=".services.MainService" | ||||
|             android:exported="true"/> | ||||
|  | ||||
|         <service | ||||
|             android:name="cc.winboll.studio.appbase.services.TestDemoBindService" | ||||
|             android:exported="true"/> | ||||
|  | ||||
|         <service | ||||
|             android:name="cc.winboll.studio.appbase.services.TestDemoService" | ||||
|             android:exported="true"/> | ||||
|  | ||||
|         <service android:name=".services.AssistantService"/> | ||||
|  | ||||
|         <receiver | ||||
|             android:name="cc.winboll.studio.appbase.receivers.MainReceiver" | ||||
|             android:exported="true"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="cc.winboll.studio.appbase.receivers.MainReceiver"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </receiver> | ||||
|  | ||||
|         <receiver | ||||
|             android:name=".widgets.APPNewsWidget" | ||||
|             android:exported="true"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="cc.winboll.studio.appbase.widgets.APPNewsWidget.ACTION_WAKEUP_SERVICE"/> | ||||
|  | ||||
|                 <action android:name="cc.winboll.studio.appbase.widgets.APPNewsWidget.ACTION_RELOAD_REPORT"/> | ||||
|  | ||||
|                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|             <meta-data | ||||
|                 android:name="android.appwidget.provider" | ||||
|                 android:resource="@xml/widget_provider_info_sos"/> | ||||
|  | ||||
|         </receiver> | ||||
|  | ||||
|         <receiver | ||||
|             android:name=".receivers.APPNewsWidgetClickListener" | ||||
|             android:exported="true"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="cc.winboll.studio.appbase.receivers.APPNewsWidgetClickListener.ACTION_PRE"/> | ||||
|  | ||||
|                 <action android:name="cc.winboll.studio.appbase.receivers.APPNewsWidgetClickListener.ACTION_NEXT"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </receiver> | ||||
|  | ||||
| 		 | ||||
|         <activity android:name=".GlobalApplication$CrashActivity"/> | ||||
| 		 | ||||
|         <meta-data | ||||
|             android:name="android.max_aspect" | ||||
|             android:value="4.0"/> | ||||
|   | ||||
| @@ -5,23 +5,15 @@ package cc.winboll.studio.appbase; | ||||
|  * @Date 2025/01/05 09:54:42 | ||||
|  * @Describe APPbase 应用类 | ||||
|  */ | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import android.content.IntentFilter; | ||||
| import cc.winboll.studio.libappbase.sos.SOSCenterServiceReceiver; | ||||
| import cc.winboll.studio.libappbase.sos.SOS; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
|  | ||||
| public class App extends GlobalApplication { | ||||
|  | ||||
|     public static final String TAG = "App"; | ||||
|      | ||||
|     SOSCenterServiceReceiver mSOSCenterServiceReceiver; | ||||
|      | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         mSOSCenterServiceReceiver = new SOSCenterServiceReceiver(); | ||||
|         IntentFilter intentFilter = new IntentFilter(); | ||||
|         intentFilter.addAction(SOS.ACTION_SOS); | ||||
|         registerReceiver(mSOSCenterServiceReceiver, intentFilter); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,44 +1,23 @@ | ||||
| package cc.winboll.studio.appbase; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.widget.CheckBox; | ||||
| import android.widget.Toast; | ||||
| import android.widget.Toolbar; | ||||
| import cc.winboll.studio.appbase.R; | ||||
| import cc.winboll.studio.appbase.activities.NewActivity; | ||||
| import cc.winboll.studio.appbase.activities.WinBoLLActivity; | ||||
| import cc.winboll.studio.appbase.services.MainService; | ||||
| import cc.winboll.studio.appbase.services.TestDemoBindService; | ||||
| import cc.winboll.studio.appbase.services.TestDemoService; | ||||
| import cc.winboll.studio.libappbase.CrashHandler; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import cc.winboll.studio.libappbase.GlobalCrashActivity; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.LogView; | ||||
| import cc.winboll.studio.libappbase.sos.SOS; | ||||
| import cc.winboll.studio.libappbase.utils.ToastUtils; | ||||
| import cc.winboll.studio.libappbase.widgets.StatusWidget; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; | ||||
| import cc.winboll.studio.libappbase.LogActivity; | ||||
| import cc.winboll.studio.libappbase.ToastUtils; | ||||
|  | ||||
| public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity { | ||||
| public class MainActivity extends Activity { | ||||
|  | ||||
|     public static final String TAG = "MainActivity"; | ||||
|  | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
|  | ||||
|     Toolbar mToolbar; | ||||
|  | ||||
|     @Override | ||||
| @@ -49,9 +28,6 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity { | ||||
|  | ||||
|         mToolbar = findViewById(R.id.toolbar); | ||||
|         setActionBar(mToolbar); | ||||
|  | ||||
|         CheckBox cbIsDebugMode = findViewById(R.id.activitymainCheckBox1); | ||||
|         cbIsDebugMode.setChecked(GlobalApplication.isDebuging()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
| @@ -62,122 +38,37 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity { | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         if(item.getItemId() == R.id.item_yun) { | ||||
|             GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(this, cc.winboll.studio.libappbase.activities.YunActivity.class); | ||||
|         } else if(item.getItemId() == R.id.item_logon) { | ||||
|             GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(this, cc.winboll.studio.libappbase.activities.LogonActivity.class); | ||||
|         } | ||||
| 		switch (item.getItemId()) { | ||||
| 			case R.id.item_home : { | ||||
| 					openWebsiteInBrowser(this); | ||||
| 				} | ||||
| 		} | ||||
|         // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。 | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         Intent intentAPPWidget = new Intent(this, StatusWidget.class); | ||||
|         intentAPPWidget.setAction(StatusWidget.ACTION_STATUS_UPDATE); | ||||
|         sendBroadcast(intentAPPWidget); | ||||
|     public void onCrashTest(View view) { | ||||
| 		for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) { | ||||
| 			getString(i); | ||||
| 		} | ||||
|     } | ||||
|  | ||||
| 	public void onSwitchDebugMode(View view) { | ||||
|         boolean isDebuging = ((CheckBox)view).isChecked(); | ||||
|         GlobalApplication.setIsDebuging(isDebuging); | ||||
|         GlobalApplication.saveDebugStatus(); | ||||
|     public void onLogTest(View view) { | ||||
|         LogActivity.startLogActivity(this); | ||||
|     } | ||||
|  | ||||
|     public void onPreviewGlobalCrashActivity(View view) { | ||||
|         Intent intent = new Intent(this, GlobalCrashActivity.class); | ||||
|         intent.putExtra(CrashHandler.EXTRA_CRASH_INFO, "Demo log..."); | ||||
|         startActivity(intent); | ||||
|     } | ||||
|  | ||||
|     public void onStartCenter(View view) { | ||||
|         MainService.startMainService(this); | ||||
|     } | ||||
|  | ||||
|     public void onStopCenter(View view) { | ||||
|         MainService.stopMainService(this); | ||||
|     } | ||||
|  | ||||
|     public void onTestStopMainServiceWithoutSettingEnable(View view) { | ||||
|         LogUtils.d(TAG, "onTestStopMainServiceWithoutSettingEnable"); | ||||
|         stopService(new Intent(this, MainService.class)); | ||||
|     } | ||||
|  | ||||
|     public void onTestUseComponentStartService(View view) { | ||||
|         LogUtils.d(TAG, "onTestUseComponentStartService"); | ||||
|  | ||||
|         // 目标服务的包名和类名 | ||||
|         String packageName = this.getPackageName(); | ||||
|         String serviceClassName = TestDemoService.class.getName(); | ||||
|  | ||||
|         // 构建Intent | ||||
|         Intent intentService = new Intent(); | ||||
|         intentService.setComponent(new ComponentName(packageName, serviceClassName)); | ||||
|  | ||||
|         startService(intentService); | ||||
|     } | ||||
|  | ||||
|     public void onTestDemoServiceSOS(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoService.class); | ||||
|         stopService(intent); | ||||
|         if (App.isDebuging()) { | ||||
|             SOS.sosToAppBaseBeta(this, TestDemoService.class.getName()); | ||||
|         } else { | ||||
|             SOS.sosToAppBase(this, TestDemoService.class.getName()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void onSartTestDemoService(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoService.class); | ||||
|         intent.setAction(TestDemoService.ACTION_ENABLE); | ||||
|         startService(intent); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public void onStopTestDemoService(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoService.class); | ||||
|         intent.setAction(TestDemoService.ACTION_DISABLE); | ||||
|         startService(intent); | ||||
|  | ||||
|         Intent intentStop = new Intent(this, TestDemoService.class); | ||||
|         stopService(intentStop); | ||||
|     } | ||||
|  | ||||
|     public void onStopTestDemoServiceNoSettings(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoService.class); | ||||
|         stopService(intent); | ||||
|     } | ||||
|  | ||||
|     public void onSartTestDemoBindService(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoBindService.class); | ||||
|         intent.setAction(TestDemoBindService.ACTION_ENABLE); | ||||
|         startService(intent); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public void onStopTestDemoBindService(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoBindService.class); | ||||
|         intent.setAction(TestDemoBindService.ACTION_DISABLE); | ||||
|         startService(intent); | ||||
|  | ||||
|         Intent intentStop = new Intent(this, TestDemoBindService.class); | ||||
|         stopService(intentStop); | ||||
|     } | ||||
|  | ||||
|     public void onStopTestDemoBindServiceNoSettings(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoBindService.class); | ||||
|         stopService(intent); | ||||
|     } | ||||
|  | ||||
|     public void onTestOpenNewActivity(View view) { | ||||
|         GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(this, NewActivity.class); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onResume() { | ||||
|         super.onResume(); | ||||
|     } | ||||
|  | ||||
|  | ||||
| 	/** | ||||
| 	 * 唤起默认浏览器打开指定网站 | ||||
| 	 * @param context 上下文(如 Activity.this) | ||||
| 	 */ | ||||
| 	public void openWebsiteInBrowser(Context context) { | ||||
| 		// 目标网站地址 | ||||
| 		String url = "https://www.winboll.cc"; | ||||
| 		// 构建打开浏览器的意图 | ||||
| 		Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); | ||||
| 		// 设置标志:避免创建新的任务栈(可选,按需求调整) | ||||
| 		intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
| 		context.startActivity(intent); | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -1,79 +0,0 @@ | ||||
| package cc.winboll.studio.appbase; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/13 19:30:10 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.service.quicksettings.Tile; | ||||
| import android.service.quicksettings.TileService; | ||||
| import cc.winboll.studio.appbase.models.MainServiceBean; | ||||
| import cc.winboll.studio.appbase.services.MainService; | ||||
|  | ||||
| public class MyTileService extends TileService { | ||||
|     public static final String TAG = "MyTileService"; | ||||
|  | ||||
|     volatile static MyTileService _MyTileService; | ||||
|  | ||||
|     @Override | ||||
|     public void onStartListening() { | ||||
|         super.onStartListening(); | ||||
|         _MyTileService = this; | ||||
|         Tile tile = getQsTile(); | ||||
|         MainServiceBean bean = MainServiceBean.loadBean(this, MainServiceBean.class); | ||||
|         if (bean != null && bean.isEnable()) { | ||||
|             //MainService.startMainService(context); | ||||
|             tile.setState(Tile.STATE_ACTIVE); | ||||
|             tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud)); | ||||
|         } else { | ||||
|             //MainService.stopMainService(context); | ||||
|             tile.setState(Tile.STATE_INACTIVE); | ||||
|             tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud_outline)); | ||||
|         } | ||||
|         tile.updateTile(); | ||||
| //        Tile tile = getQsTile(); | ||||
| //        tile.setState(Tile.STATE_INACTIVE); | ||||
| //        tile.setLabel(getString(R.string.tileservice_name)); | ||||
| //        tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud_outline)); | ||||
| //        tile.updateTile(); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onClick() { | ||||
|         super.onClick(); | ||||
|         Tile tile = getQsTile(); | ||||
|         MainServiceBean bean = MainServiceBean.loadBean(this, MainServiceBean.class); | ||||
|         if (bean == null) { | ||||
|             bean = new MainServiceBean(); | ||||
|         } | ||||
|  | ||||
|         if (tile.getState() == Tile.STATE_ACTIVE) { | ||||
|             bean.setIsEnable(false); | ||||
|             MainServiceBean.saveBean(this, bean); | ||||
|             MainService.stopMainService(this); | ||||
|         } else if (tile.getState() == Tile.STATE_INACTIVE) { | ||||
|             bean.setIsEnable(true); | ||||
|             MainServiceBean.saveBean(this, bean); | ||||
|             MainService.startMainService(this); | ||||
|         } | ||||
|         updateServiceIconStatus(this); | ||||
|     } | ||||
|  | ||||
|     public static void updateServiceIconStatus(Context context) { | ||||
|         if (_MyTileService == null) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         Tile tile = _MyTileService.getQsTile(); | ||||
|         MainServiceBean bean = MainServiceBean.loadBean(context, MainServiceBean.class); | ||||
|         if (bean != null && bean.isEnable()) { | ||||
|             tile.setState(Tile.STATE_ACTIVE); | ||||
|             tile.setIcon(android.graphics.drawable.Icon.createWithResource(context, R.drawable.ic_cloud)); | ||||
|         } else { | ||||
|             tile.setState(Tile.STATE_INACTIVE); | ||||
|             tile.setIcon(android.graphics.drawable.Icon.createWithResource(context, R.drawable.ic_cloud_outline)); | ||||
|         } | ||||
|         tile.updateTile(); | ||||
|     } | ||||
| } | ||||
| @@ -1,77 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.activities; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/03/25 11:46:40 | ||||
|  * @Describe 测试窗口2 | ||||
|  */ | ||||
| import android.app.Activity; | ||||
| import android.os.Bundle; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.widget.Toolbar; | ||||
| import cc.winboll.studio.appbase.R; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; | ||||
|  | ||||
| public class New2Activity extends WinBoLLActivity implements IWinBoLLActivity { | ||||
|  | ||||
|     public static final String TAG = "New2Activity"; | ||||
|  | ||||
|     Toolbar mToolbar; | ||||
|     //LogView mLogView; | ||||
|  | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_new2); | ||||
|  | ||||
| //        mLogView = findViewById(R.id.logview); | ||||
| //        mLogView.start(); | ||||
|         mToolbar = findViewById(R.id.toolbar); | ||||
|         setActionBar(mToolbar); | ||||
|          | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onResume() { | ||||
|         super.onResume(); | ||||
|         //mLogView.start(); | ||||
|     } | ||||
|  | ||||
|     public void onCloseThisActivity(View view) { | ||||
|         GlobalApplication.getWinBoLLActivityManager().finish(this); | ||||
|     } | ||||
|  | ||||
|     public void onCloseAllActivity(View view) { | ||||
|         GlobalApplication.getWinBoLLActivityManager().finishAll(); | ||||
|     } | ||||
|  | ||||
|     public void onNewActivity(View view) { | ||||
|         GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(this, NewActivity.class); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         getMenuInflater().inflate(R.menu.toolbar_main, menu); | ||||
|         return super.onCreateOptionsMenu(menu); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。 | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
| } | ||||
| @@ -1,75 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.activities; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/03/25 05:04:22 | ||||
|  */ | ||||
| import android.app.Activity; | ||||
| import android.os.Bundle; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.widget.Toolbar; | ||||
| import cc.winboll.studio.appbase.R; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; | ||||
|  | ||||
| public class NewActivity extends WinBoLLActivity implements IWinBoLLActivity { | ||||
|  | ||||
|     public static final String TAG = "NewActivity"; | ||||
|  | ||||
|     Toolbar mToolbar; | ||||
|     //LogView mLogView; | ||||
|  | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_new); | ||||
| //        mLogView = findViewById(R.id.logview); | ||||
| //        mLogView.start(); | ||||
|         mToolbar = findViewById(R.id.toolbar); | ||||
|         setActionBar(mToolbar); | ||||
|          | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onResume() { | ||||
|         super.onResume(); | ||||
|         //mLogView.start(); | ||||
|     } | ||||
|  | ||||
|     public void onCloseThisActivity(View view) { | ||||
|         GlobalApplication.getWinBoLLActivityManager().finish(this); | ||||
|     } | ||||
|  | ||||
|     public void onCloseAllActivity(View view) { | ||||
|         GlobalApplication.getWinBoLLActivityManager().finishAll(); | ||||
|     } | ||||
|  | ||||
|     public void onNew2Activity(View view) { | ||||
|         GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(this, New2Activity.class); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         getMenuInflater().inflate(R.menu.toolbar_main, menu); | ||||
|         return super.onCreateOptionsMenu(menu); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。 | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
| } | ||||
| @@ -1,61 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.activities; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/05/10 09:48 | ||||
|  * @Describe WinBoLL 窗口基础类 | ||||
|  */ | ||||
| import android.app.Activity; | ||||
| import android.os.Bundle; | ||||
| import android.view.MenuItem; | ||||
| import cc.winboll.studio.appbase.MainActivity; | ||||
| import cc.winboll.studio.appbase.R; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; | ||||
|  | ||||
| public class WinBoLLActivity extends Activity implements IWinBoLLActivity { | ||||
|  | ||||
|     public static final String TAG = "WinBoLLActivity"; | ||||
|  | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
|  | ||||
|     @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) { | ||||
|             GlobalApplication.getWinBoLLActivityManager().startLogActivity(this); | ||||
|             return true; | ||||
|         } else if (item.getItemId() == R.id.item_home) { | ||||
|             GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(getApplicationContext(), MainActivity.class); | ||||
|             return true; | ||||
|         } | ||||
|         // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。 | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onPostCreate(Bundle savedInstanceState) { | ||||
|         super.onPostCreate(savedInstanceState); | ||||
|         GlobalApplication.getWinBoLLActivityManager().add(this); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         GlobalApplication.getWinBoLLActivityManager().registeRemove(this); | ||||
|     } | ||||
| } | ||||
| @@ -1,38 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.handlers; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/14 03:51:40 | ||||
|  */ | ||||
| import android.os.Handler; | ||||
| import android.os.Message; | ||||
| import cc.winboll.studio.appbase.services.MainService; | ||||
| import java.lang.ref.WeakReference; | ||||
|  | ||||
| public class MainServiceHandler extends Handler { | ||||
|     public static final String TAG = "MainServiceHandler"; | ||||
|  | ||||
|     public static final int MSG_REMINDTHREAD = 0; | ||||
|  | ||||
|     WeakReference<MainService> serviceWeakReference; | ||||
|     public MainServiceHandler(MainService service) { | ||||
|         serviceWeakReference = new WeakReference<MainService>(service); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void handleMessage(Message msg) { | ||||
|         switch (msg.what) { | ||||
|             case MSG_REMINDTHREAD: // 处理下载完成消息,更新UI | ||||
|                 { | ||||
|                     // 显示提醒消息 | ||||
|                     // | ||||
|                     //LogUtils.d(TAG, "显示提醒消息"); | ||||
|                     MainService mainService = serviceWeakReference.get(); | ||||
|                     if (mainService != null) { | ||||
|                         mainService.appenMessage((String)msg.obj); | ||||
|                     } | ||||
|                     break; | ||||
|                 } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,67 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.models; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/13 07:06:13 | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.libappbase.BaseBean; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class MainServiceBean extends BaseBean { | ||||
|  | ||||
|     public static final String TAG = "MainServiceBean"; | ||||
|  | ||||
|     boolean isEnable; | ||||
|  | ||||
|     public MainServiceBean() { | ||||
|         this.isEnable = false; | ||||
|     } | ||||
|  | ||||
|     public void setIsEnable(boolean isEnable) { | ||||
|         this.isEnable = isEnable; | ||||
|     } | ||||
|  | ||||
|     public boolean isEnable() { | ||||
|         return isEnable; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return MainServiceBean.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         jsonWriter.name("isEnable").value(isEnable()); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { | ||||
|             if (name.equals("isEnable")) { | ||||
|                 setIsEnable(jsonReader.nextBoolean()); | ||||
|             } else { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { | ||||
|         jsonReader.beginObject(); | ||||
|         while (jsonReader.hasNext()) { | ||||
|             String name = jsonReader.nextName(); | ||||
|             if (!initObjectsFromJsonReader(jsonReader, name)) { | ||||
|                 jsonReader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         // 结束 JSON 对象 | ||||
|         jsonReader.endObject(); | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
| @@ -1,67 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.models; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/03/07 12:47:22 | ||||
|  * @Describe TestServiceBean | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.libappbase.BaseBean; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class TestDemoBindServiceBean extends BaseBean { | ||||
|  | ||||
|     public static final String TAG = "TestServiceBean"; | ||||
|  | ||||
|     boolean isEnable; | ||||
|  | ||||
|     public TestDemoBindServiceBean() { | ||||
|         this.isEnable = false; | ||||
|     } | ||||
|  | ||||
|     public void setIsEnable(boolean isEnable) { | ||||
|         this.isEnable = isEnable; | ||||
|     } | ||||
|  | ||||
|     public boolean isEnable() { | ||||
|         return isEnable; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return TestDemoBindServiceBean.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         jsonWriter.name("isEnable").value(isEnable()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { | ||||
|             if (name.equals("isEnable")) { | ||||
|                 setIsEnable(jsonReader.nextBoolean()); | ||||
|             } else { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { | ||||
|         jsonReader.beginObject(); | ||||
|         while (jsonReader.hasNext()) { | ||||
|             String name = jsonReader.nextName(); | ||||
|             if (!initObjectsFromJsonReader(jsonReader, name)) { | ||||
|                 jsonReader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         // 结束 JSON 对象 | ||||
|         jsonReader.endObject(); | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
| @@ -1,68 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.models; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/03/07 12:49:21 | ||||
|  * @Describe TestDemoServiceBean | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.libappbase.BaseBean; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class TestDemoServiceBean extends BaseBean { | ||||
|  | ||||
|     public static final String TAG = "TestDemoServiceBean"; | ||||
|  | ||||
|     boolean isEnable; | ||||
|  | ||||
|     public TestDemoServiceBean() { | ||||
|         this.isEnable = false; | ||||
|     } | ||||
|  | ||||
|     public void setIsEnable(boolean isEnable) { | ||||
|         this.isEnable = isEnable; | ||||
|     } | ||||
|  | ||||
|     public boolean isEnable() { | ||||
|         return isEnable; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return TestDemoServiceBean.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         jsonWriter.name("isEnable").value(isEnable()); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { | ||||
|             if (name.equals("isEnable")) { | ||||
|                 setIsEnable(jsonReader.nextBoolean()); | ||||
|             } else { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { | ||||
|         jsonReader.beginObject(); | ||||
|         while (jsonReader.hasNext()) { | ||||
|             String name = jsonReader.nextName(); | ||||
|             if (!initObjectsFromJsonReader(jsonReader, name)) { | ||||
|                 jsonReader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         // 结束 JSON 对象 | ||||
|         jsonReader.endObject(); | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
| @@ -1,36 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.receivers; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/03/24 07:11:44 | ||||
|  */ | ||||
| import android.content.BroadcastReceiver; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import cc.winboll.studio.appbase.widgets.APPNewsWidget; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
|  | ||||
| public class APPNewsWidgetClickListener extends BroadcastReceiver { | ||||
|  | ||||
|     public static final String TAG = "APPNewsWidgetClickListener"; | ||||
|     public static final String ACTION_PRE = APPNewsWidgetClickListener.class.getName() + ".ACTION_PRE"; | ||||
|     public static final String ACTION_NEXT = APPNewsWidgetClickListener.class.getName() + ".ACTION_NEXT"; | ||||
|  | ||||
|     @Override | ||||
|     public void onReceive(Context context, Intent intent) { | ||||
|         String action = intent.getAction(); | ||||
|         if (action == null) { | ||||
|             LogUtils.d(TAG, String.format("action %s", action)); | ||||
|             return; | ||||
|         } | ||||
|         if (action.equals(ACTION_PRE)) { | ||||
|             LogUtils.d(TAG, "ACTION_PRE"); | ||||
|             APPNewsWidget.prePage(context); | ||||
|         } else if (action.equals(ACTION_NEXT)) { | ||||
|             LogUtils.d(TAG, "ACTION_NEXT"); | ||||
|             APPNewsWidget.nextPage(context); | ||||
|         } else { | ||||
|             LogUtils.d(TAG, String.format("action %s", action)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,119 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.receivers; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/13 06:58:04 | ||||
|  * @Describe 主要广播接收器 | ||||
|  */ | ||||
| import android.content.BroadcastReceiver; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.IntentFilter; | ||||
| import cc.winboll.studio.appbase.services.MainService; | ||||
| import cc.winboll.studio.appbase.widgets.APPNewsWidget; | ||||
| import cc.winboll.studio.libappbase.AppUtils; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.models.APPModel; | ||||
| import cc.winboll.studio.libappbase.models.WinBoLLModel; | ||||
| import cc.winboll.studio.libappbase.models.WinBoLLNewsBean; | ||||
| import cc.winboll.studio.libappbase.sos.SOS; | ||||
| import cc.winboll.studio.libappbase.sos.SOSObject; | ||||
| import cc.winboll.studio.libappbase.utils.ToastUtils; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; | ||||
| import cc.winboll.studio.libappbase.winboll.WinBoLL; | ||||
| import java.io.IOException; | ||||
| import java.lang.ref.WeakReference; | ||||
| import java.text.SimpleDateFormat; | ||||
| import java.util.Date; | ||||
|  | ||||
| public class MainReceiver extends BroadcastReceiver { | ||||
|  | ||||
|     public static final String TAG = "MainReceiver"; | ||||
|  | ||||
|     public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED"; | ||||
|  | ||||
|     WeakReference<MainService> mwrService; | ||||
|  | ||||
|     public MainReceiver(MainService service) { | ||||
|         mwrService = new WeakReference<MainService>(service); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onReceive(Context context, Intent intent) { | ||||
|         String szAction = intent.getAction(); | ||||
|         if (szAction.equals(ACTION_BOOT_COMPLETED)) { | ||||
|             ToastUtils.show("ACTION_BOOT_COMPLETED"); | ||||
|         } else if (szAction.equals(IWinBoLLActivity.ACTION_BIND)) { | ||||
|             LogUtils.d(TAG, "ACTION_BIND"); | ||||
|             LogUtils.d(TAG, String.format("context.getPackageName() %s", context.getPackageName())); | ||||
|             LogUtils.d(TAG, String.format("intent.getAction() %s", intent.getAction())); | ||||
|             String szWinBoLLModel = intent.getStringExtra(WinBoLL.EXTRA_WINBOLLMODEL); | ||||
|             LogUtils.d(TAG, String.format("szAPPModel %s", szWinBoLLModel)); | ||||
|             if (szWinBoLLModel != null && !szWinBoLLModel.equals("")) { | ||||
|                 try { | ||||
|                     WinBoLLModel bean = WinBoLLModel.parseStringToBean(szWinBoLLModel, WinBoLLModel.class); | ||||
|                     if (bean != null) { | ||||
|                         String szAppPackageName = bean.getAppPackageName(); | ||||
|                         LogUtils.d(TAG, String.format("szAppPackageName %s", szAppPackageName)); | ||||
|                         String szAppMainServiveName = bean.getAppMainServiveName(); | ||||
|                         LogUtils.d(TAG, String.format("szAppMainServiveName %s", szAppMainServiveName)); | ||||
|                         mwrService.get().bindWinBoLLModelConnection(bean); | ||||
|                     } | ||||
|                 } catch (IOException e) { | ||||
|                     LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|                 } | ||||
|             } | ||||
|         } else if (intent.getAction().equals(SOS.ACTION_SOS)) { | ||||
|             LogUtils.d(TAG, "ACTION_SOS"); | ||||
|             String sos = intent.getStringExtra(SOS.EXTRA_OBJECT); | ||||
|             LogUtils.d(TAG, String.format("SOS %s", sos)); | ||||
|             if (sos != null && !sos.equals("")) { | ||||
|                 SOSObject bean = SOS.parseSOSObject(sos); | ||||
|                 if (bean != null) { | ||||
|                     String szObjectPackageName = bean.getObjectPackageName(); | ||||
|                     LogUtils.d(TAG, String.format("szObjectPackageName %s", szObjectPackageName)); | ||||
|                     String szObjectServiveName = bean.getObjectServiveName(); | ||||
|                     LogUtils.d(TAG, String.format("szObjectServiveName %s", szObjectServiveName)); | ||||
|  | ||||
|                     Intent intentService = new Intent(); | ||||
|                     intentService.setComponent(new ComponentName(szObjectPackageName, szObjectServiveName)); | ||||
|                     context.startService(intentService); | ||||
|  | ||||
|                     String appName = AppUtils.getAppNameByPackageName(context, szObjectPackageName); | ||||
|                     LogUtils.d(TAG, String.format("appName %s", appName)); | ||||
|                     WinBoLLNewsBean appWinBoLLNewsBean = new WinBoLLNewsBean(appName); | ||||
|                     SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); | ||||
|                     String currentTime = sdf.format(new Date()); | ||||
|                     StringBuilder sbLine = new StringBuilder(); | ||||
|                     sbLine.append("["); | ||||
|                     sbLine.append(currentTime); | ||||
|                     sbLine.append("] Power to "); | ||||
|                     sbLine.append(appName); | ||||
|                     appWinBoLLNewsBean.setMessage(sbLine.toString()); | ||||
|  | ||||
|                     APPNewsWidget.addWinBoLLNewsBean(context, appWinBoLLNewsBean); | ||||
|  | ||||
|                     Intent intentWidget = new Intent(context, APPNewsWidget.class); | ||||
|                     intentWidget.setAction(APPNewsWidget.ACTION_RELOAD_REPORT); | ||||
|                     context.sendBroadcast(intentWidget); | ||||
|                 } | ||||
|  | ||||
|  | ||||
|             } | ||||
|         } else { | ||||
|             ToastUtils.show(szAction); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 注册 Receiver | ||||
|     // | ||||
|     public void registerAction(MainService service) { | ||||
|         IntentFilter filter=new IntentFilter(); | ||||
|         filter.addAction(ACTION_BOOT_COMPLETED); | ||||
|         filter.addAction(SOS.ACTION_SOS); | ||||
|         filter.addAction(WinBoLL.ACTION_BIND); | ||||
|         //filter.addAction(Intent.ACTION_BATTERY_CHANGED); | ||||
|         service.registerReceiver(this, filter); | ||||
|     } | ||||
| } | ||||
| @@ -1,138 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.services; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/14 03:38:31 | ||||
|  * @Describe 守护进程服务 | ||||
|  */ | ||||
| import android.app.Service; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.ServiceConnection; | ||||
| import android.os.IBinder; | ||||
| import cc.winboll.studio.appbase.models.MainServiceBean; | ||||
| import cc.winboll.studio.appbase.services.AssistantService; | ||||
| import cc.winboll.studio.appbase.services.MainService; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import android.os.Binder; | ||||
|  | ||||
| public class AssistantService extends Service { | ||||
|  | ||||
|     public static final String TAG = "AssistantService"; | ||||
|  | ||||
|     MainServiceBean mMainServiceBean; | ||||
|     MyServiceConnection mMyServiceConnection; | ||||
|     MainService mMainService; | ||||
|     boolean isBound = false; | ||||
|     volatile boolean isThreadAlive = false; | ||||
|  | ||||
|     public synchronized void setIsThreadAlive(boolean isThreadAlive) { | ||||
|         LogUtils.d(TAG, "setIsThreadAlive(...)"); | ||||
|         LogUtils.d(TAG, String.format("isThreadAlive %s", isThreadAlive)); | ||||
|         this.isThreadAlive = isThreadAlive; | ||||
|     } | ||||
|  | ||||
|     public boolean isThreadAlive() { | ||||
|         return isThreadAlive; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public IBinder onBind(Intent intent) { | ||||
|         return new MyBinder(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         LogUtils.d(TAG, "onCreate"); | ||||
|         super.onCreate(); | ||||
|  | ||||
|         //mMyBinder = new MyBinder(); | ||||
|         if (mMyServiceConnection == null) { | ||||
|             mMyServiceConnection = new MyServiceConnection(); | ||||
|         } | ||||
|         // 设置运行参数 | ||||
|         setIsThreadAlive(false); | ||||
|         assistantService(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int onStartCommand(Intent intent, int flags, int startId) { | ||||
|         LogUtils.d(TAG, "call onStartCommand(...)"); | ||||
|         assistantService(); | ||||
|         return START_STICKY; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|         //LogUtils.d(TAG, "onDestroy"); | ||||
|         setIsThreadAlive(false); | ||||
|         // 解除绑定 | ||||
|         if (isBound) { | ||||
|             unbindService(mMyServiceConnection); | ||||
|             isBound = false; | ||||
|         } | ||||
|         super.onDestroy(); | ||||
|     } | ||||
|  | ||||
|     // 运行服务内容 | ||||
|     // | ||||
|     void assistantService() { | ||||
|         LogUtils.d(TAG, "assistantService()"); | ||||
|         mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); | ||||
|         LogUtils.d(TAG, String.format("mMainServiceBean.isEnable() %s", mMainServiceBean.isEnable())); | ||||
|         if (mMainServiceBean.isEnable()) { | ||||
|             LogUtils.d(TAG, String.format("mIsThreadAlive %s", isThreadAlive())); | ||||
|             if (isThreadAlive() == false) { | ||||
|                 // 设置运行状态 | ||||
|                 setIsThreadAlive(true); | ||||
|                 // 唤醒和绑定主进程 | ||||
|                 wakeupAndBindMain(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 唤醒和绑定主进程 | ||||
|     // | ||||
|     void wakeupAndBindMain() { | ||||
|         LogUtils.d(TAG, "wakeupAndBindMain()"); | ||||
|         // 绑定服务的Intent | ||||
|         Intent intent = new Intent(this, MainService.class); | ||||
|         startService(new Intent(this, MainService.class)); | ||||
|         bindService(intent, mMyServiceConnection, Context.BIND_IMPORTANT); | ||||
|      | ||||
| //        startService(new Intent(this, MainService.class)); | ||||
| //        bindService(new Intent(AssistantService.this, MainService.class), mMyServiceConnection, Context.BIND_IMPORTANT); | ||||
|     } | ||||
|  | ||||
|     // 主进程与守护进程连接时需要用到此类 | ||||
|     // | ||||
|     class MyServiceConnection implements ServiceConnection { | ||||
|         @Override | ||||
|         public void onServiceConnected(ComponentName name, IBinder service) { | ||||
|             LogUtils.d(TAG, "onServiceConnected(...)"); | ||||
|             MainService.MyBinder binder = (MainService.MyBinder) service; | ||||
|             mMainService = binder.getService(); | ||||
|             isBound = true; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onServiceDisconnected(ComponentName name) { | ||||
|             LogUtils.d(TAG, "onServiceDisconnected(...)"); | ||||
|             mMainServiceBean = MainServiceBean.loadBean(AssistantService.this, MainServiceBean.class); | ||||
|             if (mMainServiceBean.isEnable()) { | ||||
|                 wakeupAndBindMain(); | ||||
|             } | ||||
|             isBound = false; | ||||
|             mMainService = null; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     // 用于返回服务实例的Binder | ||||
|     public class MyBinder extends Binder { | ||||
|         AssistantService getService() { | ||||
|             LogUtils.d(TAG, "AssistantService MyBinder getService()"); | ||||
|             return AssistantService.this; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,317 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.services; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/13 06:56:41 | ||||
|  * @Describe 拨号主服务 | ||||
|  * 参考: | ||||
|  * 进程保活-双进程守护的正确姿势 | ||||
|  * https://blog.csdn.net/sinat_35159441/article/details/75267380 | ||||
|  * Android Service之onStartCommand方法研究 | ||||
|  * https://blog.csdn.net/cyp331203/article/details/38920491 | ||||
|  */ | ||||
| import android.app.Service; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.ServiceConnection; | ||||
| import android.os.Binder; | ||||
| import android.os.IBinder; | ||||
| import cc.winboll.studio.appbase.MyTileService; | ||||
| import cc.winboll.studio.appbase.handlers.MainServiceHandler; | ||||
| import cc.winboll.studio.appbase.models.MainServiceBean; | ||||
| import cc.winboll.studio.appbase.receivers.MainReceiver; | ||||
| import cc.winboll.studio.appbase.services.AssistantService; | ||||
| import cc.winboll.studio.appbase.threads.MainServiceThread; | ||||
| import cc.winboll.studio.appbase.widgets.APPNewsWidget; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.models.APPModel; | ||||
| import cc.winboll.studio.libappbase.models.WinBoLLModel; | ||||
| import java.util.ArrayList; | ||||
|  | ||||
| public class MainService extends Service { | ||||
|  | ||||
|     public static final String TAG = "MainService"; | ||||
|  | ||||
|     public static final int MSG_UPDATE_STATUS = 0; | ||||
|  | ||||
|     static MainService _mControlCenterService; | ||||
|  | ||||
|     volatile boolean isServiceRunning; | ||||
|  | ||||
|     MainServiceBean mMainServiceBean; | ||||
|     MainServiceThread mMainServiceThread; | ||||
|     MainServiceHandler mMainServiceHandler; | ||||
|     MyServiceConnection mMyServiceConnection; | ||||
|     AssistantService mAssistantService; | ||||
|     boolean isBound = false; | ||||
|     MainReceiver mMainReceiver; | ||||
|     ArrayList<APPConnection> mAPPModelConnectionList; | ||||
|  | ||||
|     @Override | ||||
|     public IBinder onBind(Intent intent) { | ||||
|         return new MyBinder(); | ||||
|     } | ||||
|  | ||||
|     public MainServiceThread getRemindThread() { | ||||
|         return mMainServiceThread; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         LogUtils.d(TAG, "onCreate()"); | ||||
|         mAPPModelConnectionList = new ArrayList<APPConnection>(); | ||||
|  | ||||
|         _mControlCenterService = MainService.this; | ||||
|         isServiceRunning = false; | ||||
|         mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); | ||||
|  | ||||
|         if (mMyServiceConnection == null) { | ||||
|             mMyServiceConnection = new MyServiceConnection(); | ||||
|         } | ||||
|         mMainServiceHandler = new MainServiceHandler(this); | ||||
|  | ||||
|         // 运行服务内容 | ||||
|         mainService(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int onStartCommand(Intent intent, int flags, int startId) { | ||||
|         LogUtils.d(TAG, "onStartCommand(...)"); | ||||
|         // 运行服务内容 | ||||
|         mainService(); | ||||
|         return (mMainServiceBean.isEnable()) ? START_STICKY : super.onStartCommand(intent, flags, startId); | ||||
|     } | ||||
|  | ||||
|     // 运行服务内容 | ||||
|     // | ||||
|     void mainService() { | ||||
|         LogUtils.d(TAG, "mainService()"); | ||||
|         mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); | ||||
|         if (mMainServiceBean.isEnable() && isServiceRunning == false) { | ||||
|             LogUtils.d(TAG, "mainService() start running"); | ||||
|             isServiceRunning = true; | ||||
|             // 唤醒守护进程 | ||||
|             wakeupAndBindAssistant(); | ||||
|  | ||||
|             if (mMainReceiver == null) { | ||||
|                 // 注册广播接收器 | ||||
|                 mMainReceiver = new MainReceiver(this); | ||||
|                 mMainReceiver.registerAction(this); | ||||
|             } | ||||
|  | ||||
|             // 启动小部件 | ||||
|             Intent intentTimeWidget = new Intent(this, APPNewsWidget.class); | ||||
|             intentTimeWidget.setAction(APPNewsWidget.ACTION_RELOAD_REPORT); | ||||
|             this.sendBroadcast(intentTimeWidget); | ||||
|  | ||||
|             startMainServiceThread(); | ||||
|  | ||||
|             MyTileService.updateServiceIconStatus(this); | ||||
|  | ||||
|             LogUtils.i(TAG, "Main Service Is Start."); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 唤醒和绑定守护进程 | ||||
|     // | ||||
|     void wakeupAndBindAssistant() { | ||||
|         LogUtils.d(TAG, "wakeupAndBindAssistant()"); | ||||
|  | ||||
|         Intent intent = new Intent(this, AssistantService.class); | ||||
|         startService(intent); | ||||
|         // 绑定服务的Intent | ||||
|         bindService(intent, mMyServiceConnection, Context.BIND_IMPORTANT); | ||||
|     } | ||||
|  | ||||
|     // 开启提醒铃声线程 | ||||
|     // | ||||
|     public void startMainServiceThread() { | ||||
|         LogUtils.d(TAG, "startMainServiceThread"); | ||||
|         if (mMainServiceThread == null) { | ||||
|             mMainServiceThread = new MainServiceThread(this, mMainServiceHandler); | ||||
|             LogUtils.d(TAG, "new MainServiceThread"); | ||||
|         } else { | ||||
|             if (mMainServiceThread.isExist() == true) { | ||||
|                 mMainServiceThread = new MainServiceThread(this, mMainServiceHandler); | ||||
|                 LogUtils.d(TAG, "renew MainServiceThread"); | ||||
|             } else { | ||||
|                 // 提醒进程正在进行中就更新状态后退出 | ||||
|                 LogUtils.d(TAG, "A mMainServiceThread running."); | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|         mMainServiceThread.start(); | ||||
|     } | ||||
|  | ||||
|     public void stopRemindThread() { | ||||
|         if (mMainServiceThread != null) { | ||||
|             mMainServiceThread.setIsExist(true); | ||||
|             mMainServiceThread = null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|         //LogUtils.d(TAG, "onDestroy"); | ||||
|         mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); | ||||
|         if (mMainServiceBean.isEnable() == false) { | ||||
|             // 设置运行状态 | ||||
|             isServiceRunning = false;// 解除绑定 | ||||
|             if (isBound) { | ||||
|                 unbindService(mMyServiceConnection); | ||||
|                 isBound = false; | ||||
|             } | ||||
|             // 停止守护进程 | ||||
|             Intent intent = new Intent(this, AssistantService.class); | ||||
|             stopService(intent); | ||||
|             // 停止Receiver | ||||
|             if (mMainReceiver != null) { | ||||
|                 unregisterReceiver(mMainReceiver); | ||||
|                 mMainReceiver = null; | ||||
|             } | ||||
|             // 停止前台通知栏 | ||||
|             stopForeground(true); | ||||
|             // 停止消息提醒进程 | ||||
|             stopRemindThread(); | ||||
|  | ||||
|             MyTileService.updateServiceIconStatus(this); | ||||
|  | ||||
|             super.onDestroy(); | ||||
|             //LogUtils.d(TAG, "onDestroy done"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void bindWinBoLLModelConnection(WinBoLLModel bean) { | ||||
|         LogUtils.d(TAG, "bindAPPModelConnection(...)"); | ||||
|         // 清理旧的绑定链接 | ||||
|         for (int i = mAPPModelConnectionList.size() - 1; i > -1; i--) { | ||||
|             APPConnection item = mAPPModelConnectionList.get(i); | ||||
|             if (item.isBindToAPP(bean)) { | ||||
|                 LogUtils.d(TAG, "Bind Servive exist."); | ||||
|                 unbindService(item); | ||||
|                 mAPPModelConnectionList.remove(i); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // 绑定服务 | ||||
|         APPConnection appConnection = new APPConnection(); | ||||
|         Intent intentService = new Intent(); | ||||
|         intentService.setComponent(new ComponentName(bean.getAppPackageName(), bean.getAppMainServiveName())); | ||||
|         bindService(intentService, appConnection, Context.BIND_IMPORTANT); | ||||
|         mAPPModelConnectionList.add(appConnection); | ||||
|          | ||||
|         Intent intentWidget = new Intent(this, APPNewsWidget.class); | ||||
|         intentWidget.setAction(APPNewsWidget.ACTION_WAKEUP_SERVICE); | ||||
|         WinBoLLModel appSOSBean = new WinBoLLModel(bean.getAppPackageName(), bean.getAppMainServiveName()); | ||||
|         intentWidget.putExtra("APPSOSBean", appSOSBean.toString()); | ||||
|         sendBroadcast(intentWidget); | ||||
|     } | ||||
|  | ||||
|     public class APPConnection implements ServiceConnection { | ||||
|  | ||||
|         ComponentName mComponentName; | ||||
|  | ||||
|         boolean isBindToAPP(WinBoLLModel bean) { | ||||
|             return mComponentName != null | ||||
|                 && mComponentName.getClassName().equals(bean.getAppMainServiveName()) | ||||
|                 && mComponentName.getPackageName().equals(bean.getAppPackageName()); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onServiceConnected(ComponentName name, IBinder service) { | ||||
|             LogUtils.d(TAG, "onServiceConnected(...)"); | ||||
|             mComponentName = name; | ||||
|             LogUtils.d(TAG, String.format("onServiceConnected : \ngetClassName %s\ngetPackageName %s", name.getClassName(), name.getPackageName())); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onServiceDisconnected(ComponentName name) { | ||||
|             LogUtils.d(TAG, "onServiceDisconnected(...)"); | ||||
|             LogUtils.d(TAG, String.format("onServiceDisconnected : \ngetClassName %s\ngetPackageName %s", name.getClassName(), name.getPackageName())); | ||||
|  | ||||
|             // 尝试无参数启动一下服务 | ||||
|             String appPackage = mComponentName.getPackageName(); | ||||
|             LogUtils.d(TAG, String.format("appPackage %s", appPackage)); | ||||
|             String appMainServiceClassName = mComponentName.getClassName(); | ||||
|             LogUtils.d(TAG, String.format("appMainServiceClassName %s", appMainServiceClassName)); | ||||
|  | ||||
|             Intent intentService = new Intent(); | ||||
|             intentService.setComponent(new ComponentName(appPackage, appMainServiceClassName)); | ||||
|             startService(intentService); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     // 主进程与守护进程连接时需要用到此类 | ||||
|     // | ||||
|     private class MyServiceConnection implements ServiceConnection { | ||||
|         @Override | ||||
|         public void onServiceConnected(ComponentName name, IBinder service) { | ||||
|             LogUtils.d(TAG, "onServiceConnected(...)"); | ||||
|             AssistantService.MyBinder binder = (AssistantService.MyBinder) service; | ||||
|             mAssistantService = binder.getService(); | ||||
|             isBound = true; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onServiceDisconnected(ComponentName name) { | ||||
|             LogUtils.d(TAG, "onServiceDisconnected(...)"); | ||||
|  | ||||
|             if (mMainServiceBean.isEnable()) { | ||||
|                 // 唤醒守护进程 | ||||
|                 wakeupAndBindAssistant(); | ||||
|             } | ||||
|             isBound = false; | ||||
|             mAssistantService = null; | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|  | ||||
|     // 用于返回服务实例的Binder | ||||
|     public class MyBinder extends Binder { | ||||
|         MainService getService() { | ||||
|             LogUtils.d(TAG, "MainService MyBinder getService()"); | ||||
|             return MainService.this; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| //    // | ||||
| //    // 启动服务 | ||||
| //    // | ||||
| //    public static void startControlCenterService(Context context) { | ||||
| //        Intent intent = new Intent(context, MainService.class); | ||||
| //        context.startForegroundService(intent); | ||||
| //    } | ||||
| // | ||||
| //    // | ||||
| //    // 停止服务 | ||||
| //    // | ||||
| //    public static void stopControlCenterService(Context context) { | ||||
| //        Intent intent = new Intent(context, MainService.class); | ||||
| //        context.stopService(intent); | ||||
| //    } | ||||
|  | ||||
|     public void appenMessage(String message) { | ||||
|         LogUtils.d(TAG, String.format("Message : %s", message)); | ||||
|     } | ||||
|  | ||||
|     public static void stopMainService(Context context) { | ||||
|         LogUtils.d(TAG, "stopMainService"); | ||||
|         MainServiceBean bean = new MainServiceBean(); | ||||
|         bean.setIsEnable(false); | ||||
|         MainServiceBean.saveBean(context, bean); | ||||
|         context.stopService(new Intent(context, MainService.class)); | ||||
|     } | ||||
|  | ||||
|     public static void startMainService(Context context) { | ||||
|         LogUtils.d(TAG, "startMainService"); | ||||
|         MainServiceBean bean = new MainServiceBean(); | ||||
|         bean.setIsEnable(true); | ||||
|         MainServiceBean.saveBean(context, bean); | ||||
|         context.startService(new Intent(context, MainService.class)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1,179 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.services; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/03/07 12:45:49 | ||||
|  * @Describe 启动时申请绑定到APPBase主服务的服务示例 | ||||
|  */ | ||||
| import android.app.Service; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.Binder; | ||||
| import android.os.IBinder; | ||||
| import cc.winboll.studio.appbase.App; | ||||
| import cc.winboll.studio.appbase.models.TestDemoBindServiceBean; | ||||
| import cc.winboll.studio.appbase.services.TestDemoBindService; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.sos.SOS; | ||||
| import cc.winboll.studio.libappbase.winboll.WinBoLL; | ||||
|  | ||||
| public class TestDemoBindService extends Service { | ||||
|  | ||||
|     public static final String TAG = "TestDemoBindService"; | ||||
|  | ||||
|     public static final String ACTION_ENABLE = TestDemoBindService.class.getName() + ".ACTION_ENABLE"; | ||||
|     public static final String ACTION_DISABLE = TestDemoBindService.class.getName() + ".ACTION_DISABLE"; | ||||
|  | ||||
|     volatile static TestThread _TestThread; | ||||
|  | ||||
|     volatile static boolean _IsRunning; | ||||
|  | ||||
|     public synchronized static void setIsRunning(boolean isRunning) { | ||||
|         _IsRunning = isRunning; | ||||
|     } | ||||
|  | ||||
|     public static boolean isRunning() { | ||||
|         return _IsRunning; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public IBinder onBind(Intent intent) { | ||||
|         return new MyBinder(); | ||||
|     } | ||||
|  | ||||
|     public class MyBinder extends Binder { | ||||
|         public TestDemoBindService getService() { | ||||
|             return TestDemoBindService.this; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         LogUtils.d(TAG, "onCreate()"); | ||||
|  | ||||
|         run(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int onStartCommand(Intent intent, int flags, int startId) { | ||||
|         LogUtils.d(TAG, "onStartCommand(...)"); | ||||
|         TestDemoBindServiceBean bean = TestDemoBindServiceBean.loadBean(this, TestDemoBindServiceBean.class); | ||||
|         if (bean == null) { | ||||
|             bean = new TestDemoBindServiceBean(); | ||||
|         } | ||||
|  | ||||
|         if (intent.getAction() != null) { | ||||
|             if (intent.getAction().equals(ACTION_ENABLE)) { | ||||
|                 bean.setIsEnable(true); | ||||
|                 LogUtils.d(TAG, "setIsEnable(true);"); | ||||
|                 TestDemoBindServiceBean.saveBean(this, bean); | ||||
|             } else if (intent.getAction().equals(ACTION_DISABLE)) { | ||||
|                 bean.setIsEnable(false); | ||||
|                 LogUtils.d(TAG, "setIsEnable(false);"); | ||||
|                 TestDemoBindServiceBean.saveBean(this, bean); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         run(); | ||||
|  | ||||
|         return (bean.isEnable()) ? START_STICKY : super.onStartCommand(intent, flags, startId); | ||||
|         //return super.onStartCommand(intent, flags, startId); | ||||
|     } | ||||
|  | ||||
|     void run() { | ||||
|         LogUtils.d(TAG, "run()"); | ||||
|         TestDemoBindServiceBean bean = TestDemoBindServiceBean.loadBean(this, TestDemoBindServiceBean.class); | ||||
|         if (bean == null) { | ||||
|             bean = new TestDemoBindServiceBean(); | ||||
|             TestDemoBindServiceBean.saveBean(this, bean); | ||||
|         } | ||||
|         if (bean.isEnable()) { | ||||
|             LogUtils.d(TAG, "run() bean.isEnable()"); | ||||
|             TestThread.getInstance(this).start(); | ||||
|             LogUtils.d(TAG, "_TestThread.start()"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         LogUtils.d(TAG, "onDestroy()"); | ||||
|         TestDemoBindServiceBean bean = TestDemoBindServiceBean.loadBean(this, TestDemoBindServiceBean.class); | ||||
|         if (bean == null) { | ||||
|             bean = new TestDemoBindServiceBean(); | ||||
|         } | ||||
|  | ||||
|         TestThread.getInstance(this).setIsExit(true); | ||||
|          | ||||
|         // 预防 APPBase 应用重启绑定失效。 | ||||
|         // 所以退出时检查本服务是否配置启用,如果启用就发送一个 SOS 信号。 | ||||
|         // 这样 APPBase 就会用组件方式启动本服务。 | ||||
|         if (bean.isEnable()) { | ||||
|             if (App.isDebuging()) { | ||||
|                 SOS.sosToAppBaseBeta(this, TestDemoBindService.class.getName()); | ||||
|             } else { | ||||
|                 SOS.sosToAppBase(this, TestDemoBindService.class.getName()); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         _IsRunning = false; | ||||
|     } | ||||
|  | ||||
|     static class TestThread extends Thread { | ||||
|  | ||||
|         volatile static TestThread _TestThread; | ||||
|         Context mContext; | ||||
|         volatile boolean isStarted = false; | ||||
|         volatile boolean isExit = false; | ||||
|  | ||||
|         TestThread(Context context) { | ||||
|             super(); | ||||
|             mContext = context; | ||||
|         } | ||||
|  | ||||
|         public static synchronized TestThread getInstance(Context context) { | ||||
|             if (_TestThread != null) { | ||||
|                 _TestThread.setIsExit(true); | ||||
|             } | ||||
|             _TestThread = new TestThread(context); | ||||
|  | ||||
|             return _TestThread; | ||||
|         } | ||||
|  | ||||
|         public synchronized void setIsExit(boolean isExit) { | ||||
|             this.isExit = isExit; | ||||
|         } | ||||
|  | ||||
|         public boolean isExit() { | ||||
|             return isExit; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void run() { | ||||
|             if (isStarted == false) { | ||||
|                 isStarted = true; | ||||
|                 super.run(); | ||||
|                 LogUtils.d(TAG, "run() start"); | ||||
|                 if (App.isDebuging()) { | ||||
|                     WinBoLL.bindToAPPBaseBeta(mContext, TestDemoBindService.class.getName()); | ||||
|                 } else { | ||||
|                     WinBoLL.bindToAPPBase(mContext, TestDemoBindService.class.getName()); | ||||
|                 } | ||||
|  | ||||
|                 while (!isExit()) { | ||||
|                     LogUtils.d(TAG, "run()"); | ||||
|  | ||||
|                     try { | ||||
|                         Thread.sleep(1000); | ||||
|                     } catch (InterruptedException e) { | ||||
|                         LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 LogUtils.d(TAG, "run() exit"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,155 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.services; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/03/07 12:39:24 | ||||
|  * @Describe 普通服务示例 | ||||
|  */ | ||||
| import android.app.Service; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.Binder; | ||||
| import android.os.IBinder; | ||||
| import cc.winboll.studio.appbase.models.TestDemoServiceBean; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
|  | ||||
| public class TestDemoService extends Service { | ||||
|  | ||||
|     public static final String TAG = "TestDemoService"; | ||||
|  | ||||
|     public static final String ACTION_ENABLE = TestDemoService.class.getName() + ".ACTION_ENABLE"; | ||||
|     public static final String ACTION_DISABLE = TestDemoService.class.getName() + ".ACTION_DISABLE"; | ||||
|  | ||||
|     volatile static TestThread _TestThread; | ||||
|  | ||||
|     volatile static boolean _IsRunning; | ||||
|  | ||||
|     public synchronized static void setIsRunning(boolean isRunning) { | ||||
|         _IsRunning = isRunning; | ||||
|     } | ||||
|  | ||||
|     public static boolean isRunning() { | ||||
|         return _IsRunning; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public IBinder onBind(Intent intent) { | ||||
|         return new MyBinder(); | ||||
|     } | ||||
|  | ||||
|     public class MyBinder extends Binder { | ||||
|         public TestDemoService getService() { | ||||
|             return TestDemoService.this; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         LogUtils.d(TAG, "onCreate()"); | ||||
|  | ||||
|  | ||||
|         run(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int onStartCommand(Intent intent, int flags, int startId) { | ||||
|         LogUtils.d(TAG, "onStartCommand(...)"); | ||||
|         TestDemoServiceBean bean = TestDemoServiceBean.loadBean(this, TestDemoServiceBean.class); | ||||
|         if (bean == null) { | ||||
|             bean = new TestDemoServiceBean(); | ||||
|         } | ||||
|  | ||||
|         if (intent.getAction() != null) { | ||||
|             if (intent.getAction().equals(ACTION_ENABLE)) { | ||||
|                 bean.setIsEnable(true); | ||||
|                 LogUtils.d(TAG, "setIsEnable(true);"); | ||||
|                 TestDemoServiceBean.saveBean(this, bean); | ||||
|             } else if (intent.getAction().equals(ACTION_DISABLE)) { | ||||
|                 bean.setIsEnable(false); | ||||
|                 LogUtils.d(TAG, "setIsEnable(false);"); | ||||
|                 TestDemoServiceBean.saveBean(this, bean); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         run(); | ||||
|  | ||||
|         return (bean.isEnable()) ? START_STICKY : super.onStartCommand(intent, flags, startId); | ||||
|         //return super.onStartCommand(intent, flags, startId); | ||||
|     } | ||||
|  | ||||
|     void run() { | ||||
|         LogUtils.d(TAG, "run()"); | ||||
|         TestDemoServiceBean bean = TestDemoServiceBean.loadBean(this, TestDemoServiceBean.class); | ||||
|         if (bean == null) { | ||||
|             bean = new TestDemoServiceBean(); | ||||
|             TestDemoServiceBean.saveBean(this, bean); | ||||
|         } | ||||
|         if (bean.isEnable()) { | ||||
|             LogUtils.d(TAG, "run() bean.isEnable()"); | ||||
|             TestThread.getInstance(this).start(); | ||||
|             LogUtils.d(TAG, "_TestThread.start()"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         LogUtils.d(TAG, "onDestroy()"); | ||||
|         TestThread.getInstance(this).setIsExit(true); | ||||
|  | ||||
|         _IsRunning = false; | ||||
|     } | ||||
|  | ||||
|     static class TestThread extends Thread { | ||||
|  | ||||
|         volatile static TestThread _TestThread; | ||||
|         Context mContext; | ||||
|         volatile boolean isStarted = false; | ||||
|         volatile boolean isExit = false; | ||||
|  | ||||
|         TestThread(Context context) { | ||||
|             super(); | ||||
|             mContext = context; | ||||
|         } | ||||
|  | ||||
|         public static synchronized TestThread getInstance(Context context) { | ||||
|             if (_TestThread != null) { | ||||
|                 _TestThread.setIsExit(true); | ||||
|             } | ||||
|             _TestThread = new TestThread(context); | ||||
|  | ||||
|             return _TestThread; | ||||
|         } | ||||
|  | ||||
|         public synchronized void setIsExit(boolean isExit) { | ||||
|             this.isExit = isExit; | ||||
|         } | ||||
|  | ||||
|         public boolean isExit() { | ||||
|             return isExit; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void run() { | ||||
|             if (isStarted == false) { | ||||
|                 isStarted = true; | ||||
|                 super.run(); | ||||
|                 LogUtils.d(TAG, "run() start"); | ||||
|  | ||||
|                 while (!isExit()) { | ||||
|                     LogUtils.d(TAG, "run()"); | ||||
|  | ||||
|                     try { | ||||
|                         Thread.sleep(1000); | ||||
|                     } catch (InterruptedException e) { | ||||
|                         LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 LogUtils.d(TAG, "run() exit"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,54 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.threads; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/14 03:46:44 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import cc.winboll.studio.appbase.handlers.MainServiceHandler; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import java.lang.ref.WeakReference; | ||||
|  | ||||
| public class MainServiceThread extends Thread { | ||||
|  | ||||
|     public static final String TAG = "MainServiceThread"; | ||||
|  | ||||
|     Context mContext; | ||||
|  | ||||
|     // 控制线程是否退出的标志 | ||||
|     volatile boolean isExist = false; | ||||
|  | ||||
|     // 服务Handler, 用于线程发送消息使用 | ||||
|     WeakReference<MainServiceHandler> mwrMainServiceHandler; | ||||
|  | ||||
|     public void setIsExist(boolean isExist) { | ||||
|         this.isExist = isExist; | ||||
|     } | ||||
|  | ||||
|     public boolean isExist() { | ||||
|         return isExist; | ||||
|     } | ||||
|  | ||||
|     public MainServiceThread(Context context, MainServiceHandler handler) { | ||||
|         mContext = context; | ||||
|         mwrMainServiceHandler = new WeakReference<MainServiceHandler>(handler); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void run() { | ||||
|         LogUtils.d(TAG, "run()"); | ||||
|  | ||||
|         while (!isExist()) { | ||||
|             //ToastUtils.show("run()"); | ||||
|             //LogUtils.d(TAG, "run()"); | ||||
|  | ||||
|             try { | ||||
|                 Thread.sleep(1000); | ||||
|             } catch (InterruptedException e) { | ||||
|                 LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|             } | ||||
|         } | ||||
|         LogUtils.d(TAG, "run() exit."); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,187 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.widgets; | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/15 14:41:25 | ||||
|  * @Describe TimeWidget | ||||
|  */ | ||||
| import android.app.PendingIntent; | ||||
| import android.appwidget.AppWidgetManager; | ||||
| import android.appwidget.AppWidgetProvider; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.widget.RemoteViews; | ||||
| import cc.winboll.studio.appbase.R; | ||||
| import cc.winboll.studio.appbase.receivers.APPNewsWidgetClickListener; | ||||
| import cc.winboll.studio.libappbase.AppUtils; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.models.APPModel; | ||||
| import cc.winboll.studio.libappbase.models.WinBoLLNewsBean; | ||||
| import cc.winboll.studio.libappbase.winboll.WinBoLL; | ||||
| import java.io.IOException; | ||||
| import java.text.SimpleDateFormat; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Date; | ||||
| import cc.winboll.studio.libappbase.models.WinBoLLModel; | ||||
|  | ||||
| public class APPNewsWidget extends AppWidgetProvider { | ||||
|  | ||||
|     public static final String TAG = "APPNewsWidget"; | ||||
|      | ||||
|     public static final String ACTION_WAKEUP_SERVICE = APPNewsWidget.class.getName() + ".ACTION_WAKEUP_SERVICE"; | ||||
|     public static final String ACTION_RELOAD_REPORT = APPNewsWidget.class.getName() + ".ACTION_RELOAD_REPORT"; | ||||
|  | ||||
|  | ||||
|     volatile static ArrayList<WinBoLLNewsBean> _WinBoLLNewsBeanList; | ||||
|     final static int _MAX_PAGES = 10; | ||||
|     final static int _OnePageLinesCount = 5; | ||||
|     volatile static int _CurrentPageIndex = 0; | ||||
|  | ||||
|     @Override | ||||
|     public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { | ||||
|         initWinBoLLNewsBeanList(context); | ||||
|         for (int appWidgetId : appWidgetIds) { | ||||
|             updateAppWidget(context, appWidgetManager, appWidgetId); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onReceive(Context context, Intent intent) { | ||||
|         super.onReceive(context, intent); | ||||
|         initWinBoLLNewsBeanList(context); | ||||
|         if (intent.getAction().equals(ACTION_RELOAD_REPORT)) { | ||||
|             LogUtils.d(TAG, "ACTION_RELOAD_REPORT"); | ||||
|             AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); | ||||
|             int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, APPNewsWidget.class)); | ||||
|             for (int appWidgetId : appWidgetIds) { | ||||
|                 updateAppWidget(context, appWidgetManager, appWidgetId); | ||||
|             } | ||||
|         }else if (intent.getAction().equals(ACTION_WAKEUP_SERVICE)) { | ||||
|             LogUtils.d(TAG, "ACTION_WAKEUP_SERVICE"); | ||||
|             String szWinBoLLModel = intent.getStringExtra(WinBoLL.EXTRA_WINBOLLMODEL); | ||||
|             LogUtils.d(TAG, String.format("szWinBoLLModel %s", szWinBoLLModel)); | ||||
|             if (szWinBoLLModel != null && !szWinBoLLModel.equals("")) { | ||||
|                 try { | ||||
|                     WinBoLLModel bean = WinBoLLModel.parseStringToBean(szWinBoLLModel, WinBoLLModel.class); | ||||
|                     if (bean != null) { | ||||
|                         String szAppPackageName = bean.getAppPackageName(); | ||||
|                         LogUtils.d(TAG, String.format("szAppPackageName %s", szAppPackageName)); | ||||
|                         String szAppMainServiveName = bean.getAppMainServiveName(); | ||||
|                         LogUtils.d(TAG, String.format("szAppMainServiveName %s", szAppMainServiveName)); | ||||
|  | ||||
|                          | ||||
|                         String appName = AppUtils.getAppNameByPackageName(context, szAppPackageName); | ||||
|                         LogUtils.d(TAG, String.format("appName %s", appName)); | ||||
|                         WinBoLLNewsBean winBollNewsBean = new WinBoLLNewsBean(appName); | ||||
|                         SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); | ||||
|                         String currentTime = sdf.format(new Date()); | ||||
|                         StringBuilder sbLine = new StringBuilder(); | ||||
|                         sbLine.append("["); | ||||
|                         sbLine.append(currentTime); | ||||
|                         sbLine.append("] Wake up "); | ||||
|                         sbLine.append(appName); | ||||
|                         winBollNewsBean.setMessage(sbLine.toString()); | ||||
|                          | ||||
|                         addWinBoLLNewsBean(context, winBollNewsBean); | ||||
|  | ||||
|                         AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); | ||||
|                         int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, APPNewsWidget.class)); | ||||
|                         for (int appWidgetId : appWidgetIds) { | ||||
|                             updateAppWidget(context, appWidgetManager, appWidgetId); | ||||
|                         } | ||||
|                     } | ||||
|                 } catch (IOException e) { | ||||
|                     LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 加入新报告信息 | ||||
|     // | ||||
|     public synchronized static void addWinBoLLNewsBean(Context context, WinBoLLNewsBean bean) { | ||||
|         initWinBoLLNewsBeanList(context); | ||||
|         _WinBoLLNewsBeanList.add(0, bean); | ||||
|         // 控制记录总数 | ||||
|         while (_WinBoLLNewsBeanList.size() > _MAX_PAGES * _OnePageLinesCount) { | ||||
|             _WinBoLLNewsBeanList.remove(_WinBoLLNewsBeanList.size() - 1); | ||||
|         } | ||||
|         WinBoLLNewsBean.saveBeanList(context, _WinBoLLNewsBeanList, WinBoLLNewsBean.class); | ||||
|     } | ||||
|  | ||||
|     synchronized static void initWinBoLLNewsBeanList(Context context) { | ||||
|         if (_WinBoLLNewsBeanList == null) { | ||||
|             _WinBoLLNewsBeanList = new ArrayList<WinBoLLNewsBean>(); | ||||
|             WinBoLLNewsBean.loadBeanList(context, _WinBoLLNewsBeanList, WinBoLLNewsBean.class); | ||||
|         } | ||||
|         if (_WinBoLLNewsBeanList == null) { | ||||
|             _WinBoLLNewsBeanList = new ArrayList<WinBoLLNewsBean>(); | ||||
|             WinBoLLNewsBean.saveBeanList(context, _WinBoLLNewsBeanList, WinBoLLNewsBean.class); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { | ||||
|         LogUtils.d(TAG, "updateAppWidget(...)"); | ||||
|  | ||||
|         RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_news); | ||||
|         //设置按钮点击事件 | ||||
|         Intent intentPre = new Intent(context, APPNewsWidgetClickListener.class); | ||||
|         intentPre.setAction(APPNewsWidgetClickListener.ACTION_PRE); | ||||
|         PendingIntent pendingIntentPre = PendingIntent.getBroadcast(context, 0, intentPre, PendingIntent.FLAG_UPDATE_CURRENT); | ||||
|         views.setOnClickPendingIntent(R.id.widget_button_pre, pendingIntentPre); | ||||
|         Intent intentNext = new Intent(context, APPNewsWidgetClickListener.class); | ||||
|         intentNext.setAction(APPNewsWidgetClickListener.ACTION_NEXT); | ||||
|         PendingIntent pendingIntentNext = PendingIntent.getBroadcast(context, 0, intentNext, PendingIntent.FLAG_UPDATE_CURRENT); | ||||
|         views.setOnClickPendingIntent(R.id.widget_button_next, pendingIntentNext); | ||||
|  | ||||
|         views.setTextViewText(R.id.tv_msg, getPageInfo()); | ||||
|         views.setTextViewText(R.id.tv_news, getMessage()); | ||||
|         appWidgetManager.updateAppWidget(appWidgetId, views); | ||||
|     } | ||||
|  | ||||
|     public static String getMessage() { | ||||
|         ArrayList<String> msgTemp = new ArrayList<String>(); | ||||
|         if (_WinBoLLNewsBeanList != null) { | ||||
|             int start = _OnePageLinesCount * _CurrentPageIndex; | ||||
|             start = _WinBoLLNewsBeanList.size() > start ? start : _WinBoLLNewsBeanList.size() - 1; | ||||
|             for (int i = start, j = 0; i < _WinBoLLNewsBeanList.size() && j < _OnePageLinesCount && start > -1; i++, j++) { | ||||
|                 msgTemp.add(_WinBoLLNewsBeanList.get(i).getMessage()); | ||||
|             } | ||||
|             String message = String.join("\n", msgTemp); | ||||
|             return message; | ||||
|         } | ||||
|         return ""; | ||||
|     } | ||||
|  | ||||
|     public static void prePage(Context context) { | ||||
|         if (_WinBoLLNewsBeanList != null) { | ||||
|             if (_CurrentPageIndex > 0) { | ||||
|                 _CurrentPageIndex = _CurrentPageIndex - 1; | ||||
|             } | ||||
|             Intent intentWidget = new Intent(context, APPNewsWidget.class); | ||||
|             intentWidget.setAction(APPNewsWidget.ACTION_RELOAD_REPORT); | ||||
|             context.sendBroadcast(intentWidget); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void nextPage(Context context) { | ||||
|         if (_WinBoLLNewsBeanList != null) { | ||||
|             if ((_CurrentPageIndex + 1) * _OnePageLinesCount < _WinBoLLNewsBeanList.size()) { | ||||
|                 _CurrentPageIndex = _CurrentPageIndex + 1; | ||||
|             } | ||||
|             Intent intentWidget = new Intent(context, APPNewsWidget.class); | ||||
|             intentWidget.setAction(APPNewsWidget.ACTION_RELOAD_REPORT); | ||||
|             context.sendBroadcast(intentWidget); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     String getPageInfo() { | ||||
|         if (_WinBoLLNewsBeanList == null) { | ||||
|             return "0/0"; | ||||
|         } | ||||
|         int leftCount = _WinBoLLNewsBeanList.size() % _OnePageLinesCount; | ||||
|         int currentPageCount = _WinBoLLNewsBeanList.size() / _OnePageLinesCount + (leftCount == 0 ?0: 1); | ||||
|         return String.format("%d/%d", _CurrentPageIndex + 1, currentPageCount); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										7
									
								
								appbase/src/main/res/drawable/btn_light_blue.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								appbase/src/main/res/drawable/btn_light_blue.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <shape xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:shape="rectangle"> | ||||
|     <solid android:color="#81C7F5"/> <!-- 浅蓝色填充 --> | ||||
|     <corners android:radius="8dp"/> <!-- 8dp 圆角 --> | ||||
| </shape> | ||||
|  | ||||
| @@ -1,11 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportHeight="24" | ||||
|     android:viewportWidth="24"> | ||||
|     <path | ||||
|         android:fillColor="#ff000000" | ||||
|         android:pathData="M6.5,20Q4.22,20 2.61,18.43 1,16.85 1,14.58 1,12.63 2.17,11.1 3.35,9.57 5.25,9.15 5.88,6.85 7.75,5.43 9.63,4 12,4 14.93,4 16.96,6.04 19,8.07 19,11 20.73,11.2 21.86,12.5 23,13.78 23,15.5 23,17.38 21.69,18.69 20.38,20 18.5,20Z"/> | ||||
|  | ||||
| </vector> | ||||
| @@ -1,11 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportHeight="24" | ||||
|     android:viewportWidth="24"> | ||||
|     <path | ||||
|         android:fillColor="#ff000000" | ||||
|         android:pathData="M6.5,20Q4.22,20 2.61,18.43 1,16.85 1,14.58 1,12.63 2.17,11.1 3.35,9.57 5.25,9.15 5.88,6.85 7.75,5.43 9.63,4 12,4 14.93,4 16.96,6.04 19,8.07 19,11 20.73,11.2 21.86,12.5 23,13.78 23,15.5 23,17.38 21.69,18.69 20.38,20 18.5,20M6.5,18H18.5Q19.55,18 20.27,17.27 21,16.55 21,15.5 21,14.45 20.27,13.73 19.55,13 18.5,13H17V11Q17,8.93 15.54,7.46 14.08,6 12,6 9.93,6 8.46,7.46 7,8.93 7,11H6.5Q5.05,11 4.03,12.03 3,13.05 3,14.5 3,15.95 4.03,17 5.05,18 6.5,18M12,12Z"/> | ||||
|  | ||||
| </vector> | ||||
| @@ -3,219 +3,45 @@ | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent"> | ||||
| 	android:layout_height="match_parent" | ||||
| 	android:padding="16dp"> | ||||
|  | ||||
| 	<android.widget.Toolbar | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:id="@+id/toolbar"/> | ||||
|  | ||||
| 	<ScrollView | ||||
| 	<LinearLayout | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:layout_weight="1.0"> | ||||
| 		android:layout_weight="1" | ||||
| 		android:orientation="vertical" | ||||
| 		android:gravity="center_vertical" | ||||
| 		android:spacing="12dp"> | ||||
|  | ||||
| 		<LinearLayout | ||||
| 			xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 		<Button | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:orientation="vertical" | ||||
| 			android:gravity="center"> | ||||
| 			android:text="应用崩溃测试" | ||||
| 			android:textSize="16sp" | ||||
| 			android:textColor="@android:color/white" | ||||
| 			android:background="#81C7F5" | ||||
| 			android:paddingVertical="12dp" | ||||
| 			android:layout_marginHorizontal="24dp" | ||||
| 			android:onClick="onCrashTest"/> | ||||
|  | ||||
| 			<LinearLayout | ||||
| 				android:orientation="vertical" | ||||
| 				android:layout_width="match_parent" | ||||
| 				android:layout_height="0dp" | ||||
| 				android:layout_weight="1.0" | ||||
| 				android:gravity="center_horizontal"> | ||||
| 		<Button | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="应用日志测试" | ||||
| 			android:textSize="16sp" | ||||
| 			android:textColor="@android:color/white" | ||||
| 			android:background="#81C7F5" | ||||
| 			android:paddingVertical="12dp" | ||||
| 			android:layout_marginHorizontal="24dp" | ||||
| 			android:onClick="onLogTest"/> | ||||
|  | ||||
| 				<TextView | ||||
| 					android:layout_width="wrap_content" | ||||
| 					android:layout_height="wrap_content" | ||||
| 					android:text="安卓R对应的是Android 11,其API级别是30。以下是Android 11中一些重要的API相关特性: | ||||
| 	</LinearLayout> | ||||
|  | ||||
|                     \n- 隐私保护方面:引入单次授权,让用户可以选择授予应用对位置信息、麦克风和摄像头的临时访问权限。还增加了数据访问审核功能,能让开发者深入了解应用在何处访问私密数据。 | ||||
|                      | ||||
|                     \n- 系统功能方面:提供了ControlsProviderService API,用于向连接的外部设备提供控件,这些控件显示于Android电源菜单中的设备控件下。媒体控件也得到更新,显示于快捷设置旁,来自多个应用的会话排列在一个可滑动的轮播界面中。 | ||||
|                      | ||||
|                     \n- 硬件支持方面:提供了一些API以支持瀑布屏,通过将窗口布局属性  layoutInDisplayCutoutMode  设为  LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS ,可允许窗口延伸到屏幕各个边缘上的刘海和瀑布区域。对于合页式屏幕配置的设备,提供了具有  TYPE_HINGE_ANGLE  的新传感器以及新的  SensorEvent ,用于监控合页角度。 | ||||
|                      | ||||
|                     \n- 安全方面:对生物识别身份验证机制进行了更新,引入了  BiometricManager.Authenticators  接口,定义了  BIOMETRIC_STRONG 、 BIOMETRIC_WEAK 、 DEVICE_CREDENTIAL  等身份验证类型。还在  BiometricPrompt  类中提供了对“每次使用时进行身份验证”密钥的更多支持。 | ||||
|                      | ||||
|                     \n- 性能和质量方面:支持无线调试,通过Android调试桥(adb)从工作站以无线方式部署和调试应用,避免了常见的USB连接问题。"/> | ||||
|                  | ||||
|                      | ||||
| 				<HorizontalScrollView | ||||
| 					android:layout_width="match_parent" | ||||
| 					android:layout_height="wrap_content"> | ||||
|  | ||||
| 					<LinearLayout | ||||
| 						android:orientation="horizontal" | ||||
| 						android:layout_height="wrap_content" | ||||
| 						android:gravity="right|center_vertical" | ||||
| 						android:layout_width="wrap_content"> | ||||
|  | ||||
| 						<CheckBox | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:text="Debug Mode" | ||||
| 							android:layout_weight="1.0" | ||||
| 							android:onClick="onSwitchDebugMode" | ||||
| 							android:id="@+id/activitymainCheckBox1"/> | ||||
|  | ||||
| 						<Button | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:text="Test Application CrashReport" | ||||
| 							android:textAllCaps="false" | ||||
| 							android:onClick="onTestApplicationCrashReport"/> | ||||
|  | ||||
| 						<Button | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:text="PreviewGlobalCrashActivity" | ||||
| 							android:textAllCaps="false" | ||||
| 							android:onClick="onPreviewGlobalCrashActivity"/> | ||||
|  | ||||
| 					</LinearLayout> | ||||
|  | ||||
| 				</HorizontalScrollView> | ||||
|  | ||||
| 				<ScrollView | ||||
| 					android:layout_width="match_parent" | ||||
| 					android:layout_height="400dp"> | ||||
|  | ||||
| 					<LinearLayout | ||||
| 						android:orientation="vertical" | ||||
| 						android:layout_width="match_parent" | ||||
| 						android:layout_height="wrap_content" | ||||
| 						android:gravity="right"> | ||||
|  | ||||
| 						<LinearLayout | ||||
| 							android:orientation="horizontal" | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content"> | ||||
|  | ||||
| 							<Button | ||||
| 								android:layout_width="wrap_content" | ||||
| 								android:layout_height="wrap_content" | ||||
| 								android:text="StartCenter" | ||||
| 								android:textAllCaps="false" | ||||
| 								android:onClick="onStartCenter"/> | ||||
|  | ||||
| 							<Button | ||||
| 								android:layout_width="wrap_content" | ||||
| 								android:layout_height="wrap_content" | ||||
| 								android:text="StopCenter" | ||||
| 								android:textAllCaps="false" | ||||
| 								android:onClick="onStopCenter"/> | ||||
|  | ||||
| 						</LinearLayout> | ||||
|  | ||||
| 						<HorizontalScrollView | ||||
| 							android:layout_width="match_parent" | ||||
| 							android:layout_height="wrap_content"> | ||||
|  | ||||
| 							<LinearLayout | ||||
| 								android:orientation="horizontal" | ||||
| 								android:layout_width="wrap_content" | ||||
| 								android:layout_height="wrap_content"> | ||||
|  | ||||
| 								<Button | ||||
| 									android:layout_width="wrap_content" | ||||
| 									android:layout_height="wrap_content" | ||||
| 									android:text="SartTestDemoService" | ||||
| 									android:textAllCaps="false" | ||||
| 									android:onClick="onSartTestDemoService"/> | ||||
|  | ||||
| 								<Button | ||||
| 									android:layout_width="wrap_content" | ||||
| 									android:layout_height="wrap_content" | ||||
| 									android:text="StopTestDemoService" | ||||
| 									android:textAllCaps="false" | ||||
| 									android:onClick="onStopTestDemoService"/> | ||||
|  | ||||
| 								<Button | ||||
| 									android:layout_width="wrap_content" | ||||
| 									android:layout_height="wrap_content" | ||||
| 									android:text="StopTestDemoServiceNoSettings" | ||||
| 									android:textAllCaps="false" | ||||
| 									android:onClick="onStopTestDemoServiceNoSettings"/> | ||||
|  | ||||
| 							</LinearLayout> | ||||
|  | ||||
| 						</HorizontalScrollView> | ||||
|  | ||||
| 						<HorizontalScrollView | ||||
| 							android:layout_width="match_parent" | ||||
| 							android:layout_height="wrap_content"> | ||||
|  | ||||
| 							<LinearLayout | ||||
| 								android:orientation="horizontal" | ||||
| 								android:layout_width="wrap_content" | ||||
| 								android:layout_height="wrap_content"> | ||||
|  | ||||
| 								<Button | ||||
| 									android:layout_width="wrap_content" | ||||
| 									android:layout_height="wrap_content" | ||||
| 									android:text="SartTestDemoBindService" | ||||
| 									android:textAllCaps="false" | ||||
| 									android:onClick="onSartTestDemoBindService"/> | ||||
|  | ||||
| 								<Button | ||||
| 									android:layout_width="wrap_content" | ||||
| 									android:layout_height="wrap_content" | ||||
| 									android:text="StopTestDemoBindService" | ||||
| 									android:textAllCaps="false" | ||||
| 									android:onClick="onStopTestDemoBindService"/> | ||||
|  | ||||
| 								<Button | ||||
| 									android:layout_width="wrap_content" | ||||
| 									android:layout_height="wrap_content" | ||||
| 									android:text="StopTestDemoBindServiceNoSettings" | ||||
| 									android:textAllCaps="false" | ||||
| 									android:onClick="onStopTestDemoBindServiceNoSettings"/> | ||||
|  | ||||
| 							</LinearLayout> | ||||
|  | ||||
| 						</HorizontalScrollView> | ||||
|  | ||||
| 						<Button | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:text="TestStopMainServiceWithoutSettingEnable" | ||||
| 							android:textAllCaps="false" | ||||
| 							android:onClick="onTestStopMainServiceWithoutSettingEnable"/> | ||||
|  | ||||
| 						<Button | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:text="TestUseComponentStartService" | ||||
| 							android:textAllCaps="false" | ||||
| 							android:onClick="onTestUseComponentStartService"/> | ||||
|  | ||||
| 						<Button | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:text="TestDemoServiceSOS" | ||||
| 							android:textAllCaps="false" | ||||
| 							android:onClick="onTestDemoServiceSOS"/> | ||||
|  | ||||
| 						<Button | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:text="TestOpenNewActivity" | ||||
| 							android:textAllCaps="false" | ||||
| 							android:onClick="onTestOpenNewActivity"/> | ||||
|  | ||||
| 					</LinearLayout> | ||||
|  | ||||
| 				</ScrollView> | ||||
|  | ||||
| 			</LinearLayout> | ||||
|  | ||||
| 		</LinearLayout> | ||||
|  | ||||
| 	</ScrollView> | ||||
| </LinearLayout> | ||||
|  | ||||
|   | ||||
| @@ -1,43 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent"> | ||||
|  | ||||
|     <android.widget.Toolbar | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
| 		android:id="@+id/toolbar"/> | ||||
|      | ||||
| 	<TextView | ||||
| 		android:layout_width="wrap_content" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:text="NewActivity"/> | ||||
|  | ||||
|     <Button | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:text="CloseThisActivity" | ||||
|         android:textAllCaps="false" | ||||
|         android:onClick="onCloseThisActivity"/> | ||||
|  | ||||
|     <Button | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:text="CloseAllActivity" | ||||
|         android:textAllCaps="false" | ||||
|         android:onClick="onCloseAllActivity"/> | ||||
|  | ||||
|     <Button | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:text="New2Activity" | ||||
|         android:textAllCaps="false" | ||||
|         android:onClick="onNew2Activity"/> | ||||
|  | ||||
|      | ||||
|      | ||||
| </LinearLayout> | ||||
|  | ||||
| @@ -1,43 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent"> | ||||
|  | ||||
|     <android.widget.Toolbar | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
| 		android:id="@+id/toolbar"/> | ||||
|  | ||||
| 	<TextView | ||||
| 		android:layout_width="wrap_content" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:text="New2Activity"/> | ||||
|  | ||||
| 	<Button | ||||
| 		android:layout_width="wrap_content" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:text="CloseThisActivity" | ||||
| 		android:textAllCaps="false" | ||||
| 		android:onClick="onCloseThisActivity"/> | ||||
|  | ||||
| 	<Button | ||||
| 		android:layout_width="wrap_content" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:text="CloseAllActivity" | ||||
| 		android:textAllCaps="false" | ||||
| 		android:onClick="onCloseAllActivity"/> | ||||
|  | ||||
| 	<Button | ||||
| 		android:layout_width="wrap_content" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:text="NewActivity" | ||||
| 		android:textAllCaps="false" | ||||
| 		android:onClick="onNewActivity"/> | ||||
|  | ||||
| 	 | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
| @@ -1,51 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent" | ||||
| 	android:orientation="vertical" | ||||
| 	android:background="#FFFFFFFF"> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="horizontal" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:gravity="right|center_vertical"> | ||||
|  | ||||
| 		<TextView | ||||
| 			android:layout_width="0dp" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:id="@+id/tv_title" | ||||
| 			android:layout_weight="1.0" | ||||
| 			android:text="WinBoLLNews" | ||||
| 			android:textStyle="bold" | ||||
| 			android:textSize="16sp"/> | ||||
|  | ||||
| 		<Button | ||||
| 			android:layout_width="48dp" | ||||
| 			android:layout_height="48dp" | ||||
| 			android:text="⇦" | ||||
| 			android:id="@+id/widget_button_pre"/> | ||||
|  | ||||
| 		<Button | ||||
| 			android:layout_width="48dp" | ||||
| 			android:layout_height="48dp" | ||||
| 			android:text="⇨" | ||||
| 			android:id="@+id/widget_button_next"/> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
|     <TextView | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:id="@+id/tv_msg"/> | ||||
|      | ||||
| 	<TextView | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:id="@+id/tv_news" | ||||
| 		android:layout_weight="1.0"/> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
| @@ -3,18 +3,6 @@ | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto"> | ||||
|     <item | ||||
|         android:id="@+id/item_home" | ||||
|         android:title="HOME" | ||||
|         android:title="WinBoLL Home" | ||||
|         android:icon="@drawable/ic_winboll"/> | ||||
|     <item | ||||
|         android:id="@+id/item_yun" | ||||
|         android:title="YUN" | ||||
|         android:icon="@drawable/ic_winboll"/> | ||||
|     <item | ||||
|         android:id="@+id/item_logon" | ||||
|         android:title="Logon" | ||||
|         android:icon="@drawable/ic_winboll"/> | ||||
|     <item | ||||
|         android:id="@+id/item_log" | ||||
|         android:title="LOG" | ||||
|         android:icon="@drawable/ic_winboll_log"/> | ||||
| </menu> | ||||
|   | ||||
| @@ -1,12 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <network-security-config> | ||||
|     <!-- 允许访问 winboll.cc 及其子域名(原配置) --> | ||||
|     <domain-config cleartextTrafficPermitted="true"> | ||||
|         <domain includeSubdomains="true">winboll.cc</domain> | ||||
|     </domain-config> | ||||
|  | ||||
|     <!-- **新增:允许访问 IP 地址 10.8.0.250** --> | ||||
|     <domain-config cleartextTrafficPermitted="true"> | ||||
|         <domain includeSubdomains="false">10.8.0.250</domain> <!-- 不包含子域名 --> | ||||
|     </domain-config> | ||||
| </network-security-config> | ||||
| @@ -1,7 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:minWidth="200dp" | ||||
|     android:minHeight="100dp" | ||||
|     android:updatePeriodMillis="1000" | ||||
|     android:initialLayout="@layout/widget_news"> | ||||
| </appwidget-provider> | ||||
| @@ -1,8 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Tue Jun 24 09:54:47 HKT 2025 | ||||
| stageCount=3 | ||||
| #Sun Sep 28 12:44:55 HKT 2025 | ||||
| stageCount=4 | ||||
| libraryProject= | ||||
| baseVersion=15.2 | ||||
| publishVersion=15.2.2 | ||||
| publishVersion=15.2.3 | ||||
| buildCount=0 | ||||
| baseBetaVersion=15.2.3 | ||||
| baseBetaVersion=15.2.4 | ||||
|   | ||||
							
								
								
									
										1
									
								
								keystore
									
									
									
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								keystore
									
									
									
									
									
								
							 Submodule keystore deleted from e7f70226c1
									
								
							| @@ -1,8 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Mon Aug 18 03:56:26 HKT 2025 | ||||
| stageCount=6 | ||||
| #Sat Sep 27 21:03:08 HKT 2025 | ||||
| stageCount=10 | ||||
| libraryProject=libappbase | ||||
| baseVersion=15.9 | ||||
| publishVersion=15.9.5 | ||||
| baseVersion=15.10 | ||||
| publishVersion=15.10.9 | ||||
| buildCount=0 | ||||
| baseBetaVersion=15.9.6 | ||||
| baseBetaVersion=15.10.10 | ||||
|   | ||||
| @@ -3,15 +3,6 @@ | ||||
|     xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     package="cc.winboll.studio.libappbase"> | ||||
|  | ||||
|     <!-- 拥有完全的网络访问权限 --> | ||||
|     <uses-permission android:name="android.permission.INTERNET"/> | ||||
|  | ||||
|     <!-- 发送持久广播 --> | ||||
|     <uses-permission android:name="android.permission.BROADCAST_STICKY"/> | ||||
|  | ||||
|     <!-- 对正在运行的应用重新排序 --> | ||||
|     <uses-permission android:name="android.permission.REORDER_TASKS"/> | ||||
|  | ||||
|     <application> | ||||
|  | ||||
|         <activity | ||||
| @@ -27,7 +18,7 @@ | ||||
|             android:process=":GlobalCrashActivity"/> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".winboll.LogActivity" | ||||
|             android:name=".LogActivity" | ||||
|             android:label="LogActivity" | ||||
|             android:resizeableActivity="true" | ||||
|             android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" | ||||
| @@ -37,76 +28,6 @@ | ||||
|  | ||||
|         </activity> | ||||
|  | ||||
|         <service | ||||
|             android:name=".SimpleOperateSignalCenterService" | ||||
|             android:exported="true"> | ||||
|  | ||||
|         </service> | ||||
|  | ||||
|         <service | ||||
|             android:name=".services.TestService" | ||||
|             android:exported="true"/> | ||||
|  | ||||
|         <receiver | ||||
|             android:name=".receiver.MyBroadcastReceiver" | ||||
|             android:exported="true"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="cc.winboll.studio.libappbase.action.SOS"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </receiver> | ||||
|  | ||||
|         <receiver | ||||
|             android:name=".widgets.StatusWidget" | ||||
|             android:exported="true"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> | ||||
|  | ||||
|                 <action android:name="cc.winboll.studio.libappbase.widgets.StatusWidget.ACTION_STATUS_UPDATE"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|             <meta-data | ||||
|                 android:name="android.appwidget.provider" | ||||
|                 android:resource="@xml/widget_provider_info_status"/> | ||||
|  | ||||
|         </receiver> | ||||
|  | ||||
|         <receiver | ||||
|             android:name=".widgets.StatusWidgetClickListener" | ||||
|             android:exported="true"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="cc.winboll.studio.libappbase.widgets.StatusWidgetClickListener.ACTION_IVAPP"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </receiver> | ||||
|  | ||||
|         <service android:name="cc.winboll.studio.libappbase.sos.SOSCenter"/> | ||||
|  | ||||
|         <receiver | ||||
|             android:name="cc.winboll.studio.libappbase.sos.SOSCenterServiceReceiver" | ||||
|             android:exported="true"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="cc.winboll.studio.libappbase.sos.SOSCenterServiceReceiver"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </receiver> | ||||
|  | ||||
|         <activity android:name="cc.winboll.studio.libappbase.activities.YunActivity"/> | ||||
|  | ||||
|         <activity android:name="cc.winboll.studio.libappbase.activities.LogonActivity"/> | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| package cc.winboll.studio.libappbase.models; | ||||
| package cc.winboll.studio.libappbase; | ||||
| 
 | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
| @@ -1,28 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/15 20:05:03 | ||||
|  * @Describe AppUtils | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.content.pm.ApplicationInfo; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.content.pm.PackageManager.NameNotFoundException; | ||||
|  | ||||
| public class AppUtils { | ||||
|      | ||||
|     public static final String TAG = "AppUtils"; | ||||
|      | ||||
|     public static String getAppNameByPackageName(Context context, String packageName) { | ||||
|         PackageManager packageManager = context.getPackageManager(); | ||||
|         try { | ||||
|             ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName, 0); | ||||
|             return (String) packageManager.getApplicationLabel(applicationInfo); | ||||
|         } catch (NameNotFoundException e) { | ||||
|             LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|             return ""; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -10,88 +10,53 @@ import android.content.Context; | ||||
| import android.content.pm.ApplicationInfo; | ||||
| import android.content.pm.PackageManager; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import cc.winboll.studio.libappbase.models.APPModel; | ||||
| import cc.winboll.studio.libappbase.utils.ToastUtils; | ||||
| import cc.winboll.studio.libappbase.winboll.MyActivityLifecycleCallbacks; | ||||
| import cc.winboll.studio.libappbase.winboll.WinBoLLActivityManager; | ||||
|  | ||||
| public class GlobalApplication extends Application { | ||||
|  | ||||
|     public static final String TAG = "GlobalApplication"; | ||||
|  | ||||
|     volatile static GlobalApplication _GlobalApplication; | ||||
|     // 是否处于调试状态 | ||||
| 	 | ||||
|     // 应用是否处于调试状态 | ||||
|     volatile static boolean isDebuging = false; | ||||
|     MyActivityLifecycleCallbacks mMyActivityLifecycleCallbacks; | ||||
|  | ||||
|      | ||||
|     public static void setIsDebuging(boolean isDebuging) { | ||||
|         GlobalApplication.isDebuging = isDebuging; | ||||
|     } | ||||
|      | ||||
|     public static void saveDebugStatus() { | ||||
|         if (_GlobalApplication != null) { | ||||
|             APPModel.saveBeanToFile(getAPPModelFilePath(), new APPModel(GlobalApplication.isDebuging)); | ||||
|         } | ||||
|     public static void saveDebugStatus(Context context) { | ||||
|         APPModel.saveBeanToFile(getAPPModelFilePath(context), new APPModel(GlobalApplication.isDebuging)); | ||||
|     } | ||||
|  | ||||
|     public static GlobalApplication getInstance() { | ||||
|         return _GlobalApplication; | ||||
|     } | ||||
|  | ||||
|     static String getAPPModelFilePath() { | ||||
|         return _GlobalApplication.getDataDir().getPath() + "/APPModel.json"; | ||||
| 	 | ||||
|     static String getAPPModelFilePath(Context context) { | ||||
|         return context.getDataDir().getPath() + "/APPModel.json"; | ||||
|     } | ||||
|  | ||||
|     public static boolean isDebuging() { | ||||
|         return isDebuging; | ||||
|     } | ||||
|  | ||||
|     public static WinBoLLActivityManager getWinBoLLActivityManager() { | ||||
|         return WinBoLLActivityManager.getInstance(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         // 保存初始实例 | ||||
|         _GlobalApplication = this; | ||||
|          | ||||
| 		 | ||||
|         setIsDebuging(true); | ||||
|         // 添加日志模块 | ||||
|         LogUtils.init(this); | ||||
|         //LogUtils.setLogLevel(LogUtils.LOG_LEVEL.Debug); | ||||
|         //LogUtils.setTAGListEnable(GlobalApplication.TAG, true); | ||||
|         //LogUtils.setALlTAGListEnable(true); | ||||
|         //LogUtils.d(TAG, "LogUtils init"); | ||||
|         // 设置应用异常处理窗口 | ||||
|         CrashHandler.init(this); | ||||
|         // 初始化 Toast 框架 | ||||
|         ToastUtils.init(this); | ||||
|  | ||||
|         // 应用保存的调试标志 | ||||
|         APPModel appModel = APPModel.loadBeanFromFile(getAPPModelFilePath(), APPModel.class); | ||||
|         APPModel appModel = APPModel.loadBeanFromFile(getAPPModelFilePath(this), APPModel.class); | ||||
|         if (appModel == null) { | ||||
|             setIsDebuging(false); | ||||
|             saveDebugStatus(); | ||||
|             saveDebugStatus(this); | ||||
|         } else { | ||||
|             setIsDebuging(appModel.isDebuging()); | ||||
|         } | ||||
|          | ||||
|         getWinBoLLActivityManager().setWinBoLLUI_TYPE(WinBoLLActivityManager.WinBoLLUI_TYPE.Service); | ||||
|         // 注册窗口回调监听 | ||||
|         mMyActivityLifecycleCallbacks = new MyActivityLifecycleCallbacks(); | ||||
|         registerActivityLifecycleCallbacks(mMyActivityLifecycleCallbacks); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     public void onTerminate() { | ||||
|         super.onTerminate(); | ||||
|         // 注销回调(非必须,但建议释放资源) | ||||
|         unregisterActivityLifecycleCallbacks(mMyActivityLifecycleCallbacks); | ||||
|     } | ||||
|  | ||||
|     public static String getAppName(Context context) { | ||||
| 	 | ||||
| 	public static String getAppName(Context context) { | ||||
|         PackageManager packageManager = context.getPackageManager(); | ||||
|         try { | ||||
|             ApplicationInfo applicationInfo = packageManager.getApplicationInfo( | ||||
| @@ -102,27 +67,4 @@ public class GlobalApplication extends Application { | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| // | ||||
| //    @Override | ||||
| //    public void helpISOSService(Intent intent) { | ||||
| //        String szServiceName = intent.getStringExtra(EXTRA_SERVICE); | ||||
| //        String szPackageName = intent.getStringExtra(EXTRA_PACKAGE); | ||||
| //        if (szServiceName != null && !szServiceName.equals("") | ||||
| //            && szPackageName != null && !szPackageName.equals("")) { | ||||
| //            LogUtils.d(TAG, "szPackageName " + szPackageName); | ||||
| //            LogUtils.d(TAG, "szServiceName " + szServiceName); | ||||
| // | ||||
| //            // 目标服务的包名和类名 | ||||
| //            //String packageName = this.getPackageName(); | ||||
| //            //String serviceClassName = SimpleOperateSignalCenterService.class.getName(); | ||||
| // | ||||
| //            // 构建Intent | ||||
| //            Intent intentService = new Intent(); | ||||
| //            intentService.setComponent(new ComponentName(szPackageName, szServiceName)); | ||||
| //            intentService.putExtra(ISOSService.EXTRA_ENABLE, true); | ||||
| //            startService(intentService); | ||||
| //            LogUtils.d(TAG, "startService(intentService)"); | ||||
| //        } | ||||
| //        LogUtils.d(TAG, "helpISOSService"); | ||||
| //    } | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| package cc.winboll.studio.libappbase.views; | ||||
| package cc.winboll.studio.libappbase; | ||||
| 
 | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
| @@ -1,4 +1,4 @@ | ||||
| package cc.winboll.studio.libappbase.winboll; | ||||
| package cc.winboll.studio.libappbase; | ||||
| 
 | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
| @@ -6,29 +6,18 @@ package cc.winboll.studio.libappbase.winboll; | ||||
|  * @Describe 应用日志窗口 | ||||
|  */ | ||||
| import android.app.Activity; | ||||
| import android.os.Build; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
| import android.view.WindowManager; | ||||
| import cc.winboll.studio.libappbase.LogView; | ||||
| import cc.winboll.studio.libappbase.R; | ||||
| import cc.winboll.studio.libappbase.utils.ToastUtils; | ||||
| 
 | ||||
| public class LogActivity extends Activity implements IWinBoLLActivity { | ||||
| public class LogActivity extends Activity { | ||||
| 
 | ||||
|     public static final String TAG = "LogActivity"; | ||||
| 
 | ||||
|     LogView mLogView; | ||||
| 
 | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
| @@ -45,4 +34,13 @@ public class LogActivity extends Activity implements IWinBoLLActivity { | ||||
|         mLogView.start(); | ||||
|     } | ||||
| 
 | ||||
| 	public static void startLogActivity(Context context) { | ||||
| 		Intent intent = new Intent(context, LogActivity.class); | ||||
|         // 打开多任务窗口 | ||||
|         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); | ||||
|         context.startActivity(intent); | ||||
| 	} | ||||
| } | ||||
| @@ -28,7 +28,6 @@ import android.widget.Spinner; | ||||
| import android.widget.TextView; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.R; | ||||
| import cc.winboll.studio.libappbase.views.HorizontalListView; | ||||
| import java.text.Collator; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| package cc.winboll.studio.libappbase.utils; | ||||
| import android.content.Context; | ||||
| import android.widget.Toast; | ||||
| package cc.winboll.studio.libappbase; | ||||
| 
 | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/03/12 12:02:31 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.widget.Toast; | ||||
| 
 | ||||
| public class ToastUtils { | ||||
| 
 | ||||
|     public static final String TAG = "ToastUtils"; | ||||
| @@ -1,150 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.activities; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.os.Bundle; | ||||
| import android.view.View; | ||||
| import android.widget.RadioButton; | ||||
| import cc.winboll.studio.libappbase.BuildConfig; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.LogView; | ||||
| import cc.winboll.studio.libappbase.R; | ||||
| import cc.winboll.studio.libappbase.models.UserInfoModel; | ||||
| import cc.winboll.studio.libappbase.utils.RSAUtils; | ||||
| import cc.winboll.studio.libappbase.utils.YunUtils; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; | ||||
| import java.security.KeyPair; | ||||
| import java.security.PrivateKey; | ||||
| import java.security.PublicKey; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/06/04 13:29 | ||||
|  * @Describe 用户登录框 | ||||
|  */ | ||||
| public class LogonActivity extends Activity implements IWinBoLLActivity { | ||||
|  | ||||
|     public static final String TAG = "LogonActivity"; | ||||
|  | ||||
|     public static final String DEBUG_HOST = "http://10.8.0.250:456"; | ||||
|     public static final String YUN_HOST = "https://yun.winboll.cc"; | ||||
|      | ||||
|      | ||||
|     String mHost = ""; | ||||
|     RadioButton mrbYunHost; | ||||
|     RadioButton mrbDebugHost; | ||||
|     LogView mLogView; | ||||
|      | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_logon); | ||||
|         mLogView = findViewById(R.id.logview); | ||||
|         mLogView.start(); | ||||
|  | ||||
|         mHost = BuildConfig.DEBUG ? DEBUG_HOST: YUN_HOST; | ||||
|         if (BuildConfig.DEBUG) { | ||||
|             mrbYunHost = findViewById(R.id.rb_yunhost); | ||||
|             mrbDebugHost = findViewById(R.id.rb_debughost); | ||||
|             mrbYunHost.setChecked(!BuildConfig.DEBUG); | ||||
|             mrbDebugHost.setChecked(BuildConfig.DEBUG); | ||||
|         } else { | ||||
|             findViewById(R.id.ll_hostbar).setVisibility(View.GONE); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     public void onSwitchHost(View view) { | ||||
|         if (view.getId() == R.id.rb_yunhost) { | ||||
|             mrbDebugHost.setChecked(false); | ||||
|             mHost = YUN_HOST; | ||||
|         } else if (view.getId() == R.id.rb_debughost) { | ||||
|             mrbYunHost.setChecked(false); | ||||
|             mHost = DEBUG_HOST; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onResume() { | ||||
|         super.onResume(); | ||||
|         mLogView.start(); | ||||
|     } | ||||
|  | ||||
|     public void onTestLogin(View view) { | ||||
|         LogUtils.d(TAG, "onTestLogin"); | ||||
|         final YunUtils yunUtils = YunUtils.getInstance(this); | ||||
|          | ||||
|         UserInfoModel userInfoModel = new UserInfoModel(); | ||||
|         userInfoModel.setUsername("jian"); | ||||
|         userInfoModel.setPassword("kkiio"); | ||||
|         userInfoModel.setToken("aaa111"); | ||||
|         yunUtils.login(mHost, userInfoModel); | ||||
|     } | ||||
|  | ||||
|     public void onTestRSA(View view) { | ||||
|         LogUtils.d(TAG, "onTestRSA"); | ||||
|         RSAUtils utils = RSAUtils.getInstance(this); | ||||
|          | ||||
|         try { | ||||
|             // 测试 1:首次生成密钥对 | ||||
|             LogUtils.d(TAG, "==== 首次生成密钥对 ===="); | ||||
|             if (utils.keysExist()) { | ||||
|                 LogUtils.d(TAG, "密钥对已生成"); | ||||
|             } else { | ||||
|                 utils.generateAndSaveKeys(); | ||||
|                 LogUtils.d(TAG, "密钥对生成成功。"); | ||||
|             } | ||||
|  | ||||
|             // 测试 2:获取密钥对(自动读取已生成的文件) | ||||
|             KeyPair keyPair = utils.getOrGenerateKeys(); | ||||
|             PublicKey publicKey = keyPair.getPublic(); | ||||
|             PrivateKey privateKey = keyPair.getPrivate(); | ||||
|  | ||||
|             // 打印密钥信息 | ||||
|             LogUtils.d(TAG, "\n==== 密钥信息 ===="); | ||||
|             LogUtils.d(TAG, "公钥算法:" + publicKey.getAlgorithm()); | ||||
|             LogUtils.d(TAG, "公钥编码长度:" + publicKey.getEncoded().length + "字节"); | ||||
|             LogUtils.d(TAG, "私钥算法:" + privateKey.getAlgorithm()); | ||||
|             LogUtils.d(TAG, "私钥编码长度:" + privateKey.getEncoded().length + "字节"); | ||||
|  | ||||
|             // 测试 3:重复调用时检查是否复用文件 | ||||
|             LogUtils.d(TAG, "\n==== 二次调用 ===="); | ||||
|             KeyPair reusedPair = utils.getOrGenerateKeys(); | ||||
|             LogUtils.d(TAG, "是否为同一公钥:" + (publicKey.equals(reusedPair.getPublic()))); // true(单例引用) | ||||
|             LogUtils.d(TAG, "操作完成"); | ||||
|  | ||||
|             String testMessage = "Hello, RSA Encryption!"; | ||||
|  | ||||
|             // 1. 获取或生成密钥对 | ||||
|             PublicKey publicKeyReused = reusedPair.getPublic(); | ||||
|             PrivateKey privateKeyReused = reusedPair.getPrivate(); | ||||
|  | ||||
|             // 2. 公钥加密 | ||||
|             byte[] encryptedData = utils.encryptWithPublicKey(testMessage, publicKeyReused); | ||||
|             LogUtils.d(TAG, "加密后数据(字节长度):" + encryptedData.length); | ||||
|  | ||||
|             // 3. 私钥解密 | ||||
|             String decryptedMessage = utils.decryptWithPrivateKey(encryptedData, privateKeyReused); | ||||
|             LogUtils.d(TAG, "解密结果: " + decryptedMessage); | ||||
|              | ||||
|             // 4. 验证解密是否成功 | ||||
|             if (testMessage.equals(decryptedMessage)) { | ||||
|                 LogUtils.d(TAG, "加密解密测试通过!"); | ||||
|             } else { | ||||
|                 LogUtils.d(TAG, "测试失败:内容不一致"); | ||||
|             } | ||||
|         } catch (Exception e) { | ||||
|             LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|  | ||||
| } | ||||
| @@ -1,126 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.activities; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.os.Bundle; | ||||
| import android.view.View; | ||||
| import cc.winboll.studio.libappbase.BuildConfig; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.R; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; | ||||
| import java.io.IOException; | ||||
| import okhttp3.OkHttpClient; | ||||
| import okhttp3.Request; | ||||
| import okhttp3.Response; | ||||
| import android.widget.RadioButton; | ||||
| import cc.winboll.studio.libappbase.LogView; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/06/04 11:06 | ||||
|  * @Describe 云宝云 | ||||
|  */ | ||||
| public class YunActivity extends Activity implements IWinBoLLActivity { | ||||
|  | ||||
|     public static final String TAG = "YunActivity"; | ||||
|  | ||||
|     public static final String DEBUG_HOST = "http://10.8.0.250:456"; | ||||
|     public static final String YUN_HOST = "https://yun.winboll.cc"; | ||||
|  | ||||
|     String mHost = ""; | ||||
|     RadioButton mrbYunHost; | ||||
|     RadioButton mrbDebugHost; | ||||
|     LogView mLogView; | ||||
|  | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_yun); | ||||
|         mLogView = findViewById(R.id.logview); | ||||
|         mLogView.start(); | ||||
|  | ||||
|         mHost = BuildConfig.DEBUG ? DEBUG_HOST: YUN_HOST; | ||||
|         if (BuildConfig.DEBUG) { | ||||
|             mrbYunHost = findViewById(R.id.rb_yunhost); | ||||
|             mrbDebugHost = findViewById(R.id.rb_debughost); | ||||
|             mrbYunHost.setChecked(!BuildConfig.DEBUG); | ||||
|             mrbDebugHost.setChecked(BuildConfig.DEBUG); | ||||
|         } else { | ||||
|             findViewById(R.id.ll_hostbar).setVisibility(View.GONE); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void onSwitchHost(View view) { | ||||
|         if (view.getId() == R.id.rb_yunhost) { | ||||
|             mrbDebugHost.setChecked(false); | ||||
|             mHost = YUN_HOST; | ||||
|         } else if (view.getId() == R.id.rb_debughost) { | ||||
|             mrbYunHost.setChecked(false); | ||||
|             mHost = DEBUG_HOST; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onResume() { | ||||
|         super.onResume(); | ||||
|         mLogView.start(); | ||||
|     } | ||||
|  | ||||
|     public void onTestYun(View view) { | ||||
|         LogUtils.d(TAG, "onTestYun"); | ||||
|         (new Thread(new Runnable(){ | ||||
|                 @Override | ||||
|                 public void run() { | ||||
|                     testYun(); | ||||
|                 } | ||||
|             })).start(); | ||||
|     } | ||||
|  | ||||
|     void testYun() { | ||||
|         OkHttpClient client = new OkHttpClient(); | ||||
|         Request request = new Request.Builder() | ||||
|             .url(mHost + "/backups/") | ||||
|             .build(); | ||||
|  | ||||
|         Response response = null; | ||||
|         try { | ||||
|             response = client.newCall(request).execute(); | ||||
|             if (response.isSuccessful()) { | ||||
|                 String responseBody = ""; | ||||
|                 if (response.body() != null) { | ||||
|                     responseBody = response.body().string(); | ||||
|                 } | ||||
|  | ||||
|                 // 正则匹配:任意主机名 -> Test OK(主机名部分匹配非空字符) | ||||
|                 boolean isMatch = responseBody.matches(".+? -> Test OK"); | ||||
|  | ||||
|                 if (isMatch) { | ||||
|                     LogUtils.d(TAG, responseBody); | ||||
|                 } else { | ||||
|                     LogUtils.d(TAG, "响应内容不匹配,内容:" + responseBody); | ||||
|                 } | ||||
|             } else { | ||||
|                 LogUtils.d(TAG, "请求失败,状态码:" + response.code()); | ||||
|             } | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, "读取响应体失败:" + e.getMessage()); | ||||
|         } catch (Exception e) { | ||||
|             LogUtils.d(TAG, "异常:" + e.getMessage()); | ||||
|             e.printStackTrace(); // Java 7 需显式打印堆栈 | ||||
|         } finally { | ||||
|             // 手动关闭 Response(Java 7 不支持 try-with-resources) | ||||
|             if (response != null && response.body() != null) { | ||||
|                 response.body().close(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,60 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.dialogs; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @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(); | ||||
|     } | ||||
| } | ||||
| @@ -1,53 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.models; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/06/05 11:26 | ||||
|  */ | ||||
|  | ||||
| public class ResponseData { | ||||
|      | ||||
|     public static final String STATUS_SUCCESS = "success"; | ||||
|     public static final String STATUS_ERROR = "error"; | ||||
|      | ||||
|     private String status; | ||||
|     private String message; | ||||
|     private UserInfoModel data; | ||||
|      | ||||
|     public ResponseData() { | ||||
|         this.status = ""; | ||||
|         this.message = ""; | ||||
|         this.data = new UserInfoModel(); | ||||
|     } | ||||
|      | ||||
|     public ResponseData(String status, String message, UserInfoModel data) { | ||||
|         this.status = status; | ||||
|         this.message = message; | ||||
|         this.data = data; | ||||
|     } | ||||
|  | ||||
|     public void setStatus(String status) { | ||||
|         this.status = status; | ||||
|     } | ||||
|  | ||||
|     public String getStatus() { | ||||
|         return status; | ||||
|     } | ||||
|  | ||||
|     public void setMessage(String message) { | ||||
|         this.message = message; | ||||
|     } | ||||
|  | ||||
|     public String getMessage() { | ||||
|         return message; | ||||
|     } | ||||
|  | ||||
|     public void setData(UserInfoModel data) { | ||||
|         this.data = data; | ||||
|     } | ||||
|  | ||||
|     public UserInfoModel getData() { | ||||
|         return data; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1,92 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.models; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/06/04 19:14 | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.libappbase.BaseBean; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class UserInfoModel extends BaseBean { | ||||
|  | ||||
|     public static final String TAG = "UserInfoModel"; | ||||
|  | ||||
|     String username; | ||||
|     String password; | ||||
|     String token; | ||||
|  | ||||
|     public UserInfoModel() { | ||||
|         this.username = ""; | ||||
|         this.password = ""; | ||||
|         this.token = ""; | ||||
|     } | ||||
|  | ||||
|     public void setUsername(String username) { | ||||
|         this.username = username; | ||||
|     } | ||||
|  | ||||
|     public String getUsername() { | ||||
|         return username; | ||||
|     } | ||||
|  | ||||
|     public void setPassword(String password) { | ||||
|         this.password = password; | ||||
|     } | ||||
|  | ||||
|     public String getPassword() { | ||||
|         return password; | ||||
|     } | ||||
|  | ||||
|     public void setToken(String token) { | ||||
|         this.token = token; | ||||
|     } | ||||
|  | ||||
|     public String getToken() { | ||||
|         return token; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return UserInfoModel.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         jsonWriter.name("username").value(getUsername()); | ||||
|         jsonWriter.name("password").value(getPassword()); | ||||
|         jsonWriter.name("token").value(getToken()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { | ||||
|             if (name.equals("username")) { | ||||
|                 setUsername(jsonReader.nextString()); | ||||
|             } else if (name.equals("password")) { | ||||
|                 setPassword(jsonReader.nextString()); | ||||
|             } else if (name.equals("token")) { | ||||
|                 setToken(jsonReader.nextString()); | ||||
|             } 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; | ||||
|     } | ||||
| } | ||||
| @@ -1,91 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.models; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/05/10 10:16 | ||||
|  * @Describe WinBoLLModel | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.libappbase.BaseBean; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class WinBoLLModel extends BaseBean { | ||||
|      | ||||
|     public static final String TAG = "WinBoLLModel"; | ||||
|      | ||||
|     String appPackageName; | ||||
|     String appMainServiveName; | ||||
|  | ||||
|     public WinBoLLModel() { | ||||
|         this.appPackageName = ""; | ||||
|         this.appMainServiveName = ""; | ||||
|     } | ||||
|  | ||||
|     public WinBoLLModel(boolean isDebuging, String appPackageName, String appMainServiveName) { | ||||
|         this.appPackageName = appPackageName; | ||||
|         this.appMainServiveName = appMainServiveName; | ||||
|     } | ||||
|  | ||||
|     public WinBoLLModel(String appPackageName, String appMainServiveName) { | ||||
|         this.appPackageName = appPackageName; | ||||
|         this.appMainServiveName = appMainServiveName; | ||||
|     } | ||||
|  | ||||
|     public void setAppPackageName(String appPackageName) { | ||||
|         this.appPackageName = appPackageName; | ||||
|     } | ||||
|  | ||||
|     public String getAppPackageName() { | ||||
|         return appPackageName; | ||||
|     } | ||||
|  | ||||
|     public void setAppMainServiveName(String appMainServiveName) { | ||||
|         this.appMainServiveName = appMainServiveName; | ||||
|     } | ||||
|  | ||||
|     public String getAppMainServiveName() { | ||||
|         return appMainServiveName; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return APPModel.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         jsonWriter.name("appPackageName").value(getAppPackageName()); | ||||
|         jsonWriter.name("appMainServiveName").value(getAppMainServiveName()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { | ||||
|             if (name.equals("appPackageName")) { | ||||
|                 setAppPackageName(jsonReader.nextString()); | ||||
|             } else if (name.equals("appMainServiveName")) { | ||||
|                 setAppMainServiveName(jsonReader.nextString()); | ||||
|             } 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; | ||||
|     } | ||||
| } | ||||
|      | ||||
| @@ -1,70 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.models; | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.libappbase.BaseBean; | ||||
| import java.io.IOException; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/05/10 09:36 | ||||
|  * @Describe WinBoLL 应用消息数据模型 | ||||
|  */ | ||||
| public class WinBoLLNewsBean extends BaseBean { | ||||
|      | ||||
|     public static final String TAG = "WinBoLLNewsBean"; | ||||
|      | ||||
|     String message; | ||||
|      | ||||
|     public WinBoLLNewsBean() { | ||||
|         this.message = ""; | ||||
|     } | ||||
|  | ||||
|     public WinBoLLNewsBean(String message) { | ||||
|         this.message = message; | ||||
|     } | ||||
|  | ||||
|     public void setMessage(String message) { | ||||
|         this.message = message; | ||||
|     } | ||||
|  | ||||
|     public String getMessage() { | ||||
|         return message; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return WinBoLLNewsBean.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         jsonWriter.name("message").value(getMessage()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { | ||||
|             if (name.equals("message")) { | ||||
|                 setMessage(jsonReader.nextString()); | ||||
|             } 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; | ||||
|     } | ||||
| } | ||||
| @@ -1,29 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.receiver; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/13 21:19:09 | ||||
|  * @Describe MyBroadcastReceiver | ||||
|  */ | ||||
| import android.content.BroadcastReceiver; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.R; | ||||
|  | ||||
| public class MyBroadcastReceiver extends BroadcastReceiver { | ||||
|      | ||||
|     public static final String TAG = "MyBroadcastReceiver"; | ||||
|      | ||||
|     @Override | ||||
|     public void onReceive(Context context, Intent intent) { | ||||
|         if (context.getString(R.string.action_sos).equals(intent.getAction())) { | ||||
|             String message = intent.getStringExtra("message"); | ||||
|             String sosPackage = intent.getStringExtra("sosPackage"); | ||||
|              | ||||
|             // 处理接收到的广播消息 | ||||
|             LogUtils.d(TAG, String.format("MyBroadcastReceiver action %s \n%s\n%s", intent.getAction(), sosPackage, message)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1,59 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.sos; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/03/02 09:36:29 | ||||
|  * @Describe WinBoLL 应用 SOS 机理保护类 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class SOS { | ||||
|  | ||||
|     public static final String TAG = "SOS"; | ||||
|  | ||||
|     public static final String ACTION_SOS = SOS.class.getName() + ".ACTION_SOS"; | ||||
|     public static final String EXTRA_OBJECT = "EXTRA_OBJECT"; | ||||
|  | ||||
|     public static void sosToAppBase(Context context, String sosService) { | ||||
|         LogUtils.d(TAG, "sosToAppBase()"); | ||||
|         String szToPackage = "cc.winboll.studio.appbase"; | ||||
|         sos(context, szToPackage, sosService); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public static void sosToAppBaseBeta(Context context, String sosService) { | ||||
|         LogUtils.d(TAG, "sosToAppBaseBeta()"); | ||||
|         String szToPackage = "cc.winboll.studio.appbase.beta"; | ||||
|         sos(context, szToPackage, sosService); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     static void sos(Context context, String szToPackage, String sosService) { | ||||
|         LogUtils.d(TAG, "sos(...)"); | ||||
|         Intent intent = new Intent(ACTION_SOS); | ||||
|         intent.putExtra(EXTRA_OBJECT, genSOSObject(context.getPackageName(), sosService)); | ||||
|         intent.setPackage(szToPackage); | ||||
|         LogUtils.d(TAG, String.format("ACTION_SOS :\nTo Package : %sSOS Service : %s\n", szToPackage, sosService)); | ||||
|         context.sendBroadcast(intent); | ||||
|     } | ||||
|  | ||||
|     public static SOSObject parseSOSObject(String szSOSObject) { | ||||
|         try { | ||||
|             return SOSObject.parseStringToBean(szSOSObject, SOSObject.class); | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     public static String sosObjectToString(SOSObject object) { | ||||
|         return object.toString(); | ||||
|     } | ||||
|  | ||||
|     public static String genSOSObject(String objectPackageName, String objectServiveName) { | ||||
|         return (new SOSObject(objectPackageName, objectServiveName)).toString(); | ||||
|     } | ||||
| } | ||||
| @@ -1,182 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.sos; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/27 14:00:21 | ||||
|  * @Describe Simple Operate Signal Service Center. | ||||
|  *           简单操作信号服务中心 | ||||
|  */ | ||||
| import android.app.Service; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.IBinder; | ||||
| import android.os.IInterface; | ||||
| import android.os.Parcel; | ||||
| import android.os.RemoteException; | ||||
| import java.io.FileDescriptor; | ||||
| import android.app.Service; | ||||
| import android.content.Intent; | ||||
| import android.os.IBinder; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
|  | ||||
| public class SOSCenterService extends Service { | ||||
|  | ||||
|     public static final String TAG = "SOSCenterService"; | ||||
|      | ||||
|     private final IBinder binder =(IBinder)new SOSBinder(); | ||||
|  | ||||
|     SOSCenterServiceModel mSOSCenterServiceModel; | ||||
|     static MainThread _MainThread; | ||||
|     public static synchronized MainThread getMainThreadInstance() { | ||||
|         if (_MainThread == null) { | ||||
|             _MainThread = new MainThread(); | ||||
|         } | ||||
|         return _MainThread; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public IBinder onBind(Intent intent) { | ||||
|         return binder; | ||||
|     } | ||||
|  | ||||
|     public class SOSBinder implements IBinder { | ||||
|  | ||||
|         @Override | ||||
|         public void dump(FileDescriptor fileDescriptor, String[] string) throws RemoteException { | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void dumpAsync(FileDescriptor fileDescriptor, String[] string) throws RemoteException { | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public String getInterfaceDescriptor() throws RemoteException { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public boolean isBinderAlive() { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void linkToDeath(IBinder.DeathRecipient deathRecipient, int p) throws RemoteException { | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public boolean pingBinder() { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public IInterface queryLocalInterface(String string) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public boolean transact(int p, Parcel parcel, Parcel parcel1, int p1) throws RemoteException { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public boolean unlinkToDeath(IBinder.DeathRecipient deathRecipient, int p) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         public static final String TAG = "SOSBinder"; | ||||
|         SOSCenterService getService() { | ||||
|             return SOSCenterService.this; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         LogUtils.d(TAG, "onCreate"); | ||||
|         mSOSCenterServiceModel = SOSCenterServiceModel.loadBean(this, SOSCenterServiceModel.class); | ||||
|         if(mSOSCenterServiceModel == null) { | ||||
|             mSOSCenterServiceModel = new SOSCenterServiceModel(); | ||||
|             SOSCenterServiceModel.saveBean(this, mSOSCenterServiceModel); | ||||
|         } | ||||
|         runMainThread(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int onStartCommand(Intent intent, int flags, int startId) { | ||||
|         LogUtils.d(TAG, "onStartCommand"); | ||||
|  | ||||
|         runMainThread(); | ||||
|  | ||||
|         return mSOSCenterServiceModel.isEnable() ? Service.START_STICKY: super.onStartCommand(intent, flags, startId); | ||||
|     } | ||||
|  | ||||
|     void runMainThread() { | ||||
|         mSOSCenterServiceModel = mSOSCenterServiceModel.loadBean(this, SOSCenterServiceModel.class); | ||||
|         if (mSOSCenterServiceModel.isEnable() | ||||
|             && _MainThread == null) { | ||||
|             getMainThreadInstance().start(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         LogUtils.d(TAG, "onDestroy"); | ||||
|         mSOSCenterServiceModel = SOSCenterServiceModel.loadBean(this, SOSCenterServiceModel.class); | ||||
|         if (mSOSCenterServiceModel.isEnable()) { | ||||
|             LogUtils.d(TAG, "mSOSCenterServiceModel.isEnable()"); | ||||
| //            ISOSAPP iSOSAPP = (ISOSAPP)getApplication(); | ||||
| //            iSOSAPP.helpISOSService(getISOSServiceIntentWhichAskForHelp()); | ||||
|         }  | ||||
|         if (_MainThread != null) { | ||||
|             _MainThread.isExist = true; | ||||
|             _MainThread = null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void stopISOSService(Context context) { | ||||
|         LogUtils.d(TAG, "stopISOSService"); | ||||
|         SOSCenterServiceModel bean = new SOSCenterServiceModel(); | ||||
|         bean.setIsEnable(false); | ||||
|         SOSCenterServiceModel.saveBean(context, bean); | ||||
|         context.stopService(new Intent(context, SOSCenterServiceModel.class)); | ||||
|     } | ||||
|  | ||||
|     public static void startISOSService(Context context) { | ||||
|         LogUtils.d(TAG, "startISOSService"); | ||||
|         SOSCenterServiceModel bean = new SOSCenterServiceModel(); | ||||
|         bean.setIsEnable(true); | ||||
|         SOSCenterServiceModel.saveBean(context, bean); | ||||
|         context.startService(new Intent(context, SOSCenterServiceModel.class)); | ||||
|     } | ||||
|  | ||||
|     public String getMessage() { | ||||
|         return "Hello from SOSCenterServiceModel"; | ||||
|     } | ||||
|  | ||||
|     static class MainThread extends Thread { | ||||
|         volatile boolean isExist = false; | ||||
|  | ||||
|         public void setIsExist(boolean isExist) { | ||||
|             this.isExist = isExist; | ||||
|         } | ||||
|  | ||||
|         public boolean isExist() { | ||||
|             return isExist; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void run() { | ||||
|             super.run(); | ||||
|             while (!isExist) { | ||||
|                 LogUtils.d(TAG, "run"); | ||||
|                 try { | ||||
|                     sleep(1000); | ||||
|                 } catch (InterruptedException e) { | ||||
|                     LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -1,69 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.sos; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/03/02 09:49:45 | ||||
|  * @Describe SOSCenterServiceModel | ||||
|  *           Simple Operate Signal Service Model. | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.libappbase.BaseBean; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class SOSCenterServiceModel extends BaseBean { | ||||
|  | ||||
|     public static final String TAG = "SOSCenterServiceModel"; | ||||
|  | ||||
|     boolean isEnable; | ||||
|  | ||||
|     public SOSCenterServiceModel() { | ||||
|         this.isEnable = false; | ||||
|     } | ||||
|  | ||||
|     public void setIsEnable(boolean isEnable) { | ||||
|         this.isEnable = isEnable; | ||||
|     } | ||||
|  | ||||
|     public boolean isEnable() { | ||||
|         return isEnable; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return SOSCenterServiceModel.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         jsonWriter.name("isEnable").value(isEnable()); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { | ||||
|             if (name.equals("isEnable")) { | ||||
|                 setIsEnable(jsonReader.nextBoolean()); | ||||
|             } else { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { | ||||
|         jsonReader.beginObject(); | ||||
|         while (jsonReader.hasNext()) { | ||||
|             String name = jsonReader.nextName(); | ||||
|             if (!initObjectsFromJsonReader(jsonReader, name)) { | ||||
|                 jsonReader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         // 结束 JSON 对象 | ||||
|         jsonReader.endObject(); | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
| @@ -1,29 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.sos; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/27 14:04:35 | ||||
|  * @Describe SOSCenterServiceReceiver | ||||
|  */ | ||||
| import android.content.BroadcastReceiver; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
|  | ||||
| public class SOSCenterServiceReceiver extends BroadcastReceiver { | ||||
|  | ||||
|     public static final String TAG = "SOSCenterServiceReceiver"; | ||||
|  | ||||
|     public static final String ACTION_SOS = SOSCenterServiceReceiver.class.getName() + ".ACTION_SOS"; | ||||
|      | ||||
|     @Override | ||||
|     public void onReceive(Context context, Intent intent) { | ||||
|         String action = intent.getAction(); | ||||
|         if (action.equals(ACTION_SOS)) { | ||||
|             // 处理接收到的广播消息 | ||||
|             LogUtils.d(TAG, String.format("Action %s \n%s\n%s", action)); | ||||
|         } else { | ||||
|             LogUtils.d(TAG, String.format("%s", action)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,86 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.sos; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/27 14:12:05 | ||||
|  * @Describe SOSBean | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.libappbase.BaseBean; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class SOSObject extends BaseBean { | ||||
|  | ||||
|     public static final String TAG = "SOSObject"; | ||||
|  | ||||
|     String objectPackageName; | ||||
|     String objectServiveName; | ||||
|  | ||||
|     public SOSObject() { | ||||
|         this.objectPackageName = ""; | ||||
|         this.objectServiveName = ""; | ||||
|     } | ||||
|  | ||||
|     public SOSObject(String objectPackageName, String objectServiveName) { | ||||
|         this.objectPackageName = objectPackageName; | ||||
|         this.objectServiveName = objectServiveName; | ||||
|     } | ||||
|  | ||||
|     public void setObjectPackageName(String objectPackageName) { | ||||
|         this.objectPackageName = objectPackageName; | ||||
|     } | ||||
|  | ||||
|     public String getObjectPackageName() { | ||||
|         return objectPackageName; | ||||
|     } | ||||
|  | ||||
|     public void setObjectServiveName(String objectServiveName) { | ||||
|         this.objectServiveName = objectServiveName; | ||||
|     } | ||||
|  | ||||
|     public String getObjectServiveName() { | ||||
|         return objectServiveName; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return SOSObject.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         jsonWriter.name("objectPackageName").value(getObjectPackageName()); | ||||
|         jsonWriter.name("objectServiveName").value(getObjectServiveName()); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { | ||||
|             if (name.equals("objectPackageName")) { | ||||
|                 setObjectPackageName(jsonReader.nextString()); | ||||
|             } else if (name.equals("objectServiveName")) { | ||||
|                 setObjectServiveName(jsonReader.nextString()); | ||||
|             } 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; | ||||
|     } | ||||
| } | ||||
| @@ -1,128 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/06/04 20:15 | ||||
|  * @Describe 文件操作类 | ||||
|  */ | ||||
| import java.io.BufferedReader; | ||||
| import java.io.BufferedWriter; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.FileReader; | ||||
| import java.io.FileWriter; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class FileUtils { | ||||
|     public static final String TAG = "FileUtils"; | ||||
|  | ||||
|     /** | ||||
|      * 读取文件为字节数组(Java 7 语法) | ||||
|      */ | ||||
|     public static byte[] readFileToByteArray(String filePath) { | ||||
|         FileInputStream fis = null; | ||||
|         ByteArrayOutputStream bos = null; | ||||
|         try { | ||||
|             fis = new FileInputStream(filePath); | ||||
|             bos = new ByteArrayOutputStream(); | ||||
|             byte[] buffer = new byte[4096]; | ||||
|             int bytesRead; | ||||
|             while ((bytesRead = fis.read(buffer)) != -1) { | ||||
|                 bos.write(buffer, 0, bytesRead); | ||||
|             } | ||||
|             return bos.toByteArray(); | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|             return null; | ||||
|         } finally { | ||||
|             // 手动关闭流(Java 7 不支持 try-with-resources) | ||||
|             if (fis != null) { | ||||
|                 try { | ||||
|                     fis.close(); | ||||
|                 } catch (IOException e) { | ||||
|                     e.printStackTrace(); | ||||
|                 } | ||||
|             } | ||||
|             if (bos != null) { | ||||
|                 try { | ||||
|                     bos.close(); | ||||
|                 } catch (IOException e) { | ||||
|                     e.printStackTrace(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 写入字节数组到文件(Java 7 语法) | ||||
|      */ | ||||
|     public static boolean writeByteArrayToFile(byte[] data, String filePath) { | ||||
|         FileOutputStream fos = null; | ||||
|         try { | ||||
|             fos = new FileOutputStream(filePath); | ||||
|             fos.write(data); | ||||
|             return true; | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|             return false; | ||||
|         } finally { | ||||
|             if (fos != null) { | ||||
|                 try { | ||||
|                     fos.close(); | ||||
|                 } catch (IOException e) { | ||||
|                     e.printStackTrace(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 原字符串读写方法(适配 Java 7) | ||||
|     public static String readFileToString(String filePath) { | ||||
|         BufferedReader reader = null; | ||||
|         try { | ||||
|             reader = new BufferedReader(new FileReader(filePath)); | ||||
|             StringBuilder content = new StringBuilder(); | ||||
|             String line; | ||||
|             while ((line = reader.readLine()) != null) { | ||||
|                 content.append(line).append(System.getProperty("line.separator")); | ||||
|             } | ||||
|             // 去除最后一个换行符(可选) | ||||
|             if (content.length() > 0) { | ||||
|                 content.deleteCharAt(content.length() - 1); | ||||
|             } | ||||
|             return content.toString(); | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|             return null; | ||||
|         } finally { | ||||
|             if (reader != null) { | ||||
|                 try { | ||||
|                     reader.close(); | ||||
|                 } catch (IOException e) { | ||||
|                     e.printStackTrace(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static boolean writeStringToFile(String content, String filePath, boolean append) { | ||||
|         BufferedWriter writer = null; | ||||
|         try { | ||||
|             writer = new BufferedWriter(new FileWriter(filePath, append)); | ||||
|             writer.write(content); | ||||
|             return true; | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|             return false; | ||||
|         } finally { | ||||
|             if (writer != null) { | ||||
|                 try { | ||||
|                     writer.close(); | ||||
|                 } catch (IOException e) { | ||||
|                     e.printStackTrace(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,222 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/06/04 13:36 | ||||
|  * @Describe RSA加密工具 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.util.Base64; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.security.KeyFactory; | ||||
| import java.security.KeyPair; | ||||
| import java.security.KeyPairGenerator; | ||||
| import java.security.NoSuchAlgorithmException; | ||||
| import java.security.PrivateKey; | ||||
| import java.security.PublicKey; | ||||
| import java.security.spec.InvalidKeySpecException; | ||||
| import java.security.spec.PKCS8EncodedKeySpec; | ||||
| import java.security.spec.X509EncodedKeySpec; | ||||
| import java.util.Objects; | ||||
| import javax.crypto.Cipher; | ||||
|  | ||||
| public class RSAUtils { | ||||
|     private static final String TAG = "RSAUtils"; | ||||
|     private static final int KEY_SIZE = 2048; | ||||
|     private static final String KEY_ALGORITHM = "RSA"; | ||||
|     private static final String PUBLIC_KEY_FILE = "public.key"; | ||||
|     private static final String PRIVATE_KEY_FILE = "private.key"; | ||||
|     private static final String CIPHER_ALGORITHM = KEY_ALGORITHM + "/ECB/PKCS1Padding"; // 保留原加密方式 | ||||
|  | ||||
|     private final String keyPath; | ||||
|     private static volatile RSAUtils INSTANCE; | ||||
|  | ||||
|     /** | ||||
|      * 构造方法:初始化密钥存储路径(内部存储) | ||||
|      */ | ||||
|     private RSAUtils(Context context) { | ||||
|         keyPath = context.getFilesDir() + File.separator + "keys" + File.separator; // 修正路径格式 | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取单例实例 | ||||
|      */ | ||||
|     public static synchronized RSAUtils getInstance(Context context) { | ||||
|         if (INSTANCE == null) { | ||||
|             INSTANCE = new RSAUtils(context); | ||||
|         } | ||||
|         return INSTANCE; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 检查密钥文件是否存在 | ||||
|      */ | ||||
|     public boolean keysExist() { | ||||
|         File publicKeyFile = new File(keyPath + PUBLIC_KEY_FILE); | ||||
|         File privateKeyFile = new File(keyPath + PRIVATE_KEY_FILE); | ||||
|         return publicKeyFile.exists() && privateKeyFile.exists(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 生成密钥对并保存到文件 | ||||
|      */ | ||||
|     public void generateAndSaveKeys() throws Exception { | ||||
|         LogUtils.d(TAG, "开始生成 RSA 密钥对(2048位)"); | ||||
|         KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_ALGORITHM); | ||||
|         generator.initialize(KEY_SIZE); | ||||
|         KeyPair keyPair = generator.generateKeyPair(); | ||||
|  | ||||
|         saveKey(PUBLIC_KEY_FILE, keyPair.getPublic().getEncoded()); | ||||
|         saveKey(PRIVATE_KEY_FILE, keyPair.getPrivate().getEncoded()); | ||||
|         LogUtils.d(TAG, "密钥对生成并保存成功"); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取或生成密钥对(线程安全) | ||||
|      */ | ||||
|     public KeyPair getOrGenerateKeys() throws Exception { | ||||
|         if (!keysExist()) { | ||||
|             synchronized (RSAUtils.class) { // 双重检查锁,避免多线程重复生成 | ||||
|                 if (!keysExist()) { | ||||
|                     generateAndSaveKeys(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return readKeysFromFile(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 从文件读取密钥对 | ||||
|      */ | ||||
|     private KeyPair readKeysFromFile() throws Exception { | ||||
|         LogUtils.d(TAG, "读取密钥对文件"); | ||||
|         try { | ||||
|             byte[] publicKeyBytes = readFileToBytes(keyPath + PUBLIC_KEY_FILE); | ||||
|             byte[] privateKeyBytes = readFileToBytes(keyPath + PRIVATE_KEY_FILE); | ||||
|  | ||||
|             X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(publicKeyBytes); | ||||
|             PKCS8EncodedKeySpec privateSpec = new PKCS8EncodedKeySpec(privateKeyBytes); | ||||
|  | ||||
|             KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM); | ||||
|             PublicKey publicKey = factory.generatePublic(publicSpec); | ||||
|             PrivateKey privateKey = factory.generatePrivate(privateSpec); | ||||
|  | ||||
|             return new KeyPair(publicKey, privateKey); | ||||
|         } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) { | ||||
|             LogUtils.e(TAG, "密钥文件读取失败:" + e.getMessage()); | ||||
|             throw new Exception("密钥文件损坏或格式错误", e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 保存密钥到文件(通用方法) | ||||
|      */ | ||||
|     private void saveKey(String fileName, byte[] keyBytes) throws IOException { | ||||
|         Objects.requireNonNull(keyBytes, "密钥字节数据不可为空"); | ||||
|         File dir = new File(keyPath); | ||||
|         if (!dir.exists() && !dir.mkdirs()) { | ||||
|             throw new IOException("创建密钥目录失败:" + keyPath); | ||||
|         } | ||||
|  | ||||
|         FileOutputStream fos = null; | ||||
|         try { | ||||
|             fos = new FileOutputStream(keyPath + fileName); | ||||
|             fos.write(keyBytes); | ||||
|         } finally { | ||||
|             if (fos != null) { | ||||
|                 try { | ||||
|                     fos.close(); | ||||
|                 } catch (IOException e) { | ||||
|                     LogUtils.e(TAG, "关闭文件流失败:" + e.getMessage()); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 读取文件为字节数组(Java 7 兼容) | ||||
|      */ | ||||
|     private byte[] readFileToBytes(String filePath) throws IOException { | ||||
|         File file = new File(filePath); | ||||
|         if (!file.exists() || file.isDirectory()) { | ||||
|             throw new IOException("文件不存在或为目录:" + filePath); | ||||
|         } | ||||
|  | ||||
|         FileInputStream fis = null; | ||||
|         try { | ||||
|             fis = new FileInputStream(file); | ||||
|             byte[] data = new byte[(int) file.length()]; | ||||
|             int bytesRead = fis.read(data); | ||||
|             if (bytesRead != data.length) { | ||||
|                 throw new IOException("文件读取不完整"); | ||||
|             } | ||||
|             return data; | ||||
|         } finally { | ||||
|             if (fis != null) { | ||||
|                 try { | ||||
|                     fis.close(); | ||||
|                 } catch (IOException e) { | ||||
|                     LogUtils.e(TAG, "关闭文件流失败:" + e.getMessage()); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 公钥加密(带参数校验) | ||||
|      */ | ||||
|     public byte[] encryptWithPublicKey(String plainText, PublicKey publicKey) throws Exception { | ||||
|         Objects.requireNonNull(plainText, "明文不可为空"); | ||||
|         Objects.requireNonNull(publicKey, "公钥不可为空"); | ||||
|  | ||||
|         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); | ||||
|         cipher.init(Cipher.ENCRYPT_MODE, publicKey); | ||||
|  | ||||
|         // 检查数据长度是否超过 RSA 限制(2048位密钥最大明文为 214字节,PKCS1Padding) | ||||
|         int maxPlainTextSize = cipher.getBlockSize() - 11; // PKCS1Padding 固定填充长度 | ||||
|         if (plainText.getBytes("UTF-8").length > maxPlainTextSize) { | ||||
|             throw new IllegalArgumentException("明文过长,最大支持 " + maxPlainTextSize + " 字节"); | ||||
|         } | ||||
|  | ||||
|         return cipher.doFinal(plainText.getBytes("UTF-8")); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 私钥解密(带参数校验) | ||||
|      */ | ||||
|     public String decryptWithPrivateKey(byte[] encryptedData, PrivateKey privateKey) throws Exception { | ||||
|         Objects.requireNonNull(encryptedData, "密文不可为空"); | ||||
|         Objects.requireNonNull(privateKey, "私钥不可为空"); | ||||
|  | ||||
|         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); | ||||
|         cipher.init(Cipher.DECRYPT_MODE, privateKey); | ||||
|         byte[] decryptedBytes = cipher.doFinal(encryptedData); | ||||
|         return new String(decryptedBytes, "UTF-8"); | ||||
|     } | ||||
|     /** | ||||
|      * 将 HTTP 传输的 Base64 字符串还原为加密字节数组(Java 7 兼容) | ||||
|      * @param httpString Base64 字符串(非 null) | ||||
|      * @return 加密字节数组 | ||||
|      * @throws IllegalArgumentException 解码失败时抛出 | ||||
|      */ | ||||
|     public byte[] httpStringToEncryptBytes(String httpString) { | ||||
|         Objects.requireNonNull(httpString, "HTTP 字符串不可为空"); | ||||
|  | ||||
|         // 计算缺失的填充符数量(Java 7 不支持 repeat(),手动拼接) | ||||
|         int pad = httpString.length() % 4; | ||||
|         StringBuilder paddedString = new StringBuilder(httpString); | ||||
|         if (pad != 0) { | ||||
|             for (int i = 0; i < pad; i++) { | ||||
|                 paddedString.append('='); // 补全 '=' | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // 使用 Base64 解码(Android 原生 Base64 类兼容 Java 7) | ||||
|         return Base64.decode(paddedString.toString(), Base64.URL_SAFE); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1,48 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/17 19:38:20 | ||||
|  * @Describe 服务工具集 | ||||
|  */ | ||||
| import android.app.ActivityManager; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.Build; | ||||
| import android.util.Log; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import java.util.List; | ||||
|  | ||||
| public class ServiceUtils { | ||||
|  | ||||
|     public static final String TAG = "ServiceUtils"; | ||||
|  | ||||
|     /** | ||||
|      * 检查指定服务是否正在运行 | ||||
|      * @param context 上下文 | ||||
|      * @param serviceClass 服务类 | ||||
|      * @return true 如果服务正在运行,否则返回 false | ||||
|      */ | ||||
|     public static boolean isServiceRunning(Context context, String serviceClassName) { | ||||
|         ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); | ||||
|         if (activityManager == null) { | ||||
|             return false; | ||||
|         } | ||||
|         List<ActivityManager.RunningServiceInfo> runningServices; | ||||
| //        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { | ||||
| //            Intent intent = new Intent(context, serviceClass); | ||||
| //            runningServices = activityManager.getRunningServices(100, intent); | ||||
| //        } else { | ||||
|         runningServices = activityManager.getRunningServices(100); | ||||
|         //} | ||||
|         for (ActivityManager.RunningServiceInfo serviceInfo : runningServices) { | ||||
|             if (serviceClassName.equals(serviceInfo.service.getClassName())) { | ||||
|                 LogUtils.d(TAG, "Service is running: " + serviceInfo.service.getClassName()); | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         LogUtils.d(TAG, "Service is not running: " + serviceClassName); | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1,281 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/06/04 17:21 | ||||
|  * @Describe 应用登录与接口工具 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.os.Handler; | ||||
| import android.os.Looper; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.models.ResponseData; | ||||
| import cc.winboll.studio.libappbase.models.UserInfoModel; | ||||
| import com.google.gson.Gson; | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.net.URLDecoder; | ||||
| import java.nio.charset.StandardCharsets; | ||||
| import java.security.KeyPair; | ||||
| import java.security.PrivateKey; | ||||
| import java.security.PublicKey; | ||||
| import java.util.concurrent.TimeUnit; | ||||
| import okhttp3.Call; | ||||
| import okhttp3.Callback; | ||||
| import okhttp3.MediaType; | ||||
| import okhttp3.OkHttpClient; | ||||
| import okhttp3.Request; | ||||
| import okhttp3.RequestBody; | ||||
| import okhttp3.Response; | ||||
| import java.io.UnsupportedEncodingException; | ||||
|  | ||||
| public class YunUtils { | ||||
|     public static final String TAG = "YunUtils"; | ||||
|     // 私有静态实例,类加载时创建 | ||||
|     private static volatile YunUtils INSTANCE; | ||||
|     Context mContext; | ||||
|     UserInfoModel mUserInfoModel; | ||||
|     String token = ""; | ||||
|     String mDataFolderPath = ""; | ||||
|     String mUserInfoModelPath = ""; | ||||
|  | ||||
|     private static final int CONNECT_TIMEOUT = 15; // 连接超时时间(秒) | ||||
|     private static final int READ_TIMEOUT = 20;    // 读取超时时间(秒) | ||||
|     private static volatile YunUtils instance; | ||||
|     private OkHttpClient okHttpClient; | ||||
|     private Handler mainHandler; // 主线程 Handler | ||||
|  | ||||
|     // 私有构造方法,防止外部实例化 | ||||
|     private YunUtils(Context context) { | ||||
|         LogUtils.d(TAG, "YunUtils"); | ||||
|         mContext = context; | ||||
|         mDataFolderPath = mContext.getExternalFilesDir(TAG).toString(); | ||||
|         File fTest = new File(mDataFolderPath); | ||||
|         if (!fTest.exists()) { | ||||
|             fTest.mkdirs(); | ||||
|         } | ||||
|         mUserInfoModelPath = mDataFolderPath + File.separator + "UserInfoModel.rsajson"; | ||||
|  | ||||
|         okHttpClient = new OkHttpClient.Builder() | ||||
|             .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS) | ||||
|             .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS) | ||||
|             .build(); | ||||
|         mainHandler = new Handler(Looper.getMainLooper()); // 获取主线程 Looper | ||||
|     } | ||||
|  | ||||
|     // 公共静态方法,返回唯一实例 | ||||
|     public static synchronized YunUtils getInstance(Context context) { | ||||
|         LogUtils.d(TAG, "getInstance"); | ||||
|         if (INSTANCE == null) { | ||||
|             INSTANCE = new YunUtils(context); | ||||
|         } | ||||
|         return INSTANCE; | ||||
|     } | ||||
|  | ||||
|     public void checkLoginStatus() { | ||||
|         String token = getLocalToken(); | ||||
|         LogUtils.d(TAG, String.format("checkLoginStatus token is %s", token)); | ||||
|     } | ||||
|  | ||||
|     String getLocalToken() { | ||||
|         UserInfoModel userInfoModel = loadUserInfoModel(); | ||||
|         return (userInfoModel == null) ?"": userInfoModel.getToken(); | ||||
|     } | ||||
|  | ||||
|     public void login(String host, UserInfoModel userInfoModel) { | ||||
|         LogUtils.d(TAG, "login"); | ||||
|  | ||||
|         // 发送 POST 请求 | ||||
|         String apiUrl = host + "/login/index.php"; | ||||
|         // 序列化对象为JSON | ||||
|         Gson gson = new Gson(); | ||||
|         String jsonData = gson.toJson(userInfoModel); // 自动生成标准JSON | ||||
|         //String jsonData = userInfoModel.toString(); | ||||
|         LogUtils.d(TAG, "要发送的数据 : " + jsonData); | ||||
|  | ||||
|         sendPostRequest(apiUrl, jsonData, new OnResponseListener() { | ||||
|                 // 成功回调(主线程) | ||||
|                 @Override | ||||
|                 public void onSuccess(String responseBody) { | ||||
|                     LogUtils.d(TAG, "onSuccess"); | ||||
|                     LogUtils.d(TAG, String.format("responseBody %s", responseBody)); | ||||
|                     Gson gson = new Gson(); | ||||
|                     ResponseData result = gson.fromJson(responseBody, ResponseData.class); // 转为 Result 实例 | ||||
|                     if(result.getStatus().equals(ResponseData.STATUS_SUCCESS)) { | ||||
|                          | ||||
|                             UserInfoModel userInfoModel = result.getData(); | ||||
|                             if (userInfoModel != null) { | ||||
|                                 LogUtils.d(TAG, "收到网站 UserInfoModel"); | ||||
|                                 String token = userInfoModel.getToken(); | ||||
|                                 saveLocalToken(token); | ||||
|                                 checkLoginStatus(); | ||||
|                             } | ||||
|                         | ||||
|                     } else if(result.getStatus().equals(ResponseData.STATUS_ERROR)) { | ||||
|                         try { | ||||
|                             String decodedMessage = URLDecoder.decode(result.getMessage(), "UTF-8"); | ||||
|                             LogUtils.d(TAG, "服务器返回信息: " + decodedMessage); | ||||
|                         } catch (UnsupportedEncodingException e) { | ||||
|                             LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 // 失败回调(主线程) | ||||
|                 @Override | ||||
|                 public void onFailure(String errorMsg) { | ||||
|                     LogUtils.d(TAG, errorMsg); | ||||
|                     // 处理错误 | ||||
|                 } | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|     public void saveLocalToken(String token) { | ||||
|         UserInfoModel userInfoModel = new UserInfoModel(); | ||||
|         userInfoModel.setToken(token); | ||||
|         saveUserInfoModel(userInfoModel); | ||||
|     } | ||||
|  | ||||
|     UserInfoModel loadUserInfoModel() { | ||||
|         LogUtils.d(TAG, "loadUserInfoModel"); | ||||
|         if (new File(mUserInfoModelPath).exists()) { | ||||
|             try { | ||||
|                 // 加载加密后的模型数据 | ||||
|                 byte[] encryptedData = FileUtils.readFileToByteArray(mUserInfoModelPath); | ||||
|                 // 加载 RSA 工具 | ||||
|                 RSAUtils utils = RSAUtils.getInstance(mContext); | ||||
|                 KeyPair keyPair = utils.getOrGenerateKeys(); | ||||
|                 //PublicKey publicKey = keyPair.getPublic(); | ||||
|                 PrivateKey privateKey = keyPair.getPrivate(); | ||||
|                 // 私钥解密模型数据 | ||||
|                 String szInfo = utils.decryptWithPrivateKey(encryptedData, keyPair.getPrivate()); | ||||
|                 LogUtils.d(TAG, String.format("szInfo %s", szInfo)); | ||||
|                 mUserInfoModel = UserInfoModel.parseStringToBean(szInfo, UserInfoModel.class); | ||||
|                 if (mUserInfoModel == null) { | ||||
|                     LogUtils.d(TAG, "模型数据解析为空数据。"); | ||||
|                 } | ||||
|                 LogUtils.d(TAG, "UserInfoModel 解密加载结束。"); | ||||
|             } catch (Exception e) { | ||||
|                 LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|             } | ||||
|         } else { | ||||
|             LogUtils.d(TAG, "云服务登录信息不存在。"); | ||||
|             mUserInfoModel = null; | ||||
|         } | ||||
|         return mUserInfoModel; | ||||
|     } | ||||
|  | ||||
|     void saveUserInfoModel(UserInfoModel userInfoModel) { | ||||
|         LogUtils.d(TAG, "saveUserInfoModel"); | ||||
|         try { | ||||
|             String szInfo = userInfoModel.toString(); | ||||
|             LogUtils.d(TAG, "原始数据: " + szInfo); | ||||
|  | ||||
|             RSAUtils utils = RSAUtils.getInstance(mContext); | ||||
|             KeyPair keyPair = utils.getOrGenerateKeys(); | ||||
|             PublicKey publicKey = keyPair.getPublic(); | ||||
|  | ||||
|             // 公钥加密(传入字节数组,避免中间字符串转换) | ||||
|             byte[] encryptedData = utils.encryptWithPublicKey(szInfo, publicKey); | ||||
|  | ||||
|             // 保存加密字节数组到文件(直接操作字节,无需转字符串) | ||||
|             FileUtils.writeByteArrayToFile(encryptedData, mUserInfoModelPath); | ||||
|             LogUtils.d(TAG, "加密数据已保存"); | ||||
|  | ||||
|             // 测试解密(仅调试用) | ||||
|             String szInfo2 = utils.decryptWithPrivateKey(encryptedData, keyPair.getPrivate()); | ||||
|             LogUtils.d(TAG, "解密结果: " + szInfo2); | ||||
|  | ||||
|             mUserInfoModel = UserInfoModel.parseStringToBean(szInfo2, UserInfoModel.class); | ||||
|             if (mUserInfoModel == null) { | ||||
|                 LogUtils.d(TAG, "模型解析失败"); | ||||
|             } | ||||
|         } catch (Exception e) { | ||||
|             LogUtils.d(TAG, "加密/解密失败: " + e.getMessage()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 发送 POST 请求(JSON 数据) | ||||
|     public void sendPostRequest(String url, String data, OnResponseListener listener) { | ||||
|         RequestBody requestBody = RequestBody.create( | ||||
|             MediaType.parse("application/json; charset=utf-8"), // 关键头信息 | ||||
|             data.getBytes(StandardCharsets.UTF_8) | ||||
|         ); | ||||
|  | ||||
|         Request request = new Request.Builder() | ||||
|             .url(url) | ||||
|             .post(requestBody) | ||||
|             .addHeader("Content-Type", "application/json") // 显式添加头 | ||||
|             .build(); | ||||
|  | ||||
|         executeRequest(request, listener); | ||||
|     } | ||||
|  | ||||
|     // 发送 GET 请求 | ||||
|     public void sendGetRequest(String url, OnResponseListener listener) { | ||||
|         Request request = new Request.Builder() | ||||
|             .url(url) | ||||
|             .get() | ||||
|             .build(); | ||||
|         executeRequest(request, listener); | ||||
|     } | ||||
|  | ||||
|     // 执行请求(子线程处理) | ||||
|     private void executeRequest(final Request request, final OnResponseListener listener) { | ||||
|         okHttpClient.newCall(request).enqueue(new Callback() { | ||||
|                 // 响应成功(子线程) | ||||
|                 @Override | ||||
|                 public void onResponse(Call call, Response response) throws IOException { | ||||
|                     try { | ||||
|                         if (!response.isSuccessful()) { | ||||
|                             postFailure(listener, "响应码错误:" + response.code()); | ||||
|                             return; | ||||
|                         } | ||||
|                         String responseBody = response.body().string(); | ||||
|                         postSuccess(listener, responseBody); | ||||
|                     } catch (Exception e) { | ||||
|                         postFailure(listener, "解析失败:" + e.getMessage()); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 // 响应失败(子线程) | ||||
|                 @Override | ||||
|                 public void onFailure(Call call, IOException e) { | ||||
|                     postFailure(listener, "网络失败:" + e.getMessage()); | ||||
|                 } | ||||
|  | ||||
|                 // 主线程回调(使用 Handler) | ||||
|                 private void postSuccess(final OnResponseListener listener, final String msg) { | ||||
|                     mainHandler.post(new Runnable() { | ||||
|                             @Override | ||||
|                             public void run() { | ||||
|                                 listener.onSuccess(msg); | ||||
|                             } | ||||
|                         }); | ||||
|                 } | ||||
|  | ||||
|                 private void postFailure(final OnResponseListener listener, final String msg) { | ||||
|                     mainHandler.post(new Runnable() { | ||||
|                             @Override | ||||
|                             public void run() { | ||||
|                                 listener.onFailure(msg); | ||||
|                             } | ||||
|                         }); | ||||
|                 } | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|     public interface OnResponseListener { | ||||
|         /** | ||||
|          * 成功响应(主线程回调) | ||||
|          * @param responseBody 响应体字符串 | ||||
|          */ | ||||
|         void onSuccess(String responseBody); | ||||
|  | ||||
|         /** | ||||
|          * 失败回调(包含错误信息) | ||||
|          * @param errorMsg 错误描述 | ||||
|          */ | ||||
|         void onFailure(String errorMsg); | ||||
|     } | ||||
| } | ||||
| @@ -1,63 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.widgets; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/17 20:32:12 | ||||
|  */ | ||||
| import android.app.PendingIntent; | ||||
| import android.appwidget.AppWidgetManager; | ||||
| import android.appwidget.AppWidgetProvider; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.widget.RemoteViews; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.R; | ||||
| import cc.winboll.studio.libappbase.utils.ServiceUtils; | ||||
| import android.content.ServiceConnection; | ||||
| import android.os.IBinder; | ||||
| import cc.winboll.studio.libappbase.utils.ToastUtils; | ||||
|  | ||||
| public class StatusWidget extends AppWidgetProvider { | ||||
|  | ||||
|     public static final String TAG = "StatusWidget"; | ||||
|  | ||||
|     public static final String ACTION_STATUS_UPDATE = "cc.winboll.studio.libappbase.widgets.APPWidget.ACTION_STATUS_UPDATE"; | ||||
|  | ||||
|     @Override | ||||
|     public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { | ||||
|         for (int appWidgetId : appWidgetIds) { | ||||
|             updateAppWidget(context, appWidgetManager, appWidgetId); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onReceive(Context context, Intent intent) { | ||||
|         super.onReceive(context, intent); | ||||
|         if (intent.getAction().equals(ACTION_STATUS_UPDATE)) { | ||||
|             ToastUtils.show("Test"); | ||||
|             AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); | ||||
|             int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, StatusWidget.class)); | ||||
|             for (int appWidgetId : appWidgetIds) { | ||||
|                 updateAppWidget(context, appWidgetManager, appWidgetId); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { | ||||
|         RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_status); | ||||
|         //设置按钮点击事件 | ||||
|         Intent intentAppButton = new Intent(context, StatusWidgetClickListener.class); | ||||
|         intentAppButton.setAction(StatusWidgetClickListener.ACTION_IVAPP); | ||||
|         PendingIntent pendingIntentAppButton = PendingIntent.getBroadcast(context, 0, intentAppButton, PendingIntent.FLAG_UPDATE_CURRENT); | ||||
|         views.setOnClickPendingIntent(R.id.ivapp, pendingIntentAppButton); | ||||
|  | ||||
| //        boolean isActive = ServiceUtils.isServiceRunning(context, TestService.class.getName()); | ||||
| //        if (isActive) { | ||||
| //            views.setImageViewResource(R.id.ivapp, cc.winboll.studio.libappbase.R.drawable.ic_launcher); | ||||
| //        } else { | ||||
| //            views.setImageViewResource(R.id.ivapp, cc.winboll.studio.libappbase.R.drawable.ic_launcher_disable); | ||||
| //        } | ||||
|         appWidgetManager.updateAppWidget(appWidgetId, views); | ||||
|     } | ||||
| } | ||||
| @@ -1,33 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.widgets; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/17 20:33:53 | ||||
|  * @Describe APPWidgetClickListener | ||||
|  */ | ||||
| import android.content.BroadcastReceiver; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.utils.ToastUtils; | ||||
|  | ||||
| public class StatusWidgetClickListener extends BroadcastReceiver { | ||||
|      | ||||
|     public static final String TAG = "APPWidgetClickListener"; | ||||
|  | ||||
|     public static final String ACTION_IVAPP = "cc.winboll.studio.libappbase.widgets.StatusWidgetClickListener.ACTION_IVAPP"; | ||||
|  | ||||
|     @Override | ||||
|     public void onReceive(Context context, Intent intent) { | ||||
|         String action = intent.getAction(); | ||||
|         if (action == null) { | ||||
|             LogUtils.d(TAG, String.format("action %s", action)); | ||||
|             return; | ||||
|         } | ||||
|         if (action.equals(ACTION_IVAPP)) { | ||||
|             ToastUtils.show("ACTION_LAUNCHER"); | ||||
|         } else { | ||||
|             LogUtils.d(TAG, String.format("action %s", action)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,17 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.winboll; | ||||
| import android.app.Activity; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/05/10 09:34 | ||||
|  * @Describe WinBoLL 窗口操作接口 | ||||
|  */ | ||||
| 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(); | ||||
| } | ||||
| @@ -1,98 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.winboll; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @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; | ||||
| import cc.winboll.studio.libappbase.utils.ToastUtils;  | ||||
|  | ||||
| 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"); | ||||
|     }  | ||||
| } | ||||
| @@ -1,40 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.winboll; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/05/10 10:13 | ||||
|  * @Describe WinBoLL 系列应用通用管理类 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.models.WinBoLLModel; | ||||
|  | ||||
| public class WinBoLL { | ||||
|  | ||||
|     public static final String TAG = "WinBoLL"; | ||||
|  | ||||
|     public static final String ACTION_BIND = WinBoLL.class.getName() + ".ACTION_BIND"; | ||||
|     public static final String EXTRA_WINBOLLMODEL = "EXTRA_WINBOLLMODEL"; | ||||
|  | ||||
|     public static void bindToAPPBase(Context context, String appMainService) { | ||||
|         LogUtils.d(TAG, "bindToAPPBase(...)"); | ||||
|         String toPackage = "cc.winboll.studio.appbase"; | ||||
|         startBind(context, toPackage, appMainService); | ||||
|     } | ||||
|  | ||||
|     public static void bindToAPPBaseBeta(Context context, String appMainService) { | ||||
|         LogUtils.d(TAG, "bindToAPPBaseBeta(...)"); | ||||
|         String toPackage = "cc.winboll.studio.appbase.beta"; | ||||
|         startBind(context, toPackage, appMainService); | ||||
|     } | ||||
|  | ||||
|     static void startBind(Context context, String toPackage, String appMainService) { | ||||
|         Intent intent = new Intent(ACTION_BIND); | ||||
|         intent.putExtra(EXTRA_WINBOLLMODEL, (new WinBoLLModel(toPackage, appMainService)).toString()); | ||||
|         intent.setPackage(toPackage); | ||||
|         LogUtils.d(TAG, String.format("ACTION_BIND :\nTo Package : %s\nAPP Main Service : %s", toPackage, appMainService)); | ||||
|         context.sendBroadcast(intent); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,287 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.winboll; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @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.app.TaskStackBuilder; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.utils.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 } | ||||
|  | ||||
|     Context mContext; | ||||
|     volatile static WinBoLLActivityManager _mIWinBoLLActivityManager; | ||||
|     Map<String, IWinBoLLActivity> 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() { | ||||
|         mContext = GlobalApplication.getInstance(); | ||||
|         mActivityListMap = new HashMap<String, IWinBoLLActivity>(); | ||||
|     } | ||||
|  | ||||
|     public static synchronized WinBoLLActivityManager getInstance() { | ||||
|         if (_mIWinBoLLActivityManager == null) { | ||||
|             _mIWinBoLLActivityManager = new WinBoLLActivityManager(); | ||||
|         } | ||||
|         return _mIWinBoLLActivityManager; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 把Activity添加到管理中 | ||||
|      */ | ||||
|     public <T extends IWinBoLLActivity> 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 <T extends IWinBoLLActivity> void startWinBoLLActivity(Context context, Class<T> 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 <T extends IWinBoLLActivity> void startWinBoLLActivity(Context context, Intent intent, Class<T> 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 <T extends IWinBoLLActivity> 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 <T extends IWinBoLLActivity> boolean resumeActivity(Class<T> 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 <T extends IWinBoLLActivity> boolean resumeActivity(String tag) { | ||||
|         Activity activity = getActivityByTag(tag); | ||||
|         if (activity != null) { | ||||
|             return resumeActivity(activity); | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台 | ||||
|     // | ||||
|     public <T extends IWinBoLLActivity> 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 (GlobalApplication.getWinBoLLActivityManager().getWinBoLLUI_TYPE() == WinBoLLUI_TYPE.Service) { | ||||
|                         // 结束窗口和最近任务栏, 建议前台服务类应用使用,可以方便用户再次调用 UI 操作。 | ||||
|                         iWinBoLLActivity.getActivity().finishAndRemoveTask(); | ||||
|                         //ToastUtils.show("finishAll() activity.finishAndRemoveTask();"); | ||||
|                     } else if (GlobalApplication.getWinBoLLActivityManager().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 <T extends IWinBoLLActivity> 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<String, IWinBoLLActivity> 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 <T extends IWinBoLLActivity> 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<Map.Entry<String, IWinBoLLActivity>> iterator = mActivityListMap.entrySet().iterator(); | ||||
|             while (iterator.hasNext()) { | ||||
|                 Map.Entry<String, IWinBoLLActivity> 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."); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1,41 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?>  | ||||
| <layer-list xmlns:android="http://schemas.android.com/apk/res/android" >  | ||||
|     <!-- 阴影部分 -->  | ||||
|     <!-- 个人觉得更形象的表达:top代表下边的阴影高度,left代表右边的阴影宽度。其实也就是相对应的offset,solid中的颜色是阴影的颜色,也可以设置角度等等 -->  | ||||
|     <item  | ||||
|         android:left="2dp"  | ||||
|         android:top="2dp"  | ||||
|         android:right="2dp"  | ||||
|         android:bottom="2dp">  | ||||
|         <shape android:shape="rectangle" >  | ||||
|             <gradient  | ||||
|                 android:angle="270"  | ||||
|                 android:endColor="#0F000000"  | ||||
|                 android:startColor="#0F000000" />  | ||||
|             <corners  | ||||
|                 android:bottomLeftRadius="6dip"  | ||||
|                 android:bottomRightRadius="6dip"  | ||||
|                 android:topLeftRadius="6dip"  | ||||
|                 android:topRightRadius="6dip" />  | ||||
|         </shape>  | ||||
|     </item>  | ||||
|     <!-- 背景部分 -->  | ||||
|     <!-- 形象的表达:bottom代表背景部分在上边缘超出阴影的高度,right代表背景部分在左边超出阴影的宽度(相对应的offset) -->  | ||||
|     <item  | ||||
|         android:left="3dp"  | ||||
|         android:top="3dp"  | ||||
|         android:right="3dp"  | ||||
|         android:bottom="5dp">  | ||||
|         <shape android:shape="rectangle" >  | ||||
|             <gradient  | ||||
|                 android:angle="270"  | ||||
|                 android:endColor="@color/colorAccent"  | ||||
|                 android:startColor="@color/colorAccent" />  | ||||
|             <corners  | ||||
|                 android:bottomLeftRadius="6dip"  | ||||
|                 android:bottomRightRadius="6dip"  | ||||
|                 android:topLeftRadius="6dip"  | ||||
|                 android:topRightRadius="6dip" />  | ||||
|         </shape>  | ||||
|     </item>  | ||||
| </layer-list> | ||||
| @@ -1,11 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportHeight="24" | ||||
|     android:viewportWidth="24"> | ||||
|     <path | ||||
|         android:fillColor="#ff000000" | ||||
|         android:pathData="M4,1C2.89,1 2,1.89 2,3V7C2,8.11 2.89,9 4,9H1V11H13V9H10C11.11,9 12,8.11 12,7V3C12,1.89 11.11,1 10,1H4M4,3H10V7H4V3M3,12V14H5V12H3M14,13C12.89,13 12,13.89 12,15V19C12,20.11 12.89,21 14,21H11V23H23V21H20C21.11,21 22,20.11 22,19V15C22,13.89 21.11,13 20,13H14M3,15V17H5V15H3M14,15H20V19H14V15M3,18V20H5V18H3M6,18V20H8V18H6M9,18V20H11V18H9Z"/> | ||||
|  | ||||
| </vector> | ||||
| @@ -1,11 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportHeight="24" | ||||
|     android:viewportWidth="24"> | ||||
|     <path | ||||
|         android:fillColor="#ff000000" | ||||
|         android:pathData="M4,1C2.89,1 2,1.89 2,3V7C2,8.11 2.89,9 4,9H1V11H13V9H10C11.11,9 12,8.11 12,7V3C12,1.89 11.11,1 10,1H4M4,3H10V7H4V3M14,13C12.89,13 12,13.89 12,15V19C12,20.11 12.89,21 14,21H11V23H23V21H20C21.11,21 22,20.11 22,19V15C22,13.89 21.11,13 20,13H14M3.88,13.46L2.46,14.88L4.59,17L2.46,19.12L3.88,20.54L6,18.41L8.12,20.54L9.54,19.12L7.41,17L9.54,14.88L8.12,13.46L6,15.59L3.88,13.46M14,15H20V19H14V15Z"/> | ||||
|  | ||||
| </vector> | ||||
| @@ -1,11 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportHeight="24" | ||||
|     android:viewportWidth="24"> | ||||
|     <path | ||||
|         android:fillColor="#ff000000" | ||||
|         android:pathData="M22,6C22,4.9 21.1,4 20,4H4C2.9,4 2,4.9 2,6V18C2,19.1 2.9,20 4,20H20C21.1,20 22,19.1 22,18V6M20,6L12,11L4,6H20M20,18H4V8L12,13L20,8V18Z"/> | ||||
|  | ||||
| </vector> | ||||
| @@ -1,11 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportHeight="24" | ||||
|     android:viewportWidth="24"> | ||||
|     <path | ||||
|         android:fillColor="#ff000000" | ||||
|         android:pathData="M24,7H22V13H24V7M24,15H22V17H24V15M20,6C20,4.9 19.1,4 18,4H2C0.9,4 0,4.9 0,6V18C0,19.1 0.9,20 2,20H18C19.1,20 20,19.1 20,18V6M18,6L10,11L2,6H18M18,18H2V8L10,13L18,8V18Z"/> | ||||
|  | ||||
| </vector> | ||||
| @@ -1,13 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <layer-list xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:clickable="true"> | ||||
|     <item | ||||
|         android:width="256dp" | ||||
|         android:height="256dp" | ||||
|         android:left="0dp"  | ||||
|         android:top="0dp"  | ||||
|         android:right="0dp"  | ||||
|         android:bottom="0dp" | ||||
|         android:drawable="@drawable/ic_winboll_logo"> | ||||
|     </item> | ||||
| </layer-list> | ||||
| @@ -1,13 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <layer-list xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:clickable="true" | ||||
|     android:layout_width="24dp" | ||||
| 	android:layout_height="24dp"> | ||||
|     <item android:drawable="@drawable/ic_launcher_background"/>  | ||||
|     <item  | ||||
|         android:left="0dp"  | ||||
|         android:top="0dp"  | ||||
|         android:right="0dp"  | ||||
|         android:bottom="0dp" | ||||
|         android:drawable="@drawable/ic_launcher_foreground_disable"/> | ||||
| </layer-list> | ||||
| @@ -1,10 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportHeight="24" | ||||
|     android:viewportWidth="24"> | ||||
|     <path | ||||
|         android:fillColor="#FFFFFFFF" | ||||
|         android:pathData="M16.61,15.15C16.15,15.15 15.77,14.78 15.77,14.32S16.15,13.5 16.61,13.5H16.61C17.07,13.5 17.45,13.86 17.45,14.32C17.45,14.78 17.07,15.15 16.61,15.15M7.41,15.15C6.95,15.15 6.57,14.78 6.57,14.32C6.57,13.86 6.95,13.5 7.41,13.5H7.41C7.87,13.5 8.24,13.86 8.24,14.32C8.24,14.78 7.87,15.15 7.41,15.15M16.91,10.14L18.58,7.26C18.67,7.09 18.61,6.88 18.45,6.79C18.28,6.69 18.07,6.75 18,6.92L16.29,9.83C14.95,9.22 13.5,8.9 12,8.91C10.47,8.91 9,9.24 7.73,9.82L6.04,6.91C5.95,6.74 5.74,6.68 5.57,6.78C5.4,6.87 5.35,7.08 5.44,7.25L7.1,10.13C4.25,11.69 2.29,14.58 2,18H22C21.72,14.59 19.77,11.7 16.91,10.14H16.91Z"/> | ||||
| </vector> | ||||
| @@ -1,10 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportHeight="24" | ||||
|     android:viewportWidth="24"> | ||||
|     <path | ||||
|         android:fillColor="#FF808080" | ||||
|         android:pathData="M16.61,15.15C16.15,15.15 15.77,14.78 15.77,14.32S16.15,13.5 16.61,13.5H16.61C17.07,13.5 17.45,13.86 17.45,14.32C17.45,14.78 17.07,15.15 16.61,15.15M7.41,15.15C6.95,15.15 6.57,14.78 6.57,14.32C6.57,13.86 6.95,13.5 7.41,13.5H7.41C7.87,13.5 8.24,13.86 8.24,14.32C8.24,14.78 7.87,15.15 7.41,15.15M16.91,10.14L18.58,7.26C18.67,7.09 18.61,6.88 18.45,6.79C18.28,6.69 18.07,6.75 18,6.92L16.29,9.83C14.95,9.22 13.5,8.9 12,8.91C10.47,8.91 9,9.24 7.73,9.82L6.04,6.91C5.95,6.74 5.74,6.68 5.57,6.78C5.4,6.87 5.35,7.08 5.44,7.25L7.1,10.13C4.25,11.69 2.29,14.58 2,18H22C21.72,14.59 19.77,11.7 16.91,10.14H16.91Z"/> | ||||
| </vector> | ||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 21 KiB | 
| @@ -1,27 +0,0 @@ | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="512dp" | ||||
|     android:height="512dp" | ||||
|     android:viewportWidth="512" | ||||
|     android:viewportHeight="512"> | ||||
|     <path | ||||
|         android:fillColor="#FF1E9B54" | ||||
|         android:strokeColor="#FFF8E733" | ||||
|         android:strokeWidth="20.0" | ||||
|         android:strokeLineCap="round" | ||||
|         android:strokeMiterLimit="10" | ||||
|         android:pathData="M254.63 35.45C374.95 35.45 473.38 133.89 473.38 254.2 473.38 374.51 374.95 472.95 254.63 472.95 134.32 472.95 35.88 374.51 35.88 254.2 35.88 133.89 134.32 35.45 254.63 35.45"/> | ||||
|     <path | ||||
|         android:fillColor="#FF000000" | ||||
|         android:strokeColor="#FF000000" | ||||
|         android:strokeWidth="1.0" | ||||
|         android:strokeLineCap="round" | ||||
|         android:strokeMiterLimit="10" | ||||
|         android:pathData="M257.28 361.25C266.56 361.25 274.14 368.84 274.14 378.11 274.14 387.39 266.56 394.98 257.28 394.98 248.01 394.98 240.42 387.39 240.42 378.11 240.42 368.84 248.01 361.25 257.28 361.25"/> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:strokeColor="#FF000000" | ||||
|         android:strokeWidth="30.0" | ||||
|         android:strokeLineCap="round" | ||||
|         android:strokeMiterLimit="10" | ||||
|         android:pathData="M182.16 214.09C181.42 199.71 182.42 177.87 207.64 155.49 213.64 150.16 220.13 146.12 226.28 143.08 238.64 136.97 249.62 134.91 252.55 134.56 252.7 134.54 252.83 134.53 252.94 134.52 253.05 134.51 253.14 134.5 253.2 134.5 255.01 134.48 294.9 136.66 313.05 160.43 332.29 185.63 344.82 221.3 300.07 263.56 263.08 298.49 258.36 318 258.54 317.72"/> | ||||
| </vector> | ||||
| @@ -1,41 +0,0 @@ | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="512dp" | ||||
|     android:height="512dp" | ||||
|     android:viewportWidth="512" | ||||
|     android:viewportHeight="512"> | ||||
|     <path | ||||
|         android:fillColor="#FF1E9B54" | ||||
|         android:strokeColor="#FFF8E733" | ||||
|         android:strokeWidth="20.0" | ||||
|         android:strokeLineCap="round" | ||||
|         android:strokeMiterLimit="10" | ||||
|         android:pathData="M254.63 35.45C374.95 35.45 473.38 133.89 473.38 254.2 473.38 374.51 374.95 472.95 254.63 472.95 134.32 472.95 35.88 374.51 35.88 254.2 35.88 133.89 134.32 35.45 254.63 35.45"/> | ||||
|     <path | ||||
|         android:fillColor="#FFFFFFFF" | ||||
|         android:strokeColor="#FF000000" | ||||
|         android:strokeWidth="20.0" | ||||
|         android:strokeLineCap="round" | ||||
|         android:strokeMiterLimit="10" | ||||
|         android:pathData="M151.49 130.96C151.49 130.96 348.53 130.96 348.53 130.96 348.53 130.96 348.53 393.46 348.53 393.46 348.53 393.46 151.49 393.46 151.49 393.46 151.49 393.46 151.49 130.96 151.49 130.96"/> | ||||
|     <path | ||||
|         android:fillColor="#FFFFFFFF" | ||||
|         android:strokeColor="#FF000000" | ||||
|         android:strokeWidth="20.0" | ||||
|         android:strokeLineCap="round" | ||||
|         android:strokeMiterLimit="10" | ||||
|         android:pathData="M186.28 207.75C186.28 207.75 304.95 207.75 304.95 207.75 304.95 207.75 304.95 205.97 304.95 205.97 304.95 205.97 186.28 205.97 186.28 205.97 186.28 205.97 186.28 207.75 186.28 207.75"/> | ||||
|     <path | ||||
|         android:fillColor="#FFFFFFFF" | ||||
|         android:strokeColor="#FF000000" | ||||
|         android:strokeWidth="20.0" | ||||
|         android:strokeLineCap="round" | ||||
|         android:strokeMiterLimit="10" | ||||
|         android:pathData="M186.28 263.52C186.28 263.52 304.95 263.52 304.95 263.52 304.95 263.52 304.95 264.41 304.95 264.41 304.95 264.41 186.28 264.41 186.28 264.41 186.28 264.41 186.28 263.52 186.28 263.52"/> | ||||
|     <path | ||||
|         android:fillColor="#FFFFFFFF" | ||||
|         android:strokeColor="#FF000000" | ||||
|         android:strokeWidth="20.0" | ||||
|         android:strokeLineCap="round" | ||||
|         android:strokeMiterLimit="10" | ||||
|         android:pathData="M186.28 323.62C186.28 323.62 304.95 323.62 304.95 323.62 304.95 323.62 304.95 320.62 304.95 320.62 304.95 320.62 186.28 320.62 186.28 320.62 186.28 320.62 186.28 323.62 186.28 323.62"/> | ||||
| </vector> | ||||
| @@ -1,20 +0,0 @@ | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="512dp" | ||||
|     android:height="512dp" | ||||
|     android:viewportWidth="512" | ||||
|     android:viewportHeight="512"> | ||||
|     <path | ||||
|         android:fillColor="#FF1E9B54" | ||||
|         android:strokeColor="#FFF8E733" | ||||
|         android:strokeWidth="20.0" | ||||
|         android:strokeLineCap="round" | ||||
|         android:strokeMiterLimit="10" | ||||
|         android:pathData="M254.63 35.45C374.95 35.45 473.38 133.89 473.38 254.2 473.38 374.51 374.95 472.95 254.63 472.95 134.32 472.95 35.88 374.51 35.88 254.2 35.88 133.89 134.32 35.45 254.63 35.45"/> | ||||
|     <path | ||||
|         android:fillColor="#FFFFFFFF" | ||||
|         android:strokeColor="#FFFFFFFF" | ||||
|         android:strokeWidth="1.0" | ||||
|         android:strokeLineCap="round" | ||||
|         android:strokeMiterLimit="10" | ||||
|         android:pathData="M257.28 361.25C266.56 361.25 274.14 368.84 274.14 378.11 274.14 387.39 266.56 394.98 257.28 394.98 248.01 394.98 240.42 387.39 240.42 378.11 240.42 368.84 248.01 361.25 257.28 361.25"/> | ||||
| </vector> | ||||
| @@ -1,10 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <shape xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
|     <gradient | ||||
|         android:angle="180" | ||||
|         android:endColor="#FFFFFFFF" | ||||
|         android:startColor="#FFFFFFFF" | ||||
|         android:type="linear" /> | ||||
|  | ||||
|     <corners android:radius="10dp" /> | ||||
| </shape> | ||||
| @@ -1,8 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <shape xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:shape="rectangle"> | ||||
|     <stroke | ||||
|         android:width="1dp" | ||||
|         android:color="#000000" /> <!-- 这里可调整边框宽度和颜色 --> | ||||
|     <solid android:color="@android:color/transparent" /> | ||||
| </shape> | ||||
| @@ -1,68 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent"> | ||||
|  | ||||
|     <LinearLayout | ||||
|         android:orientation="horizontal" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_gravity="right" | ||||
|         android:gravity="right" | ||||
|         android:padding="10dp" | ||||
|         android:id="@+id/ll_hostbar"> | ||||
|  | ||||
|         <RadioButton | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:text="10.8.0.250:456" | ||||
|             android:id="@+id/rb_debughost" | ||||
|             android:onClick="onSwitchHost"/> | ||||
|  | ||||
|         <RadioButton | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:text="yun.winboll.cc" | ||||
|             android:id="@+id/rb_yunhost" | ||||
|             android:onClick="onSwitchHost"/> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|      | ||||
| 	<LinearLayout | ||||
| 		android:orientation="horizontal" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:gravity="right"> | ||||
|  | ||||
| 		<Button | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="Test RSA" | ||||
|             android:onClick="onTestRSA"/> | ||||
|  | ||||
|         <Button | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:text="Test Login" | ||||
|             android:onClick="onTestLogin"/> | ||||
|          | ||||
| 	</LinearLayout> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="vertical" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:layout_weight="1.0"> | ||||
|  | ||||
| 		<cc.winboll.studio.libappbase.LogView | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="match_parent" | ||||
| 			android:id="@+id/logview"/> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
| @@ -1,63 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent"> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="horizontal" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:layout_gravity="right" | ||||
| 		android:gravity="right" | ||||
| 		android:padding="10dp" | ||||
| 		android:id="@+id/ll_hostbar"> | ||||
|  | ||||
| 		<RadioButton | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="10.8.0.250:456" | ||||
| 			android:id="@+id/rb_debughost" | ||||
| 			android:onClick="onSwitchHost"/> | ||||
|  | ||||
| 		<RadioButton | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="yun.winboll.cc" | ||||
| 			android:id="@+id/rb_yunhost" | ||||
| 			android:onClick="onSwitchHost"/> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="horizontal" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:layout_gravity="right" | ||||
| 		android:gravity="right"> | ||||
|  | ||||
| 		<Button | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="TestYun" | ||||
| 			android:onClick="onTestYun"/> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="vertical" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:layout_weight="1.0"> | ||||
|  | ||||
| 		<cc.winboll.studio.libappbase.LogView | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="match_parent" | ||||
| 			android:id="@+id/logview"/> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
| @@ -99,7 +99,7 @@ | ||||
| 			android:layout_weight="1.0" | ||||
| 			android:id="@+id/viewlogHorizontalScrollView1"> | ||||
|  | ||||
| 			<cc.winboll.studio.libappbase.views.HorizontalListView | ||||
| 			<cc.winboll.studio.libappbase.HorizontalListView | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="match_parent" | ||||
| 				android:id="@+id/tags_listview"/> | ||||
|   | ||||
| @@ -1,15 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="40dp" | ||||
| 	android:layout_height="40dp"> | ||||
|  | ||||
| 	<ImageView | ||||
| 		android:layout_width="40dp" | ||||
| 		android:layout_height="40dp" | ||||
| 		android:id="@+id/ivapp"/> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
| @@ -1,8 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:minWidth="40dp" | ||||
|     android:minHeight="40dp" | ||||
|     android:updatePeriodMillis="1000" | ||||
|     android:initialLayout="@layout/widget_status" | ||||
|     android:resizeMode="none"> | ||||
| </appwidget-provider> | ||||
| @@ -3,6 +3,9 @@ | ||||
| ## library project to WinBoLL Nexus Maven Repository. | ||||
| ## | ||||
|  | ||||
| ## WinBoLL Extra APK file Output Path | ||||
| #ExtraAPKOutputPath=/sdcard/AppProjects/app.apk | ||||
|  | ||||
| ## WinBoLL Nexus UserName | ||||
| #Nexus.name=nexustestuser1 | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user