Compare commits

...

18 Commits

Author SHA1 Message Date
ZhanGSKen
358e8b3522 <appbase>APK 1.5.2 release Publish. 2025-02-17 12:09:50 +08:00
ZhanGSKen
83ab4f9417 添加用磁贴启动小部件功能 2025-02-17 12:07:52 +08:00
ZhanGSKen
26cdacf1c6 BugFix 2025-02-17 11:44:15 +08:00
ZhanGSKen
6378433424 sos报告部件重构 2025-02-17 11:13:09 +08:00
ZhanGSKen
7b05d613e4 完成小部件分页功能 2025-02-16 20:54:33 +08:00
ZhanGSKen
691f9bbd1c 基本救援设施铺设完成 2025-02-15 21:37:33 +08:00
ZhanGSKen
7a8d3329d4 完成摘要事件监控小部件 2025-02-15 19:53:24 +08:00
ZhanGSKen
bbac0c7306 添加WinBoll类 2025-02-15 12:46:23 +08:00
ZhanGSKen
8d2b325172 实现磁贴启动服务功能 2025-02-15 11:30:20 +08:00
ZhanGSKen
825dfb944e AssistantService 启动成功 2025-02-14 21:18:43 +08:00
ZhanGSKen
419244b12a 放弃使用aidl 2025-02-14 07:30:47 +08:00
ZhanGSKen
39fda1b5da Use android studio add aidl file. 2025-02-14 07:04:21 +08:00
ZhanGSKen
464f2da89f test 2025-02-14 06:25:35 +08:00
ZhanGSKen
4f37b6f0e3 test 2025-02-14 06:08:50 +08:00
ZhanGSKen
f91cd0c9c3 <appbase>Start New Stage Version. 2025-02-14 06:02:07 +08:00
ZhanGSKen
d09f0783a4 <appbase>Start New Stage Version. 2025-02-14 06:01:54 +08:00
ZhanGSKen
accca716d4 Test aidl 2025-02-14 06:01:16 +08:00
ZhanGSKen
dfd09eb647 <libappbase>Library Release 1.5.1 2025-02-14 03:01:05 +08:00
35 changed files with 1488 additions and 154 deletions

3
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

1
.idea/.name generated Normal file
View File

@@ -0,0 +1 @@
appbase

6
.idea/compiler.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" />
</component>
</project>

10
.idea/deploymentTargetDropDown.xml generated Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<value>
<entry key="appbase">
<State />
</entry>
</value>
</component>
</project>

10
.idea/migrations.xml generated Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

10
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Fri Feb 14 03:00:46 HKT 2025
stageCount=2
#Mon Feb 17 12:09:50 HKT 2025
stageCount=3
libraryProject=libappbase
baseVersion=1.5
publishVersion=1.5.1
publishVersion=1.5.2
buildCount=0
baseBetaVersion=1.5.2
baseBetaVersion=1.5.3

View File

@@ -18,13 +18,15 @@
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
// 磁贴响应设置
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name=".GlobalApplication$CrashActivity"/>
@@ -34,14 +36,38 @@
android:label="@string/tileservice_name"
android:icon="@drawable/ic_launcher"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".services.MainService"
android:exported="true"/>
<service android:name=".services.AssistantService"/>
<receiver android:name="cc.winboll.studio.appbase.receivers.MainReceiver">
<intent-filter>
<action android:name="cc.winboll.studio.appbase.receivers.MainReceiver"/>
</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>
</manifest>

View File

