重构主应用架构

This commit is contained in:
ZhanGSKen
2025-02-19 03:17:49 +08:00
parent c226a92ffe
commit e7c614ebec
31 changed files with 861 additions and 421 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Mon Feb 17 12:10:03 HKT 2025
#Tue Feb 18 19:15:30 GMT 2025
stageCount=3
libraryProject=libappbase
baseVersion=1.5
publishVersion=1.5.2
buildCount=0
buildCount=58
baseBetaVersion=1.5.3

View File

@@ -61,12 +61,38 @@
</receiver>
<receiver
android:name=".widgets.SOSWidget"
android:exported="true">
<intent-filter>
<action android:name="cc.winboll.studio.appbase.widgets.SOSWidget.ACTION_SOS"/>
<action android:name="cc.winboll.studio.appbase.widgets.SOSWidget.ACTION_RELOAD_REPORT" />
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_provider_info_sos"/>
</receiver>
<receiver android:name=".widgets.SOSWidgetClickListener">
<intent-filter>
<action android:name="cc.winboll.studio.appbase.widgets.SOSWidgetClickListener.ACTION_PRE"/>
<action android:name="cc.winboll.studio.appbase.widgets.SOSWidgetClickListener.ACTION_NEXT"/>
</intent-filter>
</receiver>
<meta-data
android:name="android.max_aspect"
android:value="4.0"/>
<service android:name="cc.winboll.studio.appbase.services.TestService"
android:exported="true"/>
</application>

View File

