20250922_005701_514
This commit is contained in:
		| @@ -1,8 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Mon Sep 15 18:05:08 HKT 2025 | ||||
| stageCount=6 | ||||
| #Sun Sep 21 16:44:01 GMT 2025 | ||||
| stageCount=0 | ||||
| libraryProject=libappbase | ||||
| baseVersion=15.9 | ||||
| publishVersion=15.9.5 | ||||
| buildCount=46 | ||||
| baseBetaVersion=15.9.6 | ||||
| baseVersion=15.10 | ||||
| publishVersion=15.10.0 | ||||
| buildCount=6 | ||||
| baseBetaVersion=15.10.1 | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| package cc.winboll.studio.libappbase.models; | ||||
| package cc.winboll.studio.libappbase; | ||||
| 
 | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
| @@ -1,28 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/15 20:05:03 | ||||
|  * @Describe AppUtils | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.content.pm.ApplicationInfo; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.content.pm.PackageManager.NameNotFoundException; | ||||
|  | ||||
| public class AppUtils { | ||||
|      | ||||
|     public static final String TAG = "AppUtils"; | ||||
|      | ||||
|     public static String getAppNameByPackageName(Context context, String packageName) { | ||||
|         PackageManager packageManager = context.getPackageManager(); | ||||
|         try { | ||||
|             ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName, 0); | ||||
|             return (String) packageManager.getApplicationLabel(applicationInfo); | ||||
|         } catch (NameNotFoundException e) { | ||||
|             LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|             return ""; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -10,88 +10,53 @@ import android.content.Context; | ||||
| import android.content.pm.ApplicationInfo; | ||||
| import android.content.pm.PackageManager; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import cc.winboll.studio.libappbase.models.APPModel; | ||||
| import cc.winboll.studio.libappbase.utils.ToastUtils; | ||||
| import cc.winboll.studio.libappbase.winboll.MyActivityLifecycleCallbacks; | ||||
| import cc.winboll.studio.libappbase.winboll.WinBoLLActivityManager; | ||||
|  | ||||
| public class GlobalApplication extends Application { | ||||
|  | ||||
|     public static final String TAG = "GlobalApplication"; | ||||
|  | ||||
|     volatile static GlobalApplication _GlobalApplication; | ||||
|     // 是否处于调试状态 | ||||
| 	 | ||||
|     // 应用是否处于调试状态 | ||||
|     volatile static boolean isDebuging = false; | ||||
|     MyActivityLifecycleCallbacks mMyActivityLifecycleCallbacks; | ||||
|  | ||||
|      | ||||
|     public static void setIsDebuging(boolean isDebuging) { | ||||
|         GlobalApplication.isDebuging = isDebuging; | ||||
|     } | ||||
|      | ||||
|     public static void saveDebugStatus() { | ||||
|         if (_GlobalApplication != null) { | ||||
|             APPModel.saveBeanToFile(getAPPModelFilePath(), new APPModel(GlobalApplication.isDebuging)); | ||||
|         } | ||||
|     public static void saveDebugStatus(GlobalApplication application) { | ||||
|         APPModel.saveBeanToFile(application.getAPPModelFilePath(application), new APPModel(GlobalApplication.isDebuging)); | ||||
|     } | ||||
|  | ||||
|     public static GlobalApplication getInstance() { | ||||
|         return _GlobalApplication; | ||||
|     } | ||||
|  | ||||
|     static String getAPPModelFilePath() { | ||||
|         return _GlobalApplication.getDataDir().getPath() + "/APPModel.json"; | ||||
| 	 | ||||
|     static String getAPPModelFilePath(GlobalApplication application) { | ||||
|         return application.getDataDir().getPath() + "/APPModel.json"; | ||||
|     } | ||||
|  | ||||
|     public static boolean isDebuging() { | ||||
|         return isDebuging; | ||||
|     } | ||||
|  | ||||
|     public static WinBoLLActivityManager getWinBoLLActivityManager() { | ||||
|         return WinBoLLActivityManager.getInstance(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         // 保存初始实例 | ||||
|         _GlobalApplication = this; | ||||
|          | ||||
| 		 | ||||
|         setIsDebuging(true); | ||||
|         // 添加日志模块 | ||||
|         LogUtils.init(this); | ||||
|         //LogUtils.setLogLevel(LogUtils.LOG_LEVEL.Debug); | ||||
|         //LogUtils.setTAGListEnable(GlobalApplication.TAG, true); | ||||
|         //LogUtils.setALlTAGListEnable(true); | ||||
|         //LogUtils.d(TAG, "LogUtils init"); | ||||
|         // 设置应用异常处理窗口 | ||||
|         CrashHandler.init(this); | ||||
|         // 初始化 Toast 框架 | ||||
|         ToastUtils.init(this); | ||||
|  | ||||
|         // 应用保存的调试标志 | ||||
|         APPModel appModel = APPModel.loadBeanFromFile(getAPPModelFilePath(), APPModel.class); | ||||
|         APPModel appModel = APPModel.loadBeanFromFile(getAPPModelFilePath(this), APPModel.class); | ||||
|         if (appModel == null) { | ||||
|             setIsDebuging(false); | ||||
|             saveDebugStatus(); | ||||
|             saveDebugStatus(this); | ||||
|         } else { | ||||
|             setIsDebuging(appModel.isDebuging()); | ||||
|         } | ||||
|          | ||||
|         getWinBoLLActivityManager().setWinBoLLUI_TYPE(WinBoLLActivityManager.WinBoLLUI_TYPE.Service); | ||||
|         // 注册窗口回调监听 | ||||
|         mMyActivityLifecycleCallbacks = new MyActivityLifecycleCallbacks(); | ||||
|         registerActivityLifecycleCallbacks(mMyActivityLifecycleCallbacks); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     public void onTerminate() { | ||||
|         super.onTerminate(); | ||||
|         // 注销回调(非必须,但建议释放资源) | ||||
|         unregisterActivityLifecycleCallbacks(mMyActivityLifecycleCallbacks); | ||||
|     } | ||||
|  | ||||
|     public static String getAppName(Context context) { | ||||
| 	 | ||||
| 	public static String getAppName(Context context) { | ||||
|         PackageManager packageManager = context.getPackageManager(); | ||||
|         try { | ||||
|             ApplicationInfo applicationInfo = packageManager.getApplicationInfo( | ||||
| @@ -102,27 +67,4 @@ public class GlobalApplication extends Application { | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| // | ||||
| //    @Override | ||||
| //    public void helpISOSService(Intent intent) { | ||||
| //        String szServiceName = intent.getStringExtra(EXTRA_SERVICE); | ||||
| //        String szPackageName = intent.getStringExtra(EXTRA_PACKAGE); | ||||
| //        if (szServiceName != null && !szServiceName.equals("") | ||||
| //            && szPackageName != null && !szPackageName.equals("")) { | ||||
| //            LogUtils.d(TAG, "szPackageName " + szPackageName); | ||||
| //            LogUtils.d(TAG, "szServiceName " + szServiceName); | ||||
| // | ||||
| //            // 目标服务的包名和类名 | ||||
| //            //String packageName = this.getPackageName(); | ||||
| //            //String serviceClassName = SimpleOperateSignalCenterService.class.getName(); | ||||
| // | ||||
| //            // 构建Intent | ||||
| //            Intent intentService = new Intent(); | ||||
| //            intentService.setComponent(new ComponentName(szPackageName, szServiceName)); | ||||
| //            intentService.putExtra(ISOSService.EXTRA_ENABLE, true); | ||||
| //            startService(intentService); | ||||
| //            LogUtils.d(TAG, "startService(intentService)"); | ||||
| //        } | ||||
| //        LogUtils.d(TAG, "helpISOSService"); | ||||
| //    } | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| package cc.winboll.studio.libappbase.views; | ||||
| package cc.winboll.studio.libappbase; | ||||
| 
 | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
| @@ -1,4 +1,4 @@ | ||||
| package cc.winboll.studio.libappbase.winboll; | ||||
| package cc.winboll.studio.libappbase; | ||||
| 
 | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
| @@ -6,29 +6,16 @@ package cc.winboll.studio.libappbase.winboll; | ||||
|  * @Describe 应用日志窗口 | ||||
|  */ | ||||
| import android.app.Activity; | ||||
| import android.os.Build; | ||||
| import android.os.Bundle; | ||||
| import android.view.WindowManager; | ||||
| import cc.winboll.studio.libappbase.LogView; | ||||
| import cc.winboll.studio.libappbase.R; | ||||
| import cc.winboll.studio.libappbase.utils.ToastUtils; | ||||
| 
 | ||||
| public class LogActivity extends Activity implements IWinBoLLActivity { | ||||
| public class LogActivity extends Activity { | ||||
| 
 | ||||
|     public static final String TAG = "LogActivity"; | ||||
| 
 | ||||
|     LogView mLogView; | ||||
| 
 | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
| @@ -28,7 +28,6 @@ import android.widget.Spinner; | ||||
| import android.widget.TextView; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.R; | ||||
| import cc.winboll.studio.libappbase.views.HorizontalListView; | ||||
| import java.text.Collator; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| package cc.winboll.studio.libappbase.utils; | ||||
| import android.content.Context; | ||||
| import android.widget.Toast; | ||||
| package cc.winboll.studio.libappbase; | ||||
| 
 | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/03/12 12:02:31 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.widget.Toast; | ||||
| 
 | ||||
| public class ToastUtils { | ||||
| 
 | ||||
|     public static final String TAG = "ToastUtils"; | ||||
| @@ -1,150 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.activities; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.os.Bundle; | ||||
| import android.view.View; | ||||
| import android.widget.RadioButton; | ||||
| import cc.winboll.studio.libappbase.BuildConfig; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.LogView; | ||||
| import cc.winboll.studio.libappbase.R; | ||||
| import cc.winboll.studio.libappbase.models.UserInfoModel; | ||||
| import cc.winboll.studio.libappbase.utils.RSAUtils; | ||||
| import cc.winboll.studio.libappbase.utils.YunUtils; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; | ||||
| import java.security.KeyPair; | ||||
| import java.security.PrivateKey; | ||||
| import java.security.PublicKey; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/06/04 13:29 | ||||
|  * @Describe 用户登录框 | ||||
|  */ | ||||
| public class LogonActivity extends Activity implements IWinBoLLActivity { | ||||
|  | ||||
|     public static final String TAG = "LogonActivity"; | ||||
|  | ||||
|     public static final String DEBUG_HOST = "http://10.8.0.250:456"; | ||||
|     public static final String YUN_HOST = "https://yun.winboll.cc"; | ||||
|      | ||||
|      | ||||
|     String mHost = ""; | ||||
|     RadioButton mrbYunHost; | ||||
|     RadioButton mrbDebugHost; | ||||
|     LogView mLogView; | ||||
|      | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_logon); | ||||
|         mLogView = findViewById(R.id.logview); | ||||
|         mLogView.start(); | ||||
|  | ||||
|         mHost = BuildConfig.DEBUG ? DEBUG_HOST: YUN_HOST; | ||||
|         if (BuildConfig.DEBUG) { | ||||
|             mrbYunHost = findViewById(R.id.rb_yunhost); | ||||
|             mrbDebugHost = findViewById(R.id.rb_debughost); | ||||
|             mrbYunHost.setChecked(!BuildConfig.DEBUG); | ||||
|             mrbDebugHost.setChecked(BuildConfig.DEBUG); | ||||
|         } else { | ||||
|             findViewById(R.id.ll_hostbar).setVisibility(View.GONE); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     public void onSwitchHost(View view) { | ||||
|         if (view.getId() == R.id.rb_yunhost) { | ||||
|             mrbDebugHost.setChecked(false); | ||||
|             mHost = YUN_HOST; | ||||
|         } else if (view.getId() == R.id.rb_debughost) { | ||||
|             mrbYunHost.setChecked(false); | ||||
|             mHost = DEBUG_HOST; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onResume() { | ||||
|         super.onResume(); | ||||
|         mLogView.start(); | ||||
|     } | ||||
|  | ||||
|     public void onTestLogin(View view) { | ||||
|         LogUtils.d(TAG, "onTestLogin"); | ||||
|         final YunUtils yunUtils = YunUtils.getInstance(this); | ||||
|          | ||||
|         UserInfoModel userInfoModel = new UserInfoModel(); | ||||
|         userInfoModel.setUsername("jian"); | ||||
|         userInfoModel.setPassword("kkiio"); | ||||
|         userInfoModel.setToken("aaa111"); | ||||
|         yunUtils.login(mHost, userInfoModel); | ||||
|     } | ||||
|  | ||||
|     public void onTestRSA(View view) { | ||||
|         LogUtils.d(TAG, "onTestRSA"); | ||||
|         RSAUtils utils = RSAUtils.getInstance(this); | ||||
|          | ||||
|         try { | ||||
|             // 测试 1:首次生成密钥对 | ||||
|             LogUtils.d(TAG, "==== 首次生成密钥对 ===="); | ||||
|             if (utils.keysExist()) { | ||||
|                 LogUtils.d(TAG, "密钥对已生成"); | ||||
|             } else { | ||||
|                 utils.generateAndSaveKeys(); | ||||
|                 LogUtils.d(TAG, "密钥对生成成功。"); | ||||
|             } | ||||
|  | ||||
|             // 测试 2:获取密钥对(自动读取已生成的文件) | ||||
|             KeyPair keyPair = utils.getOrGenerateKeys(); | ||||
|             PublicKey publicKey = keyPair.getPublic(); | ||||
|             PrivateKey privateKey = keyPair.getPrivate(); | ||||
|  | ||||
|             // 打印密钥信息 | ||||
|             LogUtils.d(TAG, "\n==== 密钥信息 ===="); | ||||
|             LogUtils.d(TAG, "公钥算法:" + publicKey.getAlgorithm()); | ||||
|             LogUtils.d(TAG, "公钥编码长度:" + publicKey.getEncoded().length + "字节"); | ||||
|             LogUtils.d(TAG, "私钥算法:" + privateKey.getAlgorithm()); | ||||
|             LogUtils.d(TAG, "私钥编码长度:" + privateKey.getEncoded().length + "字节"); | ||||
|  | ||||
|             // 测试 3:重复调用时检查是否复用文件 | ||||
|             LogUtils.d(TAG, "\n==== 二次调用 ===="); | ||||
|             KeyPair reusedPair = utils.getOrGenerateKeys(); | ||||
|             LogUtils.d(TAG, "是否为同一公钥:" + (publicKey.equals(reusedPair.getPublic()))); // true(单例引用) | ||||
|             LogUtils.d(TAG, "操作完成"); | ||||
|  | ||||
|             String testMessage = "Hello, RSA Encryption!"; | ||||
|  | ||||
|             // 1. 获取或生成密钥对 | ||||
|             PublicKey publicKeyReused = reusedPair.getPublic(); | ||||
|             PrivateKey privateKeyReused = reusedPair.getPrivate(); | ||||
|  | ||||
|             // 2. 公钥加密 | ||||
|             byte[] encryptedData = utils.encryptWithPublicKey(testMessage, publicKeyReused); | ||||
|             LogUtils.d(TAG, "加密后数据(字节长度):" + encryptedData.length); | ||||
|  | ||||
|             // 3. 私钥解密 | ||||
|             String decryptedMessage = utils.decryptWithPrivateKey(encryptedData, privateKeyReused); | ||||
|             LogUtils.d(TAG, "解密结果: " + decryptedMessage); | ||||
|              | ||||
|             // 4. 验证解密是否成功 | ||||
|             if (testMessage.equals(decryptedMessage)) { | ||||
|                 LogUtils.d(TAG, "加密解密测试通过!"); | ||||
|             } else { | ||||
|                 LogUtils.d(TAG, "测试失败:内容不一致"); | ||||
|             } | ||||
|         } catch (Exception e) { | ||||
|             LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|  | ||||
| } | ||||
| @@ -1,126 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.activities; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.os.Bundle; | ||||
| import android.view.View; | ||||
| import cc.winboll.studio.libappbase.BuildConfig; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.R; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; | ||||
| import java.io.IOException; | ||||
| import okhttp3.OkHttpClient; | ||||
| import okhttp3.Request; | ||||
| import okhttp3.Response; | ||||
| import android.widget.RadioButton; | ||||
| import cc.winboll.studio.libappbase.LogView; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/06/04 11:06 | ||||
|  * @Describe 云宝云 | ||||
|  */ | ||||
| public class YunActivity extends Activity implements IWinBoLLActivity { | ||||
|  | ||||
|     public static final String TAG = "YunActivity"; | ||||
|  | ||||
|     public static final String DEBUG_HOST = "http://10.8.0.250:456"; | ||||
|     public static final String YUN_HOST = "https://yun.winboll.cc"; | ||||
|  | ||||
|     String mHost = ""; | ||||
|     RadioButton mrbYunHost; | ||||
|     RadioButton mrbDebugHost; | ||||
|     LogView mLogView; | ||||
|  | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_yun); | ||||
|         mLogView = findViewById(R.id.logview); | ||||
|         mLogView.start(); | ||||
|  | ||||
|         mHost = BuildConfig.DEBUG ? DEBUG_HOST: YUN_HOST; | ||||
|         if (BuildConfig.DEBUG) { | ||||
|             mrbYunHost = findViewById(R.id.rb_yunhost); | ||||
|             mrbDebugHost = findViewById(R.id.rb_debughost); | ||||
|             mrbYunHost.setChecked(!BuildConfig.DEBUG); | ||||
|             mrbDebugHost.setChecked(BuildConfig.DEBUG); | ||||
|         } else { | ||||
|             findViewById(R.id.ll_hostbar).setVisibility(View.GONE); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void onSwitchHost(View view) { | ||||
|         if (view.getId() == R.id.rb_yunhost) { | ||||
|             mrbDebugHost.setChecked(false); | ||||
|             mHost = YUN_HOST; | ||||
|         } else if (view.getId() == R.id.rb_debughost) { | ||||
|             mrbYunHost.setChecked(false); | ||||
|             mHost = DEBUG_HOST; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onResume() { | ||||
|         super.onResume(); | ||||
|         mLogView.start(); | ||||
|     } | ||||
|  | ||||
|     public void onTestYun(View view) { | ||||
|         LogUtils.d(TAG, "onTestYun"); | ||||
|         (new Thread(new Runnable(){ | ||||
|                 @Override | ||||
|                 public void run() { | ||||
|                     testYun(); | ||||
|                 } | ||||
|             })).start(); | ||||
|     } | ||||
|  | ||||
|     void testYun() { | ||||
|         OkHttpClient client = new OkHttpClient(); | ||||
|         Request request = new Request.Builder() | ||||
|             .url(mHost + "/backups/") | ||||
|             .build(); | ||||
|  | ||||
|         Response response = null; | ||||
|         try { | ||||
|             response = client.newCall(request).execute(); | ||||
|             if (response.isSuccessful()) { | ||||
|                 String responseBody = ""; | ||||
|                 if (response.body() != null) { | ||||
|                     responseBody = response.body().string(); | ||||
|                 } | ||||
|  | ||||
|                 // 正则匹配:任意主机名 -> Test OK(主机名部分匹配非空字符) | ||||
|                 boolean isMatch = responseBody.matches(".+? -> Test OK"); | ||||
|  | ||||
|                 if (isMatch) { | ||||
|                     LogUtils.d(TAG, responseBody); | ||||
|                 } else { | ||||
|                     LogUtils.d(TAG, "响应内容不匹配,内容:" + responseBody); | ||||
|                 } | ||||
|             } else { | ||||
|                 LogUtils.d(TAG, "请求失败,状态码:" + response.code()); | ||||
|             } | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, "读取响应体失败:" + e.getMessage()); | ||||
|         } catch (Exception e) { | ||||
|             LogUtils.d(TAG, "异常:" + e.getMessage()); | ||||
|             e.printStackTrace(); // Java 7 需显式打印堆栈 | ||||
|         } finally { | ||||
|             // 手动关闭 Response(Java 7 不支持 try-with-resources) | ||||
|             if (response != null && response.body() != null) { | ||||
|                 response.body().close(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,60 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.dialogs; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/03/28 17:40:47 | ||||
|  * @Date 2024/08/12 14:46:25 | ||||
|  * @Describe 询问用户确定与否的选择框 | ||||
|  */ | ||||
| import android.app.AlertDialog; | ||||
| import android.content.Context; | ||||
| import android.content.DialogInterface; | ||||
|  | ||||
| public class YesNoAlertDialog { | ||||
|  | ||||
|     public static final String TAG = "YesNoAlertDialog"; | ||||
|  | ||||
|     public static void show(Context context, String szTitle, String szMessage, final OnDialogResultListener listener) { | ||||
|         AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder( | ||||
|             context); | ||||
|  | ||||
|         // set title | ||||
|         alertDialogBuilder.setTitle(szTitle); | ||||
|  | ||||
|         // set dialog message | ||||
|         alertDialogBuilder | ||||
|             .setMessage(szMessage) | ||||
|             .setCancelable(true) | ||||
|             .setOnCancelListener(new DialogInterface.OnCancelListener(){ | ||||
|                 @Override | ||||
|                 public void onCancel(DialogInterface dialog) { | ||||
|                     listener.onNo(); | ||||
|                 } | ||||
|             }) | ||||
|             .setPositiveButton("YES", new DialogInterface.OnClickListener() { | ||||
|                 public void onClick(DialogInterface dialog, int id) { | ||||
|                     // if this button is clicked, close | ||||
|                     // current activity | ||||
|                     listener.onYes(); | ||||
|                 } | ||||
|             }) | ||||
|             .setNegativeButton("NO", new DialogInterface.OnClickListener() { | ||||
|                 public void onClick(DialogInterface dialog, int id) { | ||||
|                     // if this button is clicked, just close | ||||
|                     // the dialog box and do nothing | ||||
|                     dialog.cancel(); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|         // create alert dialog | ||||
|         AlertDialog alertDialog = alertDialogBuilder.create(); | ||||
|  | ||||
|         // show it | ||||
|         alertDialog.show(); | ||||
|     } | ||||
|  | ||||
|     public interface OnDialogResultListener { | ||||
|         abstract void onYes(); | ||||
|         abstract void onNo(); | ||||
|     } | ||||
| } | ||||
| @@ -1,53 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.models; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/06/05 11:26 | ||||
|  */ | ||||
|  | ||||
| public class ResponseData { | ||||
|      | ||||
|     public static final String STATUS_SUCCESS = "success"; | ||||
|     public static final String STATUS_ERROR = "error"; | ||||
|      | ||||
|     private String status; | ||||
|     private String message; | ||||
|     private UserInfoModel data; | ||||
|      | ||||
|     public ResponseData() { | ||||
|         this.status = ""; | ||||
|         this.message = ""; | ||||
|         this.data = new UserInfoModel(); | ||||
|     } | ||||
|      | ||||
|     public ResponseData(String status, String message, UserInfoModel data) { | ||||
|         this.status = status; | ||||
|         this.message = message; | ||||
|         this.data = data; | ||||
|     } | ||||
|  | ||||
|     public void setStatus(String status) { | ||||
|         this.status = status; | ||||
|     } | ||||
|  | ||||
|     public String getStatus() { | ||||
|         return status; | ||||
|     } | ||||
|  | ||||
|     public void setMessage(String message) { | ||||
|         this.message = message; | ||||
|     } | ||||
|  | ||||
|     public String getMessage() { | ||||
|         return message; | ||||
|     } | ||||
|  | ||||
|     public void setData(UserInfoModel data) { | ||||
|         this.data = data; | ||||
|     } | ||||
|  | ||||
|     public UserInfoModel getData() { | ||||
|         return data; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1,92 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.models; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/06/04 19:14 | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.libappbase.BaseBean; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class UserInfoModel extends BaseBean { | ||||
|  | ||||
|     public static final String TAG = "UserInfoModel"; | ||||
|  | ||||
|     String username; | ||||
|     String password; | ||||
|     String token; | ||||
|  | ||||
|     public UserInfoModel() { | ||||
|         this.username = ""; | ||||
|         this.password = ""; | ||||
|         this.token = ""; | ||||
|     } | ||||
|  | ||||
|     public void setUsername(String username) { | ||||
|         this.username = username; | ||||
|     } | ||||
|  | ||||
|     public String getUsername() { | ||||
|         return username; | ||||
|     } | ||||
|  | ||||
|     public void setPassword(String password) { | ||||
|         this.password = password; | ||||
|     } | ||||
|  | ||||
|     public String getPassword() { | ||||
|         return password; | ||||
|     } | ||||
|  | ||||
|     public void setToken(String token) { | ||||
|         this.token = token; | ||||
|     } | ||||
|  | ||||
|     public String getToken() { | ||||
|         return token; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return UserInfoModel.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         jsonWriter.name("username").value(getUsername()); | ||||
|         jsonWriter.name("password").value(getPassword()); | ||||
|         jsonWriter.name("token").value(getToken()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { | ||||
|             if (name.equals("username")) { | ||||
|                 setUsername(jsonReader.nextString()); | ||||
|             } else if (name.equals("password")) { | ||||
|                 setPassword(jsonReader.nextString()); | ||||
|             } else if (name.equals("token")) { | ||||
|                 setToken(jsonReader.nextString()); | ||||
|             } else { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { | ||||
|         jsonReader.beginObject(); | ||||
|         while (jsonReader.hasNext()) { | ||||
|             String name = jsonReader.nextName(); | ||||
|             if (!initObjectsFromJsonReader(jsonReader, name)) { | ||||
|                 jsonReader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         // 结束 JSON 对象 | ||||
|         jsonReader.endObject(); | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
| @@ -1,91 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.models; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/05/10 10:16 | ||||
|  * @Describe WinBoLLModel | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.libappbase.BaseBean; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class WinBoLLModel extends BaseBean { | ||||
|      | ||||
|     public static final String TAG = "WinBoLLModel"; | ||||
|      | ||||
|     String appPackageName; | ||||
|     String appMainServiveName; | ||||
|  | ||||
|     public WinBoLLModel() { | ||||
|         this.appPackageName = ""; | ||||
|         this.appMainServiveName = ""; | ||||
|     } | ||||
|  | ||||
|     public WinBoLLModel(boolean isDebuging, String appPackageName, String appMainServiveName) { | ||||
|         this.appPackageName = appPackageName; | ||||
|         this.appMainServiveName = appMainServiveName; | ||||
|     } | ||||
|  | ||||
|     public WinBoLLModel(String appPackageName, String appMainServiveName) { | ||||
|         this.appPackageName = appPackageName; | ||||
|         this.appMainServiveName = appMainServiveName; | ||||
|     } | ||||
|  | ||||
|     public void setAppPackageName(String appPackageName) { | ||||
|         this.appPackageName = appPackageName; | ||||
|     } | ||||
|  | ||||
|     public String getAppPackageName() { | ||||
|         return appPackageName; | ||||
|     } | ||||
|  | ||||
|     public void setAppMainServiveName(String appMainServiveName) { | ||||
|         this.appMainServiveName = appMainServiveName; | ||||
|     } | ||||
|  | ||||
|     public String getAppMainServiveName() { | ||||
|         return appMainServiveName; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return APPModel.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         jsonWriter.name("appPackageName").value(getAppPackageName()); | ||||
|         jsonWriter.name("appMainServiveName").value(getAppMainServiveName()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { | ||||
|             if (name.equals("appPackageName")) { | ||||
|                 setAppPackageName(jsonReader.nextString()); | ||||
|             } else if (name.equals("appMainServiveName")) { | ||||
|                 setAppMainServiveName(jsonReader.nextString()); | ||||
|             } else { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { | ||||
|         jsonReader.beginObject(); | ||||
|         while (jsonReader.hasNext()) { | ||||
|             String name = jsonReader.nextName(); | ||||
|             if (!initObjectsFromJsonReader(jsonReader, name)) { | ||||
|                 jsonReader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         // 结束 JSON 对象 | ||||
|         jsonReader.endObject(); | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
|      | ||||
| @@ -1,70 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.models; | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.libappbase.BaseBean; | ||||
| import java.io.IOException; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/05/10 09:36 | ||||
|  * @Describe WinBoLL 应用消息数据模型 | ||||
|  */ | ||||
| public class WinBoLLNewsBean extends BaseBean { | ||||
|      | ||||
|     public static final String TAG = "WinBoLLNewsBean"; | ||||
|      | ||||
|     String message; | ||||
|      | ||||
|     public WinBoLLNewsBean() { | ||||
|         this.message = ""; | ||||
|     } | ||||
|  | ||||
|     public WinBoLLNewsBean(String message) { | ||||
|         this.message = message; | ||||
|     } | ||||
|  | ||||
|     public void setMessage(String message) { | ||||
|         this.message = message; | ||||
|     } | ||||
|  | ||||
|     public String getMessage() { | ||||
|         return message; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return WinBoLLNewsBean.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         jsonWriter.name("message").value(getMessage()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { | ||||
|             if (name.equals("message")) { | ||||
|                 setMessage(jsonReader.nextString()); | ||||
|             } else { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { | ||||
|         jsonReader.beginObject(); | ||||
|         while (jsonReader.hasNext()) { | ||||
|             String name = jsonReader.nextName(); | ||||
|             if (!initObjectsFromJsonReader(jsonReader, name)) { | ||||
|                 jsonReader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         // 结束 JSON 对象 | ||||
|         jsonReader.endObject(); | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
| @@ -1,29 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.receiver; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/13 21:19:09 | ||||
|  * @Describe MyBroadcastReceiver | ||||
|  */ | ||||
| import android.content.BroadcastReceiver; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.R; | ||||
|  | ||||
| public class MyBroadcastReceiver extends BroadcastReceiver { | ||||
|      | ||||
|     public static final String TAG = "MyBroadcastReceiver"; | ||||
|      | ||||
|     @Override | ||||
|     public void onReceive(Context context, Intent intent) { | ||||
|         if (context.getString(R.string.action_sos).equals(intent.getAction())) { | ||||
|             String message = intent.getStringExtra("message"); | ||||
|             String sosPackage = intent.getStringExtra("sosPackage"); | ||||
|              | ||||
|             // 处理接收到的广播消息 | ||||
|             LogUtils.d(TAG, String.format("MyBroadcastReceiver action %s \n%s\n%s", intent.getAction(), sosPackage, message)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1,59 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.sos; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/03/02 09:36:29 | ||||
|  * @Describe WinBoLL 应用 SOS 机理保护类 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class SOS { | ||||
|  | ||||
|     public static final String TAG = "SOS"; | ||||
|  | ||||
|     public static final String ACTION_SOS = SOS.class.getName() + ".ACTION_SOS"; | ||||
|     public static final String EXTRA_OBJECT = "EXTRA_OBJECT"; | ||||
|  | ||||
|     public static void sosToAppBase(Context context, String sosService) { | ||||
|         LogUtils.d(TAG, "sosToAppBase()"); | ||||
|         String szToPackage = "cc.winboll.studio.appbase"; | ||||
|         sos(context, szToPackage, sosService); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public static void sosToAppBaseBeta(Context context, String sosService) { | ||||
|         LogUtils.d(TAG, "sosToAppBaseBeta()"); | ||||
|         String szToPackage = "cc.winboll.studio.appbase.beta"; | ||||
|         sos(context, szToPackage, sosService); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     static void sos(Context context, String szToPackage, String sosService) { | ||||
|         LogUtils.d(TAG, "sos(...)"); | ||||
|         Intent intent = new Intent(ACTION_SOS); | ||||
|         intent.putExtra(EXTRA_OBJECT, genSOSObject(context.getPackageName(), sosService)); | ||||
|         intent.setPackage(szToPackage); | ||||
|         LogUtils.d(TAG, String.format("ACTION_SOS :\nTo Package : %sSOS Service : %s\n", szToPackage, sosService)); | ||||
|         context.sendBroadcast(intent); | ||||
|     } | ||||
|  | ||||
|     public static SOSObject parseSOSObject(String szSOSObject) { | ||||
|         try { | ||||
|             return SOSObject.parseStringToBean(szSOSObject, SOSObject.class); | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     public static String sosObjectToString(SOSObject object) { | ||||
|         return object.toString(); | ||||
|     } | ||||
|  | ||||
|     public static String genSOSObject(String objectPackageName, String objectServiveName) { | ||||
|         return (new SOSObject(objectPackageName, objectServiveName)).toString(); | ||||
|     } | ||||
| } | ||||
| @@ -1,182 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.sos; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/27 14:00:21 | ||||
|  * @Describe Simple Operate Signal Service Center. | ||||
|  *           简单操作信号服务中心 | ||||
|  */ | ||||
| import android.app.Service; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.IBinder; | ||||
| import android.os.IInterface; | ||||
| import android.os.Parcel; | ||||
| import android.os.RemoteException; | ||||
| import java.io.FileDescriptor; | ||||
| import android.app.Service; | ||||
| import android.content.Intent; | ||||
| import android.os.IBinder; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
|  | ||||
| public class SOSCenterService extends Service { | ||||
|  | ||||
|     public static final String TAG = "SOSCenterService"; | ||||
|      | ||||
|     private final IBinder binder =(IBinder)new SOSBinder(); | ||||
|  | ||||
|     SOSCenterServiceModel mSOSCenterServiceModel; | ||||
|     static MainThread _MainThread; | ||||
|     public static synchronized MainThread getMainThreadInstance() { | ||||
|         if (_MainThread == null) { | ||||
|             _MainThread = new MainThread(); | ||||
|         } | ||||
|         return _MainThread; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public IBinder onBind(Intent intent) { | ||||
|         return binder; | ||||
|     } | ||||
|  | ||||
|     public class SOSBinder implements IBinder { | ||||
|  | ||||
|         @Override | ||||
|         public void dump(FileDescriptor fileDescriptor, String[] string) throws RemoteException { | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void dumpAsync(FileDescriptor fileDescriptor, String[] string) throws RemoteException { | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public String getInterfaceDescriptor() throws RemoteException { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public boolean isBinderAlive() { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void linkToDeath(IBinder.DeathRecipient deathRecipient, int p) throws RemoteException { | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public boolean pingBinder() { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public IInterface queryLocalInterface(String string) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public boolean transact(int p, Parcel parcel, Parcel parcel1, int p1) throws RemoteException { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public boolean unlinkToDeath(IBinder.DeathRecipient deathRecipient, int p) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         public static final String TAG = "SOSBinder"; | ||||
|         SOSCenterService getService() { | ||||
|             return SOSCenterService.this; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         LogUtils.d(TAG, "onCreate"); | ||||
|         mSOSCenterServiceModel = SOSCenterServiceModel.loadBean(this, SOSCenterServiceModel.class); | ||||
|         if(mSOSCenterServiceModel == null) { | ||||
|             mSOSCenterServiceModel = new SOSCenterServiceModel(); | ||||
|             SOSCenterServiceModel.saveBean(this, mSOSCenterServiceModel); | ||||
|         } | ||||
|         runMainThread(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int onStartCommand(Intent intent, int flags, int startId) { | ||||
|         LogUtils.d(TAG, "onStartCommand"); | ||||
|  | ||||
|         runMainThread(); | ||||
|  | ||||
|         return mSOSCenterServiceModel.isEnable() ? Service.START_STICKY: super.onStartCommand(intent, flags, startId); | ||||
|     } | ||||
|  | ||||
|     void runMainThread() { | ||||
|         mSOSCenterServiceModel = mSOSCenterServiceModel.loadBean(this, SOSCenterServiceModel.class); | ||||
|         if (mSOSCenterServiceModel.isEnable() | ||||
|             && _MainThread == null) { | ||||
|             getMainThreadInstance().start(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         LogUtils.d(TAG, "onDestroy"); | ||||
|         mSOSCenterServiceModel = SOSCenterServiceModel.loadBean(this, SOSCenterServiceModel.class); | ||||
|         if (mSOSCenterServiceModel.isEnable()) { | ||||
|             LogUtils.d(TAG, "mSOSCenterServiceModel.isEnable()"); | ||||
| //            ISOSAPP iSOSAPP = (ISOSAPP)getApplication(); | ||||
| //            iSOSAPP.helpISOSService(getISOSServiceIntentWhichAskForHelp()); | ||||
|         }  | ||||
|         if (_MainThread != null) { | ||||
|             _MainThread.isExist = true; | ||||
|             _MainThread = null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void stopISOSService(Context context) { | ||||
|         LogUtils.d(TAG, "stopISOSService"); | ||||
|         SOSCenterServiceModel bean = new SOSCenterServiceModel(); | ||||
|         bean.setIsEnable(false); | ||||
|         SOSCenterServiceModel.saveBean(context, bean); | ||||
|         context.stopService(new Intent(context, SOSCenterServiceModel.class)); | ||||
|     } | ||||
|  | ||||
|     public static void startISOSService(Context context) { | ||||
|         LogUtils.d(TAG, "startISOSService"); | ||||
|         SOSCenterServiceModel bean = new SOSCenterServiceModel(); | ||||
|         bean.setIsEnable(true); | ||||
|         SOSCenterServiceModel.saveBean(context, bean); | ||||
|         context.startService(new Intent(context, SOSCenterServiceModel.class)); | ||||
|     } | ||||
|  | ||||
|     public String getMessage() { | ||||
|         return "Hello from SOSCenterServiceModel"; | ||||
|     } | ||||
|  | ||||
|     static class MainThread extends Thread { | ||||
|         volatile boolean isExist = false; | ||||
|  | ||||
|         public void setIsExist(boolean isExist) { | ||||
|             this.isExist = isExist; | ||||
|         } | ||||
|  | ||||
|         public boolean isExist() { | ||||
|             return isExist; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void run() { | ||||
|             super.run(); | ||||
|             while (!isExist) { | ||||
|                 LogUtils.d(TAG, "run"); | ||||
|                 try { | ||||
|                     sleep(1000); | ||||
|                 } catch (InterruptedException e) { | ||||
|                     LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -1,69 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.sos; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/03/02 09:49:45 | ||||
|  * @Describe SOSCenterServiceModel | ||||
|  *           Simple Operate Signal Service Model. | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.libappbase.BaseBean; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class SOSCenterServiceModel extends BaseBean { | ||||
|  | ||||
|     public static final String TAG = "SOSCenterServiceModel"; | ||||
|  | ||||
|     boolean isEnable; | ||||
|  | ||||
|     public SOSCenterServiceModel() { | ||||
|         this.isEnable = false; | ||||
|     } | ||||
|  | ||||
|     public void setIsEnable(boolean isEnable) { | ||||
|         this.isEnable = isEnable; | ||||
|     } | ||||
|  | ||||
|     public boolean isEnable() { | ||||
|         return isEnable; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return SOSCenterServiceModel.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         jsonWriter.name("isEnable").value(isEnable()); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { | ||||
|             if (name.equals("isEnable")) { | ||||
|                 setIsEnable(jsonReader.nextBoolean()); | ||||
|             } else { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { | ||||
|         jsonReader.beginObject(); | ||||
|         while (jsonReader.hasNext()) { | ||||
|             String name = jsonReader.nextName(); | ||||
|             if (!initObjectsFromJsonReader(jsonReader, name)) { | ||||
|                 jsonReader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         // 结束 JSON 对象 | ||||
|         jsonReader.endObject(); | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
| @@ -1,29 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.sos; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/27 14:04:35 | ||||
|  * @Describe SOSCenterServiceReceiver | ||||
|  */ | ||||
| import android.content.BroadcastReceiver; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
|  | ||||
| public class SOSCenterServiceReceiver extends BroadcastReceiver { | ||||
|  | ||||
|     public static final String TAG = "SOSCenterServiceReceiver"; | ||||
|  | ||||
|     public static final String ACTION_SOS = SOSCenterServiceReceiver.class.getName() + ".ACTION_SOS"; | ||||
|      | ||||
|     @Override | ||||
|     public void onReceive(Context context, Intent intent) { | ||||
|         String action = intent.getAction(); | ||||
|         if (action.equals(ACTION_SOS)) { | ||||
|             // 处理接收到的广播消息 | ||||
|             LogUtils.d(TAG, String.format("Action %s \n%s\n%s", action)); | ||||
|         } else { | ||||
|             LogUtils.d(TAG, String.format("%s", action)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,86 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.sos; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/27 14:12:05 | ||||
|  * @Describe SOSBean | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.libappbase.BaseBean; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class SOSObject extends BaseBean { | ||||
|  | ||||
|     public static final String TAG = "SOSObject"; | ||||
|  | ||||
|     String objectPackageName; | ||||
|     String objectServiveName; | ||||
|  | ||||
|     public SOSObject() { | ||||
|         this.objectPackageName = ""; | ||||
|         this.objectServiveName = ""; | ||||
|     } | ||||
|  | ||||
|     public SOSObject(String objectPackageName, String objectServiveName) { | ||||
|         this.objectPackageName = objectPackageName; | ||||
|         this.objectServiveName = objectServiveName; | ||||
|     } | ||||
|  | ||||
|     public void setObjectPackageName(String objectPackageName) { | ||||
|         this.objectPackageName = objectPackageName; | ||||
|     } | ||||
|  | ||||
|     public String getObjectPackageName() { | ||||
|         return objectPackageName; | ||||
|     } | ||||
|  | ||||
|     public void setObjectServiveName(String objectServiveName) { | ||||
|         this.objectServiveName = objectServiveName; | ||||
|     } | ||||
|  | ||||
|     public String getObjectServiveName() { | ||||
|         return objectServiveName; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return SOSObject.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         jsonWriter.name("objectPackageName").value(getObjectPackageName()); | ||||
|         jsonWriter.name("objectServiveName").value(getObjectServiveName()); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { | ||||
|             if (name.equals("objectPackageName")) { | ||||
|                 setObjectPackageName(jsonReader.nextString()); | ||||
|             } else if (name.equals("objectServiveName")) { | ||||
|                 setObjectServiveName(jsonReader.nextString()); | ||||
|             } else { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { | ||||
|         jsonReader.beginObject(); | ||||
|         while (jsonReader.hasNext()) { | ||||
|             String name = jsonReader.nextName(); | ||||
|             if (!initObjectsFromJsonReader(jsonReader, name)) { | ||||
|                 jsonReader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         // 结束 JSON 对象 | ||||
|         jsonReader.endObject(); | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
| @@ -1,128 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/06/04 20:15 | ||||
|  * @Describe 文件操作类 | ||||
|  */ | ||||
| import java.io.BufferedReader; | ||||
| import java.io.BufferedWriter; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.FileReader; | ||||
| import java.io.FileWriter; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class FileUtils { | ||||
|     public static final String TAG = "FileUtils"; | ||||
|  | ||||
|     /** | ||||
|      * 读取文件为字节数组(Java 7 语法) | ||||
|      */ | ||||
|     public static byte[] readFileToByteArray(String filePath) { | ||||
|         FileInputStream fis = null; | ||||
|         ByteArrayOutputStream bos = null; | ||||
|         try { | ||||
|             fis = new FileInputStream(filePath); | ||||
|             bos = new ByteArrayOutputStream(); | ||||
|             byte[] buffer = new byte[4096]; | ||||
|             int bytesRead; | ||||
|             while ((bytesRead = fis.read(buffer)) != -1) { | ||||
|                 bos.write(buffer, 0, bytesRead); | ||||
|             } | ||||
|             return bos.toByteArray(); | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|             return null; | ||||
|         } finally { | ||||
|             // 手动关闭流(Java 7 不支持 try-with-resources) | ||||
|             if (fis != null) { | ||||
|                 try { | ||||
|                     fis.close(); | ||||
|                 } catch (IOException e) { | ||||
|                     e.printStackTrace(); | ||||
|                 } | ||||
|             } | ||||
|             if (bos != null) { | ||||
|                 try { | ||||
|                     bos.close(); | ||||
|                 } catch (IOException e) { | ||||
|                     e.printStackTrace(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 写入字节数组到文件(Java 7 语法) | ||||
|      */ | ||||
|     public static boolean writeByteArrayToFile(byte[] data, String filePath) { | ||||
|         FileOutputStream fos = null; | ||||
|         try { | ||||
|             fos = new FileOutputStream(filePath); | ||||
|             fos.write(data); | ||||
|             return true; | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|             return false; | ||||
|         } finally { | ||||
|             if (fos != null) { | ||||
|                 try { | ||||
|                     fos.close(); | ||||
|                 } catch (IOException e) { | ||||
|                     e.printStackTrace(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 原字符串读写方法(适配 Java 7) | ||||
|     public static String readFileToString(String filePath) { | ||||
|         BufferedReader reader = null; | ||||
|         try { | ||||
|             reader = new BufferedReader(new FileReader(filePath)); | ||||
|             StringBuilder content = new StringBuilder(); | ||||
|             String line; | ||||
|             while ((line = reader.readLine()) != null) { | ||||
|                 content.append(line).append(System.getProperty("line.separator")); | ||||
|             } | ||||
|             // 去除最后一个换行符(可选) | ||||
|             if (content.length() > 0) { | ||||
|                 content.deleteCharAt(content.length() - 1); | ||||
|             } | ||||
|             return content.toString(); | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|             return null; | ||||
|         } finally { | ||||
|             if (reader != null) { | ||||
|                 try { | ||||
|                     reader.close(); | ||||
|                 } catch (IOException e) { | ||||
|                     e.printStackTrace(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static boolean writeStringToFile(String content, String filePath, boolean append) { | ||||
|         BufferedWriter writer = null; | ||||
|         try { | ||||
|             writer = new BufferedWriter(new FileWriter(filePath, append)); | ||||
|             writer.write(content); | ||||
|             return true; | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|             return false; | ||||
|         } finally { | ||||
|             if (writer != null) { | ||||
|                 try { | ||||
|                     writer.close(); | ||||
|                 } catch (IOException e) { | ||||
|                     e.printStackTrace(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,222 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/06/04 13:36 | ||||
|  * @Describe RSA加密工具 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.util.Base64; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.security.KeyFactory; | ||||
| import java.security.KeyPair; | ||||
| import java.security.KeyPairGenerator; | ||||
| import java.security.NoSuchAlgorithmException; | ||||
| import java.security.PrivateKey; | ||||
| import java.security.PublicKey; | ||||
| import java.security.spec.InvalidKeySpecException; | ||||
| import java.security.spec.PKCS8EncodedKeySpec; | ||||
| import java.security.spec.X509EncodedKeySpec; | ||||
| import java.util.Objects; | ||||
| import javax.crypto.Cipher; | ||||
|  | ||||
| public class RSAUtils { | ||||
|     private static final String TAG = "RSAUtils"; | ||||
|     private static final int KEY_SIZE = 2048; | ||||
|     private static final String KEY_ALGORITHM = "RSA"; | ||||
|     private static final String PUBLIC_KEY_FILE = "public.key"; | ||||
|     private static final String PRIVATE_KEY_FILE = "private.key"; | ||||
|     private static final String CIPHER_ALGORITHM = KEY_ALGORITHM + "/ECB/PKCS1Padding"; // 保留原加密方式 | ||||
|  | ||||
|     private final String keyPath; | ||||
|     private static volatile RSAUtils INSTANCE; | ||||
|  | ||||
|     /** | ||||
|      * 构造方法:初始化密钥存储路径(内部存储) | ||||
|      */ | ||||
|     private RSAUtils(Context context) { | ||||
|         keyPath = context.getFilesDir() + File.separator + "keys" + File.separator; // 修正路径格式 | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取单例实例 | ||||
|      */ | ||||
|     public static synchronized RSAUtils getInstance(Context context) { | ||||
|         if (INSTANCE == null) { | ||||
|             INSTANCE = new RSAUtils(context); | ||||
|         } | ||||
|         return INSTANCE; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 检查密钥文件是否存在 | ||||
|      */ | ||||
|     public boolean keysExist() { | ||||
|         File publicKeyFile = new File(keyPath + PUBLIC_KEY_FILE); | ||||
|         File privateKeyFile = new File(keyPath + PRIVATE_KEY_FILE); | ||||
|         return publicKeyFile.exists() && privateKeyFile.exists(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 生成密钥对并保存到文件 | ||||
|      */ | ||||
|     public void generateAndSaveKeys() throws Exception { | ||||
|         LogUtils.d(TAG, "开始生成 RSA 密钥对(2048位)"); | ||||
|         KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_ALGORITHM); | ||||
|         generator.initialize(KEY_SIZE); | ||||
|         KeyPair keyPair = generator.generateKeyPair(); | ||||
|  | ||||
|         saveKey(PUBLIC_KEY_FILE, keyPair.getPublic().getEncoded()); | ||||
|         saveKey(PRIVATE_KEY_FILE, keyPair.getPrivate().getEncoded()); | ||||
|         LogUtils.d(TAG, "密钥对生成并保存成功"); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取或生成密钥对(线程安全) | ||||
|      */ | ||||
|     public KeyPair getOrGenerateKeys() throws Exception { | ||||
|         if (!keysExist()) { | ||||
|             synchronized (RSAUtils.class) { // 双重检查锁,避免多线程重复生成 | ||||
|                 if (!keysExist()) { | ||||
|                     generateAndSaveKeys(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return readKeysFromFile(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 从文件读取密钥对 | ||||
|      */ | ||||
|     private KeyPair readKeysFromFile() throws Exception { | ||||
|         LogUtils.d(TAG, "读取密钥对文件"); | ||||
|         try { | ||||
|             byte[] publicKeyBytes = readFileToBytes(keyPath + PUBLIC_KEY_FILE); | ||||
|             byte[] privateKeyBytes = readFileToBytes(keyPath + PRIVATE_KEY_FILE); | ||||
|  | ||||
|             X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(publicKeyBytes); | ||||
|             PKCS8EncodedKeySpec privateSpec = new PKCS8EncodedKeySpec(privateKeyBytes); | ||||
|  | ||||
|             KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM); | ||||
|             PublicKey publicKey = factory.generatePublic(publicSpec); | ||||
|             PrivateKey privateKey = factory.generatePrivate(privateSpec); | ||||
|  | ||||
|             return new KeyPair(publicKey, privateKey); | ||||
|         } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) { | ||||
|             LogUtils.e(TAG, "密钥文件读取失败:" + e.getMessage()); | ||||
|             throw new Exception("密钥文件损坏或格式错误", e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 保存密钥到文件(通用方法) | ||||
|      */ | ||||
|     private void saveKey(String fileName, byte[] keyBytes) throws IOException { | ||||
|         Objects.requireNonNull(keyBytes, "密钥字节数据不可为空"); | ||||
|         File dir = new File(keyPath); | ||||
|         if (!dir.exists() && !dir.mkdirs()) { | ||||
|             throw new IOException("创建密钥目录失败:" + keyPath); | ||||
|         } | ||||
|  | ||||
|         FileOutputStream fos = null; | ||||
|         try { | ||||
|             fos = new FileOutputStream(keyPath + fileName); | ||||
|             fos.write(keyBytes); | ||||
|         } finally { | ||||
|             if (fos != null) { | ||||
|                 try { | ||||
|                     fos.close(); | ||||
|                 } catch (IOException e) { | ||||
|                     LogUtils.e(TAG, "关闭文件流失败:" + e.getMessage()); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 读取文件为字节数组(Java 7 兼容) | ||||
|      */ | ||||
|     private byte[] readFileToBytes(String filePath) throws IOException { | ||||
|         File file = new File(filePath); | ||||
|         if (!file.exists() || file.isDirectory()) { | ||||
|             throw new IOException("文件不存在或为目录:" + filePath); | ||||
|         } | ||||
|  | ||||
|         FileInputStream fis = null; | ||||
|         try { | ||||
|             fis = new FileInputStream(file); | ||||
|             byte[] data = new byte[(int) file.length()]; | ||||
|             int bytesRead = fis.read(data); | ||||
|             if (bytesRead != data.length) { | ||||
|                 throw new IOException("文件读取不完整"); | ||||
|             } | ||||
|             return data; | ||||
|         } finally { | ||||
|             if (fis != null) { | ||||
|                 try { | ||||
|                     fis.close(); | ||||
|                 } catch (IOException e) { | ||||
|                     LogUtils.e(TAG, "关闭文件流失败:" + e.getMessage()); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 公钥加密(带参数校验) | ||||
|      */ | ||||
|     public byte[] encryptWithPublicKey(String plainText, PublicKey publicKey) throws Exception { | ||||
|         Objects.requireNonNull(plainText, "明文不可为空"); | ||||
|         Objects.requireNonNull(publicKey, "公钥不可为空"); | ||||
|  | ||||
|         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); | ||||
|         cipher.init(Cipher.ENCRYPT_MODE, publicKey); | ||||
|  | ||||
|         // 检查数据长度是否超过 RSA 限制(2048位密钥最大明文为 214字节,PKCS1Padding) | ||||
|         int maxPlainTextSize = cipher.getBlockSize() - 11; // PKCS1Padding 固定填充长度 | ||||
|         if (plainText.getBytes("UTF-8").length > maxPlainTextSize) { | ||||
|             throw new IllegalArgumentException("明文过长,最大支持 " + maxPlainTextSize + " 字节"); | ||||
|         } | ||||
|  | ||||
|         return cipher.doFinal(plainText.getBytes("UTF-8")); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 私钥解密(带参数校验) | ||||
|      */ | ||||
|     public String decryptWithPrivateKey(byte[] encryptedData, PrivateKey privateKey) throws Exception { | ||||
|         Objects.requireNonNull(encryptedData, "密文不可为空"); | ||||
|         Objects.requireNonNull(privateKey, "私钥不可为空"); | ||||
|  | ||||
|         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); | ||||
|         cipher.init(Cipher.DECRYPT_MODE, privateKey); | ||||
|         byte[] decryptedBytes = cipher.doFinal(encryptedData); | ||||
|         return new String(decryptedBytes, "UTF-8"); | ||||
|     } | ||||
|     /** | ||||
|      * 将 HTTP 传输的 Base64 字符串还原为加密字节数组(Java 7 兼容) | ||||
|      * @param httpString Base64 字符串(非 null) | ||||
|      * @return 加密字节数组 | ||||
|      * @throws IllegalArgumentException 解码失败时抛出 | ||||
|      */ | ||||
|     public byte[] httpStringToEncryptBytes(String httpString) { | ||||
|         Objects.requireNonNull(httpString, "HTTP 字符串不可为空"); | ||||
|  | ||||
|         // 计算缺失的填充符数量(Java 7 不支持 repeat(),手动拼接) | ||||
|         int pad = httpString.length() % 4; | ||||
|         StringBuilder paddedString = new StringBuilder(httpString); | ||||
|         if (pad != 0) { | ||||
|             for (int i = 0; i < pad; i++) { | ||||
|                 paddedString.append('='); // 补全 '=' | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // 使用 Base64 解码(Android 原生 Base64 类兼容 Java 7) | ||||
|         return Base64.decode(paddedString.toString(), Base64.URL_SAFE); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1,48 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/17 19:38:20 | ||||
|  * @Describe 服务工具集 | ||||
|  */ | ||||
| import android.app.ActivityManager; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.Build; | ||||
| import android.util.Log; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import java.util.List; | ||||
|  | ||||
| public class ServiceUtils { | ||||
|  | ||||
|     public static final String TAG = "ServiceUtils"; | ||||
|  | ||||
|     /** | ||||
|      * 检查指定服务是否正在运行 | ||||
|      * @param context 上下文 | ||||
|      * @param serviceClass 服务类 | ||||
|      * @return true 如果服务正在运行,否则返回 false | ||||
|      */ | ||||
|     public static boolean isServiceRunning(Context context, String serviceClassName) { | ||||
|         ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); | ||||
|         if (activityManager == null) { | ||||
|             return false; | ||||
|         } | ||||
|         List<ActivityManager.RunningServiceInfo> runningServices; | ||||
| //        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { | ||||
| //            Intent intent = new Intent(context, serviceClass); | ||||
| //            runningServices = activityManager.getRunningServices(100, intent); | ||||
| //        } else { | ||||
|         runningServices = activityManager.getRunningServices(100); | ||||
|         //} | ||||
|         for (ActivityManager.RunningServiceInfo serviceInfo : runningServices) { | ||||
|             if (serviceClassName.equals(serviceInfo.service.getClassName())) { | ||||
|                 LogUtils.d(TAG, "Service is running: " + serviceInfo.service.getClassName()); | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         LogUtils.d(TAG, "Service is not running: " + serviceClassName); | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1,281 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/06/04 17:21 | ||||
|  * @Describe 应用登录与接口工具 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.os.Handler; | ||||
| import android.os.Looper; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.models.ResponseData; | ||||
| import cc.winboll.studio.libappbase.models.UserInfoModel; | ||||
| import com.google.gson.Gson; | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.net.URLDecoder; | ||||
| import java.nio.charset.StandardCharsets; | ||||
| import java.security.KeyPair; | ||||
| import java.security.PrivateKey; | ||||
| import java.security.PublicKey; | ||||
| import java.util.concurrent.TimeUnit; | ||||
| import okhttp3.Call; | ||||
| import okhttp3.Callback; | ||||
| import okhttp3.MediaType; | ||||
| import okhttp3.OkHttpClient; | ||||
| import okhttp3.Request; | ||||
| import okhttp3.RequestBody; | ||||
| import okhttp3.Response; | ||||
| import java.io.UnsupportedEncodingException; | ||||
|  | ||||
| public class YunUtils { | ||||
|     public static final String TAG = "YunUtils"; | ||||
|     // 私有静态实例,类加载时创建 | ||||
|     private static volatile YunUtils INSTANCE; | ||||
|     Context mContext; | ||||
|     UserInfoModel mUserInfoModel; | ||||
|     String token = ""; | ||||
|     String mDataFolderPath = ""; | ||||
|     String mUserInfoModelPath = ""; | ||||
|  | ||||
|     private static final int CONNECT_TIMEOUT = 15; // 连接超时时间(秒) | ||||
|     private static final int READ_TIMEOUT = 20;    // 读取超时时间(秒) | ||||
|     private static volatile YunUtils instance; | ||||
|     private OkHttpClient okHttpClient; | ||||
|     private Handler mainHandler; // 主线程 Handler | ||||
|  | ||||
|     // 私有构造方法,防止外部实例化 | ||||
|     private YunUtils(Context context) { | ||||
|         LogUtils.d(TAG, "YunUtils"); | ||||
|         mContext = context; | ||||
|         mDataFolderPath = mContext.getExternalFilesDir(TAG).toString(); | ||||
|         File fTest = new File(mDataFolderPath); | ||||
|         if (!fTest.exists()) { | ||||
|             fTest.mkdirs(); | ||||
|         } | ||||
|         mUserInfoModelPath = mDataFolderPath + File.separator + "UserInfoModel.rsajson"; | ||||
|  | ||||
|         okHttpClient = new OkHttpClient.Builder() | ||||
|             .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS) | ||||
|             .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS) | ||||
|             .build(); | ||||
|         mainHandler = new Handler(Looper.getMainLooper()); // 获取主线程 Looper | ||||
|     } | ||||
|  | ||||
|     // 公共静态方法,返回唯一实例 | ||||
|     public static synchronized YunUtils getInstance(Context context) { | ||||
|         LogUtils.d(TAG, "getInstance"); | ||||
|         if (INSTANCE == null) { | ||||
|             INSTANCE = new YunUtils(context); | ||||
|         } | ||||
|         return INSTANCE; | ||||
|     } | ||||
|  | ||||
|     public void checkLoginStatus() { | ||||
|         String token = getLocalToken(); | ||||
|         LogUtils.d(TAG, String.format("checkLoginStatus token is %s", token)); | ||||
|     } | ||||
|  | ||||
|     String getLocalToken() { | ||||
|         UserInfoModel userInfoModel = loadUserInfoModel(); | ||||
|         return (userInfoModel == null) ?"": userInfoModel.getToken(); | ||||
|     } | ||||
|  | ||||
|     public void login(String host, UserInfoModel userInfoModel) { | ||||
|         LogUtils.d(TAG, "login"); | ||||
|  | ||||
|         // 发送 POST 请求 | ||||
|         String apiUrl = host + "/login/index.php"; | ||||
|         // 序列化对象为JSON | ||||
|         Gson gson = new Gson(); | ||||
|         String jsonData = gson.toJson(userInfoModel); // 自动生成标准JSON | ||||
|         //String jsonData = userInfoModel.toString(); | ||||
|         LogUtils.d(TAG, "要发送的数据 : " + jsonData); | ||||
|  | ||||
|         sendPostRequest(apiUrl, jsonData, new OnResponseListener() { | ||||
|                 // 成功回调(主线程) | ||||
|                 @Override | ||||
|                 public void onSuccess(String responseBody) { | ||||
|                     LogUtils.d(TAG, "onSuccess"); | ||||
|                     LogUtils.d(TAG, String.format("responseBody %s", responseBody)); | ||||
|                     Gson gson = new Gson(); | ||||
|                     ResponseData result = gson.fromJson(responseBody, ResponseData.class); // 转为 Result 实例 | ||||
|                     if(result.getStatus().equals(ResponseData.STATUS_SUCCESS)) { | ||||
|                          | ||||
|                             UserInfoModel userInfoModel = result.getData(); | ||||
|                             if (userInfoModel != null) { | ||||
|                                 LogUtils.d(TAG, "收到网站 UserInfoModel"); | ||||
|                                 String token = userInfoModel.getToken(); | ||||
|                                 saveLocalToken(token); | ||||
|                                 checkLoginStatus(); | ||||
|                             } | ||||
|                         | ||||
|                     } else if(result.getStatus().equals(ResponseData.STATUS_ERROR)) { | ||||
|                         try { | ||||
|                             String decodedMessage = URLDecoder.decode(result.getMessage(), "UTF-8"); | ||||
|                             LogUtils.d(TAG, "服务器返回信息: " + decodedMessage); | ||||
|                         } catch (UnsupportedEncodingException e) { | ||||
|                             LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 // 失败回调(主线程) | ||||
|                 @Override | ||||
|                 public void onFailure(String errorMsg) { | ||||
|                     LogUtils.d(TAG, errorMsg); | ||||
|                     // 处理错误 | ||||
|                 } | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|     public void saveLocalToken(String token) { | ||||
|         UserInfoModel userInfoModel = new UserInfoModel(); | ||||
|         userInfoModel.setToken(token); | ||||
|         saveUserInfoModel(userInfoModel); | ||||
|     } | ||||
|  | ||||
|     UserInfoModel loadUserInfoModel() { | ||||
|         LogUtils.d(TAG, "loadUserInfoModel"); | ||||
|         if (new File(mUserInfoModelPath).exists()) { | ||||
|             try { | ||||
|                 // 加载加密后的模型数据 | ||||
|                 byte[] encryptedData = FileUtils.readFileToByteArray(mUserInfoModelPath); | ||||
|                 // 加载 RSA 工具 | ||||
|                 RSAUtils utils = RSAUtils.getInstance(mContext); | ||||
|                 KeyPair keyPair = utils.getOrGenerateKeys(); | ||||
|                 //PublicKey publicKey = keyPair.getPublic(); | ||||
|                 PrivateKey privateKey = keyPair.getPrivate(); | ||||
|                 // 私钥解密模型数据 | ||||
|                 String szInfo = utils.decryptWithPrivateKey(encryptedData, keyPair.getPrivate()); | ||||
|                 LogUtils.d(TAG, String.format("szInfo %s", szInfo)); | ||||
|                 mUserInfoModel = UserInfoModel.parseStringToBean(szInfo, UserInfoModel.class); | ||||
|                 if (mUserInfoModel == null) { | ||||
|                     LogUtils.d(TAG, "模型数据解析为空数据。"); | ||||
|                 } | ||||
|                 LogUtils.d(TAG, "UserInfoModel 解密加载结束。"); | ||||
|             } catch (Exception e) { | ||||
|                 LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|             } | ||||
|         } else { | ||||
|             LogUtils.d(TAG, "云服务登录信息不存在。"); | ||||
|             mUserInfoModel = null; | ||||
|         } | ||||
|         return mUserInfoModel; | ||||
|     } | ||||
|  | ||||
|     void saveUserInfoModel(UserInfoModel userInfoModel) { | ||||
|         LogUtils.d(TAG, "saveUserInfoModel"); | ||||
|         try { | ||||
|             String szInfo = userInfoModel.toString(); | ||||
|             LogUtils.d(TAG, "原始数据: " + szInfo); | ||||
|  | ||||
|             RSAUtils utils = RSAUtils.getInstance(mContext); | ||||
|             KeyPair keyPair = utils.getOrGenerateKeys(); | ||||
|             PublicKey publicKey = keyPair.getPublic(); | ||||
|  | ||||
|             // 公钥加密(传入字节数组,避免中间字符串转换) | ||||
|             byte[] encryptedData = utils.encryptWithPublicKey(szInfo, publicKey); | ||||
|  | ||||
|             // 保存加密字节数组到文件(直接操作字节,无需转字符串) | ||||
|             FileUtils.writeByteArrayToFile(encryptedData, mUserInfoModelPath); | ||||
|             LogUtils.d(TAG, "加密数据已保存"); | ||||
|  | ||||
|             // 测试解密(仅调试用) | ||||
|             String szInfo2 = utils.decryptWithPrivateKey(encryptedData, keyPair.getPrivate()); | ||||
|             LogUtils.d(TAG, "解密结果: " + szInfo2); | ||||
|  | ||||
|             mUserInfoModel = UserInfoModel.parseStringToBean(szInfo2, UserInfoModel.class); | ||||
|             if (mUserInfoModel == null) { | ||||
|                 LogUtils.d(TAG, "模型解析失败"); | ||||
|             } | ||||
|         } catch (Exception e) { | ||||
|             LogUtils.d(TAG, "加密/解密失败: " + e.getMessage()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 发送 POST 请求(JSON 数据) | ||||
|     public void sendPostRequest(String url, String data, OnResponseListener listener) { | ||||
|         RequestBody requestBody = RequestBody.create( | ||||
|             MediaType.parse("application/json; charset=utf-8"), // 关键头信息 | ||||
|             data.getBytes(StandardCharsets.UTF_8) | ||||
|         ); | ||||
|  | ||||
|         Request request = new Request.Builder() | ||||
|             .url(url) | ||||
|             .post(requestBody) | ||||
|             .addHeader("Content-Type", "application/json") // 显式添加头 | ||||
|             .build(); | ||||
|  | ||||
|         executeRequest(request, listener); | ||||
|     } | ||||
|  | ||||
|     // 发送 GET 请求 | ||||
|     public void sendGetRequest(String url, OnResponseListener listener) { | ||||
|         Request request = new Request.Builder() | ||||
|             .url(url) | ||||
|             .get() | ||||
|             .build(); | ||||
|         executeRequest(request, listener); | ||||
|     } | ||||
|  | ||||
|     // 执行请求(子线程处理) | ||||
|     private void executeRequest(final Request request, final OnResponseListener listener) { | ||||
|         okHttpClient.newCall(request).enqueue(new Callback() { | ||||
|                 // 响应成功(子线程) | ||||
|                 @Override | ||||
|                 public void onResponse(Call call, Response response) throws IOException { | ||||
|                     try { | ||||
|                         if (!response.isSuccessful()) { | ||||
|                             postFailure(listener, "响应码错误:" + response.code()); | ||||
|                             return; | ||||
|                         } | ||||
|                         String responseBody = response.body().string(); | ||||
|                         postSuccess(listener, responseBody); | ||||
|                     } catch (Exception e) { | ||||
|                         postFailure(listener, "解析失败:" + e.getMessage()); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 // 响应失败(子线程) | ||||
|                 @Override | ||||
|                 public void onFailure(Call call, IOException e) { | ||||
|                     postFailure(listener, "网络失败:" + e.getMessage()); | ||||
|                 } | ||||
|  | ||||
|                 // 主线程回调(使用 Handler) | ||||
|                 private void postSuccess(final OnResponseListener listener, final String msg) { | ||||
|                     mainHandler.post(new Runnable() { | ||||
|                             @Override | ||||
|                             public void run() { | ||||
|                                 listener.onSuccess(msg); | ||||
|                             } | ||||
|                         }); | ||||
|                 } | ||||
|  | ||||
|                 private void postFailure(final OnResponseListener listener, final String msg) { | ||||
|                     mainHandler.post(new Runnable() { | ||||
|                             @Override | ||||
|                             public void run() { | ||||
|                                 listener.onFailure(msg); | ||||
|                             } | ||||
|                         }); | ||||
|                 } | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|     public interface OnResponseListener { | ||||
|         /** | ||||
|          * 成功响应(主线程回调) | ||||
|          * @param responseBody 响应体字符串 | ||||
|          */ | ||||
|         void onSuccess(String responseBody); | ||||
|  | ||||
|         /** | ||||
|          * 失败回调(包含错误信息) | ||||
|          * @param errorMsg 错误描述 | ||||
|          */ | ||||
|         void onFailure(String errorMsg); | ||||
|     } | ||||
| } | ||||
| @@ -1,63 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.widgets; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/17 20:32:12 | ||||
|  */ | ||||
| import android.app.PendingIntent; | ||||
| import android.appwidget.AppWidgetManager; | ||||
| import android.appwidget.AppWidgetProvider; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.widget.RemoteViews; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.R; | ||||
| import cc.winboll.studio.libappbase.utils.ServiceUtils; | ||||
| import android.content.ServiceConnection; | ||||
| import android.os.IBinder; | ||||
| import cc.winboll.studio.libappbase.utils.ToastUtils; | ||||
|  | ||||
| public class StatusWidget extends AppWidgetProvider { | ||||
|  | ||||
|     public static final String TAG = "StatusWidget"; | ||||
|  | ||||
|     public static final String ACTION_STATUS_UPDATE = "cc.winboll.studio.libappbase.widgets.APPWidget.ACTION_STATUS_UPDATE"; | ||||
|  | ||||
|     @Override | ||||
|     public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { | ||||
|         for (int appWidgetId : appWidgetIds) { | ||||
|             updateAppWidget(context, appWidgetManager, appWidgetId); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onReceive(Context context, Intent intent) { | ||||
|         super.onReceive(context, intent); | ||||
|         if (intent.getAction().equals(ACTION_STATUS_UPDATE)) { | ||||
|             ToastUtils.show("Test"); | ||||
|             AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); | ||||
|             int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, StatusWidget.class)); | ||||
|             for (int appWidgetId : appWidgetIds) { | ||||
|                 updateAppWidget(context, appWidgetManager, appWidgetId); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { | ||||
|         RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_status); | ||||
|         //设置按钮点击事件 | ||||
|         Intent intentAppButton = new Intent(context, StatusWidgetClickListener.class); | ||||
|         intentAppButton.setAction(StatusWidgetClickListener.ACTION_IVAPP); | ||||
|         PendingIntent pendingIntentAppButton = PendingIntent.getBroadcast(context, 0, intentAppButton, PendingIntent.FLAG_UPDATE_CURRENT); | ||||
|         views.setOnClickPendingIntent(R.id.ivapp, pendingIntentAppButton); | ||||
|  | ||||
| //        boolean isActive = ServiceUtils.isServiceRunning(context, TestService.class.getName()); | ||||
| //        if (isActive) { | ||||
| //            views.setImageViewResource(R.id.ivapp, cc.winboll.studio.libappbase.R.drawable.ic_launcher); | ||||
| //        } else { | ||||
| //            views.setImageViewResource(R.id.ivapp, cc.winboll.studio.libappbase.R.drawable.ic_launcher_disable); | ||||
| //        } | ||||
|         appWidgetManager.updateAppWidget(appWidgetId, views); | ||||
|     } | ||||
| } | ||||
| @@ -1,33 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.widgets; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/02/17 20:33:53 | ||||
|  * @Describe APPWidgetClickListener | ||||
|  */ | ||||
| import android.content.BroadcastReceiver; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.utils.ToastUtils; | ||||
|  | ||||
| public class StatusWidgetClickListener extends BroadcastReceiver { | ||||
|      | ||||
|     public static final String TAG = "APPWidgetClickListener"; | ||||
|  | ||||
|     public static final String ACTION_IVAPP = "cc.winboll.studio.libappbase.widgets.StatusWidgetClickListener.ACTION_IVAPP"; | ||||
|  | ||||
|     @Override | ||||
|     public void onReceive(Context context, Intent intent) { | ||||
|         String action = intent.getAction(); | ||||
|         if (action == null) { | ||||
|             LogUtils.d(TAG, String.format("action %s", action)); | ||||
|             return; | ||||
|         } | ||||
|         if (action.equals(ACTION_IVAPP)) { | ||||
|             ToastUtils.show("ACTION_LAUNCHER"); | ||||
|         } else { | ||||
|             LogUtils.d(TAG, String.format("action %s", action)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,17 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.winboll; | ||||
| import android.app.Activity; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/05/10 09:34 | ||||
|  * @Describe WinBoLL 窗口操作接口 | ||||
|  */ | ||||
| public abstract interface IWinBoLLActivity { | ||||
|  | ||||
|     public static final String TAG = "IWinBoLLActivity"; | ||||
|  | ||||
|     public static final String ACTION_BIND = IWinBoLLActivity.class.getName() + ".ACTION_BIND"; | ||||
|  | ||||
|     public Activity getActivity(); | ||||
|     public String getTag(); | ||||
| } | ||||
| @@ -1,98 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.winboll; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/03/25 04:29:19 | ||||
|  */ | ||||
| import android.app.Activity; | ||||
| import android.app.Application; | ||||
| import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.utils.ToastUtils;  | ||||
|  | ||||
| public class MyActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {  | ||||
|  | ||||
|     public static final String TAG = "MyActivityLifecycleCallbacks"; | ||||
|  | ||||
|     public String mInfo = ""; | ||||
|  | ||||
|     public MyActivityLifecycleCallbacks() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     void createActivityeInfo(Activity activity) { | ||||
|         StringBuilder sb = new StringBuilder(); | ||||
|         Intent receivedIntent = activity.getIntent(); | ||||
|         sb.append("\nCallingActivity : \n"); | ||||
|         if (activity.getCallingActivity() != null) { | ||||
|             sb.append(activity.getCallingActivity().getPackageName()); | ||||
|         } | ||||
|         sb.append("\nReceived Intent Package : \n"); | ||||
|         sb.append(receivedIntent.getPackage()); | ||||
|  | ||||
|         Bundle extras = receivedIntent.getExtras(); | ||||
|         if (extras != null) { | ||||
|             for (String key : extras.keySet()) { | ||||
|                 sb.append("\nIntentInfo"); | ||||
|                 sb.append("\n键: "); | ||||
|                 sb.append(key); | ||||
|                 sb.append(", 值: "); | ||||
|                 sb.append(extras.get(key)); | ||||
|                 //Log.d("IntentInfo", "键: " + key + ", 值: " + extras.get(key)); | ||||
|             } | ||||
|         } | ||||
|         mInfo = sb.toString(); | ||||
|         //Log.d("IntentInfo", "发送Intent的应用包名: " + senderPackage); | ||||
|     } | ||||
|  | ||||
|     public void showActivityeInfo() { | ||||
|         //ToastUtils.show("ActivityeInfo : " + mInfo); | ||||
|         LogUtils.d(TAG, "ActivityeInfo : " + mInfo); | ||||
|     } | ||||
|  | ||||
|     @Override  | ||||
|     public void onActivityCreated(Activity activity, Bundle savedInstanceState) {  | ||||
|         // 在这里可以做一些初始化相关的操作,例如记录Activity的创建时间等  | ||||
|         //System.out.println(activity.getLocalClassName() + " was created");  | ||||
|         LogUtils.d(TAG, activity.getLocalClassName() + " was created"); | ||||
|         createActivityeInfo(activity); | ||||
|     }  | ||||
|  | ||||
|     @Override  | ||||
|     public void onActivityStarted(Activity activity) {  | ||||
|         //System.out.println(activity.getLocalClassName() + " was started"); | ||||
|         LogUtils.d(TAG, activity.getLocalClassName() + " was started"); | ||||
|         //createActivityeInfo(activity); | ||||
|     }  | ||||
|  | ||||
|     @Override  | ||||
|     public void onActivityResumed(Activity activity) {  | ||||
|         //System.out.println(activity.getLocalClassName() + " was resumed"); | ||||
|         LogUtils.d(TAG, activity.getLocalClassName() + " was resumed"); | ||||
|         //createActivityeInfo(activity); | ||||
|     }  | ||||
|  | ||||
|     @Override  | ||||
|     public void onActivityPaused(Activity activity) {  | ||||
|         //System.out.println(activity.getLocalClassName() + " was paused"); | ||||
|         LogUtils.d(TAG, activity.getLocalClassName() + " was paused"); | ||||
|     }  | ||||
|  | ||||
|     @Override  | ||||
|     public void onActivityStopped(Activity activity) {  | ||||
|         //System.out.println(activity.getLocalClassName() + " was stopped"); | ||||
|         LogUtils.d(TAG, activity.getLocalClassName() + " was stopped"); | ||||
|     }  | ||||
|  | ||||
|     @Override  | ||||
|     public void onActivitySaveInstanceState(Activity activity, Bundle outState) {  | ||||
|         // 可以在这里添加保存状态的自定义逻辑  | ||||
|     }  | ||||
|  | ||||
|     @Override  | ||||
|     public void onActivityDestroyed(Activity activity) {  | ||||
|         //System.out.println(activity.getLocalClassName() + " was destroyed"); | ||||
|         LogUtils.d(TAG, activity.getLocalClassName() + " was destroyed"); | ||||
|     }  | ||||
| } | ||||
| @@ -1,40 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.winboll; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/05/10 10:13 | ||||
|  * @Describe WinBoLL 系列应用通用管理类 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.models.WinBoLLModel; | ||||
|  | ||||
| public class WinBoLL { | ||||
|  | ||||
|     public static final String TAG = "WinBoLL"; | ||||
|  | ||||
|     public static final String ACTION_BIND = WinBoLL.class.getName() + ".ACTION_BIND"; | ||||
|     public static final String EXTRA_WINBOLLMODEL = "EXTRA_WINBOLLMODEL"; | ||||
|  | ||||
|     public static void bindToAPPBase(Context context, String appMainService) { | ||||
|         LogUtils.d(TAG, "bindToAPPBase(...)"); | ||||
|         String toPackage = "cc.winboll.studio.appbase"; | ||||
|         startBind(context, toPackage, appMainService); | ||||
|     } | ||||
|  | ||||
|     public static void bindToAPPBaseBeta(Context context, String appMainService) { | ||||
|         LogUtils.d(TAG, "bindToAPPBaseBeta(...)"); | ||||
|         String toPackage = "cc.winboll.studio.appbase.beta"; | ||||
|         startBind(context, toPackage, appMainService); | ||||
|     } | ||||
|  | ||||
|     static void startBind(Context context, String toPackage, String appMainService) { | ||||
|         Intent intent = new Intent(ACTION_BIND); | ||||
|         intent.putExtra(EXTRA_WINBOLLMODEL, (new WinBoLLModel(toPackage, appMainService)).toString()); | ||||
|         intent.setPackage(toPackage); | ||||
|         LogUtils.d(TAG, String.format("ACTION_BIND :\nTo Package : %s\nAPP Main Service : %s", toPackage, appMainService)); | ||||
|         context.sendBroadcast(intent); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,287 +0,0 @@ | ||||
| package cc.winboll.studio.libappbase.winboll; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/05/10 10:02 | ||||
|  * @Describe 应用活动窗口管理器 | ||||
|  * 参考 : | ||||
|  * android 类似微信小程序多任务窗口 及 设置 TaskDescription 修改 icon 和 label | ||||
|  * https://blog.csdn.net/qq_29364417/article/details/109379915?app_version=6.4.2&code=app_1562916241&csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22109379915%22%2C%22source%22%3A%22weixin_38986226%22%7D&uLinkId=usr1mkqgl919blen&utm_source=app | ||||
|  */ | ||||
| import android.app.Activity; | ||||
| import android.app.ActivityManager; | ||||
| import android.app.TaskStackBuilder; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.utils.ToastUtils; | ||||
| import java.util.HashMap; | ||||
| import java.util.Iterator; | ||||
| import java.util.Map; | ||||
|  | ||||
| public class WinBoLLActivityManager { | ||||
|  | ||||
|     public static final String TAG = "WinBoLLActivityManager"; | ||||
|  | ||||
|     public static final String EXTRA_TAG = "EXTRA_TAG"; | ||||
|  | ||||
|  | ||||
|     public enum WinBoLLUI_TYPE { Aplication, Service } | ||||
|  | ||||
|     Context mContext; | ||||
|     volatile static WinBoLLActivityManager _mIWinBoLLActivityManager; | ||||
|     Map<String, IWinBoLLActivity> mActivityListMap; | ||||
|  | ||||
|     volatile static WinBoLLUI_TYPE _WinBoLLUI_TYPE = WinBoLLUI_TYPE.Service; | ||||
|     public static void setWinBoLLUI_TYPE(WinBoLLUI_TYPE winBoLLUI_TYPE) { | ||||
|         _WinBoLLUI_TYPE = winBoLLUI_TYPE; | ||||
|     } | ||||
|  | ||||
|     public static WinBoLLUI_TYPE getWinBoLLUI_TYPE() { | ||||
|         return _WinBoLLUI_TYPE; | ||||
|     } | ||||
|     WinBoLLActivityManager() { | ||||
|         mContext = GlobalApplication.getInstance(); | ||||
|         mActivityListMap = new HashMap<String, IWinBoLLActivity>(); | ||||
|     } | ||||
|  | ||||
|     public static synchronized WinBoLLActivityManager getInstance() { | ||||
|         if (_mIWinBoLLActivityManager == null) { | ||||
|             _mIWinBoLLActivityManager = new WinBoLLActivityManager(); | ||||
|         } | ||||
|         return _mIWinBoLLActivityManager; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 把Activity添加到管理中 | ||||
|      */ | ||||
|     public <T extends IWinBoLLActivity> void add(T activity) { | ||||
|         if (isActivityActive(activity.getTag())) { | ||||
|             LogUtils.d(TAG, String.format("add(...) %s is active.", activity.getTag())); | ||||
|         } else { | ||||
|             mActivityListMap.put(activity.getTag(), activity); | ||||
|             LogUtils.d(TAG, String.format("Add activity : %s\n_mapActivityList.size() : %d", activity.getTag(), mActivityListMap.size())); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // activity: 为 null 时, | ||||
|     // intent.putExtra 函数 "tag" 参数为 tag | ||||
|     // activity: 不为 null 时, | ||||
|     // intent.putExtra 函数 "tag" 参数为 activity.getTag() | ||||
|     // | ||||
|     public <T extends IWinBoLLActivity> void startWinBoLLActivity(Context context, Class<T> clazz) { | ||||
|         // 如果窗口已存在就重启窗口 | ||||
|         if (!resumeActivity(clazz)) { | ||||
|             // 新建一个任务窗口 | ||||
|             Intent intent = new Intent(context, clazz); | ||||
|             //打开多任务窗口 flags | ||||
|             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); | ||||
|             intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); | ||||
|             //intent.putExtra("tag", tag); | ||||
|             context.startActivity(intent); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public <T extends IWinBoLLActivity> void startWinBoLLActivity(Context context, Intent intent, Class<T> clazz) { | ||||
|         // 如果窗口已存在就重启窗口 | ||||
|         if (!resumeActivity(clazz)) { | ||||
|             // 新建一个任务窗口 | ||||
|             //Intent intent = new Intent(context, clazz); | ||||
|             //打开多任务窗口 flags | ||||
|             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); | ||||
|             intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); | ||||
|             //intent.putExtra("tag", tag); | ||||
|             context.startActivity(intent); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public <T extends IWinBoLLActivity> void startLogActivity(Context context) { | ||||
|         // 如果窗口已存在就重启窗口 | ||||
|         //if (!resumeActivity(LogActivity.class)) { | ||||
|         // 新建一个任务窗口 | ||||
|         Intent intent = new Intent(context, LogActivity.class); | ||||
|         //打开多任务窗口 flags | ||||
|         // Define the bounds. | ||||
| //        Rect bounds = new Rect(0, 0, 800, 200); | ||||
| //        // Set the bounds as an activity option. | ||||
| //        ActivityOptions options = ActivityOptions.makeBasic(); | ||||
| //        options.setLaunchBounds(bounds); | ||||
|         intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT); | ||||
|         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); | ||||
|         intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); | ||||
|  | ||||
|         //intent.putExtra(EXTRA_TAG, tag); | ||||
|  | ||||
|         //context.startActivity(intent, options.toBundle()); | ||||
|         context.startActivity(intent); | ||||
|         //} | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 判断 tag 绑定的 Activity 是否已经创建 | ||||
|     // | ||||
|     public boolean isActivityActive(String tag) { | ||||
|         return mActivityListMap.get(tag) != null; | ||||
|     } | ||||
|  | ||||
|     Activity getActivityByTag(String tag) { | ||||
|         return (mActivityListMap.get(tag) == null) ?null: mActivityListMap.get(tag).getActivity(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     // | ||||
|     // 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台 | ||||
|     // | ||||
|     public <T extends IWinBoLLActivity> boolean resumeActivity(Class<T> clazz) { | ||||
|         try { | ||||
|             Activity activity = getActivityByTag(clazz.newInstance().getTag()); | ||||
|             if (activity != null) { | ||||
|                 return resumeActivity(activity); | ||||
|             } | ||||
|         } catch (InstantiationException | IllegalAccessException e) { | ||||
|             LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台 | ||||
|     // | ||||
|     public <T extends IWinBoLLActivity> boolean resumeActivity(String tag) { | ||||
|         Activity activity = getActivityByTag(tag); | ||||
|         if (activity != null) { | ||||
|             return resumeActivity(activity); | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 找到tag 绑定的 BaseActivity ,通过 getTaskId() 移动到前台 | ||||
|     // | ||||
|     public <T extends IWinBoLLActivity> boolean resumeActivity(Activity activity) { | ||||
|         ActivityManager am = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE); | ||||
|         //返回启动它的根任务(home 或者 MainActivity) | ||||
|         //Intent intent = new Intent(mContext, activity.getClass()); | ||||
|         //TaskStackBuilder stackBuilder = TaskStackBuilder.create(mContext); | ||||
|         //stackBuilder.addNextIntentWithParentStack(intent); | ||||
|         //stackBuilder.startActivities(); | ||||
|         am.moveTaskToFront(activity.getTaskId(), ActivityManager.MOVE_TASK_NO_USER_ACTION); | ||||
|         //ToastUtils.show("resumeActivity"); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * 结束所有 Activity | ||||
|      */ | ||||
|     public void finishAll() { | ||||
|         try { | ||||
|             //ToastUtils.show(String.format("finishAll() size : %d", _mIWinBoLLActivityList.size())); | ||||
|             for (int i = mActivityListMap.size() - 1; i > -1; i--) { | ||||
|                 IWinBoLLActivity iWinBoLLActivity = mActivityListMap.get(i); | ||||
|                 ToastUtils.show("finishAll() activity"); | ||||
|                 if (iWinBoLLActivity != null && iWinBoLLActivity.getActivity() != null && !iWinBoLLActivity.getActivity().isFinishing() && !iWinBoLLActivity.getActivity().isDestroyed()) { | ||||
|                     //ToastUtils.show("activity != null ..."); | ||||
|                     if (GlobalApplication.getWinBoLLActivityManager().getWinBoLLUI_TYPE() == WinBoLLUI_TYPE.Service) { | ||||
|                         // 结束窗口和最近任务栏, 建议前台服务类应用使用,可以方便用户再次调用 UI 操作。 | ||||
|                         iWinBoLLActivity.getActivity().finishAndRemoveTask(); | ||||
|                         //ToastUtils.show("finishAll() activity.finishAndRemoveTask();"); | ||||
|                     } else if (GlobalApplication.getWinBoLLActivityManager().getWinBoLLUI_TYPE() == WinBoLLUI_TYPE.Aplication) { | ||||
|                         // 结束窗口保留最近任务栏,建议前台服务类应用使用,可以保持应用的系统自觉性。 | ||||
|                         iWinBoLLActivity.getActivity().finish(); | ||||
|                         //ToastUtils.show("finishAll() activity.finish();"); | ||||
|                     } else { | ||||
|                         ToastUtils.show("WinBollApplication.WinBollUI_TYPE error."); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } catch (Exception e) { | ||||
|             LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 结束指定Activity | ||||
|      */ | ||||
|     public <T extends IWinBoLLActivity> void finish(T iWinBoLLActivity) { | ||||
|         try { | ||||
|             if (iWinBoLLActivity != null && iWinBoLLActivity.getActivity() != null && !iWinBoLLActivity.getActivity().isFinishing() && !iWinBoLLActivity.getActivity().isDestroyed()) { | ||||
|                 //根据tag 移除 MyActivity | ||||
|                 //String tag= activity.getTag(); | ||||
|                 //_mIWinBoLLActivityList.remove(tag); | ||||
|                 //ToastUtils.show("remove"); | ||||
|                 //ToastUtils.show("_mIWinBoLLActivityArrayMap.size() " + Integer.toString(_mIWinBoLLActivityArrayMap.size())); | ||||
|  | ||||
|                 // 窗口回调规则: | ||||
|                 // [] 当前窗口位置 >> 调度出的窗口位置 | ||||
|                 // ★:[0] 1 2 3 4 >> 1 | ||||
|                 // ★:0 1 [2] 3 4 >> 1 | ||||
|                 // ★:0 1 2 [3] 4 >> 2 | ||||
|                 // ★:0 1 2 3 [4] >> 3 | ||||
|                 // ★:[0] >> 直接关闭当前窗口 | ||||
|                 Activity preActivity = getPreActivity(iWinBoLLActivity); | ||||
|                 iWinBoLLActivity.getActivity().finish(); | ||||
|                 if (preActivity != null) { | ||||
|                     resumeActivity(preActivity); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|         } catch (Exception e) { | ||||
|             LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     Activity getPreActivity(IWinBoLLActivity iWinBoLLActivity) { | ||||
|         try { | ||||
|             boolean bingo = false; | ||||
|             IWinBoLLActivity preIWinBoLLActivity = null; | ||||
|             for (Map.Entry<String, IWinBoLLActivity> entity : mActivityListMap.entrySet()) { | ||||
|                 if (entity.getKey().equals(iWinBoLLActivity.getTag())) { | ||||
|                     bingo = true; | ||||
|                     LogUtils.d(TAG, "bingo"); | ||||
|                     break; | ||||
|                 } | ||||
|                 preIWinBoLLActivity = entity.getValue(); | ||||
|             } | ||||
|  | ||||
|             if (bingo) { | ||||
|                 return preIWinBoLLActivity.getActivity(); | ||||
|             } | ||||
|         } catch (Exception e) { | ||||
|             LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     public <T extends IWinBoLLActivity> boolean registeRemove(T iWinBoLLActivity) { | ||||
|         IWinBoLLActivity iWinBoLLActivityTest = mActivityListMap.get(iWinBoLLActivity.getTag()); | ||||
|         if (iWinBoLLActivityTest != null) { | ||||
|             mActivityListMap.remove(iWinBoLLActivity.getTag()); | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     public void printAvtivityListInfo() { | ||||
|         if (!mActivityListMap.isEmpty()) { | ||||
|             StringBuilder sb = new StringBuilder("Map entries : " + Integer.toString(mActivityListMap.size())); | ||||
|             Iterator<Map.Entry<String, IWinBoLLActivity>> iterator = mActivityListMap.entrySet().iterator(); | ||||
|             while (iterator.hasNext()) { | ||||
|                 Map.Entry<String, IWinBoLLActivity> entry = iterator.next(); | ||||
|                 sb.append("\nKey: " + entry.getKey() + ", \nValue: " + entry.getValue().getTag()); | ||||
|                 //ToastUtils.show("\nKey: " + entry.getKey() + ", Value: " + entry.getValue().getTag()); | ||||
|             } | ||||
|             sb.append("\nMap entries end."); | ||||
|             LogUtils.d(TAG, sb.toString()); | ||||
|         } else { | ||||
|             LogUtils.d(TAG, "The map is empty."); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 ZhanGSKen
					ZhanGSKen