@@ -19,7 +19,7 @@ public class App extends GlobalApplication {
public void onCreate() {
super.onCreate();
GlobalApplication.setIsDebuging(this, BuildConfig.DEBUG);
mSOSCSBroadcastReceiver = new SOSCSBroadcastReceiver(this);
mSOSCSBroadcastReceiver = new SOSCSBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(SOSCSBroadcastReceiver.ACTION_SOS);
registerReceiver(mSOSCSBroadcastReceiver, intentFilter);

View File

@@ -8,14 +8,16 @@ import android.widget.CheckBox;
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.ISOSAPP;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.LogView;
import cc.winboll.studio.libappbase.SOS;
import cc.winboll.studio.libappbase.SOSCSBroadcastReceiver;
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;
public class MainActivity extends AppCompatActivity {
@@ -51,11 +53,11 @@ public class MainActivity extends AppCompatActivity {
}
public void onStartCenter(View view) {
SimpleOperateSignalCenterService.startISOSService(this);
MainService.startMainService(this);
}
public void onStopCenter(View view) {
SimpleOperateSignalCenterService.stopISOSService(this);
MainService.stopMainService(this);
}
public void onTestStopWithoutSettingEnable(View view) {
@@ -78,34 +80,42 @@ public class MainActivity extends AppCompatActivity {
}
public void onSOS(View view) {
SOS.sendToWinBoll(this);
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 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 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");
}
}

View File

@@ -4,41 +4,76 @@ package cc.winboll.studio.appbase;
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/13 19:30:10
*/
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Build;
import android.content.Context;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
import android.widget.Toast;
import cc.winboll.studio.appbase.beans.MainServiceBean;
import cc.winboll.studio.appbase.services.MainService;
public class MyTileService extends TileService {
public static final String TAG = "MyTileService";
volatile static MyTileService _MyTileService;
@Override
public void onStartListening() {
super.onStartListening();
_MyTileService = this;
Tile tile = getQsTile();
tile.setState(Tile.STATE_INACTIVE);
tile.setLabel(getString(R.string.tileservice_name));
tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud_outline));
MainServiceBean bean = MainServiceBean.loadBean(this, MainServiceBean.class);
if (bean != null && bean.isEnable()) {
//MainService.startMainService(context);
tile.setState(Tile.STATE_ACTIVE);
tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud));
} else {
//MainService.stopMainService(context);
tile.setState(Tile.STATE_INACTIVE);
tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud_outline));
}
tile.updateTile();
// Tile tile = getQsTile();
// tile.setState(Tile.STATE_INACTIVE);
// tile.setLabel(getString(R.string.tileservice_name));
// tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud_outline));
// tile.updateTile();
}
@Override
public void onClick() {
super.onClick();
Toast.makeText(this, "磁贴被点击", Toast.LENGTH_SHORT).show();
Tile tile = getQsTile();
if (tile.getState() == Tile.STATE_INACTIVE) {
tile.setState(Tile.STATE_ACTIVE);
tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud));
MainServiceBean bean = MainServiceBean.loadBean(this, MainServiceBean.class);
if (bean == null) {
bean = new MainServiceBean();
}
if (tile.getState() == Tile.STATE_ACTIVE) {
bean.setIsEnable(false);
MainServiceBean.saveBean(this, bean);
MainService.stopMainService(this);
} else if (tile.getState() == Tile.STATE_INACTIVE) {
bean.setIsEnable(true);
MainServiceBean.saveBean(this, bean);
MainService.startMainService(this);
}
updateServiceIconStatus(this);
}
public static void updateServiceIconStatus(Context context) {
if (_MyTileService == null) {
return;
}
Tile tile = _MyTileService.getQsTile();
MainServiceBean bean = MainServiceBean.loadBean(context, MainServiceBean.class);
if (bean != null && bean.isEnable()) {
tile.setState(Tile.STATE_ACTIVE);
tile.setIcon(android.graphics.drawable.Icon.createWithResource(context, R.drawable.ic_cloud));
} else {
tile.setState(Tile.STATE_INACTIVE);
tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud_outline));
tile.setIcon(android.graphics.drawable.Icon.createWithResource(context, R.drawable.ic_cloud_outline));
}
tile.updateTile();
}
}

View File

@@ -0,0 +1,68 @@
package cc.winboll.studio.appbase.beans;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/13 07:06:13
*/
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException;
public class MainServiceBean extends BaseBean {
public static final String TAG = "MainServiceBean";
boolean isEnable;
public MainServiceBean() {
this.isEnable = false;
}
public void setIsEnable(boolean isEnable) {
this.isEnable = isEnable;
}
public boolean isEnable() {
return isEnable;
}
@Override
public String getName() {
return MainServiceBean.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
MainServiceBean bean = this;
jsonWriter.name("isEnable").value(bean.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;
}
}

View File

@@ -0,0 +1,38 @@
package cc.winboll.studio.appbase.handlers;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/14 03:51:40
*/
import android.os.Handler;
import android.os.Message;
import cc.winboll.studio.appbase.services.MainService;
import java.lang.ref.WeakReference;
public class MainServiceHandler extends Handler {
public static final String TAG = "MainServiceHandler";
public static final int MSG_REMINDTHREAD = 0;
WeakReference<MainService> serviceWeakReference;
public MainServiceHandler(MainService service) {
serviceWeakReference = new WeakReference<MainService>(service);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REMINDTHREAD: // 处理下载完成消息更新UI
{
// 显示提醒消息
//
//LogUtils.d(TAG, "显示提醒消息");
MainService mainService = serviceWeakReference.get();
if (mainService != null) {
mainService.appenMessage((String)msg.obj);
}
break;
}
}
}
}

View File

@@ -0,0 +1,48 @@
package cc.winboll.studio.appbase.receivers;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/13 06:58:04
* @Describe 主要广播接收器
*/
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import cc.winboll.studio.appbase.services.MainService;
import com.hjq.toast.ToastUtils;
import java.lang.ref.WeakReference;
public class MainReceiver extends BroadcastReceiver {
public static final String TAG = "MainReceiver";
public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
WeakReference<MainService> mwrService;
// 存储电量指示值,
// 用于校验电量消息时的电量变化
static volatile int _mnTheQuantityOfElectricityOld = -1;
static volatile boolean _mIsCharging = false;
public MainReceiver(MainService service) {
mwrService = new WeakReference<MainService>(service);
}
@Override
public void onReceive(Context context, Intent intent) {
String szAction = intent.getAction();
if (szAction.equals(ACTION_BOOT_COMPLETED)) {
ToastUtils.show("ACTION_BOOT_COMPLETED");
} else {
ToastUtils.show(szAction);
}
}
// 注册 Receiver
//
public void registerAction(Context context) {
IntentFilter filter=new IntentFilter();
filter.addAction(ACTION_BOOT_COMPLETED);
//filter.addAction(Intent.ACTION_BATTERY_CHANGED);
context.registerReceiver(this, filter);
}
}

