diff --git a/winboll/build.gradle b/winboll/build.gradle index 923a34c5..3752c5be 100644 --- a/winboll/build.gradle +++ b/winboll/build.gradle @@ -45,6 +45,8 @@ android { dependencies { api fileTree(dir: 'libs', include: ['*.jar']) + + api 'com.google.code.gson:gson:2.10.1' // SSH api 'com.jcraft:jsch:0.1.55' @@ -67,7 +69,7 @@ dependencies { //api 'androidx.vectordrawable:vectordrawable-animated:1.1.0' //api 'androidx.fragment:fragment:1.1.0' - api 'cc.winboll.studio:libaes:15.8.0' - api 'cc.winboll.studio:libapputils:15.8.2' - api 'cc.winboll.studio:libappbase:15.8.2' + api 'cc.winboll.studio:libaes:15.10.0' + api 'cc.winboll.studio:libapputils:15.10.0' + api 'cc.winboll.studio:libappbase:15.10.9' } diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/AssistantService.java b/winboll/src/main/java/cc/winboll/studio/winboll/AssistantService.java new file mode 100644 index 00000000..bdc107d0 --- /dev/null +++ b/winboll/src/main/java/cc/winboll/studio/winboll/AssistantService.java @@ -0,0 +1,97 @@ +package cc.winboll.studio.libaes.winboll; + +/** + * @Author ZhanGSKen + * @Date 2025/03/28 19:12:12 + * @Describe 应用主要服务组件类守护进程服务组件类 + */ +import android.app.Service; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import cc.winboll.studio.libaes.models.WinBoLLClientServiceBean; +import cc.winboll.studio.libaes.winboll.AssistantService; +import cc.winboll.studio.libapputils.utils.ServiceUtils; + +public class AssistantService extends Service { + + public final static String TAG = "AssistantService"; + + WinBoLLClientServiceBean mWinBoLLServiceBean; + MyServiceConnection mMyServiceConnection; + volatile boolean mIsServiceRunning; + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public void onCreate() { + super.onCreate(); + mWinBoLLServiceBean = WinBoLLClientServiceBean.loadWinBoLLClientServiceBean(this); + if (mMyServiceConnection == null) { + mMyServiceConnection = new MyServiceConnection(); + } + // 设置运行参数 + mIsServiceRunning = false; + run(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + run(); + return START_STICKY; + } + + @Override + public void onDestroy() { + mIsServiceRunning = false; + super.onDestroy(); + } + + // + // 运行服务内容 + // + void run() { + mWinBoLLServiceBean = WinBoLLClientServiceBean.loadWinBoLLClientServiceBean(this); + if (mWinBoLLServiceBean.isEnable()) { + if (mIsServiceRunning == false) { + // 设置运行状态 + mIsServiceRunning = true; + // 唤醒和绑定主进程 + wakeupAndBindMain(); + } + } + } + + // + // 唤醒和绑定主进程 + // + void wakeupAndBindMain() { + if (ServiceUtils.isServiceAlive(getApplicationContext(), WinBoLLClientService.class.getName()) == false) { + startForegroundService(new Intent(AssistantService.this, WinBoLLClientService.class)); + } + + bindService(new Intent(AssistantService.this, WinBoLLClientService.class), mMyServiceConnection, Context.BIND_IMPORTANT); + } + + // + // 主进程与守护进程连接时需要用到此类 + // + class MyServiceConnection implements ServiceConnection { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + } + + @Override + public void onServiceDisconnected(ComponentName name) { + mWinBoLLServiceBean = WinBoLLClientServiceBean.loadWinBoLLClientServiceBean(AssistantService.this); + if (mWinBoLLServiceBean.isEnable()) { + wakeupAndBindMain(); + } + } + } +} diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/EWUIStatusIconDrawable.java b/winboll/src/main/java/cc/winboll/studio/winboll/EWUIStatusIconDrawable.java new file mode 100644 index 00000000..86fd15ef --- /dev/null +++ b/winboll/src/main/java/cc/winboll/studio/winboll/EWUIStatusIconDrawable.java @@ -0,0 +1,35 @@ +package cc.winboll.studio.libaes.winboll; + +/** + * @Author ZhanGSKen + * @Date 2025/03/28 19:11:27 + * @Describe WinBoLL UI 状态图标枚举 + */ +import cc.winboll.studio.libaes.R; + +public enum EWUIStatusIconDrawable { + NORMAL(0), + NEWS(1) + ; + + static final String TAG = "WUIStatusIconDrawable"; + + static String[] _mlistCNName = { "正常", "新的消息" }; + + private int value = 0; + private EWUIStatusIconDrawable(int value) { //必须是private的,否则编译错误 + this.value = value; + } + + public static int getIconDrawableId(EWUIStatusIconDrawable drawableId) { + int res; + switch(drawableId){ + case NEWS : + res = R.drawable.ic_winbollbeta; + break; + default : + res = R.drawable.ic_winboll; + } + return res; + } +} diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/MainActivity.java b/winboll/src/main/java/cc/winboll/studio/winboll/MainActivity.java index ce829c86..5d4241cd 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/MainActivity.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/MainActivity.java @@ -10,7 +10,7 @@ public class MainActivity extends AppCompatActivity { public static final String TAG = "MainActivity"; LogView mLogView; - private TerminalView mTerminalView; + //private TerminalView mTerminalView; @Override protected void onCreate(Bundle savedInstanceState) { @@ -37,10 +37,10 @@ public class MainActivity extends AppCompatActivity { mLogView = findViewById(R.id.logview); - mTerminalView = findViewById(R.id.terminalView); + /*mTerminalView = findViewById(R.id.terminalView); // 示例:模拟用户输入 "ls" 命令 - mTerminalView.sendInput("ls"); + mTerminalView.sendInput("ls");*/ } @Override diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/MyTileService.java b/winboll/src/main/java/cc/winboll/studio/winboll/MyTileService.java index 9e174108..f17f2341 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/MyTileService.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/MyTileService.java @@ -1,14 +1,15 @@ -package cc.winboll.studio.appbase; +package cc.winboll.studio.winboll; /** * @Author ZhanGSKen * @Date 2025/02/13 19:30:10 */ import android.content.Context; +import cc.winboll.studio.winboll.R; import android.service.quicksettings.Tile; import android.service.quicksettings.TileService; -import cc.winboll.studio.appbase.models.MainServiceBean; -import cc.winboll.studio.appbase.services.MainService; +import cc.winboll.studio.winboll.models.MainServiceBean; +import cc.winboll.studio.winboll.services.MainService; public class MyTileService extends TileService { public static final String TAG = "MyTileService"; diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/WinBoLL.java b/winboll/src/main/java/cc/winboll/studio/winboll/WinBoLL.java new file mode 100644 index 00000000..dd092224 --- /dev/null +++ b/winboll/src/main/java/cc/winboll/studio/winboll/WinBoLL.java @@ -0,0 +1,40 @@ +package cc.winboll.studio.libaes.winboll; + +/** + * @Author ZhanGSKen + * @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.libaes.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); + } + +} diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/WinBoLLClientService.java b/winboll/src/main/java/cc/winboll/studio/winboll/WinBoLLClientService.java new file mode 100644 index 00000000..d4e93a68 --- /dev/null +++ b/winboll/src/main/java/cc/winboll/studio/winboll/WinBoLLClientService.java @@ -0,0 +1,21 @@ +package cc.winboll.studio.libaes.winboll; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +/** + * @Author ZhanGSKen + * @Date 2025/05/03 19:28 + */ +public class WinBoLLClientService extends Service { + + public static final String TAG = "WinBoLLClientService"; + + @Override + public IBinder onBind(Intent intent) { + + return null; + } + +} \ No newline at end of file diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/WinBoLLServiceStatusView.java b/winboll/src/main/java/cc/winboll/studio/winboll/WinBoLLServiceStatusView.java new file mode 100644 index 00000000..14a56e20 --- /dev/null +++ b/winboll/src/main/java/cc/winboll/studio/winboll/WinBoLLServiceStatusView.java @@ -0,0 +1,38 @@ +package cc.winboll.studio.libaes.winboll; +import android.content.Context; +import android.util.AttributeSet; +import android.widget.LinearLayout; + +/** + * @Author ZhanGSKen + * @Date 2025/05/03 19:14 + */ +public class WinBoLLServiceStatusView extends LinearLayout { + + public static final String TAG = "WinBoLLServiceStatusView"; + + public WinBoLLServiceStatusView(Context context) { + super(context); + } + + public WinBoLLServiceStatusView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public WinBoLLServiceStatusView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public WinBoLLServiceStatusView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + + void setServerHost(String szWinBoLLServerHost) { + + } + + void setAuthInfo(String szDevUserName, String szDevUserPassword) { + + } +} diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/activities/LogonActivity.java b/winboll/src/main/java/cc/winboll/studio/winboll/activities/LogonActivity.java index 029b1eee..f1f10fc8 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/activities/LogonActivity.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/activities/LogonActivity.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.libappbase.activities; +package cc.winboll.studio.winboll.activities; import android.app.Activity; import android.os.Bundle; @@ -7,14 +7,14 @@ 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 cc.winboll.studio.winboll.R; import java.security.KeyPair; import java.security.PrivateKey; import java.security.PublicKey; +import cc.winboll.studio.winboll.utils.YunUtils; +import cc.winboll.studio.winboll.models.UserInfoModel; +import cc.winboll.studio.winboll.utils.RSAUtils; +import cc.winboll.studio.libaes.winboll.IWinBoLLActivity; /** * @Author ZhanGSKen diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/activities/New2Activity.java b/winboll/src/main/java/cc/winboll/studio/winboll/activities/New2Activity.java index faf79d20..a480653a 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/activities/New2Activity.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/activities/New2Activity.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.appbase.activities; +package cc.winboll.studio.winboll.activities; /** * @Author ZhanGSKen @@ -11,9 +11,10 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Toolbar; -import cc.winboll.studio.appbase.R; +import cc.winboll.studio.winboll.R; import cc.winboll.studio.libappbase.GlobalApplication; -import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; +import cc.winboll.studio.libaes.winboll.IWinBoLLActivity; +import cc.winboll.studio.libaes.winboll.WinBoLLActivityManager; public class New2Activity extends WinBoLLActivity implements IWinBoLLActivity { @@ -51,15 +52,15 @@ public class New2Activity extends WinBoLLActivity implements IWinBoLLActivity { } public void onCloseThisActivity(View view) { - GlobalApplication.getWinBoLLActivityManager().finish(this); + WinBoLLActivityManager.getInstance().finish(this); } public void onCloseAllActivity(View view) { - GlobalApplication.getWinBoLLActivityManager().finishAll(); + WinBoLLActivityManager.getInstance().finishAll(); } public void onNewActivity(View view) { - GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(this, NewActivity.class); + WinBoLLActivityManager.getInstance().startWinBoLLActivity(this, NewActivity.class); } diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/activities/NewActivity.java b/winboll/src/main/java/cc/winboll/studio/winboll/activities/NewActivity.java index f87156e1..d8104867 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/activities/NewActivity.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/activities/NewActivity.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.appbase.activities; +package cc.winboll.studio.winboll.activities; /** * @Author ZhanGSKen&豆包大模型 @@ -11,9 +11,10 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Toolbar; -import cc.winboll.studio.appbase.R; +import cc.winboll.studio.winboll.R; import cc.winboll.studio.libappbase.GlobalApplication; -import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; +import cc.winboll.studio.libaes.winboll.WinBoLLActivityManager; +import cc.winboll.studio.libaes.winboll.IWinBoLLActivity; public class NewActivity extends WinBoLLActivity implements IWinBoLLActivity { @@ -50,15 +51,15 @@ public class NewActivity extends WinBoLLActivity implements IWinBoLLActivity { } public void onCloseThisActivity(View view) { - GlobalApplication.getWinBoLLActivityManager().finish(this); + WinBoLLActivityManager.getInstance().finish(this); } public void onCloseAllActivity(View view) { - GlobalApplication.getWinBoLLActivityManager().finishAll(); + WinBoLLActivityManager.getInstance().finishAll(); } public void onNew2Activity(View view) { - GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(this, New2Activity.class); + WinBoLLActivityManager.getInstance().startWinBoLLActivity(this, New2Activity.class); } diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/activities/WinBoLLActivity.java b/winboll/src/main/java/cc/winboll/studio/winboll/activities/WinBoLLActivity.java index 0721c401..1bf70903 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/activities/WinBoLLActivity.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/activities/WinBoLLActivity.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.appbase.activities; +package cc.winboll.studio.winboll.activities; /** * @Author ZhanGSKen @@ -6,13 +6,15 @@ package cc.winboll.studio.appbase.activities; * @Describe WinBoLL 窗口基础类 */ import android.app.Activity; +import android.content.Intent; import android.os.Bundle; import android.view.MenuItem; -import cc.winboll.studio.appbase.MainActivity; -import cc.winboll.studio.appbase.R; +import cc.winboll.studio.libaes.winboll.IWinBoLLActivity; import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libappbase.LogUtils; -import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; +import cc.winboll.studio.winboll.MainActivity; +import cc.winboll.studio.winboll.R; +import cc.winboll.studio.libaes.winboll.WinBoLLActivityManager; public class WinBoLLActivity extends Activity implements IWinBoLLActivity { @@ -37,10 +39,10 @@ public class WinBoLLActivity extends Activity implements IWinBoLLActivity { @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.item_log) { - GlobalApplication.getWinBoLLActivityManager().startLogActivity(this); + WinBoLLActivityManager.getInstance().startLogActivity(this); return true; } else if (item.getItemId() == R.id.item_home) { - GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(getApplicationContext(), MainActivity.class); + startActivity(new Intent(this, MainActivity.class)); return true; } // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。 @@ -50,12 +52,12 @@ public class WinBoLLActivity extends Activity implements IWinBoLLActivity { @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); - GlobalApplication.getWinBoLLActivityManager().add(this); + WinBoLLActivityManager.getInstance().add(this); } @Override protected void onDestroy() { super.onDestroy(); - GlobalApplication.getWinBoLLActivityManager().registeRemove(this); + WinBoLLActivityManager.getInstance().registeRemove(this); } } diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/activities/WinBoLLUnitTestActivity.java b/winboll/src/main/java/cc/winboll/studio/winboll/activities/WinBoLLUnitTestActivity.java index e40f48fa..713b792f 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/activities/WinBoLLUnitTestActivity.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/activities/WinBoLLUnitTestActivity.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.appbase; +package cc.winboll.studio.winboll.activities; import android.app.Activity; import android.content.ComponentName; @@ -9,12 +9,19 @@ import android.view.MenuItem; import android.view.View; import android.widget.CheckBox; import android.widget.Toolbar; -import cc.winboll.studio.appbase.R; import cc.winboll.studio.libappbase.CrashHandler; import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libappbase.GlobalCrashActivity; import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.utils.ToastUtils; +import cc.winboll.studio.winboll.App; +import cc.winboll.studio.winboll.R; +import cc.winboll.studio.winboll.services.MainService; +import cc.winboll.studio.winboll.services.TestDemoBindService; +import cc.winboll.studio.winboll.services.TestDemoService; +import cc.winboll.studio.winboll.sos.SOS; +import cc.winboll.studio.winboll.widgets.StatusWidget; +import cc.winboll.studio.libaes.winboll.WinBoLLActivityManager; public class WinBoLLUnitTestActivity extends Activity { @@ -44,9 +51,9 @@ public class WinBoLLUnitTestActivity extends Activity { @Override public boolean onOptionsItemSelected(MenuItem item) { if(item.getItemId() == R.id.item_yun) { - GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(this, cc.winboll.studio.libappbase.activities.YunActivity.class); + WinBoLLActivityManager.getInstance().startWinBoLLActivity(this, cc.winboll.studio.libappbase.activities.YunActivity.class); } else if(item.getItemId() == R.id.item_logon) { - GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(this, cc.winboll.studio.libappbase.activities.LogonActivity.class); + WinBoLLActivityManager.getInstance().startWinBoLLActivity(this, cc.winboll.studio.libappbase.activities.LogonActivity.class); } // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。 return super.onOptionsItemSelected(item); @@ -63,7 +70,7 @@ public class WinBoLLUnitTestActivity extends Activity { public void onSwitchDebugMode(View view) { boolean isDebuging = ((CheckBox)view).isChecked(); GlobalApplication.setIsDebuging(isDebuging); - GlobalApplication.saveDebugStatus(); + GlobalApplication.saveDebugStatus(this); } public void onPreviewGlobalCrashActivity(View view) { @@ -152,7 +159,7 @@ public class WinBoLLUnitTestActivity extends Activity { } public void onTestOpenNewActivity(View view) { - GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(this, NewActivity.class); + WinBoLLActivityManager.getInstance().startWinBoLLActivity(this, NewActivity.class); } @Override diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/activities/YunActivity.java b/winboll/src/main/java/cc/winboll/studio/winboll/activities/YunActivity.java index fe929f4c..39386ea3 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/activities/YunActivity.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/activities/YunActivity.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.libappbase.activities; +package cc.winboll.studio.winboll.activities; import android.app.Activity; import android.os.Bundle; diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/handlers/MainServiceHandler.java b/winboll/src/main/java/cc/winboll/studio/winboll/handlers/MainServiceHandler.java index c9d6a0e8..effeb436 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/handlers/MainServiceHandler.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/handlers/MainServiceHandler.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.appbase.handlers; +package cc.winboll.studio.winboll.handlers; /** * @Author ZhanGSKen @@ -6,8 +6,8 @@ package cc.winboll.studio.appbase.handlers; */ import android.os.Handler; import android.os.Message; -import cc.winboll.studio.appbase.services.MainService; import java.lang.ref.WeakReference; +import cc.winboll.studio.winboll.services.MainService; public class MainServiceHandler extends Handler { public static final String TAG = "MainServiceHandler"; diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/models/MainServiceBean.java b/winboll/src/main/java/cc/winboll/studio/winboll/models/MainServiceBean.java index 01dc4144..98b64a13 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/models/MainServiceBean.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/models/MainServiceBean.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.appbase.models; +package cc.winboll.studio.winboll.models; /** * @Author ZhanGSKen diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/models/ResponseData.java b/winboll/src/main/java/cc/winboll/studio/winboll/models/ResponseData.java new file mode 100644 index 00000000..ed78bdc0 --- /dev/null +++ b/winboll/src/main/java/cc/winboll/studio/winboll/models/ResponseData.java @@ -0,0 +1,53 @@ +package cc.winboll.studio.winboll.models; + +/** + * @Author ZhanGSKen + * @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; + } +} + diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/models/TestDemoBindServiceBean.java b/winboll/src/main/java/cc/winboll/studio/winboll/models/TestDemoBindServiceBean.java index 75f7184b..ab680510 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/models/TestDemoBindServiceBean.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/models/TestDemoBindServiceBean.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.appbase.models; +package cc.winboll.studio.winboll.models; /** * @Author ZhanGSKen diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/models/TestDemoServiceBean.java b/winboll/src/main/java/cc/winboll/studio/winboll/models/TestDemoServiceBean.java index 8d6a379a..5899eca1 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/models/TestDemoServiceBean.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/models/TestDemoServiceBean.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.appbase.models; +package cc.winboll.studio.winboll.models; /** * @Author ZhanGSKen diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/models/UserInfoModel.java b/winboll/src/main/java/cc/winboll/studio/winboll/models/UserInfoModel.java new file mode 100644 index 00000000..52c4e4c5 --- /dev/null +++ b/winboll/src/main/java/cc/winboll/studio/winboll/models/UserInfoModel.java @@ -0,0 +1,92 @@ +package cc.winboll.studio.winboll.models; + +/** + * @Author ZhanGSKen + * @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; + } +} diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/models/WinBoLLModel.java b/winboll/src/main/java/cc/winboll/studio/winboll/models/WinBoLLModel.java new file mode 100644 index 00000000..6b5d65d0 --- /dev/null +++ b/winboll/src/main/java/cc/winboll/studio/winboll/models/WinBoLLModel.java @@ -0,0 +1,92 @@ +package cc.winboll.studio.winboll.models; + +/** + * @Author ZhanGSKen + * @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; +import cc.winboll.studio.libappbase.APPModel; + +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; + } +} + diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/models/WinBoLLNewsBean.java b/winboll/src/main/java/cc/winboll/studio/winboll/models/WinBoLLNewsBean.java index de2b03d9..e7491963 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/models/WinBoLLNewsBean.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/models/WinBoLLNewsBean.java @@ -1,14 +1,15 @@ -package cc.winboll.studio.libappbase.models; -import android.util.JsonReader; -import android.util.JsonWriter; -import cc.winboll.studio.libappbase.BaseBean; -import java.io.IOException; +package cc.winboll.studio.winboll.models; /** * @Author ZhanGSKen * @Date 2025/05/10 09:36 * @Describe WinBoLL 应用消息数据模型 */ +import android.util.JsonReader; +import android.util.JsonWriter; +import cc.winboll.studio.libappbase.BaseBean; +import java.io.IOException; + public class WinBoLLNewsBean extends BaseBean { public static final String TAG = "WinBoLLNewsBean"; diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/receivers/APPNewsWidgetClickListener.java b/winboll/src/main/java/cc/winboll/studio/winboll/receivers/APPNewsWidgetClickListener.java index fd4a35d9..4e3681d2 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/receivers/APPNewsWidgetClickListener.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/receivers/APPNewsWidgetClickListener.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.appbase.receivers; +package cc.winboll.studio.winboll.receivers; /** * @Author ZhanGSKen @@ -7,8 +7,8 @@ package cc.winboll.studio.appbase.receivers; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import cc.winboll.studio.appbase.widgets.APPNewsWidget; import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.winboll.widgets.APPNewsWidget; public class APPNewsWidgetClickListener extends BroadcastReceiver { diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/receivers/MainReceiver.java b/winboll/src/main/java/cc/winboll/studio/winboll/receivers/MainReceiver.java index ee435a93..fb7cce2c 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/receivers/MainReceiver.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/receivers/MainReceiver.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.appbase.receivers; +package cc.winboll.studio.winboll.receivers; /** * @Author ZhanGSKen @@ -10,14 +10,17 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import cc.winboll.studio.appbase.services.MainService; -import cc.winboll.studio.appbase.widgets.APPNewsWidget; +import cc.winboll.studio.libaes.winboll.IWinBoLLActivity; +import cc.winboll.studio.libaes.winboll.WinBoLL; import cc.winboll.studio.libappbase.LogUtils; -import cc.winboll.studio.libappbase.models.WinBoLLModel; -import cc.winboll.studio.libappbase.models.WinBoLLNewsBean; -import cc.winboll.studio.libappbase.sos.SOS; -import cc.winboll.studio.libappbase.sos.SOSObject; -import cc.winboll.studio.libappbase.utils.ToastUtils; +import cc.winboll.studio.libappbase.ToastUtils; +import cc.winboll.studio.libapputils.utils.AppUtils; +import cc.winboll.studio.winboll.models.WinBoLLModel; +import cc.winboll.studio.winboll.models.WinBoLLNewsBean; +import cc.winboll.studio.winboll.services.MainService; +import cc.winboll.studio.winboll.sos.SOS; +import cc.winboll.studio.winboll.sos.SOSObject; +import cc.winboll.studio.winboll.widgets.APPNewsWidget; import java.io.IOException; import java.lang.ref.WeakReference; import java.text.SimpleDateFormat; diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/services/AssistantService.java b/winboll/src/main/java/cc/winboll/studio/winboll/services/AssistantService.java index 07702412..2fd60768 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/services/AssistantService.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/services/AssistantService.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.appbase.services; +package cc.winboll.studio.winboll.services; /** * @Author ZhanGSKen @@ -11,11 +11,9 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; -import cc.winboll.studio.appbase.models.MainServiceBean; -import cc.winboll.studio.appbase.services.AssistantService; -import cc.winboll.studio.appbase.services.MainService; import cc.winboll.studio.libappbase.LogUtils; import android.os.Binder; +import cc.winboll.studio.winboll.models.MainServiceBean; public class AssistantService extends Service { diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/services/MainService.java b/winboll/src/main/java/cc/winboll/studio/winboll/services/MainService.java index f71bdbb7..232010fc 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/services/MainService.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/services/MainService.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.appbase.services; +package cc.winboll.studio.winboll.services; /** * @Author ZhanGSKen @@ -17,16 +17,15 @@ import android.content.Intent; import android.content.ServiceConnection; import android.os.Binder; import android.os.IBinder; -import cc.winboll.studio.appbase.MyTileService; -import cc.winboll.studio.appbase.handlers.MainServiceHandler; -import cc.winboll.studio.appbase.models.MainServiceBean; -import cc.winboll.studio.appbase.receivers.MainReceiver; -import cc.winboll.studio.appbase.services.AssistantService; -import cc.winboll.studio.appbase.threads.MainServiceThread; -import cc.winboll.studio.appbase.widgets.APPNewsWidget; +import cc.winboll.studio.libaes.models.WinBoLLModel; import cc.winboll.studio.libappbase.LogUtils; -import cc.winboll.studio.libappbase.models.APPModel; -import cc.winboll.studio.libappbase.models.WinBoLLModel; +import cc.winboll.studio.winboll.MyTileService; +import cc.winboll.studio.winboll.handlers.MainServiceHandler; +import cc.winboll.studio.winboll.models.MainServiceBean; +import cc.winboll.studio.winboll.receivers.MainReceiver; +import cc.winboll.studio.winboll.services.AssistantService; +import cc.winboll.studio.winboll.threads.MainServiceThread; +import cc.winboll.studio.winboll.widgets.APPNewsWidget; import java.util.ArrayList; public class MainService extends Service { diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/services/TestDemoBindService.java b/winboll/src/main/java/cc/winboll/studio/winboll/services/TestDemoBindService.java index 7136d3ce..a351d8ea 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/services/TestDemoBindService.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/services/TestDemoBindService.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.appbase.services; +package cc.winboll.studio.winboll.services; /** * @Author ZhanGSKen @@ -10,12 +10,12 @@ import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.IBinder; -import cc.winboll.studio.appbase.App; -import cc.winboll.studio.appbase.models.TestDemoBindServiceBean; -import cc.winboll.studio.appbase.services.TestDemoBindService; +import cc.winboll.studio.libaes.winboll.WinBoLL; import cc.winboll.studio.libappbase.LogUtils; -import cc.winboll.studio.libappbase.sos.SOS; -import cc.winboll.studio.libappbase.winboll.WinBoLL; +import cc.winboll.studio.winboll.App; +import cc.winboll.studio.winboll.models.TestDemoBindServiceBean; +import cc.winboll.studio.winboll.services.TestDemoBindService; +import cc.winboll.studio.winboll.sos.SOS; public class TestDemoBindService extends Service { diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/services/TestDemoService.java b/winboll/src/main/java/cc/winboll/studio/winboll/services/TestDemoService.java index ee7de32d..7364b9bc 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/services/TestDemoService.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/services/TestDemoService.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.appbase.services; +package cc.winboll.studio.winboll.services; /** * @Author ZhanGSKen @@ -10,8 +10,9 @@ import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.IBinder; -import cc.winboll.studio.appbase.models.TestDemoServiceBean; +import cc.winboll.studio.winboll.models.TestDemoServiceBean; import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.winboll.models.TestDemoServiceBean; public class TestDemoService extends Service { diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/sos/SOS.java b/winboll/src/main/java/cc/winboll/studio/winboll/sos/SOS.java index 6d80d255..c45d8eb5 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/sos/SOS.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/sos/SOS.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.libappbase.sos; +package cc.winboll.studio.winboll.sos; /** * @Author ZhanGSKen diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/sos/SOSCenterService.java b/winboll/src/main/java/cc/winboll/studio/winboll/sos/SOSCenterService.java index 7c7c1fa7..039d8e6e 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/sos/SOSCenterService.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/sos/SOSCenterService.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.libappbase.sos; +package cc.winboll.studio.winboll.sos; /** * @Author ZhanGSKen diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/sos/SOSCenterServiceModel.java b/winboll/src/main/java/cc/winboll/studio/winboll/sos/SOSCenterServiceModel.java index f2cfc401..3f226ae7 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/sos/SOSCenterServiceModel.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/sos/SOSCenterServiceModel.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.libappbase.sos; +package cc.winboll.studio.winboll.sos; /** * @Author ZhanGSKen diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/sos/SOSCenterServiceReceiver.java b/winboll/src/main/java/cc/winboll/studio/winboll/sos/SOSCenterServiceReceiver.java index ec3341b1..14dd36a0 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/sos/SOSCenterServiceReceiver.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/sos/SOSCenterServiceReceiver.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.libappbase.sos; +package cc.winboll.studio.winboll.sos; /** * @Author ZhanGSKen diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/sos/SOSObject.java b/winboll/src/main/java/cc/winboll/studio/winboll/sos/SOSObject.java index 5f19563a..ec07b388 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/sos/SOSObject.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/sos/SOSObject.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.libappbase.sos; +package cc.winboll.studio.winboll.sos; /** * @Author ZhanGSKen diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/threads/MainServiceThread.java b/winboll/src/main/java/cc/winboll/studio/winboll/threads/MainServiceThread.java index c922e84a..80ecc3f9 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/threads/MainServiceThread.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/threads/MainServiceThread.java @@ -1,11 +1,11 @@ -package cc.winboll.studio.appbase.threads; +package cc.winboll.studio.winboll.threads; /** * @Author ZhanGSKen * @Date 2025/02/14 03:46:44 */ import android.content.Context; -import cc.winboll.studio.appbase.handlers.MainServiceHandler; +import cc.winboll.studio.winboll.handlers.MainServiceHandler; import cc.winboll.studio.libappbase.LogUtils; import java.lang.ref.WeakReference; diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/utils/RSAUtils.java b/winboll/src/main/java/cc/winboll/studio/winboll/utils/RSAUtils.java new file mode 100644 index 00000000..5258e2b7 --- /dev/null +++ b/winboll/src/main/java/cc/winboll/studio/winboll/utils/RSAUtils.java @@ -0,0 +1,222 @@ +package cc.winboll.studio.winboll.utils; + +/** + * @Author ZhanGSKen + * @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); + } +} + diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/utils/TermuxUtils.java b/winboll/src/main/java/cc/winboll/studio/winboll/utils/TermuxUtils.java index ad7a72d9..959169a5 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/utils/TermuxUtils.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/utils/TermuxUtils.java @@ -5,13 +5,15 @@ package cc.winboll.studio.winboll.utils; * @Date 2025/06/08 09:05 * @Describe Termux 应用操作工具集 */ +import android.content.Intent; + public abstract class TermuxUtils { public static final String TAG = "TermuxUtils"; private void runTermuxCommand(String command) { // 1. 创建 Intent,指定 Termux 的 RunCommandService - Intent intent = new Intent("com.termux.RUN_COMMAND"); + /*Intent intent = new Intent("com.termux.RUN_COMMAND"); intent.setPackage("com.termux"); // Termux 应用的包名 // 2. 传递命令参数(必填) @@ -26,6 +28,6 @@ public abstract class TermuxUtils { getApplicationContext().startService(intent); } catch (Exception e) { e.printStackTrace(); - } + }*/ } } diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/utils/YunUtils.java b/winboll/src/main/java/cc/winboll/studio/winboll/utils/YunUtils.java new file mode 100644 index 00000000..d0d36f92 --- /dev/null +++ b/winboll/src/main/java/cc/winboll/studio/winboll/utils/YunUtils.java @@ -0,0 +1,282 @@ +package cc.winboll.studio.winboll.utils; + +/** + * @Author ZhanGSKen + * @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 com.google.gson.Gson; +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +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 cc.winboll.studio.winboll.models.UserInfoModel; +import cc.winboll.studio.winboll.models.ResponseData; +import cc.winboll.studio.libapputils.utils.FileUtils; + +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.readByteArrayFromFile(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); + } +} diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/widgets/APPNewsWidget.java b/winboll/src/main/java/cc/winboll/studio/winboll/widgets/APPNewsWidget.java index 71a5caa1..12b7c6c8 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/widgets/APPNewsWidget.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/widgets/APPNewsWidget.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.appbase.widgets; +package cc.winboll.studio.winboll.widgets; /** * @Author ZhanGSKen * @Date 2025/02/15 14:41:25 @@ -11,18 +11,17 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.widget.RemoteViews; -import cc.winboll.studio.appbase.R; -import cc.winboll.studio.appbase.receivers.APPNewsWidgetClickListener; -import cc.winboll.studio.libappbase.AppUtils; +import cc.winboll.studio.libaes.models.WinBoLLModel; +import cc.winboll.studio.libaes.winboll.WinBoLL; import cc.winboll.studio.libappbase.LogUtils; -import cc.winboll.studio.libappbase.models.APPModel; -import cc.winboll.studio.libappbase.models.WinBoLLNewsBean; -import cc.winboll.studio.libappbase.winboll.WinBoLL; +import cc.winboll.studio.libapputils.utils.AppUtils; +import cc.winboll.studio.winboll.R; +import cc.winboll.studio.winboll.models.WinBoLLNewsBean; +import cc.winboll.studio.winboll.receivers.APPNewsWidgetClickListener; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; -import cc.winboll.studio.libappbase.models.WinBoLLModel; public class APPNewsWidget extends AppWidgetProvider { diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/widgets/StatusWidget.java b/winboll/src/main/java/cc/winboll/studio/winboll/widgets/StatusWidget.java index cf3d4ee1..454a78b4 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/widgets/StatusWidget.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/widgets/StatusWidget.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.appbase.widgets; +package cc.winboll.studio.winboll.widgets; /** * @Author ZhanGSKen @@ -11,12 +11,8 @@ 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; +import cc.winboll.studio.winboll.R; +import cc.winboll.studio.libappbase.ToastUtils; public class StatusWidget extends AppWidgetProvider { diff --git a/winboll/src/main/java/cc/winboll/studio/winboll/widgets/StatusWidgetClickListener.java b/winboll/src/main/java/cc/winboll/studio/winboll/widgets/StatusWidgetClickListener.java index 911b1d64..ae182cec 100644 --- a/winboll/src/main/java/cc/winboll/studio/winboll/widgets/StatusWidgetClickListener.java +++ b/winboll/src/main/java/cc/winboll/studio/winboll/widgets/StatusWidgetClickListener.java @@ -1,4 +1,4 @@ -package cc.winboll.studio.libappbase.widgets; +package cc.winboll.studio.winboll.widgets; /** * @Author ZhanGSKen @@ -9,7 +9,7 @@ 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; +import cc.winboll.studio.libappbase.ToastUtils; public class StatusWidgetClickListener extends BroadcastReceiver { diff --git a/winboll/src/main/res/drawable/ic_cloud.xml b/winboll/src/main/res/drawable/ic_cloud.xml new file mode 100644 index 00000000..c116648d --- /dev/null +++ b/winboll/src/main/res/drawable/ic_cloud.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/winboll/src/main/res/drawable/ic_cloud_outline.xml b/winboll/src/main/res/drawable/ic_cloud_outline.xml new file mode 100644 index 00000000..a8ed00cd --- /dev/null +++ b/winboll/src/main/res/drawable/ic_cloud_outline.xml @@ -0,0 +1,11 @@ + + + + +