diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..3553804 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +appbase \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b589d56 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml new file mode 100644 index 0000000..ed59606 --- /dev/null +++ b/.idea/deploymentTargetDropDown.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..0ad17cb --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/appbase/build.gradle b/appbase/build.gradle index 7fc290b..6193aa5 100644 --- a/appbase/build.gradle +++ b/appbase/build.gradle @@ -18,18 +18,18 @@ def genVersionName(def versionName){ } android { - compileSdkVersion 32 - buildToolsVersion "33.0.3" + compileSdkVersion 30 + buildToolsVersion "30.0.3" defaultConfig { applicationId "cc.winboll.studio.appbase" - minSdkVersion 21 - targetSdkVersion 30 + minSdkVersion 26 + targetSdkVersion 29 versionCode 1 // versionName 更新后需要手动设置 // .winboll/winbollBuildProps.properties 文件的 stageCount=0 // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" - versionName "1.0" + versionName "2.0" if(true) { versionName = genVersionName("${versionName}") } @@ -41,11 +41,6 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_11 - targetCompatibility JavaVersion.VERSION_11 - } } dependencies { diff --git a/appbase/build.properties b/appbase/build.properties index 907174b..9e59591 100644 --- a/appbase/build.properties +++ b/appbase/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Sun Jan 05 02:30:11 GMT 2025 -stageCount=0 -libraryProject= -baseVersion=1.0 -publishVersion=1.0.0 -buildCount=2 -baseBetaVersion=1.0.1 +#Tue Feb 25 16:51:17 HKT 2025 +stageCount=3 +libraryProject=libappbase +baseVersion=2.0 +publishVersion=2.0.2 +buildCount=0 +baseBetaVersion=2.0.3 diff --git a/appbase/src/main/AndroidManifest.xml b/appbase/src/main/AndroidManifest.xml index a5392b6..ed6e233 100644 --- a/appbase/src/main/AndroidManifest.xml +++ b/appbase/src/main/AndroidManifest.xml @@ -21,15 +21,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/appbase/src/main/java/cc/winboll/studio/appbase/App.java b/appbase/src/main/java/cc/winboll/studio/appbase/App.java index 874e4fa..84d0424 100644 --- a/appbase/src/main/java/cc/winboll/studio/appbase/App.java +++ b/appbase/src/main/java/cc/winboll/studio/appbase/App.java @@ -5,12 +5,23 @@ package cc.winboll.studio.appbase; * @Date 2025/01/05 09:54:42 * @Describe APPbase 应用类 */ - import cc.winboll.studio.GlobalApplication; +import cc.winboll.studio.libappbase.GlobalApplication; +import cc.winboll.studio.libappbase.SOSCSBroadcastReceiver; +import android.content.IntentFilter; public class App extends GlobalApplication { - + public static final String TAG = "App"; + SOSCSBroadcastReceiver mSOSCSBroadcastReceiver; - + @Override + public void onCreate() { + super.onCreate(); + GlobalApplication.setIsDebuging(this, BuildConfig.DEBUG); + mSOSCSBroadcastReceiver = new SOSCSBroadcastReceiver(); + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(SOSCSBroadcastReceiver.ACTION_SOS); + registerReceiver(mSOSCSBroadcastReceiver, intentFilter); + } } diff --git a/appbase/src/main/java/cc/winboll/studio/appbase/MainActivity.java b/appbase/src/main/java/cc/winboll/studio/appbase/MainActivity.java index 6100bcf..3e4cac0 100644 --- a/appbase/src/main/java/cc/winboll/studio/appbase/MainActivity.java +++ b/appbase/src/main/java/cc/winboll/studio/appbase/MainActivity.java @@ -1,15 +1,116 @@ -package cc.winboll.studio.appbase; - -import android.app.Activity; -import android.os.Bundle; - -public class MainActivity extends Activity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - } - -} \ No newline at end of file +package cc.winboll.studio.appbase; + +import android.content.ComponentName; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +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.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.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 { + + public static final String TAG = "MainActivity"; + + LogView mLogView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ToastUtils.show("onCreate"); + setContentView(R.layout.activity_main); + + Toolbar toolbar = findViewById(R.id.activitymainToolbar1); + setSupportActionBar(toolbar); + + CheckBox cbIsDebugMode = findViewById(R.id.activitymainCheckBox1); + cbIsDebugMode.setChecked(GlobalApplication.isDebuging()); + mLogView = findViewById(R.id.activitymainLogView1); + + 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"); + super.onResume(); + mLogView.start(); + } + + public void onSwitchDebugMode(View view) { + GlobalApplication.setIsDebuging(this, ((CheckBox)view).isChecked()); + } + + public void onStartCenter(View view) { + MainService.startMainService(this); + } + + public void onStopCenter(View view) { + MainService.stopMainService(this); + } + + public void onTestStopWithoutSettingEnable(View view) { + LogUtils.d(TAG, "onTestStopWithoutSettingEnable"); + stopService(new Intent(this, SimpleOperateSignalCenterService.class)); + } + + public void onTestStartWithString(View view) { + LogUtils.d(TAG, "onTestStartWithString"); + + // 目标服务的包名和类名 + String packageName = this.getPackageName(); + String serviceClassName = SimpleOperateSignalCenterService.class.getName(); + + // 构建Intent + Intent intentService = new Intent(); + intentService.setComponent(new ComponentName(packageName, serviceClassName)); + + startService(intentService); + } + + public void onSOS(View view) { + Intent intent = new Intent(this, TestService.class); + stopService(intent); + SOS.sosWinBollService(this, new APPSOSBean(getPackageName(), TestService.class.getName())); + } + + public void onStartTestService(View view) { + Intent intent = new Intent(this, TestService.class); + intent.setAction(SOS.ACTION_SERVICE_ENABLE); + startService(intent); + + } + + public void onStopTestService(View view) { + Intent intent = new Intent(this, TestService.class); + intent.setAction(SOS.ACTION_SERVICE_DISABLE); + startService(intent); + + Intent intentStop = new Intent(this, TestService.class); + stopService(intentStop); + } + + public void onStopTestServiceNoSettings(View view) { + Intent intent = new Intent(this, TestService.class); + stopService(intent); + } +} diff --git a/appbase/src/main/java/cc/winboll/studio/appbase/MyTileService.java b/appbase/src/main/java/cc/winboll/studio/appbase/MyTileService.java new file mode 100644 index 0000000..ab3b255 --- /dev/null +++ b/appbase/src/main/java/cc/winboll/studio/appbase/MyTileService.java @@ -0,0 +1,79 @@ +package cc.winboll.studio.appbase; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/13 19:30:10 + */ +import android.content.Context; +import android.service.quicksettings.Tile; +import android.service.quicksettings.TileService; +import cc.winboll.studio.appbase.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(); + MainServiceBean bean = MainServiceBean.loadBean(this, MainServiceBean.class); + if (bean != null && bean.isEnable()) { + //MainService.startMainService(context); + tile.setState(Tile.STATE_ACTIVE); + tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud)); + } else { + //MainService.stopMainService(context); + tile.setState(Tile.STATE_INACTIVE); + tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud_outline)); + } + tile.updateTile(); +// Tile tile = getQsTile(); +// tile.setState(Tile.STATE_INACTIVE); +// tile.setLabel(getString(R.string.tileservice_name)); +// tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud_outline)); +// tile.updateTile(); + + } + + @Override + public void onClick() { + super.onClick(); + Tile tile = getQsTile(); + MainServiceBean bean = MainServiceBean.loadBean(this, MainServiceBean.class); + if (bean == null) { + bean = new MainServiceBean(); + } + + if (tile.getState() == Tile.STATE_ACTIVE) { + bean.setIsEnable(false); + MainServiceBean.saveBean(this, bean); + MainService.stopMainService(this); + } else if (tile.getState() == Tile.STATE_INACTIVE) { + bean.setIsEnable(true); + MainServiceBean.saveBean(this, bean); + MainService.startMainService(this); + } + updateServiceIconStatus(this); + } + + public static void updateServiceIconStatus(Context context) { + if (_MyTileService == null) { + return; + } + + Tile tile = _MyTileService.getQsTile(); + MainServiceBean bean = MainServiceBean.loadBean(context, MainServiceBean.class); + if (bean != null && bean.isEnable()) { + tile.setState(Tile.STATE_ACTIVE); + tile.setIcon(android.graphics.drawable.Icon.createWithResource(context, R.drawable.ic_cloud)); + } else { + tile.setState(Tile.STATE_INACTIVE); + tile.setIcon(android.graphics.drawable.Icon.createWithResource(context, R.drawable.ic_cloud_outline)); + } + tile.updateTile(); + } +} diff --git a/appbase/src/main/java/cc/winboll/studio/appbase/beans/MainServiceBean.java b/appbase/src/main/java/cc/winboll/studio/appbase/beans/MainServiceBean.java new file mode 100644 index 0000000..81a3a7a --- /dev/null +++ b/appbase/src/main/java/cc/winboll/studio/appbase/beans/MainServiceBean.java @@ -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; + } +} diff --git a/appbase/src/main/java/cc/winboll/studio/appbase/beans/SOSReportBean.java b/appbase/src/main/java/cc/winboll/studio/appbase/beans/SOSReportBean.java new file mode 100644 index 0000000..d579482 --- /dev/null +++ b/appbase/src/main/java/cc/winboll/studio/appbase/beans/SOSReportBean.java @@ -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; + } +} diff --git a/appbase/src/main/java/cc/winboll/studio/appbase/handlers/MainServiceHandler.java b/appbase/src/main/java/cc/winboll/studio/appbase/handlers/MainServiceHandler.java new file mode 100644 index 0000000..9bda14b --- /dev/null +++ b/appbase/src/main/java/cc/winboll/studio/appbase/handlers/MainServiceHandler.java @@ -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 serviceWeakReference; + public MainServiceHandler(MainService service) { + serviceWeakReference = new WeakReference(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; + } + } + } +} diff --git a/appbase/src/main/java/cc/winboll/studio/appbase/receivers/MainReceiver.java b/appbase/src/main/java/cc/winboll/studio/appbase/receivers/MainReceiver.java new file mode 100644 index 0000000..36b12ed --- /dev/null +++ b/appbase/src/main/java/cc/winboll/studio/appbase/receivers/MainReceiver.java @@ -0,0 +1,132 @@ +package cc.winboll.studio.appbase.receivers; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/13 06:58:04 + * @Describe 主要广播接收器 + */ +import android.appwidget.AppWidgetManager; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import cc.winboll.studio.appbase.beans.SOSReportBean; +import cc.winboll.studio.appbase.services.MainService; +import cc.winboll.studio.appbase.widgets.SOSWidget; +import cc.winboll.studio.libappbase.AppUtils; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.SOS; +import cc.winboll.studio.libappbase.bean.APPSOSBean; +import com.hjq.toast.ToastUtils; +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class MainReceiver extends BroadcastReceiver { + + public static final String TAG = "MainReceiver"; + public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED"; + WeakReference mwrService; + // 存储电量指示值, + // 用于校验电量消息时的电量变化 + static volatile int _mnTheQuantityOfElectricityOld = -1; + static volatile boolean _mIsCharging = false; + + public MainReceiver(MainService service) { + mwrService = new WeakReference(service); + } + + @Override + public void onReceive(Context context, Intent intent) { + String szAction = intent.getAction(); + if (szAction.equals(ACTION_BOOT_COMPLETED)) { + ToastUtils.show("ACTION_BOOT_COMPLETED"); + } else if (szAction.equals(SOS.ACTION_BIND)) { + LogUtils.d(TAG, "ACTION_BIND"); + LogUtils.d(TAG, String.format("context.getPackageName() %s", context.getPackageName())); + LogUtils.d(TAG, String.format("intent.getAction() %s", intent.getAction())); + String 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)); + mwrService.get().bindSOSConnection(bean); + } + } catch (IOException e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + } + } + } else if (intent.getAction().equals(SOS.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()); + + SOSWidget.addAPPSOSReportBean(context, appSOSReportBean); + + Intent intentWidget = new Intent(context, SOSWidget.class); + intentWidget.setAction(SOSWidget.ACTION_RELOAD_REPORT); + context.sendBroadcast(intentWidget); + } + } catch (IOException e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + } + } + } else { + ToastUtils.show(szAction); + } + } + + // 注册 Receiver + // + public void registerAction(MainService service) { + IntentFilter filter=new IntentFilter(); + filter.addAction(ACTION_BOOT_COMPLETED); + filter.addAction(SOS.ACTION_SOS); + filter.addAction(SOS.ACTION_BIND); + filter.addAction(SOS.ACTION_SERVICE_ENABLE); + filter.addAction(SOS.ACTION_SERVICE_DISABLE); + //filter.addAction(Intent.ACTION_BATTERY_CHANGED); + service.registerReceiver(this, filter); + } +} diff --git a/appbase/src/main/java/cc/winboll/studio/appbase/services/AssistantService.java b/appbase/src/main/java/cc/winboll/studio/appbase/services/AssistantService.java new file mode 100644 index 0000000..b2e2f9b --- /dev/null +++ b/appbase/src/main/java/cc/winboll/studio/appbase/services/AssistantService.java @@ -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; + } + } +} diff --git a/appbase/src/main/java/cc/winboll/studio/appbase/services/MainService.java b/appbase/src/main/java/cc/winboll/studio/appbase/services/MainService.java new file mode 100644 index 0000000..93e41b7 --- /dev/null +++ b/appbase/src/main/java/cc/winboll/studio/appbase/services/MainService.java @@ -0,0 +1,326 @@ +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.appbase.widgets.SOSWidget; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.bean.APPSOSBean; +import java.util.ArrayList; + +public class MainService extends Service { + + public static final String TAG = "MainService"; + + public static final int MSG_UPDATE_STATUS = 0; + + static MainService _mControlCenterService; + + volatile boolean isServiceRunning; + + MainServiceBean mMainServiceBean; + MainServiceThread mMainServiceThread; + MainServiceHandler mMainServiceHandler; + MyServiceConnection mMyServiceConnection; + AssistantService mAssistantService; + boolean isBound = false; + MainReceiver mMainReceiver; + ArrayList mSOSConnectionList; + + @Override + public IBinder onBind(Intent intent) { + return new MyBinder(); + } + + public MainServiceThread getRemindThread() { + return mMainServiceThread; + } + + @Override + public void onCreate() { + super.onCreate(); + LogUtils.d(TAG, "onCreate()"); + mSOSConnectionList = new ArrayList(); + + _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, SOSWidget.class); + intentTimeWidget.setAction(SOSWidget.ACTION_RELOAD_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"); + } + } + + public void bindSOSConnection(APPSOSBean bean) { + LogUtils.d(TAG, "bindSOSConnection(...)"); + // 清理旧的绑定链接 + for (int i = mSOSConnectionList.size() - 1; i > -1; i--) { + SOSConnection item = mSOSConnectionList.get(i); + if (item.isBindToAPPSOSBean(bean)) { + LogUtils.d(TAG, "Bind Servive exist."); + unbindService(item); + mSOSConnectionList.remove(i); + } + } + + // 绑定服务 + SOSConnection sosConnection = new SOSConnection(); + Intent intentService = new Intent(); + intentService.setComponent(new ComponentName(bean.getSosPackage(), bean.getSosClassName())); + bindService(intentService, sosConnection, Context.BIND_IMPORTANT); + mSOSConnectionList.add(sosConnection); + + Intent intentWidget = new Intent(this, SOSWidget.class); + intentWidget.setAction(SOSWidget.ACTION_WAKEUP_SERVICE); + APPSOSBean appSOSBean = new APPSOSBean(bean.getSosPackage(), bean.getSosClassName()); + intentWidget.putExtra("APPSOSBean", appSOSBean.toString()); + sendBroadcast(intentWidget); + } + + public class SOSConnection implements ServiceConnection { + + ComponentName mComponentName; + + boolean isBindToAPPSOSBean(APPSOSBean bean) { + return mComponentName != null + && mComponentName.getClassName().equals(bean.getSosClassName()) + && mComponentName.getPackageName().equals(bean.getSosPackage()); + } + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + LogUtils.d(TAG, "onServiceConnected(...)"); + mComponentName = name; + LogUtils.d(TAG, String.format("onServiceConnected : \ngetClassName %s\ngetPackageName %s", name.getClassName(), name.getPackageName())); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + LogUtils.d(TAG, "onServiceDisconnected(...)"); + LogUtils.d(TAG, String.format("onServiceDisconnected : \ngetClassName %s\ngetPackageName %s", name.getClassName(), name.getPackageName())); + + // 尝试无参数启动一下服务 + String sosPackage = mComponentName.getPackageName(); + LogUtils.d(TAG, String.format("sosPackage %s", sosPackage)); + String sosClassName = mComponentName.getClassName(); + LogUtils.d(TAG, String.format("sosClassName %s", sosClassName)); + + Intent intentService = new Intent(); + intentService.setComponent(new ComponentName(sosPackage, sosClassName)); + startService(intentService); + } + + } + + // 主进程与守护进程连接时需要用到此类 + // + private class MyServiceConnection implements ServiceConnection { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + LogUtils.d(TAG, "onServiceConnected(...)"); + AssistantService.MyBinder binder = (AssistantService.MyBinder) service; + mAssistantService = binder.getService(); + isBound = true; + } + + @Override + public void onServiceDisconnected(ComponentName name) { + LogUtils.d(TAG, "onServiceDisconnected(...)"); + + if (mMainServiceBean.isEnable()) { + // 唤醒守护进程 + wakeupAndBindAssistant(); + } + isBound = false; + mAssistantService = null; + } + + } + + + // 用于返回服务实例的Binder + public class MyBinder extends Binder { + MainService getService() { + LogUtils.d(TAG, "MainService MyBinder getService()"); + return MainService.this; + } + } + +// // +// // 启动服务 +// // +// public static void startControlCenterService(Context context) { +// Intent intent = new Intent(context, MainService.class); +// context.startForegroundService(intent); +// } +// +// // +// // 停止服务 +// // +// public static void stopControlCenterService(Context context) { +// Intent intent = new Intent(context, MainService.class); +// context.stopService(intent); +// } + + public void appenMessage(String message) { + LogUtils.d(TAG, String.format("Message : %s", message)); + } + + public static void stopMainService(Context context) { + LogUtils.d(TAG, "stopMainService"); + MainServiceBean bean = new MainServiceBean(); + bean.setIsEnable(false); + MainServiceBean.saveBean(context, bean); + context.stopService(new Intent(context, MainService.class)); + } + + public static void startMainService(Context context) { + LogUtils.d(TAG, "startMainService"); + MainServiceBean bean = new MainServiceBean(); + bean.setIsEnable(true); + MainServiceBean.saveBean(context, bean); + context.startService(new Intent(context, MainService.class)); + } +} + diff --git a/appbase/src/main/java/cc/winboll/studio/appbase/threads/MainServiceThread.java b/appbase/src/main/java/cc/winboll/studio/appbase/threads/MainServiceThread.java new file mode 100644 index 0000000..25d7231 --- /dev/null +++ b/appbase/src/main/java/cc/winboll/studio/appbase/threads/MainServiceThread.java @@ -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 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(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."); + } + +} diff --git a/appbase/src/main/java/cc/winboll/studio/appbase/widgets/SOSWidget.java b/appbase/src/main/java/cc/winboll/studio/appbase/widgets/SOSWidget.java new file mode 100644 index 0000000..b614da9 --- /dev/null +++ b/appbase/src/main/java/cc/winboll/studio/appbase/widgets/SOSWidget.java @@ -0,0 +1,184 @@ +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_WAKEUP_SERVICE = "cc.winboll.studio.appbase.widgets.SOSWidget.ACTION_WAKEUP_SERVICE"; + public static final String ACTION_RELOAD_REPORT = "cc.winboll.studio.appbase.widgets.SOSWidget.ACTION_RELOAD_REPORT"; + + + volatile static ArrayList _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_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); + } + }else if (intent.getAction().equals(ACTION_WAKEUP_SERVICE)) { + LogUtils.d(TAG, "ACTION_WAKEUP_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)); + + + 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("] Wake up "); + 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()); + } + } + } + } + + // + // 加入新报告信息 + // + public synchronized static 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); + } + + synchronized static void initAPPSOSReportBeanList(Context context) { + if (_SOSReportBeanList == null) { + _SOSReportBeanList = new ArrayList(); + SOSReportBean.loadBeanList(context, _SOSReportBeanList, SOSReportBean.class); + } + if (_SOSReportBeanList == null) { + _SOSReportBeanList = new ArrayList(); + 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 msgTemp = new ArrayList(); + 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 && start > -1; 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); + } +} diff --git a/appbase/src/main/java/cc/winboll/studio/appbase/widgets/SOSWidgetClickListener.java b/appbase/src/main/java/cc/winboll/studio/appbase/widgets/SOSWidgetClickListener.java new file mode 100644 index 0000000..42dc31f --- /dev/null +++ b/appbase/src/main/java/cc/winboll/studio/appbase/widgets/SOSWidgetClickListener.java @@ -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)); + } + } +} diff --git a/appbase/src/main/res/drawable/ic_cloud.xml b/appbase/src/main/res/drawable/ic_cloud.xml new file mode 100644 index 0000000..62b99af --- /dev/null +++ b/appbase/src/main/res/drawable/ic_cloud.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/appbase/src/main/res/drawable/ic_cloud_outline.xml b/appbase/src/main/res/drawable/ic_cloud_outline.xml new file mode 100644 index 0000000..fb06b79 --- /dev/null +++ b/appbase/src/main/res/drawable/ic_cloud_outline.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/appbase/src/main/res/layout/activity_main.xml b/appbase/src/main/res/layout/activity_main.xml index 177c979..a17706a 100644 --- a/appbase/src/main/res/layout/activity_main.xml +++ b/appbase/src/main/res/layout/activity_main.xml @@ -4,13 +4,146 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" + android:orientation="vertical" android:gravity="center"> - + android:id="@+id/activitymainToolbar1"/> + + + + + + + + + + + +