View File

@@ -0,0 +1,138 @@
package cc.winboll.studio.appbase.services;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/14 03:38:31
* @Describe 守护进程服务
*/
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import cc.winboll.studio.appbase.beans.MainServiceBean;
import cc.winboll.studio.appbase.services.AssistantService;
import cc.winboll.studio.appbase.services.MainService;
import cc.winboll.studio.libappbase.LogUtils;
import android.os.Binder;
public class AssistantService extends Service {
public static final String TAG = "AssistantService";
MainServiceBean mMainServiceBean;
MyServiceConnection mMyServiceConnection;
MainService mMainService;
boolean isBound = false;
volatile boolean isThreadAlive = false;
public synchronized void setIsThreadAlive(boolean isThreadAlive) {
LogUtils.d(TAG, "setIsThreadAlive(...)");
LogUtils.d(TAG, String.format("isThreadAlive %s", isThreadAlive));
this.isThreadAlive = isThreadAlive;
}
public boolean isThreadAlive() {
return isThreadAlive;
}
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
@Override
public void onCreate() {
LogUtils.d(TAG, "onCreate");
super.onCreate();
//mMyBinder = new MyBinder();
if (mMyServiceConnection == null) {
mMyServiceConnection = new MyServiceConnection();
}
// 设置运行参数
setIsThreadAlive(false);
assistantService();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
LogUtils.d(TAG, "call onStartCommand(...)");
assistantService();
return START_STICKY;
}
@Override
public void onDestroy() {
//LogUtils.d(TAG, "onDestroy");
setIsThreadAlive(false);
// 解除绑定
if (isBound) {
unbindService(mMyServiceConnection);
isBound = false;
}
super.onDestroy();
}
// 运行服务内容
//
void assistantService() {
LogUtils.d(TAG, "assistantService()");
mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class);
LogUtils.d(TAG, String.format("mMainServiceBean.isEnable() %s", mMainServiceBean.isEnable()));
if (mMainServiceBean.isEnable()) {
LogUtils.d(TAG, String.format("mIsThreadAlive %s", isThreadAlive()));
if (isThreadAlive() == false) {
// 设置运行状态
setIsThreadAlive(true);
// 唤醒和绑定主进程
wakeupAndBindMain();
}
}
}
// 唤醒和绑定主进程
//
void wakeupAndBindMain() {
LogUtils.d(TAG, "wakeupAndBindMain()");
// 绑定服务的Intent
Intent intent = new Intent(this, MainService.class);
startService(new Intent(this, MainService.class));
bindService(intent, mMyServiceConnection, Context.BIND_IMPORTANT);
// startService(new Intent(this, MainService.class));
// bindService(new Intent(AssistantService.this, MainService.class), mMyServiceConnection, Context.BIND_IMPORTANT);
}
// 主进程与守护进程连接时需要用到此类
//
class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
LogUtils.d(TAG, "onServiceConnected(...)");
MainService.MyBinder binder = (MainService.MyBinder) service;
mMainService = binder.getService();
isBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
LogUtils.d(TAG, "onServiceDisconnected(...)");
mMainServiceBean = MainServiceBean.loadBean(AssistantService.this, MainServiceBean.class);
if (mMainServiceBean.isEnable()) {
wakeupAndBindMain();
}
isBound = false;
mMainService = null;
}
}
// 用于返回服务实例的Binder
public class MyBinder extends Binder {
AssistantService getService() {
LogUtils.d(TAG, "AssistantService MyBinder getService()");
return AssistantService.this;
}
}
}

View File

