diff --git a/contacts/build.gradle b/contacts/build.gradle index 86bb581..89322a4 100644 --- a/contacts/build.gradle +++ b/contacts/build.gradle @@ -64,7 +64,7 @@ dependencies { api 'com.google.android.material:material:1.1.0' api 'cc.winboll.studio:libapputils:9.3.2' - api 'cc.winboll.studio:libappbase:1.5.1' + api 'cc.winboll.studio:libappbase:1.5.5' api fileTree(dir: 'libs', include: ['*.jar']) } diff --git a/contacts/build.properties b/contacts/build.properties index ed0e69d..d1c9e68 100644 --- a/contacts/build.properties +++ b/contacts/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Thu Feb 13 19:09:39 GMT 2025 +#Thu Feb 20 03:27:00 GMT 2025 stageCount=0 libraryProject=winboll-shared baseVersion=1.0 publishVersion=1.0.0 -buildCount=13 +buildCount=91 baseBetaVersion=1.0.1 diff --git a/contacts/src/main/AndroidManifest.xml b/contacts/src/main/AndroidManifest.xml index 509b1b2..5ccab58 100644 --- a/contacts/src/main/AndroidManifest.xml +++ b/contacts/src/main/AndroidManifest.xml @@ -42,7 +42,10 @@ - + + + @@ -54,6 +57,25 @@ + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java b/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java index 952e7ba..9177664 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java @@ -1,5 +1,7 @@ package cc.winboll.studio.contacts; + + import android.content.Intent; import android.os.Bundle; import android.view.Menu; @@ -9,13 +11,15 @@ import android.widget.CheckBox; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import cc.winboll.studio.contacts.BuildConfig; +import cc.winboll.studio.contacts.MainActivity; import cc.winboll.studio.contacts.R; import cc.winboll.studio.contacts.beans.MainServiceBean; +import cc.winboll.studio.contacts.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.libapputils.app.AboutActivityFactory; +import cc.winboll.studio.libappbase.bean.APPSOSBean; import cc.winboll.studio.libapputils.app.IWinBollActivity; import cc.winboll.studio.libapputils.app.WinBollActivityManager; import cc.winboll.studio.libapputils.bean.APPInfo; @@ -27,7 +31,9 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct public static final int REQUEST_HOME_ACTIVITY = 0; public static final int REQUEST_ABOUT_ACTIVITY = 1; - + + public static final String ACTION_SOS = "cc.winboll.studio.libappbase.WinBoll.ACTION_SOS"; + LogView mLogView; Toolbar mToolbar; CheckBox cbMainService; @@ -40,21 +46,21 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct @Override public APPInfo getAppInfo() { - String szBranchName = "contacts"; - - APPInfo appInfo = AboutActivityFactory.buildDefaultAPPInfo(); - appInfo.setAppName("Contacts"); - appInfo.setAppIcon(cc.winboll.studio.libapputils.R.drawable.ic_winboll); - appInfo.setAppDescription("Contacts Description"); - appInfo.setAppGitName("APP"); - appInfo.setAppGitOwner("Studio"); - appInfo.setAppGitAPPBranch(szBranchName); - appInfo.setAppGitAPPSubProjectFolder(szBranchName); - appInfo.setAppHomePage("https://www.winboll.cc/studio/details.php?app=Contacts"); - appInfo.setAppAPKName("Contacts"); - appInfo.setAppAPKFolderName("Contacts"); - return appInfo; - //return null; +// String szBranchName = "contacts"; +// +// APPInfo appInfo = AboutActivityFactory.buildDefaultAPPInfo(); +// appInfo.setAppName("Contacts"); +// appInfo.setAppIcon(cc.winboll.studio.libapputils.R.drawable.ic_winboll); +// appInfo.setAppDescription("Contacts Description"); +// appInfo.setAppGitName("APP"); +// appInfo.setAppGitOwner("Studio"); +// appInfo.setAppGitAPPBranch(szBranchName); +// appInfo.setAppGitAPPSubProjectFolder(szBranchName); +// appInfo.setAppHomePage("https://www.winboll.cc/studio/details.php?app=Contacts"); +// appInfo.setAppAPKName("Contacts"); +// appInfo.setAppAPKFolderName("Contacts"); +// return appInfo; + return null; } @Override @@ -64,11 +70,11 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct // 以下正常创建主窗口 super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - + mLogView = findViewById(R.id.activitymainLogView1); if (GlobalApplication.isDebuging()) { mLogView.start(); } - + // 初始化工具栏 mToolbar = findViewById(R.id.activitymainToolbar1); setSupportActionBar(mToolbar); @@ -90,22 +96,48 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct cbMainService.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View view) { - SOS.sendToWinBoll(MainActivity.this); -// if (cbMainService.isChecked()) { -// MainService.startISOSService(MainActivity.this); -// } else { -// MainService.stopISOSService(MainActivity.this); -// } + if (cbMainService.isChecked()) { + MainService.startMainService(MainActivity.this); + } else { + MainService.stopMainService(MainActivity.this); + } } }); } +// public static void sosToWinBoll(Context context) { +// Intent intent = new Intent(ACTION_SOS); +// intent.putExtra("sos", "SOS"); +// intent.putExtra("sosPackage", context.getPackageName()); +// intent.putExtra("sosCalssType", "Service"); +// intent.putExtra("sosClassName", MainService.class.getName()); +// String szToPackage = ""; +// if (GlobalApplication.isDebuging()) { +// szToPackage = "cc.winboll.studio.appbase.beta"; +// } else { +// szToPackage = "cc.winboll.studio.appbase"; +// } +// intent.setPackage(szToPackage); +// context.sendBroadcast(intent); +// +// LogUtils.d(TAG, String.format("SOS Send To WinBoll. (szToPackage : %s)", szToPackage)); +// //ToastUtils.show("SOS Send To WinBoll"); +// } + @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); //setSubTitle(""); } + @Override + protected void onDestroy() { + super.onDestroy(); + LogUtils.d(TAG, "onDestroy() SOS"); + } + + + // // 处理传入的 Intent 数据 // diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/handlers/MainServiceHandler.java b/contacts/src/main/java/cc/winboll/studio/contacts/handlers/MainServiceHandler.java new file mode 100644 index 0000000..d19cd99 --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/handlers/MainServiceHandler.java @@ -0,0 +1,38 @@ +package cc.winboll.studio.contacts.handlers; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/14 03:51:40 + */ +import android.os.Handler; +import android.os.Message; +import cc.winboll.studio.contacts.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/contacts/src/main/java/cc/winboll/studio/contacts/receivers/MainReceiver.java b/contacts/src/main/java/cc/winboll/studio/contacts/receivers/MainReceiver.java index 6315f2f..7d93891 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/receivers/MainReceiver.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/receivers/MainReceiver.java @@ -1,20 +1,32 @@ package cc.winboll.studio.contacts.receivers; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import com.hjq.toast.ToastUtils; - /** * @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.contacts.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 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(); @@ -24,5 +36,13 @@ public class MainReceiver extends BroadcastReceiver { 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); + } } diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/services/AssistantService.java b/contacts/src/main/java/cc/winboll/studio/contacts/services/AssistantService.java new file mode 100644 index 0000000..a031f4b --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/services/AssistantService.java @@ -0,0 +1,139 @@ +package cc.winboll.studio.contacts.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.Binder; +import android.os.IBinder; +import cc.winboll.studio.contacts.beans.MainServiceBean; +import cc.winboll.studio.contacts.services.MainService; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.SOS; +import cc.winboll.studio.libappbase.bean.APPSOSBean; + +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/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java b/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java index 4e9d60a..efaf13e 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java @@ -1,162 +1,229 @@ package cc.winboll.studio.contacts.services; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.os.IBinder; -import cc.winboll.studio.contacts.beans.MainServiceBean; -import cc.winboll.studio.libappbase.ISOSAPP; -import cc.winboll.studio.libappbase.ISOSService; -import cc.winboll.studio.libappbase.LogUtils; -import cc.winboll.studio.libappbase.SOSCSBroadcastReceiver; -import cc.winboll.studio.libappbase.SimpleOperateSignalCenterService; -import com.hjq.toast.ToastUtils; -import android.content.ComponentName; - /** * @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 */ -public class MainService extends Service implements ISOSService { - +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.contacts.beans.MainServiceBean; +import cc.winboll.studio.contacts.handlers.MainServiceHandler; +import cc.winboll.studio.contacts.receivers.MainReceiver; +import cc.winboll.studio.contacts.services.MainService; +import cc.winboll.studio.contacts.threads.MainServiceThread; +import cc.winboll.studio.contacts.widgets.APPStatusWidget; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.SOS; +import cc.winboll.studio.libappbase.bean.APPSOSBean; + +public class MainService extends Service { + public static final String TAG = "MainService"; - - public static final String ACTION_ENABLE = MainService.class.getName() + ".ACTION_ENABLE"; - public static final String ACTION_DISABLE = MainService.class.getName() + ".ACTION_DISABLE"; + + public static final int MSG_UPDATE_STATUS = 0; + + static MainService _mControlCenterService; + + volatile boolean isServiceRunning; MainServiceBean mMainServiceBean; - static MainThread _MainThread; - public static synchronized MainThread getMainThreadInstance() { - if (_MainThread == null) { - _MainThread = new MainThread(); - } - return _MainThread; - } + MainServiceThread mMainServiceThread; + MainServiceHandler mMainServiceHandler; + MyServiceConnection mMyServiceConnection; + AssistantService mAssistantService; + boolean isBound = false; + MainReceiver mMainReceiver; @Override public IBinder onBind(Intent intent) { - return null; + return new MyBinder(); + } + + public MainServiceThread getRemindThread() { + return mMainServiceThread; } @Override public void onCreate() { super.onCreate(); - LogUtils.d(TAG, "onCreate"); + LogUtils.d(TAG, "onCreate()"); + _mControlCenterService = MainService.this; + isServiceRunning = false; mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); - runMainThread(); + + 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"); - if (intent.getBooleanExtra(ISOSService.EXTRA_ENABLE, false)) { - LogUtils.d(TAG, "onStartCommand enable service"); - mMainServiceBean.setIsEnable(true); - MainServiceBean.saveBean(this, mMainServiceBean); - } - - runMainThread(); - - //return super.onStartCommand(intent, flags, startId); - return mMainServiceBean.isEnable() ? Service.START_STICKY: super.onStartCommand(intent, flags, startId); + LogUtils.d(TAG, "onStartCommand(...)"); + // 运行服务内容 + mainService(); + return (mMainServiceBean.isEnable()) ? START_STICKY : super.onStartCommand(intent, flags, startId); } - void runMainThread() { + // 运行服务内容 + // + void mainService() { + LogUtils.d(TAG, "mainService()"); mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); - if (mMainServiceBean.isEnable() - && _MainThread == null) { - getMainThreadInstance().start(); + if (mMainServiceBean.isEnable() && isServiceRunning == false) { + LogUtils.d(TAG, "mainService() start running"); + isServiceRunning = true; + // 唤醒守护进程 + wakeupAndBindAssistant(); + // 召唤 WinBoll APP 绑定本服务 + SOS.bindToAPPService(this, new APPSOSBean(getPackageName(), MainService.class.getName())); + + if (mMainReceiver == null) { + // 注册广播接收器 + mMainReceiver = new MainReceiver(this); + mMainReceiver.registerAction(this); + } + + + MainServiceThread.getInstance(this, mMainServiceHandler).start(); + + LogUtils.i(TAG, "Main Service Is Start."); } } - @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; - } + // 唤醒和绑定守护进程 + // + 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); - @Override - public boolean isEnable() { - mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); - return mMainServiceBean.isEnable(); +// Intent intent = new Intent(this, AssistantService.class); +// startService(intent); +// LogUtils.d(TAG, "startService(intent)"); +// bindService(new Intent(this, AssistantService.class), mMyServiceConnection, Context.BIND_IMPORTANT); } @Override public void onDestroy() { - super.onDestroy(); - LogUtils.d(TAG, "onDestroy"); + //LogUtils.d(TAG, "onDestroy"); mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); - if (mMainServiceBean.isEnable()) { - LogUtils.d(TAG, "mMainServiceBean.isEnable()"); -// ISOSAPP iSOSAPP = (ISOSAPP)getApplication(); -// iSOSAPP.helpISOSService(getISOSServiceIntentWhichAskForHelp()); - sos(); - } - if (_MainThread != null) { - _MainThread.isExist = true; - _MainThread = null; + //LogUtils.d(TAG, "onDestroy done"); + 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); + + // 停止主要进程 + MainServiceThread.getInstance(this, mMainServiceHandler).setIsExit(true); + } + + super.onDestroy(); + } + + // 主进程与守护进程连接时需要用到此类 + // + 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(); + SOS.sosWinBollService(getApplicationContext(), new APPSOSBean(getPackageName(), MainService.class.getName())); + } + isBound = false; + mAssistantService = null; + } + + } + + + // 用于返回服务实例的Binder + public class MyBinder extends Binder { + MainService getService() { + LogUtils.d(TAG, "MainService MyBinder getService()"); + return MainService.this; } } - public static void stopISOSService(Context context) { - LogUtils.d(TAG, "stopISOSService"); +// // +// // 启动服务 +// // +// 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 startISOSService(Context context) { - LogUtils.d(TAG, "startISOSService"); + 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)); } - - public void sos() { - // 创建Intent对象,指定广播的action - Intent intentService = new Intent(SOSCSBroadcastReceiver.ACTION_SOS); - String packageName = this.getPackageName(); - String serviceClassName = SOSCSBroadcastReceiver.class.getName(); - intentService.setComponent(new ComponentName(packageName, serviceClassName)); - - // 目标服务的包名和类名 - intentService.putExtra(ISOSAPP.EXTRA_PACKAGE, getPackageName()); - intentService.putExtra(ISOSAPP.EXTRA_SERVICE, MainService.class.getName()); - // 发送广播 - sendBroadcast(intentService); - LogUtils.d(TAG, "sos"); - ToastUtils.show("sos"); - } - - static class MainThread extends Thread { - volatile boolean isExist = false; - - public void setIsExist(boolean isExist) { - this.isExist = isExist; - } - - public boolean isExist() { - return isExist; - } - - @Override - public void run() { - super.run(); - while (!isExist) { - LogUtils.d(TAG, "run"); - ToastUtils.show("run"); - try { - sleep(1000); - } catch (InterruptedException e) { - LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); - } - } - } - - } } + diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/threads/MainServiceThread.java b/contacts/src/main/java/cc/winboll/studio/contacts/threads/MainServiceThread.java new file mode 100644 index 0000000..0dfd918 --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/threads/MainServiceThread.java @@ -0,0 +1,77 @@ +package cc.winboll.studio.contacts.threads; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/14 03:46:44 + */ +import android.content.Context; +import cc.winboll.studio.contacts.handlers.MainServiceHandler; +import cc.winboll.studio.contacts.services.MainService; +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.lang.ref.WeakReference; + +public class MainServiceThread extends Thread { + + public static final String TAG = "MainServiceThread"; + + volatile static MainServiceThread _MainServiceThread; + // 控制线程是否退出的标志 + volatile boolean isExit = false; + volatile boolean isStarted = false; + Context mContext; + // 服务Handler, 用于线程发送消息使用 + WeakReference mwrMainServiceHandler; + + MainServiceThread(Context context, MainServiceHandler handler) { + mContext = context; + mwrMainServiceHandler = new WeakReference(handler); + } + + public void setIsExit(boolean isExit) { + this.isExit = isExit; + } + + public boolean isExit() { + return isExit; + } + + public void setIsStarted(boolean isStarted) { + this.isStarted = isStarted; + } + + public boolean isStarted() { + return isStarted; + } + + public static MainServiceThread getInstance(Context context, MainServiceHandler handler) { + if (_MainServiceThread != null) { + _MainServiceThread.setIsExit(true); + } + _MainServiceThread = new MainServiceThread(context, handler); + return _MainServiceThread; + } + + @Override + public void run() { + if (isStarted == false) { + isStarted = true; + LogUtils.d(TAG, "run()"); + + while (!isExit()) { + //ToastUtils.show("run"); + //LogUtils.d(TAG, "run()"); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + } + _MainServiceThread = null; + LogUtils.d(TAG, "run() exit"); + } + } + +} diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/widgets/APPStatusWidget.java b/contacts/src/main/java/cc/winboll/studio/contacts/widgets/APPStatusWidget.java new file mode 100644 index 0000000..8a9b7c0 --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/widgets/APPStatusWidget.java @@ -0,0 +1,76 @@ +package cc.winboll.studio.contacts.widgets; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/17 14:49:31 + * @Describe APPStatusWidget + */ +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.contacts.R; +import cc.winboll.studio.contacts.threads.MainServiceThread; +import cc.winboll.studio.libappbase.LogUtils; +import com.hjq.toast.ToastUtils; + +public class APPStatusWidget extends AppWidgetProvider { + + public static final String TAG = "APPSOSReportWidget"; + + public static final String ACTION_STATUS_ACTIVE = "cc.winboll.studio.contacts.widgets.APPStatusWidget.ACTION_STATUS_ACTIVE"; + public static final String ACTION_STATUS_NOACTIVE = "cc.winboll.studio.contacts.widgets.APPStatusWidget.ACTION_STATUS_NOACTIVE"; + + @Override + public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { + for (int appWidgetId : appWidgetIds) { + updateAppWidget(context, appWidgetManager, appWidgetId); + } + } + + @Override + public void onReceive(Context context, Intent intent) { + super.onReceive(context, intent); + if (intent.getAction().equals(ACTION_STATUS_ACTIVE)) { + AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); + int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, APPStatusWidget.class)); + for (int appWidgetId : appWidgetIds) { + updateAppWidget(context, appWidgetManager, appWidgetId); + } + } else if (intent.getAction().equals(ACTION_STATUS_NOACTIVE)) { + AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); + int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, APPStatusWidget.class)); + for (int appWidgetId : appWidgetIds) { + updateAppWidget(context, appWidgetManager, appWidgetId); + } + } + + } + + private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { + LogUtils.d(TAG, "updateAppWidget(...)"); + + RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout); + //设置按钮点击事件 + Intent intentAppButton = new Intent(context, APPStatusWidgetClickListener.class); + intentAppButton.setAction(APPStatusWidgetClickListener.ACTION_APPICON_CLICK); + PendingIntent pendingIntentAppButton = PendingIntent.getBroadcast(context, 0, intentAppButton, PendingIntent.FLAG_UPDATE_CURRENT); + views.setOnClickPendingIntent(R.id.widgetlayoutImageView1, pendingIntentAppButton); + +// boolean isActive = !MainServiceThread.isExist(); +// if (isActive) { +// views.setImageViewResource(R.id.widgetlayoutImageView1, R.drawable.ic_launcher); +// } else { +// views.setImageViewResource(R.id.widgetlayoutImageView1, R.drawable.ic_launcher_disable); +// +// } + appWidgetManager.updateAppWidget(appWidgetId, views); + } + + public static void onAPPStatusWidgetClick(Context context) { + ToastUtils.show("onAPPStatusWidgetClick"); + } +} diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/widgets/APPStatusWidgetClickListener.java b/contacts/src/main/java/cc/winboll/studio/contacts/widgets/APPStatusWidgetClickListener.java new file mode 100644 index 0000000..016ccb2 --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/widgets/APPStatusWidgetClickListener.java @@ -0,0 +1,32 @@ +package cc.winboll.studio.contacts.widgets; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/02/17 14:59:55 + * @Describe WidgetButtonClickListener + */ +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.widget.Toast; +import cc.winboll.studio.libappbase.LogUtils; + +public class APPStatusWidgetClickListener extends BroadcastReceiver { + + public static final String TAG = "APPStatusWidgetClickListener"; + + public static final String ACTION_APPICON_CLICK = "cc.winboll.studio.contacts.widgets.APPStatusWidgetClickListener.ACTION_APPICON_CLICK"; + + @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_APPICON_CLICK)) { + LogUtils.d(TAG, "ACTION_APPICON_CLICK"); + Toast.makeText(context, "ACTION_APPICON_CLICK", Toast.LENGTH_SHORT).show(); + } + } +} diff --git a/contacts/src/main/res/drawable/ic_launcher_disable.xml b/contacts/src/main/res/drawable/ic_launcher_disable.xml new file mode 100644 index 0000000..9a31905 --- /dev/null +++ b/contacts/src/main/res/drawable/ic_launcher_disable.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/contacts/src/main/res/drawable/ic_launcher_foreground_disable.xml b/contacts/src/main/res/drawable/ic_launcher_foreground_disable.xml new file mode 100644 index 0000000..763b72c --- /dev/null +++ b/contacts/src/main/res/drawable/ic_launcher_foreground_disable.xml @@ -0,0 +1,10 @@ + + + + diff --git a/contacts/src/main/res/layout/widget_layout.xml b/contacts/src/main/res/layout/widget_layout.xml new file mode 100644 index 0000000..0dc6b46 --- /dev/null +++ b/contacts/src/main/res/layout/widget_layout.xml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/contacts/src/main/res/xml/appwidget_provider_info.xml b/contacts/src/main/res/xml/appwidget_provider_info.xml new file mode 100644 index 0000000..7dda9ab --- /dev/null +++ b/contacts/src/main/res/xml/appwidget_provider_info.xml @@ -0,0 +1,8 @@ + + + diff --git a/winboll-shared/build.properties b/winboll-shared/build.properties index ed0e69d..d1c9e68 100644 --- a/winboll-shared/build.properties +++ b/winboll-shared/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Thu Feb 13 19:09:39 GMT 2025 +#Thu Feb 20 03:27:00 GMT 2025 stageCount=0 libraryProject=winboll-shared baseVersion=1.0 publishVersion=1.0.0 -buildCount=13 +buildCount=91 baseBetaVersion=1.0.1