Merge remote-tracking branch 'origin/appbase' into apputils
This commit is contained in:
		| @@ -14,7 +14,7 @@ def DefaultGroupId = 'cc.winboll.studio' // 类库所有者groupId | ||||
| def DefaultVersion = getDefaultVersion() // 版本号 | ||||
| def DeveloperId='zhangsken' // 开发者账号 | ||||
| def DeveloperName='ZhanGSKen' // 开发者名称 | ||||
| def DeveloperEMail='ZhanGSKen@QQ.COM' // 开发者邮箱地址 | ||||
| def DeveloperEMail='zhangsken@188.com' // 开发者邮箱地址 | ||||
| def LicenseName='The Apache Software License, Version 2.0' | ||||
| def LicenseUrl='http://www.apache.org/licenses/LICENSE-2.0.txt' | ||||
|  | ||||
|   | ||||
							
								
								
									
										13
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| # ☁ ☁ ☁ WinBoll APP ☁ ☁ ☁ ☁ ☁ ☁   ☁ ☁   ☁  ☁ ☁ ☁ ☁  ☁ ☁ ☁ ☁ ☁ ☁  | ||||
| # ☁    ☁ 这是 WinBoll 系列 APP 汇总项目。☁ ☁   ☁ ☁ ☁ ☁  ☁ ☁ ☁ ☁ ☁  ☁ ☁ ☁  | ||||
| # ☁ ☁ ☁ WinBoll 网站地址 https://www.winboll.cc/studio/app/ ☁ ☁ ☁ ☁  ☁ ☁ ☁ ☁ | ||||
| # ☁ ☁ ☁ WinBoLL APP ☁ ☁ ☁ ☁ ☁ ☁   ☁ ☁   ☁  ☁ ☁ ☁ ☁  ☁ ☁ ☁ ☁ ☁ ☁  | ||||
| # ☁    ☁ WinBoLL Studio Android 应用开源项目。☁ ☁   ☁ ☁ ☁ ☁  ☁ ☁ ☁ ☁ ☁  ☁ ☁ ☁  | ||||
| # ☁ ☁ ☁ WinBoLL 网站地址 https://www.winboll.cc/ ☁ ☁ ☁ ☁  ☁ ☁ ☁ ☁ | ||||
|  | ||||
| ## WinBoll 提问 | ||||
| 同样是 /sdcard 目录,在开发 Android 应用时, | ||||
| @@ -92,7 +92,12 @@ | ||||
|  | ||||
| ### ☁ 云游四方 ☁ ### | ||||
| ### ☁ 呔! ☁ WinBoll-APP 应用需求规划 | ||||
| ☁ WinBoll-APP 提供手机目录 /sdcard/WinBollStudio/Sources 的 WinBoll 项目源码管理功能。  | ||||
| ☁ 如要使用 WinBoLL Android 项目的 Gradle 编译功能,则需要设置以下两个文件夹。 | ||||
| ☁ 1. 则需要建立数据存储目录 /sdcard/WinBoLLStudio/APKs。 | ||||
|    WinBoLL 项目源码编译出来的安装包会拷贝一份到 /sdcard/WinBoLLStudio/APKs 目录下。  | ||||
| ☁ 2. 则需要建立数据存储目录 /sdcard/AppProjects。 | ||||
|    WinBoLL 项目源码编译出来的安装包会拷贝一份并命名 "app.apk" 的安装文件为到 /sdcard/AppProjects 目录下。  | ||||
|  | ||||
|  | ||||
| ### ☁ 吁! ☁ WinBoll-APP 共享计划前景 | ||||
| ☁ WinBoll-APP 将会实现 https://winboll.cc/api 访问功能。 | ||||
|   | ||||
| @@ -30,7 +30,7 @@ android { | ||||
|         // versionName 更新后需要手动设置  | ||||
|         // .winboll/winbollBuildProps.properties 文件的 stageCount=0 | ||||
|         // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" | ||||
|         versionName "15.4" | ||||
|         versionName "15.2" | ||||
|         if(true) { | ||||
|             versionName = genVersionName("${versionName}") | ||||
|         } | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Sun Apr 27 10:05:57 HKT 2025 | ||||
| stageCount=8 | ||||
| #Sat Apr 26 12:27:57 GMT 2025 | ||||
| stageCount=6 | ||||
| libraryProject=libappbase | ||||
| baseVersion=15.4 | ||||
| publishVersion=15.4.7 | ||||
| buildCount=0 | ||||
| baseBetaVersion=15.4.8 | ||||
| baseVersion=15.2 | ||||
| publishVersion=15.2.5 | ||||
| buildCount=4 | ||||
| baseBetaVersion=15.2.6 | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Sun Apr 27 10:05:40 HKT 2025 | ||||
| stageCount=8 | ||||
| #Sat Apr 26 12:27:57 GMT 2025 | ||||
| stageCount=6 | ||||
| libraryProject=libappbase | ||||
| baseVersion=15.4 | ||||
| publishVersion=15.4.7 | ||||
| buildCount=0 | ||||
| baseBetaVersion=15.4.8 | ||||
| baseVersion=15.2 | ||||
| publishVersion=15.2.5 | ||||
| buildCount=4 | ||||
| baseBetaVersion=15.2.6 | ||||
|   | ||||
 Submodule winboll-x deleted from d94d70050f
									
								
							
							
								
								
									
										1
									
								
								winboll/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								winboll/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| /build | ||||
							
								
								
									
										1
									
								
								winboll/app_update_description.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								winboll/app_update_description.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
|  | ||||
							
								
								
									
										50
									
								
								winboll/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								winboll/build.gradle
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| apply plugin: 'com.android.application' | ||||
| apply from: '../.winboll/winboll_app_build.gradle' | ||||
| apply from: '../.winboll/winboll_lint_build.gradle' | ||||
|  | ||||
| def genVersionName(def versionName){ | ||||
|     // 检查编译标志位配置 | ||||
|     assert (winbollBuildProps['stageCount'] != null) | ||||
|     assert (winbollBuildProps['baseVersion'] != null) | ||||
|     // 保存基础版本号 | ||||
|     winbollBuildProps.setProperty("baseVersion", "${versionName}"); | ||||
|     //保存编译标志配置 | ||||
|     FileOutputStream fos = new FileOutputStream(winbollBuildPropsFile) | ||||
|     winbollBuildProps.store(fos, "${winbollBuildPropsDesc}"); | ||||
|     fos.close(); | ||||
|      | ||||
|     // 返回编译版本号 | ||||
|     return "${versionName}." + winbollBuildProps['stageCount'] | ||||
| } | ||||
|  | ||||
| android { | ||||
|      | ||||
|     compileSdkVersion 32 | ||||
|     buildToolsVersion "32.0.0" | ||||
|  | ||||
|     defaultConfig { | ||||
|         applicationId "cc.winboll.studio.appbase" | ||||
|         minSdkVersion 24 | ||||
|         targetSdkVersion 29 | ||||
|         versionCode 1 | ||||
|         // versionName 更新后需要手动设置  | ||||
|         // .winboll/winbollBuildProps.properties 文件的 stageCount=0 | ||||
|         // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" | ||||
|         versionName "15.2" | ||||
|         if(true) { | ||||
|             versionName = genVersionName("${versionName}") | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     buildTypes { | ||||
|         release { | ||||
|             minifyEnabled false | ||||
|             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| dependencies { | ||||
|     api project(':libappbase') | ||||
|     api fileTree(dir: 'libs', include: ['*.jar']) | ||||
| } | ||||
							
								
								
									
										8
									
								
								winboll/build.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								winboll/build.properties
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Sat Apr 12 15:06:52 HKT 2025 | ||||
| stageCount=6 | ||||
| libraryProject=libappbase | ||||
| baseVersion=15.2 | ||||
| publishVersion=15.2.5 | ||||
| buildCount=0 | ||||
| baseBetaVersion=15.2.6 | ||||
							
								
								
									
										17
									
								
								winboll/proguard-rules.pro
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								winboll/proguard-rules.pro
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| # Add project specific ProGuard rules here. | ||||
| # By default, the flags in this file are appended to flags specified | ||||
| # in C:\tools\adt-bundle-windows-x86_64-20131030\sdk/tools/proguard/proguard-android.txt | ||||
| # You can edit the include path and order by changing the proguardFiles | ||||
| # directive in build.gradle. | ||||
| # | ||||
| # For more details, see | ||||
| #   http://developer.android.com/guide/developing/tools/proguard.html | ||||
|  | ||||
| # Add any project specific keep options here: | ||||
|  | ||||
| # If your project uses WebView with JS, uncomment the following | ||||
| # and specify the fully qualified class name to the JavaScript interface | ||||
| # class: | ||||
| #-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||||
| #   public *; | ||||
| #} | ||||
							
								
								
									
										12
									
								
								winboll/src/beta/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								winboll/src/beta/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" > | ||||
|  | ||||
|     <application> | ||||
|  | ||||
|         <!-- Put flavor specific code here --> | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
|  | ||||
							
								
								
									
										6
									
								
								winboll/src/beta/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								winboll/src/beta/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|  | ||||
|     <string name="app_name">AppBase+</string> | ||||
|  | ||||
| </resources> | ||||
							
								
								
									
										128
									
								
								winboll/src/main/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								winboll/src/main/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,128 @@ | ||||
| <?xml version='1.0' encoding='utf-8'?> | ||||
| <manifest | ||||
|     xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     package="cc.winboll.studio.appbase"> | ||||
|  | ||||
|     <application | ||||
|         android:name=".App" | ||||
|         android:icon="@drawable/ic_launcher" | ||||
|         android:label="@string/app_name" | ||||
|         android:theme="@style/MyAPPBaseTheme" | ||||
|         android:resizeableActivity="true" | ||||
|         android:process=":App"> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".MainActivity" | ||||
|             android:label="@string/app_name" | ||||
|             android:exported="true" | ||||
|             android:resizeableActivity="true" | ||||
|             android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="android.intent.action.MAIN"/> | ||||
|  | ||||
|                 <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> | ||||
|  | ||||
|         <meta-data | ||||
|             android:name="android.max_aspect" | ||||
|             android:value="4.0"/> | ||||
|  | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
							
								
								
									
										27
									
								
								winboll/src/main/java/cc/winboll/studio/appbase/App.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								winboll/src/main/java/cc/winboll/studio/appbase/App.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| package cc.winboll.studio.appbase; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @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; | ||||
|  | ||||
| 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); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,184 @@ | ||||
| package cc.winboll.studio.appbase; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
| import android.support.v7.widget.Toolbar; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.widget.CheckBox; | ||||
| import cc.winboll.studio.appbase.R; | ||||
| import cc.winboll.studio.appbase.activities.NewActivity; | ||||
| 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.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.dialogs.YesNoAlertDialog; | ||||
|  | ||||
| public class MainActivity extends WinBollActivityBase implements IWinBollActivity { | ||||
|  | ||||
|     public static final String TAG = "MainActivity"; | ||||
|  | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
|  | ||||
|     Toolbar mToolbar; | ||||
|     //LogView mLogView; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         ToastUtils.show("onCreate"); | ||||
|         setContentView(R.layout.activity_main); | ||||
|  | ||||
|         mToolbar = findViewById(R.id.toolbar); | ||||
|         setSupportActionBar(mToolbar); | ||||
|  | ||||
|         CheckBox cbIsDebugMode = findViewById(R.id.activitymainCheckBox1); | ||||
|         cbIsDebugMode.setChecked(GlobalApplication.isDebuging()); | ||||
|         //mLogView = findViewById(R.id.activitymainLogView1); | ||||
|  | ||||
| //        if (GlobalApplication.isDebuging()) { | ||||
| //            mLogView.start();  | ||||
| //            ToastUtils.show("LogView start."); | ||||
| //        } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         getMenuInflater().inflate(R.menu.toolbar_main, menu); | ||||
|         getMenuInflater().inflate(R.menu.toolbar_appbase, menu); | ||||
|         return super.onCreateOptionsMenu(menu); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。 | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     protected void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         Intent intentAPPWidget = new Intent(this, StatusWidget.class); | ||||
|         intentAPPWidget.setAction(StatusWidget.ACTION_STATUS_UPDATE); | ||||
|         sendBroadcast(intentAPPWidget); | ||||
|     } | ||||
|  | ||||
| 	public void onSwitchDebugMode(View view) { | ||||
|         boolean isDebuging = ((CheckBox)view).isChecked(); | ||||
|         GlobalApplication.setIsDebuging(isDebuging); | ||||
|         GlobalApplication.saveDebugStatus(); | ||||
|     } | ||||
|     | ||||
|     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); | ||||
|     } | ||||
|  | ||||
|      | ||||
| } | ||||
| @@ -0,0 +1,79 @@ | ||||
| package cc.winboll.studio.appbase; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/02/13 19:30:10 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.service.quicksettings.Tile; | ||||
| import android.service.quicksettings.TileService; | ||||
| import cc.winboll.studio.appbase.models.MainServiceBean; | ||||
| import cc.winboll.studio.appbase.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(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,82 @@ | ||||
| package cc.winboll.studio.appbase; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/03/28 15:34:16 | ||||
|  * @Describe 应用活动窗口基类 | ||||
|  */ | ||||
| import android.app.Activity; | ||||
| import android.os.Bundle; | ||||
| import android.os.PersistableBundle; | ||||
| import android.support.v7.app.AppCompatActivity; | ||||
| import android.view.MenuItem; | ||||
| import cc.winboll.studio.appbase.App; | ||||
| import cc.winboll.studio.appbase.R; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import cc.winboll.studio.libappbase.dialogs.YesNoAlertDialog; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBollActivity; | ||||
| import cc.winboll.studio.libappbase.winboll.WinBollActivityManager; | ||||
|  | ||||
| public class WinBollActivityBase extends AppCompatActivity implements IWinBollActivity { | ||||
|  | ||||
|     public static final String TAG = "WinBollActivityBase"; | ||||
|  | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
|  | ||||
|     WinBollActivityManager getWinBollActivityManager() { | ||||
|         return WinBollActivityManager.getInstance(GlobalApplication.getInstance()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         getWinBollActivityManager().add(this); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onPostCreate(Bundle savedInstanceState, PersistableBundle persistentState) { | ||||
|         super.onPostCreate(savedInstanceState, persistentState); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         if (item.getItemId() == cc.winboll.studio.appbase.R.id.item_log) { | ||||
|             GlobalApplication.getWinBollActivityManager().startLogActivity(this); | ||||
|             return true; | ||||
|         } else if(item.getItemId() == cc.winboll.studio.appbase.R.id.item_minimal) { | ||||
|             //moveTaskToBack(true); | ||||
|             exit(); | ||||
|         } | ||||
|         // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。 | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
|  | ||||
|     void exit() { | ||||
|         YesNoAlertDialog.show(this, "Exit " + getString(R.string.app_name), "Close all activity and exit?", new YesNoAlertDialog.OnDialogResultListener(){ | ||||
|  | ||||
|                 @Override | ||||
|                 public void onYes() { | ||||
|                     App.getWinBollActivityManager().finishAll(); | ||||
|                 } | ||||
|  | ||||
|                 @Override | ||||
|                 public void onNo() { | ||||
|                 } | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         getWinBollActivityManager().registeRemove(this); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,83 @@ | ||||
| package cc.winboll.studio.appbase.activities; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/03/25 11:46:40 | ||||
|  * @Describe 测试窗口2 | ||||
|  */ | ||||
| import android.app.Activity; | ||||
| import android.os.Bundle; | ||||
| import android.support.v7.widget.Toolbar; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import cc.winboll.studio.appbase.R; | ||||
| import cc.winboll.studio.appbase.WinBollActivityBase; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBollActivity; | ||||
|  | ||||
| public class New2Activity extends WinBollActivityBase 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); | ||||
|         setSupportActionBar(mToolbar); | ||||
|          | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onResume() { | ||||
|         super.onResume(); | ||||
|         //mLogView.start(); | ||||
|     } | ||||
|  | ||||
|     public void onCloseThisActivity(View view) { | ||||
|         GlobalApplication.getWinBollActivityManager().finish(this); | ||||
|     } | ||||
|  | ||||
|     public void onCloseAllActivity(View view) { | ||||
|         GlobalApplication.getWinBollActivityManager().finishAll(); | ||||
|     } | ||||
|  | ||||
|     public void onNewActivity(View view) { | ||||
|         GlobalApplication.getWinBollActivityManager().startWinBollActivity(this, NewActivity.class); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         getMenuInflater().inflate(R.menu.toolbar_main, menu); | ||||
|         getMenuInflater().inflate(R.menu.toolbar_appbase, menu); | ||||
|         return super.onCreateOptionsMenu(menu); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         if (item.getItemId() == cc.winboll.studio.appbase.R.id.item_log) { | ||||
|             GlobalApplication.getWinBollActivityManager().startLogActivity(this); | ||||
|             return true; | ||||
|         } | ||||
|         // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。 | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,81 @@ | ||||
| package cc.winboll.studio.appbase.activities; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/03/25 05:04:22 | ||||
|  */ | ||||
| import android.app.Activity; | ||||
| import android.os.Bundle; | ||||
| import android.support.v7.widget.Toolbar; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import cc.winboll.studio.appbase.R; | ||||
| import cc.winboll.studio.appbase.WinBollActivityBase; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBollActivity; | ||||
|  | ||||
| public class NewActivity extends WinBollActivityBase 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); | ||||
|         setSupportActionBar(mToolbar); | ||||
|          | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onResume() { | ||||
|         super.onResume(); | ||||
|         //mLogView.start(); | ||||
|     } | ||||
|  | ||||
|     public void onCloseThisActivity(View view) { | ||||
|         GlobalApplication.getWinBollActivityManager().finish(this); | ||||
|     } | ||||
|  | ||||
|     public void onCloseAllActivity(View view) { | ||||
|         GlobalApplication.getWinBollActivityManager().finishAll(); | ||||
|     } | ||||
|  | ||||
|     public void onNew2Activity(View view) { | ||||
|         GlobalApplication.getWinBollActivityManager().startWinBollActivity(this, New2Activity.class); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         getMenuInflater().inflate(R.menu.toolbar_main, menu); | ||||
|         getMenuInflater().inflate(R.menu.toolbar_appbase, menu); | ||||
|         return super.onCreateOptionsMenu(menu); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         if (item.getItemId() == cc.winboll.studio.appbase.R.id.item_log) { | ||||
|             GlobalApplication.getWinBollActivityManager().startLogActivity(this); | ||||
|             return true; | ||||
|         } | ||||
|         // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。 | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,38 @@ | ||||
| package cc.winboll.studio.appbase.handlers; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.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; | ||||
|                 } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,67 @@ | ||||
| package cc.winboll.studio.appbase.models; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.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; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,67 @@ | ||||
| package cc.winboll.studio.appbase.models; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.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; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,68 @@ | ||||
| package cc.winboll.studio.appbase.models; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.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; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,72 @@ | ||||
| package cc.winboll.studio.appbase.models; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/02/17 10:05:09 | ||||
|  * @Describe APPSOSReportBean | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.libappbase.BaseBean; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class WinBollNewsBean extends BaseBean { | ||||
|      | ||||
|     public static final String TAG = "WinBollNewsBean"; | ||||
|      | ||||
|     protected 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; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,36 @@ | ||||
| package cc.winboll.studio.appbase.receivers; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.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)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,117 @@ | ||||
| package cc.winboll.studio.appbase.receivers; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.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.models.WinBollNewsBean; | ||||
| 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.sos.APPModel; | ||||
| import cc.winboll.studio.libappbase.sos.SOS; | ||||
| import cc.winboll.studio.libappbase.sos.SOSObject; | ||||
| import cc.winboll.studio.libappbase.sos.WinBoll; | ||||
| import cc.winboll.studio.libappbase.utils.ToastUtils; | ||||
| 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(WinBoll.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 szAPPModel = intent.getStringExtra(WinBoll.EXTRA_APPMODEL); | ||||
|             LogUtils.d(TAG, String.format("szAPPModel %s", szAPPModel)); | ||||
|             if (szAPPModel != null && !szAPPModel.equals("")) { | ||||
|                 try { | ||||
|                     APPModel bean = APPModel.parseStringToBean(szAPPModel, APPModel.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().bindAPPModelConnection(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); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,138 @@ | ||||
| package cc.winboll.studio.appbase.services; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.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; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,316 @@ | ||||
| package cc.winboll.studio.appbase.services; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.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.models.MainServiceBean; | ||||
| import cc.winboll.studio.appbase.handlers.MainServiceHandler; | ||||
| 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 java.util.ArrayList; | ||||
| import cc.winboll.studio.libappbase.sos.APPModel; | ||||
|  | ||||
| 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 bindAPPModelConnection(APPModel 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); | ||||
|         APPModel appSOSBean = new APPModel(bean.getAppPackageName(), bean.getAppMainServiveName()); | ||||
|         intentWidget.putExtra("APPSOSBean", appSOSBean.toString()); | ||||
|         sendBroadcast(intentWidget); | ||||
|     } | ||||
|  | ||||
|     public class APPConnection implements ServiceConnection { | ||||
|  | ||||
|         ComponentName mComponentName; | ||||
|  | ||||
|         boolean isBindToAPP(APPModel 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)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -0,0 +1,178 @@ | ||||
| package cc.winboll.studio.appbase.services; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.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.models.TestDemoBindServiceBean; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.sos.WinBoll; | ||||
| import cc.winboll.studio.appbase.App; | ||||
| import cc.winboll.studio.libappbase.sos.SOS; | ||||
|  | ||||
| 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"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,156 @@ | ||||
| package cc.winboll.studio.appbase.services; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.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; | ||||
| import cc.winboll.studio.libappbase.sos.WinBoll; | ||||
|  | ||||
| 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"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,54 @@ | ||||
| package cc.winboll.studio.appbase.threads; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.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."); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,186 @@ | ||||
| package cc.winboll.studio.appbase.widgets; | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.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.models.WinBollNewsBean; | ||||
| import cc.winboll.studio.appbase.receivers.APPNewsWidgetClickListener; | ||||
| import cc.winboll.studio.libappbase.AppUtils; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.sos.APPModel; | ||||
| import cc.winboll.studio.libappbase.sos.WinBoll; | ||||
| import java.io.IOException; | ||||
| import java.text.SimpleDateFormat; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Date; | ||||
|  | ||||
| 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 szAPPModel = intent.getStringExtra(WinBoll.EXTRA_APPMODEL); | ||||
|             LogUtils.d(TAG, String.format("szAPPModel %s", szAPPModel)); | ||||
|             if (szAPPModel != null && !szAPPModel.equals("")) { | ||||
|                 try { | ||||
|                     APPModel bean = APPModel.parseStringToBean(szAPPModel, APPModel.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); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										11
									
								
								winboll/src/main/res/drawable/ic_cloud.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								winboll/src/main/res/drawable/ic_cloud.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| <?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> | ||||
							
								
								
									
										11
									
								
								winboll/src/main/res/drawable/ic_cloud_outline.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								winboll/src/main/res/drawable/ic_cloud_outline.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| <?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> | ||||
							
								
								
									
										216
									
								
								winboll/src/main/res/layout/activity_main.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								winboll/src/main/res/layout/activity_main.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,216 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent"> | ||||
|  | ||||
| 	<android.support.v7.widget.Toolbar | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:id="@+id/toolbar"/> | ||||
|  | ||||
| 	<ScrollView | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:layout_weight="1.0"> | ||||
|  | ||||
| 		<LinearLayout | ||||
| 			xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:orientation="vertical" | ||||
| 			android:gravity="center"> | ||||
|  | ||||
| 			<LinearLayout | ||||
| 				android:orientation="vertical" | ||||
| 				android:layout_width="match_parent" | ||||
| 				android:layout_height="0dp" | ||||
| 				android:layout_weight="1.0" | ||||
| 				android:gravity="center_horizontal"> | ||||
|  | ||||
| 				<TextView | ||||
| 					android:layout_width="wrap_content" | ||||
| 					android:layout_height="wrap_content" | ||||
| 					android:text="Hello, WinBoll!"/> | ||||
|  | ||||
| 				<TextView | ||||
| 					android:layout_width="wrap_content" | ||||
| 					android:layout_height="wrap_content" | ||||
| 					android:text="Android版本10的代号是“Q”,API级别是29。   Android 10开始谷歌不再公开使用甜品作为版本代号,但内部仍保留了大量与“Q”相关的元素。Android 10本身并没有严格对应某个特定的Java版本,但在开发Android 10应用时,通常可以使用Java 8或更高版本。   Java 8为Android开发带来了诸如Lambda表达式、方法引用等新特性,能提高开发效率和代码可读性,与Android 10开发适配良好。Java 9及更高版本也可用于Android 10开发,能使用一些新的语言特性和API,但可能需要注意兼容性和配置问题。"/> | ||||
|  | ||||
| 				<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> | ||||
|  | ||||
							
								
								
									
										43
									
								
								winboll/src/main/res/layout/activity_new.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								winboll/src/main/res/layout/activity_new.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| <?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.support.v7.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> | ||||
|  | ||||
							
								
								
									
										43
									
								
								winboll/src/main/res/layout/activity_new2.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								winboll/src/main/res/layout/activity_new2.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| <?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.support.v7.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> | ||||
|  | ||||
							
								
								
									
										51
									
								
								winboll/src/main/res/layout/widget_news.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								winboll/src/main/res/layout/widget_news.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| <?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> | ||||
|  | ||||
							
								
								
									
										6
									
								
								winboll/src/main/res/menu/toolbar_main.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								winboll/src/main/res/menu/toolbar_main.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <menu xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto"> | ||||
|      | ||||
|      | ||||
| </menu> | ||||
							
								
								
									
										7
									
								
								winboll/src/main/res/values/colors.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								winboll/src/main/res/values/colors.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|     <color name="colorPrimary">#FF00B322</color> | ||||
|     <color name="colorPrimaryDark">#FF005C12</color> | ||||
|     <color name="colorAccent">#FF8DFFA2</color> | ||||
|     <color name="colorText">#FFFFFB8D</color> | ||||
| </resources> | ||||
							
								
								
									
										5
									
								
								winboll/src/main/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								winboll/src/main/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|     <string name="app_name">AppBase</string> | ||||
|     <string name="tileservice_name">WinBoll</string> | ||||
| </resources> | ||||
							
								
								
									
										14
									
								
								winboll/src/main/res/values/styles.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								winboll/src/main/res/values/styles.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|     <style name="MyAPPBaseTheme" parent="APPBaseTheme"> | ||||
|         <item name="attrColorPrimary">@color/colorPrimary</item> | ||||
|         <item name="themeGlobalCrashActivity">@style/MyGlobalCrashActivityTheme</item> | ||||
|     </style> | ||||
|  | ||||
|     <style name="MyGlobalCrashActivityTheme" parent="GlobalCrashActivityTheme"> | ||||
|         <item name="colorTittle">#FFFFFFFF</item> | ||||
|         <item name="colorTittleBackgound">#FF00A4B3</item> | ||||
|         <item name="colorText">#FFFFFFFF</item> | ||||
|         <item name="colorTextBackgound">#FF000000</item> | ||||
| 	</style> | ||||
| </resources> | ||||
							
								
								
									
										7
									
								
								winboll/src/main/res/xml/widget_provider_info_sos.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								winboll/src/main/res/xml/widget_provider_info_sos.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| <?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> | ||||
							
								
								
									
										12
									
								
								winboll/src/stage/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								winboll/src/stage/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" > | ||||
|  | ||||
|     <application> | ||||
|  | ||||
|         <!-- Put flavor specific code here --> | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
|  | ||||
							
								
								
									
										6
									
								
								winboll/src/stage/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								winboll/src/stage/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|  | ||||
|     <!-- Put flavor specific strings here --> | ||||
|  | ||||
| </resources> | ||||
		Reference in New Issue
	
	Block a user
	 ZhanGSKen
					ZhanGSKen