@@ -0,0 +1,260 @@
package cc.winboll.studio.appbase.services;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/13 06:56:41
* @Describe 拨号主服务
* 参考:
* 进程保活-双进程守护的正确姿势
* https://blog.csdn.net/sinat_35159441/article/details/75267380
* Android Service之onStartCommand方法研究
* https://blog.csdn.net/cyp331203/article/details/38920491
*/
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import cc.winboll.studio.appbase.MyTileService;
import cc.winboll.studio.appbase.beans.MainServiceBean;
import cc.winboll.studio.appbase.handlers.MainServiceHandler;
import cc.winboll.studio.appbase.receivers.MainReceiver;
import cc.winboll.studio.appbase.services.AssistantService;
import cc.winboll.studio.appbase.threads.MainServiceThread;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.widgets.APPSOSReportWidget;
public class MainService extends Service {
public static final String TAG = "MainService";
public static final int MSG_UPDATE_STATUS = 0;
static MainService _mControlCenterService;
volatile boolean isServiceRunning;
MainServiceBean mMainServiceBean;
MainServiceThread mMainServiceThread;
MainServiceHandler mMainServiceHandler;
MyServiceConnection mMyServiceConnection;
AssistantService mAssistantService;
boolean isBound = false;
MainReceiver mMainReceiver;
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
public MainServiceThread getRemindThread() {
return mMainServiceThread;
}
@Override
public void onCreate() {
super.onCreate();
LogUtils.d(TAG, "onCreate()");
_mControlCenterService = MainService.this;
isServiceRunning = false;
mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class);
if (mMyServiceConnection == null) {
mMyServiceConnection = new MyServiceConnection();
}
mMainServiceHandler = new MainServiceHandler(this);
// 运行服务内容
mainService();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
LogUtils.d(TAG, "onStartCommand(...)");
// 运行服务内容
mainService();
return (mMainServiceBean.isEnable()) ? START_STICKY : super.onStartCommand(intent, flags, startId);
}
// 运行服务内容
//
void mainService() {
LogUtils.d(TAG, "mainService()");
mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class);
if (mMainServiceBean.isEnable() && isServiceRunning == false) {
LogUtils.d(TAG, "mainService() start running");
isServiceRunning = true;
// 唤醒守护进程
wakeupAndBindAssistant();
if (mMainReceiver == null) {
// 注册广播接收器
mMainReceiver = new MainReceiver(this);
mMainReceiver.registerAction(this);
}
// 启动小部件
Intent intentTimeWidget = new Intent(this, APPSOSReportWidget.class);
intentTimeWidget.setAction(APPSOSReportWidget.ACTION_RELOAD_SOS_REPORT);
this.sendBroadcast(intentTimeWidget);
startMainServiceThread();
MyTileService.updateServiceIconStatus(this);
LogUtils.i(TAG, "Main Service Is Start.");
}
}
// 唤醒和绑定守护进程
//
void wakeupAndBindAssistant() {
LogUtils.d(TAG, "wakeupAndBindAssistant()");
// if (ServiceUtils.isServiceAlive(getApplicationContext(), AssistantService.class.getName()) == false) {
// startService(new Intent(MainService.this, AssistantService.class));
// //LogUtils.d(TAG, "call wakeupAndBindAssistant() : Binding... AssistantService");
// bindService(new Intent(MainService.this, AssistantService.class), mMyServiceConnection, Context.BIND_IMPORTANT);
// }
Intent intent = new Intent(this, AssistantService.class);
startService(intent);
// 绑定服务的Intent
//Intent intent = new Intent(this, AssistantService.class);
bindService(intent, mMyServiceConnection, Context.BIND_IMPORTANT);
// Intent intent = new Intent(this, AssistantService.class);
// startService(intent);
// LogUtils.d(TAG, "startService(intent)");
// bindService(new Intent(this, AssistantService.class), mMyServiceConnection, Context.BIND_IMPORTANT);
}
// 开启提醒铃声线程
//
public void startMainServiceThread() {
LogUtils.d(TAG, "startMainServiceThread");
if (mMainServiceThread == null) {
mMainServiceThread = new MainServiceThread(this, mMainServiceHandler);
LogUtils.d(TAG, "new MainServiceThread");
} else {
if (mMainServiceThread.isExist() == true) {
mMainServiceThread = new MainServiceThread(this, mMainServiceHandler);
LogUtils.d(TAG, "renew MainServiceThread");
} else {
// 提醒进程正在进行中就更新状态后退出
LogUtils.d(TAG, "A mMainServiceThread running.");
return;
}
}
mMainServiceThread.start();
}
public void stopRemindThread() {
if (mMainServiceThread != null) {
mMainServiceThread.setIsExist(true);
mMainServiceThread = null;
}
}
@Override
public void onDestroy() {
//LogUtils.d(TAG, "onDestroy");
mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class);
if (mMainServiceBean.isEnable() == false) {
// 设置运行状态
isServiceRunning = false;// 解除绑定
if (isBound) {
unbindService(mMyServiceConnection);
isBound = false;
}
// 停止守护进程
Intent intent = new Intent(this, AssistantService.class);
stopService(intent);
// 停止Receiver
if (mMainReceiver != null) {
unregisterReceiver(mMainReceiver);
mMainReceiver = null;
}
// 停止前台通知栏
stopForeground(true);
// 停止消息提醒进程
stopRemindThread();
MyTileService.updateServiceIconStatus(this);
super.onDestroy();
//LogUtils.d(TAG, "onDestroy done");
}
}
// 主进程与守护进程连接时需要用到此类
//
private class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
LogUtils.d(TAG, "onServiceConnected(...)");
AssistantService.MyBinder binder = (AssistantService.MyBinder) service;
mAssistantService = binder.getService();
isBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
LogUtils.d(TAG, "onServiceDisconnected(...)");
if (mMainServiceBean.isEnable()) {
// 唤醒守护进程
wakeupAndBindAssistant();
}
isBound = false;
mAssistantService = null;
}
}
// 用于返回服务实例的Binder
public class MyBinder extends Binder {
MainService getService() {
LogUtils.d(TAG, "MainService MyBinder getService()");
return MainService.this;
}
}
// //
// // 启动服务
// //
// public static void startControlCenterService(Context context) {
// Intent intent = new Intent(context, MainService.class);
// context.startForegroundService(intent);
// }
//
// //
// // 停止服务
// //
// public static void stopControlCenterService(Context context) {
// Intent intent = new Intent(context, MainService.class);
// context.stopService(intent);
// }
public void appenMessage(String message) {
LogUtils.d(TAG, String.format("Message : %s", message));
}
public static void stopMainService(Context context) {
LogUtils.d(TAG, "stopMainService");
MainServiceBean bean = new MainServiceBean();
bean.setIsEnable(false);
MainServiceBean.saveBean(context, bean);
context.stopService(new Intent(context, MainService.class));
}
public static void startMainService(Context context) {
LogUtils.d(TAG, "startMainService");
MainServiceBean bean = new MainServiceBean();
bean.setIsEnable(true);
MainServiceBean.saveBean(context, bean);
context.startService(new Intent(context, MainService.class));
}
}