@@ -9,15 +9,15 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.appbase.R;
import cc.winboll.studio.appbase.services.MainService;
import cc.winboll.studio.appbase.services.TestService;
import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.LogView;
import cc.winboll.studio.libappbase.SOS;
import cc.winboll.studio.libappbase.SimpleOperateSignalCenterService;
import cc.winboll.studio.libappbase.widgets.APPSOSReportWidget;
import com.hjq.toast.ToastUtils;
import cc.winboll.studio.libappbase.bean.APPSOSBean;
import cc.winboll.studio.libappbase.services.TestService;
import cc.winboll.studio.libappbase.widgets.StatusWidget;
import com.hjq.toast.ToastUtils;
public class MainActivity extends AppCompatActivity {
@@ -41,6 +41,14 @@ public class MainActivity extends AppCompatActivity {
if (GlobalApplication.isDebuging()) { mLogView.start(); }
}
@Override
protected void onDestroy() {
super.onDestroy();
Intent intentAPPWidget = new Intent(this, StatusWidget.class);
intentAPPWidget.setAction(StatusWidget.ACTION_STATUS_UPDATE);
sendBroadcast(intentAPPWidget);
}
@Override
protected void onResume() {
LogUtils.d(TAG, "onResume");
@@ -83,39 +91,23 @@ public class MainActivity extends AppCompatActivity {
Intent intent = new Intent(this, TestService.class);
stopService(intent);
SOS.sosWinBollService(this, new APPSOSBean(getPackageName(), TestService.class.getName()));
// Intent intentTimeWidget = new Intent(this, TimeWidget.class);
// intentTimeWidget.setAction(TimeWidget.UPDATE_TIME_ACTION);
// intentTimeWidget.putExtra("appName", "TestName");
// sendBroadcast(intentTimeWidget);
//
}
// public void sos() {
// // 创建Intent对象指定广播的action
// Intent intent = new Intent(SOSCSBroadcastReceiver.ACTION_SOS);
// // 目标服务的包名和类名
// String packageName = this.getPackageName();
// String serviceClassName = SimpleOperateSignalCenterService.class.getName();
// intent.putExtra(ISOSAPP.EXTRA_PACKAGE, packageName);
// intent.putExtra(ISOSAPP.EXTRA_SERVICE, serviceClassName);
// // 发送广播
// sendBroadcast(intent);
// LogUtils.d(TAG, "onSOS");
// }
//
// public void sos2() {
// // 创建Intent对象指定广播的action
// Intent intent = new Intent(SOSCSBroadcastReceiver.ACTION_SOS);
// // 目标服务的包名和类名
// String packageName = this.getPackageName();
// String serviceClassName = SimpleOperateSignalCenterService.class.getName();
// intent.putExtra(ISOSAPP.EXTRA_PACKAGE, packageName);
// intent.putExtra(ISOSAPP.EXTRA_SERVICE, serviceClassName);
// // 发送广播
// sendBroadcast(intent);
// LogUtils.d(TAG, "onSOS2");
// }
public void onStartTestService(View view) {
Intent intent = new Intent(this, TestService.class);
startService(intent);
}
public void onStopTestService(View view) {
Intent intent = new Intent(this, TestService.class);
stopService(intent);
}
public void onUpdateAPPWidget(View view) {
Intent intentAPPWidget = new Intent(this, StatusWidget.class);
intentAPPWidget.setAction(StatusWidget.ACTION_STATUS_UPDATE);
sendBroadcast(intentAPPWidget);
}
}

View File

@@ -0,0 +1,72 @@
package cc.winboll.studio.appbase.beans;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/17 10:05:09
* @Describe APPSOSReportBean
*/
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException;
public class SOSReportBean extends BaseBean {
public static final String TAG = "APPSOSReportBean";
protected String sosReport;
public SOSReportBean() {
this.sosReport = "";
}
public SOSReportBean(String sosReport) {
this.sosReport = sosReport;
}
public void setSosReport(String sosReport) {
this.sosReport = sosReport;
}
public String getSosReport() {
return sosReport;
}
@Override
public String getName() {
return SOSReportBean.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
jsonWriter.name("sosReport").value(getSosReport());
}
@Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
if (name.equals("sosReport")) {
setSosReport(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;
}
}

View File

@@ -24,7 +24,7 @@ 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.libappbase.LogUtils;
import cc.winboll.studio.libappbase.widgets.APPSOSReportWidget;
import cc.winboll.studio.appbase.widgets.SOSWidget;
public class MainService extends Service {
@@ -96,8 +96,8 @@ public class MainService extends Service {
}
// 启动小部件
Intent intentTimeWidget = new Intent(this, APPSOSReportWidget.class);
intentTimeWidget.setAction(APPSOSReportWidget.ACTION_RELOAD_SOS_REPORT);
Intent intentTimeWidget = new Intent(this, SOSWidget.class);
intentTimeWidget.setAction(SOSWidget.ACTION_RELOAD_REPORT);
this.sendBroadcast(intentTimeWidget);
startMainServiceThread();

View File

@@ -1,42 +1,3 @@
package cc.winboll.studio.appbase.services;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import cc.winboll.studio.libappbase.LogUtils;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/15 20:48:36
* @Describe TestService
*/
public class TestService extends Service {
public static final String TAG = "TestService";
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
LogUtils.d(TAG, "onCreate()");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
LogUtils.d(TAG, "onStartCommand(...)");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
LogUtils.d(TAG, "onDestroy()");
}
}

View File

@@ -0,0 +1,192 @@
package cc.winboll.studio.appbase.widgets;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/15 14:41:25
* @Describe TimeWidget
*/
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.widget.RemoteViews;
import cc.winboll.studio.appbase.R;
import cc.winboll.studio.appbase.beans.SOSReportBean;
import cc.winboll.studio.libappbase.AppUtils;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.bean.APPSOSBean;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
public class SOSWidget extends AppWidgetProvider {
public static final String TAG = "SOSWidget";
public static final String ACTION_SOS = "cc.winboll.studio.appbase.widgets.SOSWidget.ACTION_SOS";
public static final String ACTION_RELOAD_REPORT = "cc.winboll.studio.appbase.widgets.SOSWidget.ACTION_RELOAD_REPORT";
volatile static ArrayList<SOSReportBean> _SOSReportBeanList;
final static int _MAX_PAGES = 10;
final static int _OnePageLinesCount = 5;
volatile static int _CurrentPageIndex = 0;
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
initAPPSOSReportBeanList(context);
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
initAPPSOSReportBeanList(context);
if (intent.getAction().equals(ACTION_SOS)) {
LogUtils.d(TAG, "ACTION_SOS");
LogUtils.d(TAG, String.format("context.getPackageName() %s", context.getPackageName()));
LogUtils.d(TAG, String.format("intent.getAction() %s", intent.getAction()));
String SOS = intent.getStringExtra("SOS");
LogUtils.d(TAG, String.format("SOS %s", SOS));
if (SOS != null && SOS.equals("Service")) {
String szAPPSOSBean = intent.getStringExtra("APPSOSBean");
LogUtils.d(TAG, String.format("szAPPSOSBean %s", szAPPSOSBean));
if (szAPPSOSBean != null && !szAPPSOSBean.equals("")) {
try {
APPSOSBean bean = APPSOSBean.parseStringToBean(szAPPSOSBean, APPSOSBean.class);
if (bean != null) {
String sosPackage = bean.getSosPackage();
LogUtils.d(TAG, String.format("sosPackage %s", sosPackage));
String sosClassName = bean.getSosClassName();
LogUtils.d(TAG, String.format("sosClassName %s", sosClassName));
Intent intentService = new Intent();
intentService.setComponent(new ComponentName(sosPackage, sosClassName));
context.startService(intentService);
String appName = AppUtils.getAppNameByPackageName(context, sosPackage);
LogUtils.d(TAG, String.format("appName %s", appName));
SOSReportBean appSOSReportBean = new SOSReportBean(appName);
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
String currentTime = sdf.format(new Date());
StringBuilder sbLine = new StringBuilder();
sbLine.append("[");
sbLine.append(currentTime);
sbLine.append("] Power to ");
sbLine.append(appName);
appSOSReportBean.setSosReport(sbLine.toString());
addAPPSOSReportBean(context, appSOSReportBean);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, SOSWidget.class));
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
}
}
} else if (intent.getAction().equals(ACTION_RELOAD_REPORT)) {
LogUtils.d(TAG, "ACTION_RELOAD_REPORT");
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, SOSWidget.class));
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
}
//
// 加入新报告信息
//
void addAPPSOSReportBean(Context context, SOSReportBean bean) {
initAPPSOSReportBeanList(context);
_SOSReportBeanList.add(0, bean);
// 控制记录总数
while (_SOSReportBeanList.size() > _MAX_PAGES * _OnePageLinesCount) {
_SOSReportBeanList.remove(_SOSReportBeanList.size() - 1);
}
SOSReportBean.saveBeanList(context, _SOSReportBeanList, SOSReportBean.class);
}
void initAPPSOSReportBeanList(Context context) {
if (_SOSReportBeanList == null) {
_SOSReportBeanList = new ArrayList<SOSReportBean>();
SOSReportBean.loadBeanList(context, _SOSReportBeanList, SOSReportBean.class);
}
if (_SOSReportBeanList == null) {
_SOSReportBeanList = new ArrayList<SOSReportBean>();
SOSReportBean.saveBeanList(context, _SOSReportBeanList, SOSReportBean.class);
}
}
private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
LogUtils.d(TAG, "updateAppWidget(...)");
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_sos);
//设置按钮点击事件
Intent intentPre = new Intent(context, SOSWidgetClickListener.class);
intentPre.setAction(SOSWidgetClickListener.ACTION_PRE);
PendingIntent pendingIntentPre = PendingIntent.getBroadcast(context, 0, intentPre, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.widget_button_pre, pendingIntentPre);
Intent intentNext = new Intent(context, SOSWidgetClickListener.class);
intentNext.setAction(SOSWidgetClickListener.ACTION_NEXT);
PendingIntent pendingIntentNext = PendingIntent.getBroadcast(context, 0, intentNext, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.widget_button_next, pendingIntentNext);
views.setTextViewText(R.id.infoTextView, getPageInfo());
views.setTextViewText(R.id.sosReportTextView, getMessage());
appWidgetManager.updateAppWidget(appWidgetId, views);
}
public static String getMessage() {
ArrayList<String> msgTemp = new ArrayList<String>();
if (_SOSReportBeanList != null) {
int start = _OnePageLinesCount * _CurrentPageIndex;
start = _SOSReportBeanList.size() > start ? start : _SOSReportBeanList.size() - 1;
for (int i = start, j = 0; i < _SOSReportBeanList.size() && j < _OnePageLinesCount; i++, j++) {
msgTemp.add(_SOSReportBeanList.get(i).getSosReport());
}
String message = String.join("\n", msgTemp);
return message;
}
return "";
}
public static void prePage(Context context) {
if (_SOSReportBeanList != null) {
if (_CurrentPageIndex > 0) {
_CurrentPageIndex = _CurrentPageIndex - 1;
}
Intent intentWidget = new Intent(context, SOSWidget.class);
intentWidget.setAction(SOSWidget.ACTION_RELOAD_REPORT);
context.sendBroadcast(intentWidget);
}
}
public static void nextPage(Context context) {
if (_SOSReportBeanList != null) {
if ((_CurrentPageIndex + 1) * _OnePageLinesCount < _SOSReportBeanList.size()) {
_CurrentPageIndex = _CurrentPageIndex + 1;
}
Intent intentWidget = new Intent(context, SOSWidget.class);
intentWidget.setAction(SOSWidget.ACTION_RELOAD_REPORT);
context.sendBroadcast(intentWidget);
}
}
String getPageInfo() {
if (_SOSReportBeanList == null) {
return "0/0";
}
int leftCount = _SOSReportBeanList.size() % _OnePageLinesCount;
int currentPageCount = _SOSReportBeanList.size() / _OnePageLinesCount + (leftCount == 0 ?0: 1);
return String.format("%d/%d", _CurrentPageIndex + 1, currentPageCount);
}
}