View File

@@ -0,0 +1,42 @@
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,54 @@
package cc.winboll.studio.appbase.threads;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/14 03:46:44
*/
import android.content.Context;
import cc.winboll.studio.appbase.handlers.MainServiceHandler;
import cc.winboll.studio.libappbase.LogUtils;
import java.lang.ref.WeakReference;
public class MainServiceThread extends Thread {
public static final String TAG = "MainServiceThread";
Context mContext;
// 控制线程是否退出的标志
volatile boolean isExist = false;
// 服务Handler, 用于线程发送消息使用
WeakReference<MainServiceHandler> mwrMainServiceHandler;
public void setIsExist(boolean isExist) {
this.isExist = isExist;
}
public boolean isExist() {
return isExist;
}
public MainServiceThread(Context context, MainServiceHandler handler) {
mContext = context;
mwrMainServiceHandler = new WeakReference<MainServiceHandler>(handler);
}
@Override
public void run() {
LogUtils.d(TAG, "run()");
while (!isExist()) {
//ToastUtils.show("run()");
//LogUtils.d(TAG, "run()");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
}
LogUtils.d(TAG, "run() exit.");
}
}

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Fri Feb 14 03:00:46 HKT 2025
stageCount=2
#Mon Feb 17 12:09:50 HKT 2025
stageCount=3
libraryProject=libappbase
baseVersion=1.5
publishVersion=1.5.1
publishVersion=1.5.2
buildCount=0
baseBetaVersion=1.5.2
baseBetaVersion=1.5.3

View File

@@ -18,16 +18,45 @@
android:label="GlobalCrashActivity"
android:launchMode="standard"/>
<service android:name=".SimpleOperateSignalCenterService"/>
<service android:name=".SimpleOperateSignalCenterService"
android:exported="true">
</service>
<activity android:name=".LogActivity"/>
<receiver android:name=".receiver.MyBroadcastReceiver">
<intent-filter>
<action android:name="cc.winboll.studio.libappbase.action.SOS" />
</intent-filter>
</receiver>
<receiver android:name="cc.winboll.studio.libappbase.receiver.WinBollReceiver"
android:exported="true">
<intent-filter>
<action android:name="cc.winboll.studio.libappbase.WinBoll.ACTION_SOS"/>
</intent-filter>
</receiver>
<receiver android:name=".widgets.APPSOSReportWidget"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="cc.winboll.studio.libappbase.widgets.APPSOSReportWidget.ACTION_ADD_SOS_REPORT" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/appwidget_provider_info" />
</receiver>
<receiver android:name=".widgets.WidgetButtonClickListener">
<intent-filter>
<action android:name="cc.winboll.studio.libappbase.widgets.WidgetButtonClickListener.ACTION_PRE" />
<action android:name="cc.winboll.studio.libappbase.widgets.WidgetButtonClickListener.ACTION_NEXT" />
</intent-filter>
</receiver>
</application>
</manifest>

View File

@@ -0,0 +1,28 @@
package cc.winboll.studio.libappbase;
/**
* @Author ZhanGSKen@AliYun.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 "";
}
}
}

View File

@@ -18,7 +18,7 @@ import android.view.Gravity;
import com.hjq.toast.ToastUtils;
import com.hjq.toast.style.WhiteToastStyle;
public class GlobalApplication extends Application implements ISOSAPP {
public class GlobalApplication extends Application {
public static final String TAG = "GlobalApplication";
@@ -93,27 +93,27 @@ public class GlobalApplication extends Application implements ISOSAPP {
}
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");
}
//
// @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");
// }
}

View File

@@ -1,17 +0,0 @@
package cc.winboll.studio.libappbase;
import android.content.Intent;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/13 03:49:35
* @Describe 简单 SOS 接口
*/
public interface ISOSAPP {
public static final String TAG = "ISOS";
public static final String EXTRA_PACKAGE = "EXTRA_PACKAGE";
public static final String EXTRA_SERVICE = "EXTRA_SERVICE";
public void helpISOSService(Intent intent);
}

View File

@@ -1,17 +0,0 @@
package cc.winboll.studio.libappbase;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/13 04:13:51
* @Describe 简单链接 SOS 体系的服务
*/
import android.content.Intent;
public interface ISOSService {
public static final String TAG = "ISOSService";
public static final String EXTRA_ENABLE = "EXTRA_ENABLE";
public Intent getISOSServiceIntentWhichAskForHelp();
public boolean isEnable();
}

View File

@@ -7,16 +7,17 @@ package cc.winboll.studio.libappbase;
*/
import android.content.Context;
import android.content.Intent;
import com.hjq.toast.ToastUtils;
import cc.winboll.studio.libappbase.bean.APPSOSBean;
public class SOS {
public static final String TAG = "SOS";
public static void sendToWinBoll(Context context) {
Intent intent = new Intent(context.getString(R.string.action_sos));
intent.putExtra("sosPackage", context.getPackageName());
intent.putExtra("message", "SOS");
public static final String ACTION_SOS = "cc.winboll.studio.libappbase.WinBoll.ACTION_SOS";
public static void sosWinBollService(Context context, APPSOSBean bean) {
Intent intent = new Intent(ACTION_SOS);
intent.putExtra("SOS", "Service");
intent.putExtra("APPSOSBean", bean.toString());
String szToPackage = "";
if (GlobalApplication.isDebuging()) {
szToPackage = "cc.winboll.studio.appbase.beta";
@@ -25,7 +26,7 @@ public class SOS {
}
intent.setPackage(szToPackage);
context.sendBroadcast(intent);
LogUtils.d(TAG, String.format("SOS Send To WinBoll. (szToPackage : %s)", szToPackage));
//ToastUtils.show("SOS Send To WinBoll");
}

View File

@@ -14,17 +14,17 @@ public class SOSCSBroadcastReceiver extends BroadcastReceiver {
public static final String TAG = "SOSCSBroadcastReceiver";
public static final String ACTION_SOS = SOSCSBroadcastReceiver.class.getName() + ".ACTION_SOS";
ISOSAPP mISOSAPP;
//ISOSAPP mISOSAPP;
public SOSCSBroadcastReceiver(ISOSAPP iSOSAPP) {
mISOSAPP = iSOSAPP;
public SOSCSBroadcastReceiver() {
//mISOSAPP = iSOSAPP;
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(ACTION_SOS)) {
LogUtils.d(TAG, "ACTION_SOS");
mISOSAPP.helpISOSService(intent);
//mISOSAPP.helpISOSService(intent);
} else {
LogUtils.d(TAG, String.format("%s", action));
}

View File

@@ -10,14 +10,20 @@ 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 cc.winboll.studio.libappbase.bean.SimpleOperateSignalCenterServiceBean;
import java.io.FileDescriptor;
public class SimpleOperateSignalCenterService extends Service implements ISOSService {
public class SimpleOperateSignalCenterService extends Service {
public static final String TAG = "SimpleOperateSignalCenterService";
public static final String ACTION_ENABLE = SimpleOperateSignalCenterService.class.getName() + ".ACTION_ENABLE";
public static final String ACTION_DISABLE = SimpleOperateSignalCenterService.class.getName() + ".ACTION_DISABLE";
private final IBinder binder =(IBinder)new SOSBinder();
SimpleOperateSignalCenterServiceBean mSimpleOperateSignalCenterServiceBean;
static MainThread _MainThread;
public static synchronized MainThread getMainThreadInstance() {
@@ -29,25 +35,79 @@ public class SimpleOperateSignalCenterService extends Service implements ISOSSer
@Override
public IBinder onBind(Intent intent) {
return null;
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";
SimpleOperateSignalCenterService getService() {
return SimpleOperateSignalCenterService.this;
}
}
@Override
public void onCreate() {
super.onCreate();
LogUtils.d(TAG, "onCreate");
mSimpleOperateSignalCenterServiceBean = SimpleOperateSignalCenterServiceBean.loadBean(this, SimpleOperateSignalCenterServiceBean.class);
if(mSimpleOperateSignalCenterServiceBean == null) {
mSimpleOperateSignalCenterServiceBean = new SimpleOperateSignalCenterServiceBean();
SimpleOperateSignalCenterServiceBean.saveBean(this, mSimpleOperateSignalCenterServiceBean);
}
runMainThread();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
LogUtils.d(TAG, "onStartCommand");
if (intent.getBooleanExtra(ISOSService.EXTRA_ENABLE, false)) {
LogUtils.d(TAG, "onStartCommand enable service");
mSimpleOperateSignalCenterServiceBean.setIsEnable(true);
SimpleOperateSignalCenterServiceBean.saveBean(this, mSimpleOperateSignalCenterServiceBean);
}
// if (intent.getBooleanExtra(ISOSService.EXTRA_ENABLE, false)) {
// LogUtils.d(TAG, "onStartCommand enable service");
// mSimpleOperateSignalCenterServiceBean.setIsEnable(true);
// SimpleOperateSignalCenterServiceBean.saveBean(this, mSimpleOperateSignalCenterServiceBean);
// }
runMainThread();
@@ -63,20 +123,6 @@ public class SimpleOperateSignalCenterService extends Service implements ISOSSer
}
}
@Override
public Intent getISOSServiceIntentWhichAskForHelp() {
Intent intentService = new Intent();
intentService.putExtra(ISOSAPP.EXTRA_PACKAGE, this.getPackageName());
intentService.putExtra(ISOSAPP.EXTRA_SERVICE, this.getClass().getName());
return intentService;
}
@Override
public boolean isEnable() {
mSimpleOperateSignalCenterServiceBean = SimpleOperateSignalCenterServiceBean.loadBean(this, SimpleOperateSignalCenterServiceBean.class);
return mSimpleOperateSignalCenterServiceBean.isEnable();
}
@Override
public void onDestroy() {
super.onDestroy();
@@ -84,8 +130,8 @@ public class SimpleOperateSignalCenterService extends Service implements ISOSSer
mSimpleOperateSignalCenterServiceBean = SimpleOperateSignalCenterServiceBean.loadBean(this, SimpleOperateSignalCenterServiceBean.class);
if (mSimpleOperateSignalCenterServiceBean.isEnable()) {
LogUtils.d(TAG, "mSimpleOperateSignalCenterServiceBean.isEnable()");
ISOSAPP iSOSAPP = (ISOSAPP)getApplication();
iSOSAPP.helpISOSService(getISOSServiceIntentWhichAskForHelp());
// ISOSAPP iSOSAPP = (ISOSAPP)getApplication();
// iSOSAPP.helpISOSService(getISOSServiceIntentWhichAskForHelp());
}
if (_MainThread != null) {
_MainThread.isExist = true;
@@ -108,6 +154,10 @@ public class SimpleOperateSignalCenterService extends Service implements ISOSSer
SimpleOperateSignalCenterServiceBean.saveBean(context, bean);
context.startService(new Intent(context, SimpleOperateSignalCenterService.class));
}
public String getMessage() {
return "Hello from SimpleOperateSignalCenterService";
}
static class MainThread extends Thread {
volatile boolean isExist = false;

View File

@@ -0,0 +1,15 @@
package cc.winboll.studio.libappbase;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/15 12:14:45
* @Describe WinBoll 类
*/
public class WinBoll {
public static final String TAG = "WinBoll";
public static final String ACTION_SOS = WinBoll.class.getName() + ".ACTION_SOS";
}

View File

@@ -0,0 +1,87 @@
package cc.winboll.studio.libappbase.bean;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/17 00:29:29
* @Describe APPSOSReportBean
*/
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException;
import java.io.Serializable;
public class APPSOSBean extends BaseBean {
public static final String TAG = "APPSOSBean";
protected String sosPackage;
protected String sosClassName;
public APPSOSBean() {
this.sosPackage = "";
this.sosClassName = "";
}
public APPSOSBean(String sosPackage, String sosClassName) {
this.sosPackage = sosPackage;
this.sosClassName = sosClassName;
}
public void setSosPackage(String sosPackage) {
this.sosPackage = sosPackage;
}
public String getSosPackage() {
return sosPackage;
}
public void setSosClassName(String sosClassName) {
this.sosClassName = sosClassName;
}
public String getSosClassName() {
return sosClassName;
}
@Override
public String getName() {
return APPSOSBean.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
jsonWriter.name("sosPackage").value(getSosPackage());
jsonWriter.name("sosClassName").value(getSosClassName());
}
@Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
if (name.equals("sosPackage")) {
setSosPackage(jsonReader.nextString());
} else if (name.equals("sosClassName")) {
setSosClassName(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

@@ -0,0 +1,72 @@
package cc.winboll.studio.libappbase.bean;
/**
* @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 APPSOSReportBean extends BaseBean {
public static final String TAG = "APPSOSReportBean";
protected String sosReport;
public APPSOSReportBean() {
this.sosReport = "";
}
public APPSOSReportBean(String sosReport) {
this.sosReport = sosReport;
}
public void setSosReport(String sosReport) {
this.sosReport = sosReport;
}
public String getSosReport() {
return sosReport;
}
@Override
public String getName() {
return APPSOSReportBean.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

@@ -0,0 +1,79 @@
package cc.winboll.studio.libappbase.receiver;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.WinBoll;
import cc.winboll.studio.libappbase.AppUtils;
import cc.winboll.studio.libappbase.widgets.APPSOSReportWidget;
import cc.winboll.studio.libappbase.bean.APPSOSBean;
import java.io.IOException;
import cc.winboll.studio.libappbase.bean.APPSOSReportBean;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/15 12:17:32
* @Describe WinBollReceiver
*/
public class WinBollReceiver extends BroadcastReceiver {
public static final String TAG = "WinBollReceiver";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(WinBoll.ACTION_SOS)) {
LogUtils.d(TAG, String.format("context.getPackageName() %s", context.getPackageName()));
LogUtils.d(TAG, String.format("action %s", action));
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));
APPSOSReportBean appSOSReportBean = new APPSOSReportBean(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());
Intent intentAPPSOSReportWidget = new Intent(context, APPSOSReportWidget.class);
intentAPPSOSReportWidget.setAction(APPSOSReportWidget.ACTION_ADD_SOS_REPORT);
intentAPPSOSReportWidget.putExtra("APPSOSReportBean", appSOSReportBean.toString());
context.sendBroadcast(intentAPPSOSReportWidget);
}
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
}
}
} else {
LogUtils.d(TAG, String.format("action %s", action));
}
}
}

View File

@@ -0,0 +1,163 @@
package cc.winboll.studio.libappbase.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.libappbase.LogUtils;
import cc.winboll.studio.libappbase.R;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import cc.winboll.studio.libappbase.bean.APPSOSReportBean;
import java.io.IOException;
public class APPSOSReportWidget extends AppWidgetProvider {
public static final String TAG = "APPSOSReportWidget";
public static final String ACTION_ADD_SOS_REPORT = "cc.winboll.studio.libappbase.widgets.APPSOSReportWidget.ACTION_ADD_SOS_REPORT";
public static final String ACTION_RELOAD_SOS_REPORT = "cc.winboll.studio.libappbase.widgets.APPSOSReportWidget.ACTION_RELOAD_SOS_REPORT";
volatile static ArrayList<APPSOSReportBean> _APPSOSReportBeanList;
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_ADD_SOS_REPORT)) {
LogUtils.d(TAG, "ACTION_ADD_SOS_REPORT");
String szAPPSOSReportBean = intent.getStringExtra("APPSOSReportBean");
LogUtils.d(TAG, String.format("szAPPSOSBean %s", szAPPSOSReportBean));
if (szAPPSOSReportBean != null && !szAPPSOSReportBean.equals("")) {
try {
APPSOSReportBean bean = APPSOSReportBean.parseStringToBean(szAPPSOSReportBean, APPSOSReportBean.class);
if (bean != null) {
addAPPSOSReportBean(context, bean);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, APPSOSReportWidget.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_SOS_REPORT)) {
LogUtils.d(TAG, "ACTION_RELOAD_SOS_REPORT");
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, APPSOSReportWidget.class));
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
}
//
// 加入新报告信息
//
void addAPPSOSReportBean(Context context, APPSOSReportBean bean) {
initAPPSOSReportBeanList(context);
_APPSOSReportBeanList.add(0, bean);
// 控制记录总数
while (_APPSOSReportBeanList.size() > _MAX_PAGES * _OnePageLinesCount) {
_APPSOSReportBeanList.remove(_APPSOSReportBeanList.size() - 1);
}
APPSOSReportBean.saveBeanList(context, _APPSOSReportBeanList, APPSOSReportBean.class);
}
void initAPPSOSReportBeanList(Context context) {
if (_APPSOSReportBeanList == null) {
_APPSOSReportBeanList = new ArrayList<APPSOSReportBean>();
APPSOSReportBean.loadBeanList(context, _APPSOSReportBeanList, APPSOSReportBean.class);
}
if (_APPSOSReportBeanList == null) {
_APPSOSReportBeanList = new ArrayList<APPSOSReportBean>();
APPSOSReportBean.saveBeanList(context, _APPSOSReportBeanList, APPSOSReportBean.class);
}
}
private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
LogUtils.d(TAG, "updateAppWidget(...)");
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
//设置按钮点击事件
Intent intentPre = new Intent(context, WidgetButtonClickListener.class);
intentPre.setAction(WidgetButtonClickListener.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, WidgetButtonClickListener.class);
intentNext.setAction(WidgetButtonClickListener.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 (_APPSOSReportBeanList != null) {
int start = _OnePageLinesCount * _CurrentPageIndex;
start = _APPSOSReportBeanList.size() > start ? start : _APPSOSReportBeanList.size() - 1;
for (int i = start, j = 0; i < _APPSOSReportBeanList.size() && j < _OnePageLinesCount; i++, j++) {
msgTemp.add(_APPSOSReportBeanList.get(i).getSosReport());
}
String message = String.join("\n", msgTemp);
return message;
}
return "";
}
public static void prePage(Context context) {
if (_APPSOSReportBeanList != null) {
if (_CurrentPageIndex > 0) {
_CurrentPageIndex = _CurrentPageIndex - 1;
}
Intent intentAPPSOSReportWidget = new Intent(context, APPSOSReportWidget.class);
intentAPPSOSReportWidget.setAction(APPSOSReportWidget.ACTION_RELOAD_SOS_REPORT);
context.sendBroadcast(intentAPPSOSReportWidget);
}
}
public static void nextPage(Context context) {
if (_APPSOSReportBeanList != null) {
if ((_CurrentPageIndex + 1) * _OnePageLinesCount < _APPSOSReportBeanList.size()) {
_CurrentPageIndex = _CurrentPageIndex + 1;
}
Intent intentAPPSOSReportWidget = new Intent(context, APPSOSReportWidget.class);
intentAPPSOSReportWidget.setAction(APPSOSReportWidget.ACTION_RELOAD_SOS_REPORT);
context.sendBroadcast(intentAPPSOSReportWidget);
}
}
String getPageInfo() {
if (_APPSOSReportBeanList == null) {
return "0/0";
}
int leftCount = _APPSOSReportBeanList.size() % _OnePageLinesCount;
int currentPageCount = _APPSOSReportBeanList.size() / _OnePageLinesCount + (leftCount == 0 ?0: 1);
return String.format("%d/%d", _CurrentPageIndex + 1, currentPageCount);
}
}

View File

@@ -0,0 +1,36 @@
package cc.winboll.studio.libappbase.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 WidgetButtonClickListener extends BroadcastReceiver {
public static final String TAG = "WidgetButtonClickListener";
public static final String ACTION_PRE = "cc.winboll.studio.libappbase.widgets.WidgetButtonClickListener.ACTION_PRE";
public static final String ACTION_NEXT = "cc.winboll.studio.libappbase.widgets.WidgetButtonClickListener.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");
APPSOSReportWidget.prePage(context);
} else if (action.equals(ACTION_NEXT)) {
LogUtils.d(TAG, "ACTION_NEXT");
APPSOSReportWidget.nextPage(context);
} else {
LogUtils.d(TAG, String.format("action %s", action));
}
}
}

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

@@ -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_layout">
</appwidget-provider>