View File

@@ -0,0 +1,36 @@
package cc.winboll.studio.appbase.widgets;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/15 17:20:46
* @Describe WidgetButtonClickListener
*/
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import cc.winboll.studio.libappbase.LogUtils;
public class SOSWidgetClickListener extends BroadcastReceiver {
public static final String TAG = "SOSWidgetClickListener";
public static final String ACTION_PRE = "cc.winboll.studio.appbase.widgets.SOSWidgetClickListener.ACTION_PRE";
public static final String ACTION_NEXT = "cc.winboll.studio.appbase.widgets.SOSWidgetClickListener.ACTION_NEXT";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null) {
LogUtils.d(TAG, String.format("action %s", action));
return;
}
if (action.equals(ACTION_PRE)) {
LogUtils.d(TAG, "ACTION_PRE");
SOSWidget.prePage(context);
} else if (action.equals(ACTION_NEXT)) {
LogUtils.d(TAG, "ACTION_NEXT");
SOSWidget.nextPage(context);
} else {
LogUtils.d(TAG, String.format("action %s", action));
}
}
}

View File

@@ -47,47 +47,88 @@
</LinearLayout>
<LinearLayout
android:orientation="vertical"
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right">
android:layout_height="400dp">
<Button
android:layout_width="wrap_content"
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="StartCenter"
android:textAllCaps="false"
android:onClick="onStartCenter"/>
android:gravity="right">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StopCenter"
android:textAllCaps="false"
android:onClick="onStopCenter"/>
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TestStopWithoutSettingEnable"
android:textAllCaps="false"
android:onClick="onTestStopWithoutSettingEnable"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TestStartWithString"
android:textAllCaps="false"
android:onClick="onTestStartWithString"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SOS"
android:onClick="onSOS"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StartTestService"
android:textAllCaps="false"
android:onClick="onStartTestService"/>
</LinearLayout>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StopTestService"
android:textAllCaps="false"
android:onClick="onStopTestService"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="UpdateAPPWidget"
android:textAllCaps="false"
android:onClick="onUpdateAPPWidget"/>
</LinearLayout>
</HorizontalScrollView>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StartCenter"
android:textAllCaps="false"
android:onClick="onStartCenter"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StopCenter"
android:textAllCaps="false"
android:onClick="onStopCenter"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TestStopWithoutSettingEnable"
android:textAllCaps="false"
android:onClick="onTestStopWithoutSettingEnable"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TestStartWithString"
android:textAllCaps="false"
android:onClick="onTestStartWithString"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SOS"
android:textAllCaps="false"
android:onClick="onSOS"/>
</LinearLayout>
</ScrollView>
<cc.winboll.studio.libappbase.LogView
android:layout_weight="1.0"

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#FFFFFFFF">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/infoTextView"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="⇦"
android:id="@+id/widget_button_pre"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="⇨"
android:id="@+id/widget_button_next"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="@+id/sosReportTextView"
android:layout_weight="1.0"/>
</LinearLayout>

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="APPBaseTheme">
<item name="attrColorPrimary">@color/colorPrimary</item>
<item name="themeGlobalCrashActivity">@style/MyGlobalCrashActivityTheme</item>
</style>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="200dp"
android:minHeight="100dp"
android:updatePeriodMillis="1000"
android:initialLayout="@layout/widget_sos">
</appwidget-provider>