Merge branch 'appbase' into positions

This commit is contained in:
ZhanGSKen 2025-03-10 19:50:59 +08:00
commit 96332c9986
233 changed files with 15751 additions and 863 deletions

View File

@ -29,7 +29,7 @@ android {
// versionName // versionName
// .winboll/winbollBuildProps.properties stageCount=0 // .winboll/winbollBuildProps.properties stageCount=0
// Gradle编译环境下合起来的 versionName "${versionName}.0" // Gradle编译环境下合起来的 versionName "${versionName}.0"
versionName "2.0" versionName "2.1"
if(true) { if(true) {
versionName = genVersionName("${versionName}") versionName = genVersionName("${versionName}")
} }
@ -45,5 +45,26 @@ android {
dependencies { dependencies {
api project(':libappbase') api project(':libappbase')
api fileTree(dir: 'libs', include: ['*.jar']) api fileTree(dir: 'libs', include: ['*.jar'])
// SSH
implementation 'com.jcraft:jsch:0.1.55'
// Html
implementation 'org.jsoup:jsoup:1.13.1'
//
implementation 'com.google.zxing:core:3.4.1'
implementation 'com.journeyapps:zxing-android-embedded:3.6.0'
//
implementation 'io.github.medyo:android-about-page:2.0.0'
//
implementation 'com.github.getActivity:ToastUtils:10.5'
//
implementation 'com.squareup.okhttp3:okhttp:4.4.1'
// Android
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.viewpager:viewpager:1.0.0'
implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
implementation 'androidx.vectordrawable:vectordrawable-animated:1.1.0'
implementation 'androidx.fragment:fragment:1.1.0'
implementation 'com.google.android.material:material:1.4.0'
} }

View File

@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Tue Feb 25 16:51:17 HKT 2025 #Sun Mar 09 09:15:39 HKT 2025
stageCount=3 stageCount=6
libraryProject=libappbase libraryProject=libappbase
baseVersion=2.0 baseVersion=2.1
publishVersion=2.0.2 publishVersion=2.1.5
buildCount=0 buildCount=0
baseBetaVersion=2.0.3 baseBetaVersion=2.1.6

View File

@ -54,19 +54,25 @@
<receiver android:name="cc.winboll.studio.appbase.receivers.MainReceiver"> <receiver android:name="cc.winboll.studio.appbase.receivers.MainReceiver">
<intent-filter> <intent-filter>
<action android:name="cc.winboll.studio.appbase.receivers.MainReceiver"/> <action android:name="cc.winboll.studio.appbase.receivers.MainReceiver"/>
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver <receiver
android:name=".widgets.SOSWidget" android:name=".widgets.APPNewsWidget"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="cc.winboll.studio.appbase.widgets.SOSWidget.ACTION_WAKEUP_SERVICE"/>
<action android:name="cc.winboll.studio.appbase.widgets.SOSWidget.ACTION_RELOAD_REPORT"/> <action android:name="cc.winboll.studio.appbase.widgets.APPNewsWidget.ACTION_WAKEUP_SERVICE"/>
<action android:name="cc.winboll.studio.appbase.widgets.APPNewsWidget.ACTION_RELOAD_REPORT"/>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter> </intent-filter>
<meta-data <meta-data
@ -75,13 +81,13 @@
</receiver> </receiver>
<receiver android:name=".widgets.SOSWidgetClickListener"> <receiver android:name=".widgets.APPNewsWidgetClickListener">
<intent-filter> <intent-filter>
<action android:name="cc.winboll.studio.appbase.widgets.SOSWidgetClickListener.ACTION_PRE"/> <action android:name="cc.winboll.studio.appbase.widgets.APPNewsWidgetClickListener.ACTION_PRE"/>
<action android:name="cc.winboll.studio.appbase.widgets.SOSWidgetClickListener.ACTION_NEXT"/> <action android:name="cc.winboll.studio.appbase.widgets.APPNewsWidgetClickListener.ACTION_NEXT"/>
</intent-filter> </intent-filter>
@ -91,6 +97,11 @@
android:name="android.max_aspect" android:name="android.max_aspect"
android:value="4.0"/> android:value="4.0"/>
<service android:name="cc.winboll.studio.appbase.services.TestDemoBindService"
android:exported="true"/>
<service android:name="cc.winboll.studio.appbase.services.TestDemoService"
android:exported="true"/>
</application> </application>

View File

@ -6,22 +6,23 @@ package cc.winboll.studio.appbase;
* @Describe APPbase 应用类 * @Describe APPbase 应用类
*/ */
import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.SOSCSBroadcastReceiver;
import android.content.IntentFilter; import android.content.IntentFilter;
import cc.winboll.studio.libappbase.sos.SOSCenterServiceReceiver;
import cc.winboll.studio.libappbase.sos.SOS;
public class App extends GlobalApplication { public class App extends GlobalApplication {
public static final String TAG = "App"; public static final String TAG = "App";
SOSCSBroadcastReceiver mSOSCSBroadcastReceiver; SOSCenterServiceReceiver mSOSCenterServiceReceiver;
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
GlobalApplication.setIsDebuging(this, BuildConfig.DEBUG); GlobalApplication.setIsDebuging(this, BuildConfig.DEBUG);
mSOSCSBroadcastReceiver = new SOSCSBroadcastReceiver(); mSOSCenterServiceReceiver = new SOSCenterServiceReceiver();
IntentFilter intentFilter = new IntentFilter(); IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(SOSCSBroadcastReceiver.ACTION_SOS); intentFilter.addAction(SOS.ACTION_SOS);
registerReceiver(mSOSCSBroadcastReceiver, intentFilter); registerReceiver(mSOSCenterServiceReceiver, intentFilter);
} }
} }

View File

@ -1,6 +1,5 @@
package cc.winboll.studio.appbase; package cc.winboll.studio.appbase;
import android.content.ComponentName;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
@ -9,15 +8,16 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.appbase.R; import cc.winboll.studio.appbase.R;
import cc.winboll.studio.appbase.services.MainService; import cc.winboll.studio.appbase.services.MainService;
import cc.winboll.studio.appbase.services.TestDemoBindService;
import cc.winboll.studio.appbase.services.TestDemoService;
import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.LogView; 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 cc.winboll.studio.libappbase.widgets.StatusWidget;
import com.hjq.toast.ToastUtils; import com.hjq.toast.ToastUtils;
import android.content.ComponentName;
import cc.winboll.studio.libappbase.sos.SOS;
import cc.winboll.studio.libappbase.sos.SOSObject;
public class MainActivity extends AppCompatActivity { public class MainActivity extends AppCompatActivity {
@ -68,17 +68,17 @@ public class MainActivity extends AppCompatActivity {
MainService.stopMainService(this); MainService.stopMainService(this);
} }
public void onTestStopWithoutSettingEnable(View view) { public void onTestStopMainServiceWithoutSettingEnable(View view) {
LogUtils.d(TAG, "onTestStopWithoutSettingEnable"); LogUtils.d(TAG, "onTestStopMainServiceWithoutSettingEnable");
stopService(new Intent(this, SimpleOperateSignalCenterService.class)); stopService(new Intent(this, MainService.class));
} }
public void onTestStartWithString(View view) { public void onTestUseComponentStartService(View view) {
LogUtils.d(TAG, "onTestStartWithString"); LogUtils.d(TAG, "onTestUseComponentStartService");
// 目标服务的包名和类名 // 目标服务的包名和类名
String packageName = this.getPackageName(); String packageName = this.getPackageName();
String serviceClassName = SimpleOperateSignalCenterService.class.getName(); String serviceClassName = TestDemoService.class.getName();
// 构建Intent // 构建Intent
Intent intentService = new Intent(); Intent intentService = new Intent();
@ -87,30 +87,55 @@ public class MainActivity extends AppCompatActivity {
startService(intentService); startService(intentService);
} }
public void onSOS(View view) { public void onTestSOS(View view) {
Intent intent = new Intent(this, TestService.class); Intent intent = new Intent(this, TestDemoService.class);
stopService(intent); stopService(intent);
SOS.sosWinBollService(this, new APPSOSBean(getPackageName(), TestService.class.getName())); if(App.isDebuging()) {
SOS.sosToAppBaseBeta(this, TestDemoService.class.getName());
} else {
SOS.sosToAppBase(this, TestDemoService.class.getName());
}
} }
public void onStartTestService(View view) { public void onSartTestDemoService(View view) {
Intent intent = new Intent(this, TestService.class); Intent intent = new Intent(this, TestDemoService.class);
intent.setAction(SOS.ACTION_SERVICE_ENABLE); intent.setAction(TestDemoService.ACTION_ENABLE);
startService(intent); startService(intent);
} }
public void onStopTestService(View view) { public void onStopTestDemoService(View view) {
Intent intent = new Intent(this, TestService.class); Intent intent = new Intent(this, TestDemoService.class);
intent.setAction(SOS.ACTION_SERVICE_DISABLE); intent.setAction(TestDemoService.ACTION_DISABLE);
startService(intent); startService(intent);
Intent intentStop = new Intent(this, TestService.class); Intent intentStop = new Intent(this, TestDemoService.class);
stopService(intentStop); stopService(intentStop);
} }
public void onStopTestServiceNoSettings(View view) { public void onStopTestDemoServiceNoSettings(View view) {
Intent intent = new Intent(this, TestService.class); Intent intent = new Intent(this, TestDemoService.class);
stopService(intent);
}
public void onSartTestDemoBindService(View view) {
Intent intent = new Intent(this, TestDemoBindService.class);
intent.setAction(TestDemoBindService.ACTION_ENABLE);
startService(intent);
}
public void onStopTestDemoBindService(View view) {
Intent intent = new Intent(this, TestDemoBindService.class);
intent.setAction(TestDemoBindService.ACTION_DISABLE);
startService(intent);
Intent intentStop = new Intent(this, TestDemoBindService.class);
stopService(intentStop);
}
public void onStopTestDemoBindServiceNoSettings(View view) {
Intent intent = new Intent(this, TestDemoBindService.class);
stopService(intent); stopService(intent);
} }
} }

View File

@ -35,8 +35,7 @@ public class MainServiceBean extends BaseBean {
@Override @Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter); super.writeThisToJsonWriter(jsonWriter);
MainServiceBean bean = this; jsonWriter.name("isEnable").value(isEnable());
jsonWriter.name("isEnable").value(bean.isEnable());
} }

View File

@ -1,8 +1,8 @@
package cc.winboll.studio.libappbase.bean; package cc.winboll.studio.appbase.beans;
/** /**
* @Author ZhanGSKen@AliYun.Com * @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/19 13:34:52 * @Date 2025/03/07 12:47:22
* @Describe TestServiceBean * @Describe TestServiceBean
*/ */
import android.util.JsonReader; import android.util.JsonReader;
@ -10,13 +10,13 @@ import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean; import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException; import java.io.IOException;
public class TestServiceBean extends BaseBean { public class TestDemoBindServiceBean extends BaseBean {
public static final String TAG = "TestServiceBean"; public static final String TAG = "TestServiceBean";
boolean isEnable; boolean isEnable;
public TestServiceBean() { public TestDemoBindServiceBean() {
this.isEnable = false; this.isEnable = false;
} }
@ -30,7 +30,7 @@ public class TestServiceBean extends BaseBean {
@Override @Override
public String getName() { public String getName() {
return TestServiceBean.class.getName(); return TestDemoBindServiceBean.class.getName();
} }
@Override @Override

View File

@ -1,20 +1,22 @@
package cc.winboll.studio.libappbase.bean; package cc.winboll.studio.appbase.beans;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/03/07 12:49:21
* @Describe TestDemoServiceBean
*/
import android.util.JsonReader; import android.util.JsonReader;
import android.util.JsonWriter; import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean; import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException; import java.io.IOException;
/** public class TestDemoServiceBean extends BaseBean {
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/13 04:27:42
*/
public class SimpleOperateSignalCenterServiceBean extends BaseBean {
public static final String TAG = "SimpleOperateSignalCenterServiceBean"; public static final String TAG = "TestDemoServiceBean";
boolean isEnable; boolean isEnable;
public SimpleOperateSignalCenterServiceBean() { public TestDemoServiceBean() {
this.isEnable = false; this.isEnable = false;
} }
@ -28,7 +30,7 @@ public class SimpleOperateSignalCenterServiceBean extends BaseBean {
@Override @Override
public String getName() { public String getName() {
return SimpleOperateSignalCenterServiceBean.class.getName(); return TestDemoServiceBean.class.getName();
} }
@Override @Override

View File

@ -10,45 +10,45 @@ import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean; import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException; import java.io.IOException;
public class SOSReportBean extends BaseBean { public class WinBollNewsBean extends BaseBean {
public static final String TAG = "APPSOSReportBean"; public static final String TAG = "WinBollNewsBean";
protected String sosReport; protected String message;
public SOSReportBean() { public WinBollNewsBean() {
this.sosReport = ""; this.message = "";
} }
public SOSReportBean(String sosReport) { public WinBollNewsBean(String message) {
this.sosReport = sosReport; this.message = message;
} }
public void setSosReport(String sosReport) { public void setMessage(String message) {
this.sosReport = sosReport; this.message = message;
} }
public String getSosReport() { public String getMessage() {
return sosReport; return message;
} }
@Override @Override
public String getName() { public String getName() {
return SOSReportBean.class.getName(); return WinBollNewsBean.class.getName();
} }
@Override @Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter); super.writeThisToJsonWriter(jsonWriter);
jsonWriter.name("sosReport").value(getSosReport()); jsonWriter.name("message").value(getMessage());
} }
@Override @Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
if (name.equals("sosReport")) { if (name.equals("message")) {
setSosReport(jsonReader.nextString()); setMessage(jsonReader.nextString());
} else { } else {
return false; return false;
} }

View File

@ -11,28 +11,28 @@ import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import cc.winboll.studio.appbase.beans.SOSReportBean; import cc.winboll.studio.appbase.beans.WinBollNewsBean;
import cc.winboll.studio.appbase.services.MainService; import cc.winboll.studio.appbase.services.MainService;
import cc.winboll.studio.appbase.widgets.SOSWidget; import cc.winboll.studio.appbase.widgets.APPNewsWidget;
import cc.winboll.studio.libappbase.AppUtils; import cc.winboll.studio.libappbase.AppUtils;
import cc.winboll.studio.libappbase.LogUtils; 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 com.hjq.toast.ToastUtils;
import java.io.IOException; import java.io.IOException;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import cc.winboll.studio.libappbase.sos.WinBoll;
import cc.winboll.studio.libappbase.sos.APPModel;
import cc.winboll.studio.libappbase.sos.SOS;
import cc.winboll.studio.libappbase.sos.SOSObject;
public class MainReceiver extends BroadcastReceiver { public class MainReceiver extends BroadcastReceiver {
public static final String TAG = "MainReceiver"; public static final String TAG = "MainReceiver";
public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED"; public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
WeakReference<MainService> mwrService; WeakReference<MainService> mwrService;
// 存储电量指示值
// 用于校验电量消息时的电量变化
static volatile int _mnTheQuantityOfElectricityOld = -1;
static volatile boolean _mIsCharging = false;
public MainReceiver(MainService service) { public MainReceiver(MainService service) {
mwrService = new WeakReference<MainService>(service); mwrService = new WeakReference<MainService>(service);
@ -43,74 +43,62 @@ public class MainReceiver extends BroadcastReceiver {
String szAction = intent.getAction(); String szAction = intent.getAction();
if (szAction.equals(ACTION_BOOT_COMPLETED)) { if (szAction.equals(ACTION_BOOT_COMPLETED)) {
ToastUtils.show("ACTION_BOOT_COMPLETED"); ToastUtils.show("ACTION_BOOT_COMPLETED");
} else if (szAction.equals(SOS.ACTION_BIND)) { } else if (szAction.equals(WinBoll.ACTION_BIND)) {
LogUtils.d(TAG, "ACTION_BIND"); LogUtils.d(TAG, "ACTION_BIND");
LogUtils.d(TAG, String.format("context.getPackageName() %s", context.getPackageName())); LogUtils.d(TAG, String.format("context.getPackageName() %s", context.getPackageName()));
LogUtils.d(TAG, String.format("intent.getAction() %s", intent.getAction())); LogUtils.d(TAG, String.format("intent.getAction() %s", intent.getAction()));
String SOS = intent.getStringExtra("SOS"); String szAPPModel = intent.getStringExtra(WinBoll.EXTRA_APPMODEL);
LogUtils.d(TAG, String.format("SOS %s", SOS)); LogUtils.d(TAG, String.format("szAPPModel %s", szAPPModel));
if (SOS != null && SOS.equals("Service")) { if (szAPPModel != null && !szAPPModel.equals("")) {
String szAPPSOSBean = intent.getStringExtra("APPSOSBean"); try {
LogUtils.d(TAG, String.format("szAPPSOSBean %s", szAPPSOSBean)); APPModel bean = APPModel.parseStringToBean(szAPPModel, APPModel.class);
if (szAPPSOSBean != null && !szAPPSOSBean.equals("")) { if (bean != null) {
try { String szAppPackageName = bean.getAppPackageName();
APPSOSBean bean = APPSOSBean.parseStringToBean(szAPPSOSBean, APPSOSBean.class); LogUtils.d(TAG, String.format("szAppPackageName %s", szAppPackageName));
if (bean != null) { String szAppMainServiveName = bean.getAppMainServiveName();
String sosPackage = bean.getSosPackage(); LogUtils.d(TAG, String.format("szAppMainServiveName %s", szAppMainServiveName));
LogUtils.d(TAG, String.format("sosPackage %s", sosPackage)); mwrService.get().bindAPPModelConnection(bean);
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());
} }
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
} }
} }
} else if (intent.getAction().equals(SOS.ACTION_SOS)) { } else if (intent.getAction().equals(SOS.ACTION_SOS)) {
LogUtils.d(TAG, "ACTION_SOS"); LogUtils.d(TAG, "ACTION_SOS");
LogUtils.d(TAG, String.format("context.getPackageName() %s", context.getPackageName())); String sos = intent.getStringExtra(SOS.EXTRA_OBJECT);
LogUtils.d(TAG, String.format("intent.getAction() %s", intent.getAction())); LogUtils.d(TAG, String.format("SOS %s", sos));
String SOS = intent.getStringExtra("SOS"); if (sos != null && !sos.equals("")) {
LogUtils.d(TAG, String.format("SOS %s", SOS)); SOSObject bean = SOS.parseSOSObject(sos);
if (SOS != null && SOS.equals("Service")) { if (bean != null) {
String szAPPSOSBean = intent.getStringExtra("APPSOSBean"); String szObjectPackageName = bean.getObjectPackageName();
LogUtils.d(TAG, String.format("szAPPSOSBean %s", szAPPSOSBean)); LogUtils.d(TAG, String.format("szObjectPackageName %s", szObjectPackageName));
if (szAPPSOSBean != null && !szAPPSOSBean.equals("")) { String szObjectServiveName = bean.getObjectServiveName();
try { LogUtils.d(TAG, String.format("szObjectServiveName %s", szObjectServiveName));
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(); Intent intentService = new Intent();
intentService.setComponent(new ComponentName(sosPackage, sosClassName)); intentService.setComponent(new ComponentName(szObjectPackageName, szObjectServiveName));
context.startService(intentService); context.startService(intentService);
String appName = AppUtils.getAppNameByPackageName(context, sosPackage); String appName = AppUtils.getAppNameByPackageName(context, szObjectPackageName);
LogUtils.d(TAG, String.format("appName %s", appName)); LogUtils.d(TAG, String.format("appName %s", appName));
SOSReportBean appSOSReportBean = new SOSReportBean(appName); WinBollNewsBean appWinBollNewsBean = new WinBollNewsBean(appName);
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
String currentTime = sdf.format(new Date()); String currentTime = sdf.format(new Date());
StringBuilder sbLine = new StringBuilder(); StringBuilder sbLine = new StringBuilder();
sbLine.append("["); sbLine.append("[");
sbLine.append(currentTime); sbLine.append(currentTime);
sbLine.append("] Power to "); sbLine.append("] Power to ");
sbLine.append(appName); sbLine.append(appName);
appSOSReportBean.setSosReport(sbLine.toString()); appWinBollNewsBean.setMessage(sbLine.toString());
SOSWidget.addAPPSOSReportBean(context, appSOSReportBean); APPNewsWidget.addWinBollNewsBean(context, appWinBollNewsBean);
Intent intentWidget = new Intent(context, SOSWidget.class); Intent intentWidget = new Intent(context, APPNewsWidget.class);
intentWidget.setAction(SOSWidget.ACTION_RELOAD_REPORT); intentWidget.setAction(APPNewsWidget.ACTION_RELOAD_REPORT);
context.sendBroadcast(intentWidget); context.sendBroadcast(intentWidget);
}
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
} }
} }
} else { } else {
ToastUtils.show(szAction); ToastUtils.show(szAction);
@ -123,9 +111,7 @@ public class MainReceiver extends BroadcastReceiver {
IntentFilter filter=new IntentFilter(); IntentFilter filter=new IntentFilter();
filter.addAction(ACTION_BOOT_COMPLETED); filter.addAction(ACTION_BOOT_COMPLETED);
filter.addAction(SOS.ACTION_SOS); filter.addAction(SOS.ACTION_SOS);
filter.addAction(SOS.ACTION_BIND); filter.addAction(WinBoll.ACTION_BIND);
filter.addAction(SOS.ACTION_SERVICE_ENABLE);
filter.addAction(SOS.ACTION_SERVICE_DISABLE);
//filter.addAction(Intent.ACTION_BATTERY_CHANGED); //filter.addAction(Intent.ACTION_BATTERY_CHANGED);
service.registerReceiver(this, filter); service.registerReceiver(this, filter);
} }

View File

@ -23,10 +23,10 @@ import cc.winboll.studio.appbase.handlers.MainServiceHandler;
import cc.winboll.studio.appbase.receivers.MainReceiver; import cc.winboll.studio.appbase.receivers.MainReceiver;
import cc.winboll.studio.appbase.services.AssistantService; import cc.winboll.studio.appbase.services.AssistantService;
import cc.winboll.studio.appbase.threads.MainServiceThread; import cc.winboll.studio.appbase.threads.MainServiceThread;
import cc.winboll.studio.appbase.widgets.SOSWidget; import cc.winboll.studio.appbase.widgets.APPNewsWidget;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.bean.APPSOSBean;
import java.util.ArrayList; import java.util.ArrayList;
import cc.winboll.studio.libappbase.sos.APPModel;
public class MainService extends Service { public class MainService extends Service {
@ -45,7 +45,7 @@ public class MainService extends Service {
AssistantService mAssistantService; AssistantService mAssistantService;
boolean isBound = false; boolean isBound = false;
MainReceiver mMainReceiver; MainReceiver mMainReceiver;
ArrayList<SOSConnection> mSOSConnectionList; ArrayList<APPConnection> mAPPModelConnectionList;
@Override @Override
public IBinder onBind(Intent intent) { public IBinder onBind(Intent intent) {
@ -60,7 +60,7 @@ public class MainService extends Service {
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
LogUtils.d(TAG, "onCreate()"); LogUtils.d(TAG, "onCreate()");
mSOSConnectionList = new ArrayList<SOSConnection>(); mAPPModelConnectionList = new ArrayList<APPConnection>();
_mControlCenterService = MainService.this; _mControlCenterService = MainService.this;
isServiceRunning = false; isServiceRunning = false;
@ -101,8 +101,8 @@ public class MainService extends Service {
} }
// 启动小部件 // 启动小部件
Intent intentTimeWidget = new Intent(this, SOSWidget.class); Intent intentTimeWidget = new Intent(this, APPNewsWidget.class);
intentTimeWidget.setAction(SOSWidget.ACTION_RELOAD_REPORT); intentTimeWidget.setAction(APPNewsWidget.ACTION_RELOAD_REPORT);
this.sendBroadcast(intentTimeWidget); this.sendBroadcast(intentTimeWidget);
startMainServiceThread(); startMainServiceThread();
@ -117,21 +117,11 @@ public class MainService extends Service {
// //
void wakeupAndBindAssistant() { void wakeupAndBindAssistant() {
LogUtils.d(TAG, "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); Intent intent = new Intent(this, AssistantService.class);
startService(intent); startService(intent);
// 绑定服务的Intent // 绑定服务的Intent
//Intent intent = new Intent(this, AssistantService.class);
bindService(intent, mMyServiceConnection, Context.BIND_IMPORTANT); 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);
} }
// 开启提醒铃声线程 // 开启提醒铃声线程
@ -192,40 +182,40 @@ public class MainService extends Service {
} }
} }
public void bindSOSConnection(APPSOSBean bean) { public void bindAPPModelConnection(APPModel bean) {
LogUtils.d(TAG, "bindSOSConnection(...)"); LogUtils.d(TAG, "bindAPPModelConnection(...)");
// 清理旧的绑定链接 // 清理旧的绑定链接
for (int i = mSOSConnectionList.size() - 1; i > -1; i--) { for (int i = mAPPModelConnectionList.size() - 1; i > -1; i--) {
SOSConnection item = mSOSConnectionList.get(i); APPConnection item = mAPPModelConnectionList.get(i);
if (item.isBindToAPPSOSBean(bean)) { if (item.isBindToAPP(bean)) {
LogUtils.d(TAG, "Bind Servive exist."); LogUtils.d(TAG, "Bind Servive exist.");
unbindService(item); unbindService(item);
mSOSConnectionList.remove(i); mAPPModelConnectionList.remove(i);
} }
} }
// 绑定服务 // 绑定服务
SOSConnection sosConnection = new SOSConnection(); APPConnection appConnection = new APPConnection();
Intent intentService = new Intent(); Intent intentService = new Intent();
intentService.setComponent(new ComponentName(bean.getSosPackage(), bean.getSosClassName())); intentService.setComponent(new ComponentName(bean.getAppPackageName(), bean.getAppMainServiveName()));
bindService(intentService, sosConnection, Context.BIND_IMPORTANT); bindService(intentService, appConnection, Context.BIND_IMPORTANT);
mSOSConnectionList.add(sosConnection); mAPPModelConnectionList.add(appConnection);
Intent intentWidget = new Intent(this, SOSWidget.class); Intent intentWidget = new Intent(this, APPNewsWidget.class);
intentWidget.setAction(SOSWidget.ACTION_WAKEUP_SERVICE); intentWidget.setAction(APPNewsWidget.ACTION_WAKEUP_SERVICE);
APPSOSBean appSOSBean = new APPSOSBean(bean.getSosPackage(), bean.getSosClassName()); APPModel appSOSBean = new APPModel(bean.getAppPackageName(), bean.getAppMainServiveName());
intentWidget.putExtra("APPSOSBean", appSOSBean.toString()); intentWidget.putExtra("APPSOSBean", appSOSBean.toString());
sendBroadcast(intentWidget); sendBroadcast(intentWidget);
} }
public class SOSConnection implements ServiceConnection { public class APPConnection implements ServiceConnection {
ComponentName mComponentName; ComponentName mComponentName;
boolean isBindToAPPSOSBean(APPSOSBean bean) { boolean isBindToAPP(APPModel bean) {
return mComponentName != null return mComponentName != null
&& mComponentName.getClassName().equals(bean.getSosClassName()) && mComponentName.getClassName().equals(bean.getAppMainServiveName())
&& mComponentName.getPackageName().equals(bean.getSosPackage()); && mComponentName.getPackageName().equals(bean.getAppPackageName());
} }
@Override @Override
@ -241,13 +231,13 @@ public class MainService extends Service {
LogUtils.d(TAG, String.format("onServiceDisconnected : \ngetClassName %s\ngetPackageName %s", name.getClassName(), name.getPackageName())); LogUtils.d(TAG, String.format("onServiceDisconnected : \ngetClassName %s\ngetPackageName %s", name.getClassName(), name.getPackageName()));
// 尝试无参数启动一下服务 // 尝试无参数启动一下服务
String sosPackage = mComponentName.getPackageName(); String appPackage = mComponentName.getPackageName();
LogUtils.d(TAG, String.format("sosPackage %s", sosPackage)); LogUtils.d(TAG, String.format("appPackage %s", appPackage));
String sosClassName = mComponentName.getClassName(); String appMainServiceClassName = mComponentName.getClassName();
LogUtils.d(TAG, String.format("sosClassName %s", sosClassName)); LogUtils.d(TAG, String.format("appMainServiceClassName %s", appMainServiceClassName));
Intent intentService = new Intent(); Intent intentService = new Intent();
intentService.setComponent(new ComponentName(sosPackage, sosClassName)); intentService.setComponent(new ComponentName(appPackage, appMainServiceClassName));
startService(intentService); startService(intentService);
} }

View File

@ -0,0 +1,178 @@
package cc.winboll.studio.appbase.services;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/03/07 12:45:49
* @Describe 启动时申请绑定到APPBase主服务的服务示例
*/
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import cc.winboll.studio.appbase.beans.TestDemoBindServiceBean;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.sos.WinBoll;
import cc.winboll.studio.appbase.App;
import cc.winboll.studio.libappbase.sos.SOS;
public class TestDemoBindService extends Service {
public static final String TAG = "TestDemoBindService";
public static final String ACTION_ENABLE = TestDemoBindService.class.getName() + ".ACTION_ENABLE";
public static final String ACTION_DISABLE = TestDemoBindService.class.getName() + ".ACTION_DISABLE";
volatile static TestThread _TestThread;
volatile static boolean _IsRunning;
public synchronized static void setIsRunning(boolean isRunning) {
_IsRunning = isRunning;
}
public static boolean isRunning() {
return _IsRunning;
}
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
public class MyBinder extends Binder {
public TestDemoBindService getService() {
return TestDemoBindService.this;
}
}
@Override
public void onCreate() {
super.onCreate();
LogUtils.d(TAG, "onCreate()");
run();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
LogUtils.d(TAG, "onStartCommand(...)");
TestDemoBindServiceBean bean = TestDemoBindServiceBean.loadBean(this, TestDemoBindServiceBean.class);
if (bean == null) {
bean = new TestDemoBindServiceBean();
}
if (intent.getAction() != null) {
if (intent.getAction().equals(ACTION_ENABLE)) {
bean.setIsEnable(true);
LogUtils.d(TAG, "setIsEnable(true);");
TestDemoBindServiceBean.saveBean(this, bean);
} else if (intent.getAction().equals(ACTION_DISABLE)) {
bean.setIsEnable(false);
LogUtils.d(TAG, "setIsEnable(false);");
TestDemoBindServiceBean.saveBean(this, bean);
}
}
run();
return (bean.isEnable()) ? START_STICKY : super.onStartCommand(intent, flags, startId);
//return super.onStartCommand(intent, flags, startId);
}
void run() {
LogUtils.d(TAG, "run()");
TestDemoBindServiceBean bean = TestDemoBindServiceBean.loadBean(this, TestDemoBindServiceBean.class);
if (bean == null) {
bean = new TestDemoBindServiceBean();
TestDemoBindServiceBean.saveBean(this, bean);
}
if (bean.isEnable()) {
LogUtils.d(TAG, "run() bean.isEnable()");
TestThread.getInstance(this).start();
LogUtils.d(TAG, "_TestThread.start()");
}
}
@Override
public void onDestroy() {
super.onDestroy();
LogUtils.d(TAG, "onDestroy()");
TestDemoBindServiceBean bean = TestDemoBindServiceBean.loadBean(this, TestDemoBindServiceBean.class);
if (bean == null) {
bean = new TestDemoBindServiceBean();
}
TestThread.getInstance(this).setIsExit(true);
// 预防 APPBase 应用重启绑定失效
// 所以退出时检查本服务是否配置启用如果启用就发送一个 SOS 信号
// 这样 APPBase 就会用组件方式启动本服务
if (bean.isEnable()) {
if (App.isDebuging()) {
SOS.sosToAppBaseBeta(this, TestDemoBindService.class.getName());
} else {
SOS.sosToAppBase(this, TestDemoBindService.class.getName());
}
}
_IsRunning = false;
}
static class TestThread extends Thread {
volatile static TestThread _TestThread;
Context mContext;
volatile boolean isStarted = false;
volatile boolean isExit = false;
TestThread(Context context) {
super();
mContext = context;
}
public static synchronized TestThread getInstance(Context context) {
if (_TestThread != null) {
_TestThread.setIsExit(true);
}
_TestThread = new TestThread(context);
return _TestThread;
}
public synchronized void setIsExit(boolean isExit) {
this.isExit = isExit;
}
public boolean isExit() {
return isExit;
}
@Override
public void run() {
if (isStarted == false) {
isStarted = true;
super.run();
LogUtils.d(TAG, "run() start");
if (App.isDebuging()) {
WinBoll.bindToAPPBaseBeta(mContext, TestDemoBindService.class.getName());
} else {
WinBoll.bindToAPPBase(mContext, TestDemoBindService.class.getName());
}
while (!isExit()) {
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,23 +1,25 @@
package cc.winboll.studio.libappbase.services; package cc.winboll.studio.appbase.services;
/** /**
* @Author ZhanGSKen@AliYun.Com * @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/15 20:48:36 * @Date 2025/03/07 12:39:24
* @Describe TestService * @Describe 普通服务示例
*/ */
import android.app.Service; import android.app.Service;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import cc.winboll.studio.appbase.beans.TestDemoServiceBean;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.SOS; import cc.winboll.studio.libappbase.sos.WinBoll;
import cc.winboll.studio.libappbase.bean.APPSOSBean;
import cc.winboll.studio.libappbase.bean.TestServiceBean;
public class TestService extends Service { public class TestDemoService extends Service {
public static final String TAG = "TestService"; public static final String TAG = "TestDemoService";
public static final String ACTION_ENABLE = TestDemoService.class.getName() + ".ACTION_ENABLE";
public static final String ACTION_DISABLE = TestDemoService.class.getName() + ".ACTION_DISABLE";
volatile static TestThread _TestThread; volatile static TestThread _TestThread;
@ -37,8 +39,8 @@ public class TestService extends Service {
} }
public class MyBinder extends Binder { public class MyBinder extends Binder {
public TestService getService() { public TestDemoService getService() {
return TestService.this; return TestDemoService.this;
} }
} }
@ -54,29 +56,35 @@ public class TestService extends Service {
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
LogUtils.d(TAG, "onStartCommand(...)"); LogUtils.d(TAG, "onStartCommand(...)");
TestServiceBean bean = TestServiceBean.loadBean(this, TestServiceBean.class); TestDemoServiceBean bean = TestDemoServiceBean.loadBean(this, TestDemoServiceBean.class);
if (bean == null) { if (bean == null) {
bean = new TestServiceBean(); bean = new TestDemoServiceBean();
} }
if (intent.getAction() != null && intent.getAction().equals(SOS.ACTION_SERVICE_ENABLE)) {
bean.setIsEnable(true); if (intent.getAction() != null) {
TestServiceBean.saveBean(this, bean); if (intent.getAction().equals(ACTION_ENABLE)) {
run(); bean.setIsEnable(true);
} else if (intent.getAction() != null && intent.getAction().equals(SOS.ACTION_SERVICE_DISABLE)) { LogUtils.d(TAG, "setIsEnable(true);");
bean.setIsEnable(false); TestDemoServiceBean.saveBean(this, bean);
TestServiceBean.saveBean(this, bean); } else if (intent.getAction().equals(ACTION_DISABLE)) {
bean.setIsEnable(false);
LogUtils.d(TAG, "setIsEnable(false);");
TestDemoServiceBean.saveBean(this, bean);
}
} }
LogUtils.d(TAG, String.format("TestServiceBean.saveBean setIsEnable %s", bean.isEnable()));
run();
return (bean.isEnable()) ? START_STICKY : super.onStartCommand(intent, flags, startId); return (bean.isEnable()) ? START_STICKY : super.onStartCommand(intent, flags, startId);
//return super.onStartCommand(intent, flags, startId); //return super.onStartCommand(intent, flags, startId);
} }
void run() { void run() {
LogUtils.d(TAG, "run()"); LogUtils.d(TAG, "run()");
TestServiceBean bean = TestServiceBean.loadBean(this, TestServiceBean.class); TestDemoServiceBean bean = TestDemoServiceBean.loadBean(this, TestDemoServiceBean.class);
if (bean == null) { if (bean == null) {
bean = new TestServiceBean(); bean = new TestDemoServiceBean();
TestServiceBean.saveBean(this, bean); TestDemoServiceBean.saveBean(this, bean);
} }
if (bean.isEnable()) { if (bean.isEnable()) {
LogUtils.d(TAG, "run() bean.isEnable()"); LogUtils.d(TAG, "run() bean.isEnable()");
@ -130,7 +138,6 @@ public class TestService extends Service {
isStarted = true; isStarted = true;
super.run(); super.run();
LogUtils.d(TAG, "run() start"); LogUtils.d(TAG, "run() start");
SOS.bindToAPPService(mContext, new APPSOSBean(mContext.getPackageName(), TestService.class.getName()));
while (!isExit()) { while (!isExit()) {
LogUtils.d(TAG, "run()"); LogUtils.d(TAG, "run()");

View File

@ -12,31 +12,32 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.widget.RemoteViews; import android.widget.RemoteViews;
import cc.winboll.studio.appbase.R; import cc.winboll.studio.appbase.R;
import cc.winboll.studio.appbase.beans.SOSReportBean; import cc.winboll.studio.appbase.beans.WinBollNewsBean;
import cc.winboll.studio.libappbase.AppUtils; import cc.winboll.studio.libappbase.AppUtils;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.bean.APPSOSBean;
import java.io.IOException; import java.io.IOException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import cc.winboll.studio.libappbase.sos.APPModel;
import cc.winboll.studio.libappbase.sos.WinBoll;
public class SOSWidget extends AppWidgetProvider { public class APPNewsWidget extends AppWidgetProvider {
public static final String TAG = "SOSWidget"; public static final String TAG = "APPNewsWidget";
public static final String ACTION_WAKEUP_SERVICE = "cc.winboll.studio.appbase.widgets.SOSWidget.ACTION_WAKEUP_SERVICE"; public static final String ACTION_WAKEUP_SERVICE = APPNewsWidget.class.getName() + ".ACTION_WAKEUP_SERVICE";
public static final String ACTION_RELOAD_REPORT = "cc.winboll.studio.appbase.widgets.SOSWidget.ACTION_RELOAD_REPORT"; public static final String ACTION_RELOAD_REPORT = APPNewsWidget.class.getName() + ".ACTION_RELOAD_REPORT";
volatile static ArrayList<SOSReportBean> _SOSReportBeanList; volatile static ArrayList<WinBollNewsBean> _WinBollNewsBeanList;
final static int _MAX_PAGES = 10; final static int _MAX_PAGES = 10;
final static int _OnePageLinesCount = 5; final static int _OnePageLinesCount = 5;
volatile static int _CurrentPageIndex = 0; volatile static int _CurrentPageIndex = 0;
@Override @Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
initAPPSOSReportBeanList(context); initWinBollNewsBeanList(context);
for (int appWidgetId : appWidgetIds) { for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId); updateAppWidget(context, appWidgetManager, appWidgetId);
} }
@ -45,31 +46,31 @@ public class SOSWidget extends AppWidgetProvider {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent); super.onReceive(context, intent);
initAPPSOSReportBeanList(context); initWinBollNewsBeanList(context);
if (intent.getAction().equals(ACTION_RELOAD_REPORT)) { if (intent.getAction().equals(ACTION_RELOAD_REPORT)) {
LogUtils.d(TAG, "ACTION_RELOAD_REPORT"); LogUtils.d(TAG, "ACTION_RELOAD_REPORT");
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, SOSWidget.class)); int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, APPNewsWidget.class));
for (int appWidgetId : appWidgetIds) { for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId); updateAppWidget(context, appWidgetManager, appWidgetId);
} }
}else if (intent.getAction().equals(ACTION_WAKEUP_SERVICE)) { }else if (intent.getAction().equals(ACTION_WAKEUP_SERVICE)) {
LogUtils.d(TAG, "ACTION_WAKEUP_SERVICE"); LogUtils.d(TAG, "ACTION_WAKEUP_SERVICE");
String szAPPSOSBean = intent.getStringExtra("APPSOSBean"); String szAPPModel = intent.getStringExtra(WinBoll.EXTRA_APPMODEL);
LogUtils.d(TAG, String.format("szAPPSOSBean %s", szAPPSOSBean)); LogUtils.d(TAG, String.format("szAPPModel %s", szAPPModel));
if (szAPPSOSBean != null && !szAPPSOSBean.equals("")) { if (szAPPModel != null && !szAPPModel.equals("")) {
try { try {
APPSOSBean bean = APPSOSBean.parseStringToBean(szAPPSOSBean, APPSOSBean.class); APPModel bean = APPModel.parseStringToBean(szAPPModel, APPModel.class);
if (bean != null) { if (bean != null) {
String sosPackage = bean.getSosPackage(); String szAppPackageName = bean.getAppPackageName();
LogUtils.d(TAG, String.format("sosPackage %s", sosPackage)); LogUtils.d(TAG, String.format("szAppPackageName %s", szAppPackageName));
String sosClassName = bean.getSosClassName(); String szAppMainServiveName = bean.getAppMainServiveName();
LogUtils.d(TAG, String.format("sosClassName %s", sosClassName)); LogUtils.d(TAG, String.format("szAppMainServiveName %s", szAppMainServiveName));
String appName = AppUtils.getAppNameByPackageName(context, sosPackage); String appName = AppUtils.getAppNameByPackageName(context, szAppPackageName);
LogUtils.d(TAG, String.format("appName %s", appName)); LogUtils.d(TAG, String.format("appName %s", appName));
SOSReportBean appSOSReportBean = new SOSReportBean(appName); WinBollNewsBean winBollNewsBean = new WinBollNewsBean(appName);
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
String currentTime = sdf.format(new Date()); String currentTime = sdf.format(new Date());
StringBuilder sbLine = new StringBuilder(); StringBuilder sbLine = new StringBuilder();
@ -77,12 +78,12 @@ public class SOSWidget extends AppWidgetProvider {
sbLine.append(currentTime); sbLine.append(currentTime);
sbLine.append("] Wake up "); sbLine.append("] Wake up ");
sbLine.append(appName); sbLine.append(appName);
appSOSReportBean.setSosReport(sbLine.toString()); winBollNewsBean.setMessage(sbLine.toString());
addAPPSOSReportBean(context, appSOSReportBean); addWinBollNewsBean(context, winBollNewsBean);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, SOSWidget.class)); int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, APPNewsWidget.class));
for (int appWidgetId : appWidgetIds) { for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId); updateAppWidget(context, appWidgetManager, appWidgetId);
} }
@ -97,53 +98,53 @@ public class SOSWidget extends AppWidgetProvider {
// //
// 加入新报告信息 // 加入新报告信息
// //
public synchronized static void addAPPSOSReportBean(Context context, SOSReportBean bean) { public synchronized static void addWinBollNewsBean(Context context, WinBollNewsBean bean) {
initAPPSOSReportBeanList(context); initWinBollNewsBeanList(context);
_SOSReportBeanList.add(0, bean); _WinBollNewsBeanList.add(0, bean);
// 控制记录总数 // 控制记录总数
while (_SOSReportBeanList.size() > _MAX_PAGES * _OnePageLinesCount) { while (_WinBollNewsBeanList.size() > _MAX_PAGES * _OnePageLinesCount) {
_SOSReportBeanList.remove(_SOSReportBeanList.size() - 1); _WinBollNewsBeanList.remove(_WinBollNewsBeanList.size() - 1);
} }
SOSReportBean.saveBeanList(context, _SOSReportBeanList, SOSReportBean.class); WinBollNewsBean.saveBeanList(context, _WinBollNewsBeanList, WinBollNewsBean.class);
} }
synchronized static void initAPPSOSReportBeanList(Context context) { synchronized static void initWinBollNewsBeanList(Context context) {
if (_SOSReportBeanList == null) { if (_WinBollNewsBeanList == null) {
_SOSReportBeanList = new ArrayList<SOSReportBean>(); _WinBollNewsBeanList = new ArrayList<WinBollNewsBean>();
SOSReportBean.loadBeanList(context, _SOSReportBeanList, SOSReportBean.class); WinBollNewsBean.loadBeanList(context, _WinBollNewsBeanList, WinBollNewsBean.class);
} }
if (_SOSReportBeanList == null) { if (_WinBollNewsBeanList == null) {
_SOSReportBeanList = new ArrayList<SOSReportBean>(); _WinBollNewsBeanList = new ArrayList<WinBollNewsBean>();
SOSReportBean.saveBeanList(context, _SOSReportBeanList, SOSReportBean.class); WinBollNewsBean.saveBeanList(context, _WinBollNewsBeanList, WinBollNewsBean.class);
} }
} }
private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
LogUtils.d(TAG, "updateAppWidget(...)"); LogUtils.d(TAG, "updateAppWidget(...)");
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_sos); RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_news);
//设置按钮点击事件 //设置按钮点击事件
Intent intentPre = new Intent(context, SOSWidgetClickListener.class); Intent intentPre = new Intent(context, APPNewsWidgetClickListener.class);
intentPre.setAction(SOSWidgetClickListener.ACTION_PRE); intentPre.setAction(APPNewsWidgetClickListener.ACTION_PRE);
PendingIntent pendingIntentPre = PendingIntent.getBroadcast(context, 0, intentPre, PendingIntent.FLAG_UPDATE_CURRENT); PendingIntent pendingIntentPre = PendingIntent.getBroadcast(context, 0, intentPre, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.widget_button_pre, pendingIntentPre); views.setOnClickPendingIntent(R.id.widget_button_pre, pendingIntentPre);
Intent intentNext = new Intent(context, SOSWidgetClickListener.class); Intent intentNext = new Intent(context, APPNewsWidgetClickListener.class);
intentNext.setAction(SOSWidgetClickListener.ACTION_NEXT); intentNext.setAction(APPNewsWidgetClickListener.ACTION_NEXT);
PendingIntent pendingIntentNext = PendingIntent.getBroadcast(context, 0, intentNext, PendingIntent.FLAG_UPDATE_CURRENT); PendingIntent pendingIntentNext = PendingIntent.getBroadcast(context, 0, intentNext, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.widget_button_next, pendingIntentNext); views.setOnClickPendingIntent(R.id.widget_button_next, pendingIntentNext);
views.setTextViewText(R.id.infoTextView, getPageInfo()); views.setTextViewText(R.id.tv_msg, getPageInfo());
views.setTextViewText(R.id.sosReportTextView, getMessage()); views.setTextViewText(R.id.tv_news, getMessage());
appWidgetManager.updateAppWidget(appWidgetId, views); appWidgetManager.updateAppWidget(appWidgetId, views);
} }
public static String getMessage() { public static String getMessage() {
ArrayList<String> msgTemp = new ArrayList<String>(); ArrayList<String> msgTemp = new ArrayList<String>();
if (_SOSReportBeanList != null) { if (_WinBollNewsBeanList != null) {
int start = _OnePageLinesCount * _CurrentPageIndex; int start = _OnePageLinesCount * _CurrentPageIndex;
start = _SOSReportBeanList.size() > start ? start : _SOSReportBeanList.size() - 1; start = _WinBollNewsBeanList.size() > start ? start : _WinBollNewsBeanList.size() - 1;
for (int i = start, j = 0; i < _SOSReportBeanList.size() && j < _OnePageLinesCount && start > -1; i++, j++) { for (int i = start, j = 0; i < _WinBollNewsBeanList.size() && j < _OnePageLinesCount && start > -1; i++, j++) {
msgTemp.add(_SOSReportBeanList.get(i).getSosReport()); msgTemp.add(_WinBollNewsBeanList.get(i).getMessage());
} }
String message = String.join("\n", msgTemp); String message = String.join("\n", msgTemp);
return message; return message;
@ -152,33 +153,33 @@ public class SOSWidget extends AppWidgetProvider {
} }
public static void prePage(Context context) { public static void prePage(Context context) {
if (_SOSReportBeanList != null) { if (_WinBollNewsBeanList != null) {
if (_CurrentPageIndex > 0) { if (_CurrentPageIndex > 0) {
_CurrentPageIndex = _CurrentPageIndex - 1; _CurrentPageIndex = _CurrentPageIndex - 1;
} }
Intent intentWidget = new Intent(context, SOSWidget.class); Intent intentWidget = new Intent(context, APPNewsWidget.class);
intentWidget.setAction(SOSWidget.ACTION_RELOAD_REPORT); intentWidget.setAction(APPNewsWidget.ACTION_RELOAD_REPORT);
context.sendBroadcast(intentWidget); context.sendBroadcast(intentWidget);
} }
} }
public static void nextPage(Context context) { public static void nextPage(Context context) {
if (_SOSReportBeanList != null) { if (_WinBollNewsBeanList != null) {
if ((_CurrentPageIndex + 1) * _OnePageLinesCount < _SOSReportBeanList.size()) { if ((_CurrentPageIndex + 1) * _OnePageLinesCount < _WinBollNewsBeanList.size()) {
_CurrentPageIndex = _CurrentPageIndex + 1; _CurrentPageIndex = _CurrentPageIndex + 1;
} }
Intent intentWidget = new Intent(context, SOSWidget.class); Intent intentWidget = new Intent(context, APPNewsWidget.class);
intentWidget.setAction(SOSWidget.ACTION_RELOAD_REPORT); intentWidget.setAction(APPNewsWidget.ACTION_RELOAD_REPORT);
context.sendBroadcast(intentWidget); context.sendBroadcast(intentWidget);
} }
} }
String getPageInfo() { String getPageInfo() {
if (_SOSReportBeanList == null) { if (_WinBollNewsBeanList == null) {
return "0/0"; return "0/0";
} }
int leftCount = _SOSReportBeanList.size() % _OnePageLinesCount; int leftCount = _WinBollNewsBeanList.size() % _OnePageLinesCount;
int currentPageCount = _SOSReportBeanList.size() / _OnePageLinesCount + (leftCount == 0 ?0: 1); int currentPageCount = _WinBollNewsBeanList.size() / _OnePageLinesCount + (leftCount == 0 ?0: 1);
return String.format("%d/%d", _CurrentPageIndex + 1, currentPageCount); return String.format("%d/%d", _CurrentPageIndex + 1, currentPageCount);
} }
} }

View File

@ -10,11 +10,11 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
public class SOSWidgetClickListener extends BroadcastReceiver { public class APPNewsWidgetClickListener extends BroadcastReceiver {
public static final String TAG = "SOSWidgetClickListener"; public static final String TAG = "APPNewsWidgetClickListener";
public static final String ACTION_PRE = "cc.winboll.studio.appbase.widgets.SOSWidgetClickListener.ACTION_PRE"; public static final String ACTION_PRE = APPNewsWidgetClickListener.class.getName() + ".ACTION_PRE";
public static final String ACTION_NEXT = "cc.winboll.studio.appbase.widgets.SOSWidgetClickListener.ACTION_NEXT"; public static final String ACTION_NEXT = APPNewsWidgetClickListener.class.getName() + ".ACTION_NEXT";
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
@ -25,10 +25,10 @@ public class SOSWidgetClickListener extends BroadcastReceiver {
} }
if (action.equals(ACTION_PRE)) { if (action.equals(ACTION_PRE)) {
LogUtils.d(TAG, "ACTION_PRE"); LogUtils.d(TAG, "ACTION_PRE");
SOSWidget.prePage(context); APPNewsWidget.prePage(context);
} else if (action.equals(ACTION_NEXT)) { } else if (action.equals(ACTION_NEXT)) {
LogUtils.d(TAG, "ACTION_NEXT"); LogUtils.d(TAG, "ACTION_NEXT");
SOSWidget.nextPage(context); APPNewsWidget.nextPage(context);
} else { } else {
LogUtils.d(TAG, String.format("action %s", action)); LogUtils.d(TAG, String.format("action %s", action));
} }

View File

@ -1,149 +1,194 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" 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:orientation="vertical"
android:gravity="center"> android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/activitymainToolbar1"/> android:id="@+id/activitymainToolbar1"/>
<LinearLayout <ScrollView
android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1.0" android:layout_weight="1.0">
android:gravity="center_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, WinBoll!"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Android版本10的代号是“Q”API级别是29。 Android 10开始谷歌不再公开使用甜品作为版本代号但内部仍保留了大量与“Q”相关的元素。Android 10本身并没有严格对应某个特定的Java版本但在开发Android 10应用时通常可以使用Java 8或更高版本。
Java 8为Android开发带来了诸如Lambda表达式、方法引用等新特性能提高开发效率和代码可读性与Android 10开发适配良好。Java 9及更高版本也可用于Android 10开发能使用一些新的语言特性和API但可能需要注意兼容性和配置问题。"/>
<LinearLayout <LinearLayout
android:orientation="horizontal" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="right|center_vertical"> android:orientation="vertical"
android:gravity="center">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Debug Mode"
android:layout_weight="1.0"
android:onClick="onSwitchDebugMode"
android:id="@+id/activitymainCheckBox1"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test Application CrashReport"
android:textAllCaps="false"
android:onClick="onTestApplicationCrashReport"/>
</LinearLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="400dp">
<LinearLayout <LinearLayout
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="0dp"
android:gravity="right"> android:layout_weight="1.0"
android:gravity="center_horizontal">
<HorizontalScrollView <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, WinBoll!"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Android版本10的代号是“Q”API级别是29。 Android 10开始谷歌不再公开使用甜品作为版本代号但内部仍保留了大量与“Q”相关的元素。Android 10本身并没有严格对应某个特定的Java版本但在开发Android 10应用时通常可以使用Java 8或更高版本。 Java 8为Android开发带来了诸如Lambda表达式、方法引用等新特性能提高开发效率和代码可读性与Android 10开发适配良好。Java 9及更高版本也可用于Android 10开发能使用一些新的语言特性和API但可能需要注意兼容性和配置问题。"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
android:gravity="right|center_vertical">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Debug Mode"
android:layout_weight="1.0"
android:onClick="onSwitchDebugMode"
android:id="@+id/activitymainCheckBox1"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test Application CrashReport"
android:textAllCaps="false"
android:onClick="onTestApplicationCrashReport"/>
</LinearLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="400dp">
<LinearLayout <LinearLayout
android:orientation="horizontal" android:orientation="vertical"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
android:gravity="right">
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SartTestDemoService"
android:textAllCaps="false"
android:onClick="onSartTestDemoService"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StopTestDemoService"
android:textAllCaps="false"
android:onClick="onStopTestDemoService"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StopTestDemoServiceNoSettings"
android:textAllCaps="false"
android:onClick="onStopTestDemoServiceNoSettings"/>
</LinearLayout>
</HorizontalScrollView>
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SartTestDemoBindService"
android:textAllCaps="false"
android:onClick="onSartTestDemoBindService"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StopTestDemoBindService"
android:textAllCaps="false"
android:onClick="onStopTestDemoBindService"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StopTestDemoBindServiceNoSettings"
android:textAllCaps="false"
android:onClick="onStopTestDemoBindServiceNoSettings"/>
</LinearLayout>
</HorizontalScrollView>
<Button <Button
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="StartTestService" android:text="StartCenter"
android:textAllCaps="false" android:textAllCaps="false"
android:onClick="onStartTestService"/> android:onClick="onStartCenter"/>
<Button <Button
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="StopTestService" android:text="StopCenter"
android:textAllCaps="false" android:textAllCaps="false"
android:onClick="onStopTestService"/> android:onClick="onStopCenter"/>
<Button <Button
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="StopTestServiceNoSettings" android:text="TestStopMainServiceWithoutSettingEnable"
android:textAllCaps="false" android:textAllCaps="false"
android:onClick="onStopTestServiceNoSettings"/> android:onClick="onTestStopMainServiceWithoutSettingEnable"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TestUseComponentStartService"
android:textAllCaps="false"
android:onClick="onTestUseComponentStartService"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TestSOS"
android:textAllCaps="false"
android:onClick="onTestSOS"/>
</LinearLayout> </LinearLayout>
</HorizontalScrollView> </ScrollView>
<Button <cc.winboll.studio.libappbase.LogView
android:layout_width="wrap_content" android:layout_height="500dp"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:text="StartCenter" android:id="@+id/activitymainLogView1"/>
android:textAllCaps="false"
android:onClick="onStartCenter"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="StopCenter"
android:textAllCaps="false"
android:onClick="onStopCenter"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TestStopWithoutSettingEnable"
android:textAllCaps="false"
android:onClick="onTestStopWithoutSettingEnable"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TestStartWithString"
android:textAllCaps="false"
android:onClick="onTestStartWithString"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SOS"
android:textAllCaps="false"
android:onClick="onSOS"/>
</LinearLayout> </LinearLayout>
</ScrollView> </LinearLayout>
<cc.winboll.studio.libappbase.LogView </ScrollView>
android:layout_weight="1.0"
android:layout_height="0dp"
android:layout_width="match_parent"
android:id="@+id/activitymainLogView1"/>
</LinearLayout>
</LinearLayout> </LinearLayout>

View File

@ -11,31 +11,40 @@
android:orientation="horizontal" android:orientation="horizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="right"> android:gravity="right|center_vertical">
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/infoTextView"/> android:id="@+id/tv_title"
android:layout_weight="1.0"
<Button android:text="WinBollNews"
android:layout_width="wrap_content" android:textStyle="bold"
android:layout_height="wrap_content" android:textSize="16sp"/>
android:text="⇦"
android:id="@+id/widget_button_pre"/>
<Button <Button
android:layout_width="wrap_content" android:layout_width="48dp"
android:layout_height="wrap_content" android:layout_height="48dp"
android:text="⇦"
android:id="@+id/widget_button_pre"/>
<Button
android:layout_width="48dp"
android:layout_height="48dp"
android:text="⇨" android:text="⇨"
android:id="@+id/widget_button_next"/> android:id="@+id/widget_button_next"/>
</LinearLayout> </LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tv_msg"/>
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:id="@+id/sosReportTextView" android:id="@+id/tv_news"
android:layout_weight="1.0"/> android:layout_weight="1.0"/>
</LinearLayout> </LinearLayout>

View File

@ -3,5 +3,5 @@
android:minWidth="200dp" android:minWidth="200dp"
android:minHeight="100dp" android:minHeight="100dp"
android:updatePeriodMillis="1000" android:updatePeriodMillis="1000"
android:initialLayout="@layout/widget_sos"> android:initialLayout="@layout/widget_news">
</appwidget-provider> </appwidget-provider>

View File

@ -9,13 +9,14 @@ buildscript {
maven { url "https://jitpack.io" } maven { url "https://jitpack.io" }
mavenCentral() mavenCentral()
google() google()
mavenLocal()
// Nexus Maven // Nexus Maven
// "WinBoll Release" // "WinBoll Release"
maven { url "https://nexus.winboll.cc/repository/maven-public/" } maven { url "https://nexus.winboll.cc/repository/maven-public/" }
// "WinBoll Snapshot" // "WinBoll Snapshot"
maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" } maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" }
mavenLocal()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.2.1' classpath 'com.android.tools.build:gradle:7.2.1'
@ -26,13 +27,6 @@ buildscript {
allprojects { allprojects {
repositories { repositories {
maven {
url "https://mirrors.tencent.com/repository/maven/tencent_public/"
}
maven {
url "https://mirrors.tencent.com/repository/maven/tencent_public_snapshots"
}
maven { url 'https://maven.aliyun.com/repository/public/' } maven { url 'https://maven.aliyun.com/repository/public/' }
maven { url 'https://maven.aliyun.com/repository/google/' } maven { url 'https://maven.aliyun.com/repository/google/' }
maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' } maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' }
@ -41,13 +35,14 @@ allprojects {
maven { url "https://jitpack.io" } maven { url "https://jitpack.io" }
mavenCentral() mavenCentral()
google() google()
mavenLocal()
// Nexus Maven // Nexus Maven
// "WinBoll Release" // "WinBoll Release"
maven { url "https://nexus.winboll.cc/repository/maven-public/" } maven { url "https://nexus.winboll.cc/repository/maven-public/" }
// "WinBoll Snapshot" // "WinBoll Snapshot"
maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" } maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" }
mavenLocal()
} }
ext { ext {
// //

40
contacts/README.md Normal file
View File

@ -0,0 +1,40 @@
# Contacts
源码参考自:
https://github.com/aJIEw/PhoneCallApp.git
#### 介绍
通讯录与拨号
#### 软件架构
适配安卓应用 [AIDE Pro] 的 Gradle 编译结构。
也适配安卓应用 [AndroidIDE] 的 Gradle 编译结构。
#### Gradle 编译说明
调试版编译命令 gradle assembleBetaDebug
阶段版编译命令 gradle assembleStageRelease
#### 使用说明
在安卓系统中需要设置两个权限允许。
1.自启动权限允许。
2.省电策略-无限制权限允许。
#### 参与贡献
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码 : ZhanGSKen(ZhanGSKen@AliYun.Com)
4. 新建 Pull Request
#### 特技
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
#### 参考文档

View File

@ -0,0 +1 @@

71
contacts/build.gradle Normal file
View File

@ -0,0 +1,71 @@
apply plugin: 'com.android.application'
apply from: '../.winboll/winboll_app_build.gradle'
apply from: '../.winboll/winboll_lint_build.gradle'
def genVersionName(def versionName){
//
assert (winbollBuildProps['stageCount'] != null)
assert (winbollBuildProps['baseVersion'] != null)
//
winbollBuildProps.setProperty("baseVersion", "${versionName}");
//
FileOutputStream fos = new FileOutputStream(winbollBuildPropsFile)
winbollBuildProps.store(fos, "${winbollBuildPropsDesc}");
fos.close();
//
return "${versionName}." + winbollBuildProps['stageCount']
}
android {
compileSdkVersion 32
buildToolsVersion "33.0.3"
defaultConfig {
applicationId "cc.winboll.studio.contacts"
minSdkVersion 21
targetSdkVersion 30
versionCode 1
// versionName
// build.gradle stageCount=0
// Gradle编译环境下合起来的 versionName "${versionName}.0"
versionName "1.0"
if(true) {
versionName = genVersionName("${versionName}")
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
}
dependencies {
// 使
api 'com.google.zxing:core:3.4.1'
api 'com.journeyapps:zxing-android-embedded:3.6.0'
api 'io.github.medyo:android-about-page:2.0.0'
api 'com.github.getActivity:ToastUtils:10.5'
api 'com.jcraft:jsch:0.1.55'
api 'org.jsoup:jsoup:1.13.1'
api 'com.squareup.okhttp3:okhttp:4.4.1'
api 'androidx.appcompat:appcompat:1.1.0'
api 'androidx.viewpager:viewpager:1.0.0'
api 'androidx.fragment:fragment:1.1.0'
api 'com.google.android.material:material:1.4.0'
api 'cc.winboll.studio:libapputils:9.3.2'
api 'cc.winboll.studio:libappbase:1.5.6'
api fileTree(dir: 'libs', include: ['*.jar'])
}

View File

@ -0,0 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Tue Feb 25 00:17:29 HKT 2025
stageCount=2
libraryProject=
baseVersion=1.0
publishVersion=1.0.1
buildCount=0
baseBetaVersion=1.0.2

17
contacts/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\tools\adt-bundle-windows-x86_64-20131030\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" >
<application
tools:replace="android:icon"
android:icon="@drawable/ic_winbollbeta">
<!-- Put flavor specific code here -->
</application>
</manifest>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Contacts+</string>
</resources>

View File

@ -0,0 +1,187 @@
<?xml version='1.0' encoding='utf-8'?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="cc.winboll.studio.contacts">
<!-- BIND_AUTOFILL_SERVICE -->
<uses-permission android:name="android.permission.BIND_AUTOFILL_SERVICE"/>
<!-- 拨打电话 -->
<uses-permission android:name="android.permission.CALL_PHONE"/>
<!-- 读取手机状态和身份 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<!-- 修改系统设置 -->
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<!-- 重新设置外拨电话的路径 -->
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<!-- 读取联系人 -->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<!-- 修改您的通讯录 -->
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<!-- 此应用可显示在其他应用上方 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<!-- 更改您的音频设置 -->
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<application
android:name=".App"
android:allowBackup="true"
android:icon="@drawable/ic_winboll"
android:label="@string/app_name"
android:theme="@style/MyAppTheme"
android:supportsRtl="true">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".activities.CallActivity"
android:label="CallActivity"
android:launchMode="singleTask"
android:exported="true">
</activity>
<activity
android:name=".phonecallui.PhoneCallActivity"
android:launchMode="singleInstance"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.DIAL"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="tel"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.DIAL"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name="cc.winboll.studio.contacts.activities.SettingsActivity"/>
<service
android:name="cc.winboll.studio.contacts.services.MainService"
android:exported="true"/>
<service android:name="cc.winboll.studio.contacts.services.AssistantService"/>
<service
android:name=".phonecallui.PhoneCallService"
android:permission="android.permission.BIND_INCALL_SERVICE"
android:exported="false">
<meta-data
android:name="android.telecom.IN_CALL_SERVICE_UI"
android:value="true"/>
<intent-filter>
<action android:name="android.telecom.InCallService"/>
</intent-filter>
</service>
<service
android:name=".listenphonecall.CallListenerService"
android:enabled="true"
android:exported="false">
<intent-filter android:priority="1000">
<action android:name=".service.CallShowService"/>
</intent-filter>
</service>
<receiver android:name=".receivers.MainReceiver">
<intent-filter>
<action android:name="cc.winboll.studio.contacts.receivers.MainReceiver"/>
</intent-filter>
</receiver>
<receiver
android:name=".widgets.APPStatusWidget"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
<action android:name="cc.winboll.studio.contacts.widgets.APPStatusWidget.ACTION_STATUS_ACTIVE"/>
<action android:name="cc.winboll.studio.contacts.widgets.APPStatusWidget.ACTION_STATUS_NOACTIVE"/>
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/appwidget_provider_info"/>
</receiver>
<receiver android:name=".widgets.APPStatusWidgetClickListener">
<intent-filter>
<action android:name="cc.winboll.studio.contacts.widgets.APPStatusWidgetClickListener.ACTION_APPICON_CLICK"/>
</intent-filter>
</receiver>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/studio_provider"/>
</provider>
</application>
</manifest>

View File

@ -0,0 +1,59 @@
package cc.winboll.studio.contacts;
import android.app.Activity;
import java.util.ArrayList;
import java.util.List;
public class ActivityStack {
private static final ActivityStack INSTANCE = new ActivityStack();
private List<Activity> activities = new ArrayList<>();
public static ActivityStack getInstance() {
return INSTANCE;
}
public void addActivity(Activity activity) {
activities.add(activity);
}
public Activity getTopActivity() {
if (activities.isEmpty()) {
return null;
}
return activities.get(activities.size() - 1);
}
public void finishTopActivity() {
if (!activities.isEmpty()) {
activities.remove(activities.size() - 1).finish();
}
}
public void finishActivity(Activity activity) {
if (activity != null) {
activities.remove(activity);
activity.finish();
}
}
public void finishActivity(Class activityClass) {
for (Activity activity : activities) {
if (activity.getClass().equals(activityClass)) {
finishActivity(activity);
}
}
}
public void finishAllActivity() {
if (!activities.isEmpty()) {
for (Activity activity : activities) {
activity.finish();
activities.remove(activity);
}
}
}
}

View File

@ -0,0 +1,28 @@
package cc.winboll.studio.contacts;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2024/12/08 15:10:51
* @Describe 全局应用类
*/
import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libapputils.app.WinBollActivityManager;
public class App extends GlobalApplication {
public static final String TAG = "App";
@Override
public void onCreate() {
// 必须在调用基类前设置应用调试标志
// 这样可以预先设置日志与数据的存储根目录
setIsDebuging(this, BuildConfig.DEBUG);
super.onCreate();
// 设置 WinBoll 应用 UI 类型
WinBollActivityManager.getInstance(this).setWinBollUI_TYPE(WinBollActivityManager.WinBollUI_TYPE.Aplication);
LogUtils.d(TAG, "onCreate");
}
}

View File

@ -0,0 +1,406 @@
package cc.winboll.studio.contacts;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.role.RoleManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.telecom.TelecomManager;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Switch;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.viewpager.widget.ViewPager;
import cc.winboll.studio.contacts.R;
import cc.winboll.studio.contacts.activities.CallActivity;
import cc.winboll.studio.contacts.adapters.MyPagerAdapter;
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.LogView;
import cc.winboll.studio.libapputils.app.IWinBollActivity;
import cc.winboll.studio.libapputils.app.WinBollActivityManager;
import cc.winboll.studio.libapputils.bean.APPInfo;
import cc.winboll.studio.libapputils.view.YesNoAlertDialog;
import cc.winboll.studio.contacts.listenphonecall.CallListenerService;
import com.google.android.material.tabs.TabLayout;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import android.content.DialogInterface;
import cc.winboll.studio.contacts.activities.SettingsActivity;
final public class MainActivity extends AppCompatActivity implements IWinBollActivity, ViewPager.OnPageChangeListener, View.OnClickListener {
public static final String TAG = "MainActivity";
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;
MainServiceBean mMainServiceBean;
ViewPager viewPager;
private List<View> views; //用来存放放进ViewPager里面的布局
//实例化存储imageView导航原点的集合
ImageView[] imageViews;
//MyPagerAdapter adapter;//适配器
MyPagerAdapter pagerAdapter;
LinearLayout linearLayout;//下标所在在LinearLayout布局里
int currentPoint = 0;//当前被选中中页面的下标
private static final int DIALER_REQUEST_CODE = 1;
@Override
public AppCompatActivity getActivity() {
return this;
}
@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;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// 接收并处理 Intent 数据函数 Intent 处理接收就直接返回
//if (prosessIntents(getIntent())) return;
// 以下正常创建主窗口
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化工具栏
mToolbar = findViewById(R.id.activitymainToolbar1);
setSupportActionBar(mToolbar);
if (isEnableDisplayHomeAsUp()) {
// 显示后退按钮
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
getSupportActionBar().setSubtitle(getTag());
initData();
initView();
//initPoint();//调用初始化导航原点的方法
viewPager.addOnPageChangeListener(this);//滑动事件
ViewPager viewPager = findViewById(R.id.activitymainViewPager1);
MyPagerAdapter pagerAdapter = new MyPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(pagerAdapter);
TabLayout tabLayout = findViewById(R.id.activitymainTabLayout1);
tabLayout.setupWithViewPager(viewPager);
// mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class);
// if (mMainServiceBean == null) {
// mMainServiceBean = new MainServiceBean();
// }
// cbMainService = findViewById(R.id.activitymainCheckBox1);
// cbMainService.setChecked(mMainServiceBean.isEnable());
// cbMainService.setOnClickListener(new View.OnClickListener(){
// @Override
// public void onClick(View view) {
// if (cbMainService.isChecked()) {
// MainService.startMainService(MainActivity.this);
// } else {
// MainService.stopMainService(MainActivity.this);
// }
// }
// });
MainService.startMainService(MainActivity.this);
}
//初始化view即显示的图片
void initView() {
viewPager = findViewById(R.id.activitymainViewPager1);
pagerAdapter = new MyPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(pagerAdapter);
//adapter = new MyPagerAdapter(views);
//viewPager = findViewById(R.id.activitymainViewPager1);
//viewPager.setAdapter(adapter);
//linearLayout = findViewById(R.id.activitymainLinearLayout1);
//initPoint();//初始化页面下方的点
viewPager.setOnPageChangeListener(this);
}
//初始化所要显示的布局
void initData() {
ViewPager viewPager = findViewById(R.id.activitymainViewPager1);
LayoutInflater inflater = LayoutInflater.from(getActivity());
View view1 = inflater.inflate(R.layout.fragment_call, viewPager, false);
View view2 = inflater.inflate(R.layout.fragment_contacts, viewPager, false);
View view3 = inflater.inflate(R.layout.fragment_log, viewPager, false);
views = new ArrayList<>();
views.add(view1);
views.add(view2);
views.add(view3);
}
// void initPoint() {
// imageViews = new ImageView[5];//实例化5个图片
// for (int i = 0; i < linearLayout.getChildCount(); i++) {
// imageViews[i] = (ImageView) linearLayout.getChildAt(i);
// imageViews[i].setImageResource(R.drawable.ic_launcher);
// imageViews[i].setOnClickListener(this);//点击导航点即可跳转
// imageViews[i].setTag(i);//重复利用实例化的对象
// }
// currentPoint = 0;//默认第一个坐标
// imageViews[currentPoint].setImageResource(R.drawable.ic_launcher);
// }
//OnPageChangeListener接口要实现的三个方法
/* onPageScrollStateChanged(int state)
此方法是在状态改变的时候调用其中state这个参数有三种状态
SCROLL_STATE_DRAGGING1表示用户手指按在屏幕上并且开始拖动的状态
手指按下但是还没有拖动的时候还不是这个状态只有按下并且手指开始拖动后log才打出
SCROLL_STATE_IDLE0滑动动画做完的状态
SCROLL_STATE_SETTLING2手指离开屏幕的状态*/
@Override
public void onPageScrollStateChanged(int state) {
}
/* onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
当页面在滑动的时候会调用此方法在滑动被停止之前此方法回一直得到调用其中三个参数的含义分别为
position :当前页面即你点击滑动的页面从A滑B则是A页面的position
positionOffset:当前页面偏移的百分比
positionOffsetPixels:当前页面偏移的像素位置*/
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
/* onPageSelected(int position)
此方法是页面滑动完后得到调用position是你当前选中的页面的Position位置编号
(从A滑动到B就是B的position)*/
public void onPageSelected(int position) {
// ImageView preView = imageViews[currentPoint];
// preView.setImageResource(R.drawable.ic_launcher);
// ImageView currView = imageViews[position];
// currView.setImageResource(R.drawable.ic_launcher);
// currentPoint = position;
}
//小圆点点击事件
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
//通过getTag(),可以判断是哪个控件
// int i = (Integer) v.getTag();
// viewPager.setCurrentItem(i);//直接跳转到某一个页面的情况
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
//setSubTitle("");
}
@Override
protected void onDestroy() {
super.onDestroy();
LogUtils.d(TAG, "onDestroy() SOS");
}
//
// 处理传入的 Intent 数据
//
// boolean prosessIntents(Intent intent) {
// if (intent == null
// || intent.getAction() == null
// || intent.getAction().equals(""))
// return false;
//
// if (intent.getAction().equals(StringToQrCodeView.ACTION_UNITTEST_QRCODE)) {
// try {
// WinBollActivity clazzActivity = UnitTestActivity.class.newInstance();
// String tag = clazzActivity.getTag();
// LogUtils.d(TAG, "String tag = clazzActivity.getTag(); tag " + tag);
// Intent subIntent = new Intent(this, UnitTestActivity.class);
// subIntent.setAction(intent.getAction());
// File file = new File(getCacheDir(), UUID.randomUUID().toString());
// //取出文件uri
// Uri uri = intent.getData();
// if (uri == null) {
// uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
// }
// //获取文件真实地址
// String szSrcPath = UriUtils.getFileFromUri(getApplication(), uri);
// if (TextUtils.isEmpty(szSrcPath)) {
// return false;
// }
//
// Files.copy(Paths.get(szSrcPath), Paths.get(file.getPath()));
// //startWinBollActivity(subIntent, tag);
// WinBollActivityManager.getInstance(this).startWinBollActivity(this, subIntent, UnitTestActivity.class);
// } catch (IllegalAccessException | InstantiationException | IOException e) {
// LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
// // 函数处理异常返回失败
// return false;
// }
// } else {
// LogUtils.d(TAG, "prosessIntents|" + intent.getAction() + "|yet");
// return false;
// }
// return true;
// }
@Override
public String getTag() {
return TAG;
}
@Override
public Toolbar initToolBar() {
return findViewById(R.id.activitymainToolbar1);
}
@Override
public boolean isAddWinBollToolBar() {
return true;
}
@Override
public boolean isEnableDisplayHomeAsUp() {
return false;
}
@Override
public void onBackPressed() {
exit();
}
void exit() {
YesNoAlertDialog.OnDialogResultListener listener = new YesNoAlertDialog.OnDialogResultListener(){
@Override
public void onYes() {
WinBollActivityManager.getInstance(getApplicationContext()).finishAll();
}
@Override
public void onNo() {
}
};
YesNoAlertDialog.show(this, "[ " + getString(R.string.app_name) + " ]", "Exit(Yes/No).\nIs close all activity?", listener);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar_main, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.item_call) {
Intent intent = new Intent(this, CallActivity.class);
startActivity(intent);
//WinBollActivityManager.getInstance(this).startWinBollActivity(this, CallActivity.class);
} else if (item.getItemId() == R.id.item_settings) {
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
//WinBollActivityManager.getInstance(this).startWinBollActivity(this, CallActivity.class);
}
// } else
// if (item.getItemId() == R.id.item_exit) {
// exit();
// return true;
// }
return super.onOptionsItemSelected(item);
}
@Override
protected void onResume() {
super.onResume();
}
/**
* Android M 及以上检查是否是系统默认电话应用
*/
public boolean isDefaultPhoneCallApp() {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
TelecomManager manger = (TelecomManager) getSystemService(TELECOM_SERVICE);
if (manger != null && manger.getDefaultDialerPackage() != null) {
return manger.getDefaultDialerPackage().equals(getPackageName());
}
}
return false;
}
public boolean isServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
if (manager == null) return false;
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(
Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// switch (resultCode) {
// case REQUEST_HOME_ACTIVITY : {
// LogUtils.d(TAG, "REQUEST_HOME_ACTIVITY");
// break;
// }
// case REQUEST_ABOUT_ACTIVITY : {
// LogUtils.d(TAG, "REQUEST_ABOUT_ACTIVITY");
// break;
// }
// default : {
// super.onActivityResult(requestCode, resultCode, data);
// }
// }
if (requestCode == DIALER_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
Toast.makeText(MainActivity.this, getString(R.string.app_name) + " 已成为默认电话应用",
Toast.LENGTH_SHORT).show();
}
}
}
}

View File

@ -0,0 +1,35 @@
package cc.winboll.studio.contacts;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/20 21:14:52
* @Describe PhoneCallManager
*/
import android.telecom.Call;
import android.telecom.VideoProfile;
public class PhoneCallManager {
public static final String TAG = "PhoneCallManager";
public static Call call;
/**
* 接听电话
*/
public void answer() {
if (call != null) {
call.answer(VideoProfile.STATE_AUDIO_ONLY);
}
}
/**
* 断开电话包括来电时的拒接以及接听后的挂断
*/
public void disconnect() {
if (call != null) {
call.disconnect();
}
}
}

View File

@ -0,0 +1,118 @@
package cc.winboll.studio.contacts.activities;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/20 17:15:46
* @Describe 拨号窗口
*/
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import cc.winboll.studio.contacts.MainActivity;
import cc.winboll.studio.contacts.R;
public class CallActivity extends AppCompatActivity {
public static final String TAG = "CallActivity";
private static final int REQUEST_CALL_PHONE = 1;
private EditText phoneNumberEditText;
private TextView callStatusTextView;
private TelephonyManager telephonyManager;
private MyPhoneStateListener phoneStateListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
setContentView(R.layout.activity_call);
phoneNumberEditText = findViewById(R.id.phone_number);
Button dialButton = findViewById(R.id.dial_button);
callStatusTextView = findViewById(R.id.call_status);
dialButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String phoneNumber = phoneNumberEditText.getText().toString().trim();
if (!phoneNumber.isEmpty()) {
if (ContextCompat.checkSelfPermission(CallActivity.this, Manifest.permission.CALL_PHONE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(CallActivity.this,
new String[]{Manifest.permission.CALL_PHONE},
REQUEST_CALL_PHONE);
} else {
dialPhoneNumber(phoneNumber);
}
} else {
Toast.makeText(CallActivity.this, "请输入电话号码", Toast.LENGTH_SHORT).show();
}
}
});
// 初始化TelephonyManager和PhoneStateListener
telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
phoneStateListener = new MyPhoneStateListener();
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CALL_PHONE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
String phoneNumber = phoneNumberEditText.getText().toString().trim();
dialPhoneNumber(phoneNumber);
} else {
Toast.makeText(this, "未授予拨打电话权限", Toast.LENGTH_SHORT).show();
}
}
}
private void dialPhoneNumber(String phoneNumber) {
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(android.net.Uri.parse("tel:" + phoneNumber));
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
return;
}
startActivity(intent);
}
private class MyPhoneStateListener extends PhoneStateListener {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
callStatusTextView.setText("电话已挂断");
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
callStatusTextView.setText("正在通话中");
break;
case TelephonyManager.CALL_STATE_RINGING:
callStatusTextView.setText("来电: " + incomingNumber);
break;
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// 取消监听
if (telephonyManager != null) {
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
}
}
}

View File

@ -0,0 +1,40 @@
package cc.winboll.studio.contacts.activities;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/20 20:18:26
*/
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import androidx.appcompat.app.AppCompatActivity;
import cc.winboll.studio.contacts.R;
public class DialerActivity extends AppCompatActivity {
public static final String TAG = "DialerActivity";
private EditText phoneNumberEditText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dialer);
phoneNumberEditText = findViewById(R.id.phone_number_edit_text);
Button dialButton = findViewById(R.id.dial_button);
dialButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String phoneNumber = phoneNumberEditText.getText().toString();
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + phoneNumber));
startActivity(intent);
}
});
}
}

View File

@ -0,0 +1,143 @@
package cc.winboll.studio.contacts.activities;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/21 05:37:42
*/
import android.app.NotificationManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.view.View;
import android.view.WindowManager;
import android.widget.Switch;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.contacts.R;
import cc.winboll.studio.contacts.beans.RingTongBean;
import cc.winboll.studio.libappbase.IWinBollActivity;
import cc.winboll.studio.libappbase.bean.APPInfo;
import com.hjq.toast.ToastUtils;
import java.lang.reflect.Field;
public class SettingsActivity extends AppCompatActivity implements IWinBollActivity {
public static final String TAG = "SettingsActivity";
Toolbar mToolbar;
Switch swSilent;
@Override
public APPInfo getAppInfo() {
return null;
}
@Override
public AppCompatActivity getActivity() {
return this;
}
@Override
public String getTag() {
return TAG;
}
@Override
public Toolbar initToolBar() {
return findViewById(R.id.activitymainToolbar1);
}
@Override
public boolean isAddWinBollToolBar() {
return true;
}
@Override
public boolean isEnableDisplayHomeAsUp() {
return false;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
// 初始化工具栏
mToolbar = findViewById(R.id.activitymainToolbar1);
setSupportActionBar(mToolbar);
if (isEnableDisplayHomeAsUp()) {
// 显示后退按钮
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
getSupportActionBar().setSubtitle(getTag());
}
public void onDefaultPhone(View view) {
Intent intent = new Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS);
startActivity(intent);
}
public void onCanDrawOverlays(View view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& !Settings.canDrawOverlays(this)) {
// 请求 悬浮框 权限
askForDrawOverlay();
} else {
ToastUtils.show("悬浮窗已开启");
}
}
private void askForDrawOverlay() {
AlertDialog alertDialog = new AlertDialog.Builder(this)
.setTitle("允许显示悬浮框")
.setMessage("为了使电话监听服务正常工作,请允许这项权限")
.setPositiveButton("去设置", new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
openDrawOverlaySettings();
dialog.dismiss();
}
})
.setNegativeButton("稍后再说", new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.create();
//noinspection ConstantConditions
alertDialog.getWindow().setFlags(
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
alertDialog.show();
}
/**
* 跳转悬浮窗管理设置界面
*/
private void openDrawOverlaySettings() {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Android M 以上引导用户去系统设置中打开允许悬浮窗
// 使用反射是为了用尽可能少的代码保证在大部分机型上都可用
try {
Context context = this;
Class clazz = Settings.class;
Field field = clazz.getDeclaredField("ACTION_MANAGE_OVERLAY_PERMISSION");
Intent intent = new Intent(field.get(null).toString());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setData(Uri.parse("package:" + context.getPackageName()));
context.startActivity(intent);
} catch (Exception e) {
Toast.makeText(this, "请在悬浮窗管理中打开权限", Toast.LENGTH_LONG).show();
}
}
}
}

View File

@ -0,0 +1,14 @@
package cc.winboll.studio.contacts.adapters;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/20 14:20:38
* @Describe ImagePagerAdapter
*/
public class ImagePagerAdapter {
public static final String TAG = "ImagePagerAdapter";
}

View File

@ -0,0 +1,42 @@
package cc.winboll.studio.contacts.adapters;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/20 13:33:04
* @Describe MyPagerAdapter
*/
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import cc.winboll.studio.contacts.fragments.CallFragment;
import cc.winboll.studio.contacts.fragments.ContactsFragment;
import cc.winboll.studio.contacts.fragments.LogFragment;
public class MyPagerAdapter extends FragmentPagerAdapter {
public static final String TAG = "MyPagerAdapter";
private static final int PAGE_COUNT = 3;
public MyPagerAdapter(@NonNull FragmentManager fm) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
@NonNull
@Override
public Fragment getItem(int position) {
if(position == 1) {
return ContactsFragment.newInstance(position);
} else if(position == 2) {
return LogFragment.newInstance(position);
} else {
return CallFragment.newInstance(position);
}
}
@Override
public int getCount() {
return PAGE_COUNT;
}
}

View File

@ -0,0 +1,68 @@
package cc.winboll.studio.contacts.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,88 @@
package cc.winboll.studio.contacts.beans;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/21 09:52:10
* @Describe 电话黑名单规则
*/
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException;
public class PhoneBlackRuleBean extends BaseBean {
public static final String TAG = "PhoneBlackRuleBean";
String ruleText;
boolean isEnable;
public PhoneBlackRuleBean() {
this.ruleText = "";
this.isEnable = false;
}
public PhoneBlackRuleBean(String ruleText, boolean isEnable) {
this.ruleText = ruleText;
this.isEnable = isEnable;
}
public void setRuleText(String ruleText) {
this.ruleText = ruleText;
}
public String getRuleText() {
return ruleText;
}
public void setIsEnable(boolean isEnable) {
this.isEnable = isEnable;
}
public boolean isEnable() {
return isEnable;
}
@Override
public String getName() {
return PhoneBlackRuleBean.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
jsonWriter.name("ruleText").value(getRuleText());
jsonWriter.name("isEnable").value(isEnable());
}
@Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
if (name.equals("ruleText")) {
setRuleText(jsonReader.nextString());
} 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,74 @@
package cc.winboll.studio.contacts.beans;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/24 18:47:11
* @Describe 手机铃声设置参数类
*/
import cc.winboll.studio.libappbase.BaseBean;
import android.util.JsonWriter;
import java.io.IOException;
import android.media.AudioManager;
import android.util.JsonReader;
public class RingTongBean extends BaseBean {
public static final String TAG = "AudioRingTongBean";
// 模式
int ringerMode;
public RingTongBean() {
this.ringerMode = AudioManager.RINGER_MODE_NORMAL;
}
public RingTongBean(int ringerMode) {
this.ringerMode = ringerMode;
}
public void setRingerMode(int ringerMode) {
this.ringerMode = ringerMode;
}
public int getRingerMode() {
return ringerMode;
}
@Override
public String getName() {
return RingTongBean.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
jsonWriter.name("ringerMode").value(getRingerMode());
}
@Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
if (name.equals("ringerMode")) {
setRingerMode(jsonReader.nextInt());
} 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,76 @@
package cc.winboll.studio.contacts.dun;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/21 06:15:10
* @Describe 云盾防御规则
*/
import cc.winboll.studio.contacts.beans.PhoneBlackRuleBean;
import java.util.ArrayList;
import java.util.regex.Pattern;
import android.content.Context;
public class Rules {
public static final String TAG = "Rules";
ArrayList<PhoneBlackRuleBean> _PhoneBlacRuleBeanList;
static volatile Rules _Rules;
Context mContext;
Rules(Context context) {
mContext = context;
_PhoneBlacRuleBeanList = new ArrayList<PhoneBlackRuleBean>();
PhoneBlackRuleBean.loadBeanList(mContext, _PhoneBlacRuleBeanList, PhoneBlackRuleBean.class);
}
public static synchronized Rules getInstance(Context context) {
if (_Rules == null) {
_Rules = new Rules(context);
}
return _Rules;
}
public boolean isAllowed(String phoneNumber) {
// 黑名单拒接
for (int i = 0; i < _PhoneBlacRuleBeanList.size(); i++) {
if (_PhoneBlacRuleBeanList.get(i).isEnable()) {
String regex = _PhoneBlacRuleBeanList.get(i).getRuleText();
if (Pattern.matches(regex, phoneNumber)) {
return false;
}
}
}
// 手机号码允许
// 中国手机号码正则表达式以1开头第二位可以是3456789后面跟9位数字
String regex = "^1[3-9]\\d{9}$";
if (Pattern.matches(regex, phoneNumber)) {
return true;
}
// 指定区号号码允许
regex = "^0660\\d+$";
if (Pattern.matches(regex, phoneNumber)) {
return true;
}
// 指定区号号码允许
regex = "^020\\d+$";
if (Pattern.matches(regex, phoneNumber)) {
return true;
}
// 其他拒接
return false;
}
public void add(String phoneRuleBlack, boolean isEnable) {
_PhoneBlacRuleBeanList.add(new PhoneBlackRuleBean(phoneRuleBlack, isEnable));
PhoneBlackRuleBean.saveBeanList(mContext, _PhoneBlacRuleBeanList, PhoneBlackRuleBean.class);
}
public ArrayList<PhoneBlackRuleBean> getPhoneBlacRuleBeanList() {
return _PhoneBlacRuleBeanList;
}
}

View File

@ -0,0 +1,51 @@
package cc.winboll.studio.contacts.fragments;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/20 12:57:00
* @Describe 拨号
*/
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import cc.winboll.studio.contacts.R;
import cc.winboll.studio.libappbase.LogView;
import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
import android.widget.TextView;
public class CallFragment extends Fragment {
public static final String TAG = "CallFragment";
private static final String ARG_PAGE = "ARG_PAGE";
private int mPage;
public static CallFragment newInstance(int page) {
Bundle args = new Bundle();
args.putInt(ARG_PAGE, page);
CallFragment fragment = new CallFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments()!= null) {
mPage = getArguments().getInt(ARG_PAGE);
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_call, container, false);
TextView textView = view.findViewById(R.id.page_text);
textView.setText("这是第 " + mPage + "");
return view;
}
}

View File

@ -0,0 +1,50 @@
package cc.winboll.studio.contacts.fragments;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/20 12:57:50
* @Describe 联系人
*/
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import cc.winboll.studio.contacts.R;
public class ContactsFragment extends Fragment {
public static final String TAG = "ContactsFragment";
private static final String ARG_PAGE = "ARG_PAGE";
private int mPage;
public static ContactsFragment newInstance(int page) {
Bundle args = new Bundle();
args.putInt(ARG_PAGE, page);
ContactsFragment fragment = new ContactsFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments()!= null) {
mPage = getArguments().getInt(ARG_PAGE);
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_contacts, container, false);
TextView textView = view.findViewById(R.id.page_text);
textView.setText("这是第 " + mPage + "");
return view;
}
}

View File

@ -0,0 +1,50 @@
package cc.winboll.studio.contacts.fragments;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/20 12:58:15
* @Describe 应用日志
*/
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import cc.winboll.studio.contacts.R;
import cc.winboll.studio.libappbase.LogView;
public class LogFragment extends Fragment {
public static final String TAG = "LogFragment";
private static final String ARG_PAGE = "ARG_PAGE";
private int mPage;
public static LogFragment newInstance(int page) {
Bundle args = new Bundle();
args.putInt(ARG_PAGE, page);
LogFragment fragment = new LogFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mPage = getArguments().getInt(ARG_PAGE);
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_log, container, false);
LogView logView = view.findViewById(R.id.logview);
logView.start();
return view;
}
}

View File

@ -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<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,206 @@
package cc.winboll.studio.contacts.listenphonecall;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
import android.os.Build;
import android.os.IBinder;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import cc.winboll.studio.contacts.MainActivity;
import cc.winboll.studio.contacts.R;
public class CallListenerService extends Service {
private View phoneCallView;
private TextView tvCallNumber;
private Button btnOpenApp;
private WindowManager windowManager;
private WindowManager.LayoutParams params;
private PhoneStateListener phoneStateListener;
private TelephonyManager telephonyManager;
private String callNumber;
private boolean hasShown;
private boolean isCallingIn;
@Override
public void onCreate() {
super.onCreate();
initPhoneStateListener();
initPhoneCallView();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
/**
* 初始化来电状态监听器
*/
private void initPhoneStateListener() {
phoneStateListener = new PhoneStateListener() {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
callNumber = incomingNumber;
switch (state) {
case TelephonyManager.CALL_STATE_IDLE: // 待机即无电话时挂断时触发
dismiss();
break;
case TelephonyManager.CALL_STATE_RINGING: // 响铃来电时触发
isCallingIn = true;
updateUI();
show();
break;
case TelephonyManager.CALL_STATE_OFFHOOK: // 摘机接听或拨出电话时触发
updateUI();
show();
break;
default:
break;
}
}
};
// 设置来电监听器
telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
if (telephonyManager != null) {
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
}
}
private void initPhoneCallView() {
windowManager = (WindowManager) getApplicationContext()
.getSystemService(Context.WINDOW_SERVICE);
int width = windowManager.getDefaultDisplay().getWidth();
int height = windowManager.getDefaultDisplay().getHeight();
params = new WindowManager.LayoutParams();
params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
params.width = width;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
// 设置图片格式效果为背景透明
params.format = PixelFormat.TRANSLUCENT;
// 设置 Window flag 为系统级弹框 | 覆盖表层
params.type = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
WindowManager.LayoutParams.TYPE_PHONE;
// 不可聚集不响应返回键| 全屏
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
// API 19 以上则还可以开启透明状态栏与导航栏
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
params.flags = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
}
FrameLayout interceptorLayout = new FrameLayout(this) {
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
return true;
}
}
return super.dispatchKeyEvent(event);
}
};
phoneCallView = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE))
.inflate(R.layout.view_phone_call, interceptorLayout);
tvCallNumber = phoneCallView.findViewById(R.id.tv_call_number);
btnOpenApp = phoneCallView.findViewById(R.id.btn_open_app);
btnOpenApp.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
CallListenerService.this.startActivity(intent);
}
});
}
/**
* 显示顶级弹框展示通话信息
*/
private void show() {
if (!hasShown) {
windowManager.addView(phoneCallView, params);
hasShown = true;
}
}
/**
* 取消显示
*/
private void dismiss() {
if (hasShown) {
windowManager.removeView(phoneCallView);
isCallingIn = false;
hasShown = false;
}
}
private void updateUI() {
tvCallNumber.setText(formatPhoneNumber(callNumber));
int callTypeDrawable = isCallingIn ? R.drawable.ic_phone_call_in : R.drawable.ic_phone_call_out;
tvCallNumber.setCompoundDrawablesWithIntrinsicBounds(null, null,
getResources().getDrawable(callTypeDrawable), null);
}
public static String formatPhoneNumber(String phoneNum) {
if (!TextUtils.isEmpty(phoneNum) && phoneNum.length() == 11) {
return phoneNum.substring(0, 3) + "-"
+ phoneNum.substring(3, 7) + "-"
+ phoneNum.substring(7);
}
return phoneNum;
}
@Override
public void onDestroy() {
super.onDestroy();
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
}
}

View File

@ -0,0 +1,166 @@
package cc.winboll.studio.contacts.phonecallui;
import static cc.winboll.studio.contacts.listenphonecall.CallListenerService.formatPhoneNumber;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import cc.winboll.studio.contacts.ActivityStack;
import cc.winboll.studio.contacts.R;
import java.util.Timer;
import java.util.TimerTask;
/**
* 提供接打电话的界面仅支持 Android M (6.0, API 23) 及以上的系统
*
* @author aJIEw
*/
@RequiresApi(api = Build.VERSION_CODES.M)
public class PhoneCallActivity extends AppCompatActivity implements View.OnClickListener {
private TextView tvCallNumberLabel;
private TextView tvCallNumber;
private TextView tvPickUp;
private TextView tvCallingTime;
private TextView tvHangUp;
private PhoneCallManager phoneCallManager;
private PhoneCallService.CallType callType;
private String phoneNumber;
private Timer onGoingCallTimer;
private int callingTime;
public static void actionStart(Context context, String phoneNumber,
PhoneCallService.CallType callType) {
Intent intent = new Intent(context, PhoneCallActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_MIME_TYPES, callType);
intent.putExtra(Intent.EXTRA_PHONE_NUMBER, phoneNumber);
context.startActivity(intent);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_phone_call);
ActivityStack.getInstance().addActivity(this);
initData();
initView();
}
private void initData() {
phoneCallManager = new PhoneCallManager(this);
onGoingCallTimer = new Timer();
if (getIntent() != null) {
phoneNumber = getIntent().getStringExtra(Intent.EXTRA_PHONE_NUMBER);
callType = (PhoneCallService.CallType) getIntent().getSerializableExtra(Intent.EXTRA_MIME_TYPES);
}
}
private void initView() {
int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION //hide navigationBar
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
getWindow().getDecorView().setSystemUiVisibility(uiOptions);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
tvCallNumberLabel = findViewById(R.id.tv_call_number_label);
tvCallNumber = findViewById(R.id.tv_call_number);
tvPickUp = findViewById(R.id.tv_phone_pick_up);
tvCallingTime = findViewById(R.id.tv_phone_calling_time);
tvHangUp = findViewById(R.id.tv_phone_hang_up);
tvCallNumber.setText(formatPhoneNumber(phoneNumber));
tvPickUp.setOnClickListener(this);
tvHangUp.setOnClickListener(this);
// 打进的电话
if (callType == PhoneCallService.CallType.CALL_IN) {
tvCallNumberLabel.setText("来电号码");
tvPickUp.setVisibility(View.VISIBLE);
}
// 打出的电话
else if (callType == PhoneCallService.CallType.CALL_OUT) {
tvCallNumberLabel.setText("呼叫号码");
tvPickUp.setVisibility(View.GONE);
phoneCallManager.openSpeaker();
}
showOnLockScreen();
}
public void showOnLockScreen() {
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
WindowManager.LayoutParams.FLAG_FULLSCREEN |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON,
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
WindowManager.LayoutParams.FLAG_FULLSCREEN |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.tv_phone_pick_up) {
phoneCallManager.answer();
tvPickUp.setVisibility(View.GONE);
tvCallingTime.setVisibility(View.VISIBLE);
onGoingCallTimer.schedule(new TimerTask() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@SuppressLint("SetTextI18n")
@Override
public void run() {
callingTime++;
tvCallingTime.setText("通话中:" + getCallingTime());
}
});
}
}, 0, 1000);
} else if (v.getId() == R.id.tv_phone_hang_up) {
phoneCallManager.disconnect();
stopTimer();
}
}
private String getCallingTime() {
int minute = callingTime / 60;
int second = callingTime % 60;
return (minute < 10 ? "0" + minute : minute) +
":" +
(second < 10 ? "0" + second : second);
}
private void stopTimer() {
if (onGoingCallTimer != null) {
onGoingCallTimer.cancel();
}
callingTime = 0;
}
@Override
protected void onDestroy() {
super.onDestroy();
phoneCallManager.destroy();
}
}

View File

@ -0,0 +1,62 @@
package cc.winboll.studio.contacts.phonecallui;
import android.content.Context;
import android.media.AudioManager;
import android.os.Build;
import android.telecom.Call;
import android.telecom.VideoProfile;
import androidx.annotation.RequiresApi;
import cc.winboll.studio.contacts.dun.Rules;
@RequiresApi(api = Build.VERSION_CODES.M)
public class PhoneCallManager {
public static Call call;
private Context context;
private AudioManager audioManager;
public PhoneCallManager(Context context) {
this.context = context;
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
}
/**
* 接听电话
*/
public void answer() {
if (call != null) {
call.answer(VideoProfile.STATE_AUDIO_ONLY);
openSpeaker();
}
}
/**
* 断开电话包括来电时的拒接以及接听后的挂断
*/
public void disconnect() {
if (call != null) {
call.disconnect();
}
}
/**
* 打开免提
*/
public void openSpeaker() {
if (audioManager != null) {
audioManager.setMode(AudioManager.MODE_IN_CALL);
audioManager.setSpeakerphoneOn(true);
}
}
/**
* 销毁资源
*/
public void destroy() {
call = null;
context = null;
audioManager = null;
}
}

View File

@ -0,0 +1,103 @@
package cc.winboll.studio.contacts.phonecallui;
/**
* 监听电话通信状态的服务实现该类的同时必须提供电话管理的 UI
*
* @author aJIEw
* @see PhoneCallActivity
* @see android.telecom.InCallService
*/
import android.media.AudioManager;
import android.os.Build;
import android.telecom.Call;
import android.telecom.InCallService;
import androidx.annotation.RequiresApi;
import cc.winboll.studio.contacts.ActivityStack;
import cc.winboll.studio.contacts.beans.RingTongBean;
import cc.winboll.studio.contacts.dun.Rules;
import cc.winboll.studio.libappbase.LogUtils;
@RequiresApi(api = Build.VERSION_CODES.M)
public class PhoneCallService extends InCallService {
public static final String TAG = "PhoneCallService";
private volatile int originalRingVolume;
private final Call.Callback callback = new Call.Callback() {
@Override
public void onStateChanged(Call call, int state) {
super.onStateChanged(call, state);
switch (state) {
case Call.STATE_ACTIVE: {
break;
}
case Call.STATE_DISCONNECTED: {
ActivityStack.getInstance().finishActivity(PhoneCallActivity.class);
break;
}
}
}
};
@Override
public void onCallAdded(Call call) {
super.onCallAdded(call);
call.registerCallback(callback);
PhoneCallManager.call = call;
CallType callType = null;
if (call.getState() == Call.STATE_RINGING) {
callType = CallType.CALL_IN;
} else if (call.getState() == Call.STATE_CONNECTING) {
callType = CallType.CALL_OUT;
}
if (callType != null) {
Call.Details details = call.getDetails();
String phoneNumber = details.getHandle().getSchemeSpecificPart();
// 记录原始铃声音量
AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
originalRingVolume = audioManager.getStreamVolume(AudioManager.STREAM_RING);
// 检查电话接收规则
if (!Rules.getInstance(this).isAllowed(phoneNumber)) {
// 预先静音
audioManager.setStreamVolume(AudioManager.STREAM_RING, 0, 0);
// 断开电话
call.disconnect();
// 停顿1秒预防第一声铃声响动
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
LogUtils.d(TAG, "");
}
// 恢复铃声音量
audioManager.setStreamVolume(AudioManager.STREAM_RING, originalRingVolume, 0);
// 屏蔽电话结束
return;
}
// 正常接听电话
PhoneCallActivity.actionStart(this, phoneNumber, callType);
}
}
@Override
public void onCallRemoved(Call call) {
super.onCallRemoved(call);
call.unregisterCallback(callback);
PhoneCallManager.call = null;
AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
// 恢复铃声音量
audioManager.setStreamVolume(AudioManager.STREAM_RING, originalRingVolume, 0);
}
public enum CallType {
CALL_IN,
CALL_OUT,
}
}

View File

@ -0,0 +1,49 @@
package cc.winboll.studio.contacts.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 android.media.RingtoneManager;
import android.net.Uri;
import android.util.Log;
import cc.winboll.studio.contacts.services.MainService;
import com.hjq.toast.ToastUtils;
import java.lang.ref.WeakReference;
import cc.winboll.studio.libappbase.LogUtils;
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;
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");
MainService.startMainService(context);
} 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,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;
}
}
}

View File

@ -0,0 +1,247 @@
package cc.winboll.studio.contacts.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 cc.winboll.studio.contacts.listenphonecall.CallListenerService;
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;
import cc.winboll.studio.contacts.dun.Rules;
import android.media.AudioManager;
import com.hjq.toast.ToastUtils;
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();
// 召唤 WinBoll APP 绑定本服务
SOS.bindToAPPService(this, new APPSOSBean(getPackageName(), MainService.class.getName()));
if (mMainReceiver == null) {
// 注册广播接收器
mMainReceiver = new MainReceiver(this);
mMainReceiver.registerAction(this);
}
Rules.getInstance(this);
//Rules.getInstance(this).add("18888888888", true);
//Rules.getInstance(this).add("16769764848", true);
startPhoneCallListener();
MainServiceThread.getInstance(this, mMainServiceHandler).start();
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);
}
void startPhoneCallListener() {
Intent callListener = new Intent(this, CallListenerService.class);
startService(callListener);
}
@Override
public void onDestroy() {
//LogUtils.d(TAG, "onDestroy");
mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class);
//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 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,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<MainServiceHandler> mwrMainServiceHandler;
MainServiceThread(Context context, MainServiceHandler handler) {
mContext = context;
mwrMainServiceHandler = new WeakReference<MainServiceHandler>(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");
}
}
}

View File

@ -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");
}
}

View File

@ -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();
}
}
}

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:clickable="true">
<item android:drawable="@drawable/ic_launcher_background"/>
<item
android:left="15dp"
android:top="15dp"
android:right="15dp"
android:bottom="15dp"
android:drawable="@drawable/ic_launcher_foreground"/>
</layer-list>

View File

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="@color/colorPrimary"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:clickable="true">
<item android:drawable="@drawable/ic_launcher_background"/>
<item
android:left="15dp"
android:top="15dp"
android:right="15dp"
android:bottom="15dp"
android:drawable="@drawable/ic_launcher_foreground_disable"/>
</layer-list>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M16.61,15.15C16.15,15.15 15.77,14.78 15.77,14.32S16.15,13.5 16.61,13.5H16.61C17.07,13.5 17.45,13.86 17.45,14.32C17.45,14.78 17.07,15.15 16.61,15.15M7.41,15.15C6.95,15.15 6.57,14.78 6.57,14.32C6.57,13.86 6.95,13.5 7.41,13.5H7.41C7.87,13.5 8.24,13.86 8.24,14.32C8.24,14.78 7.87,15.15 7.41,15.15M16.91,10.14L18.58,7.26C18.67,7.09 18.61,6.88 18.45,6.79C18.28,6.69 18.07,6.75 18,6.92L16.29,9.83C14.95,9.22 13.5,8.9 12,8.91C10.47,8.91 9,9.24 7.73,9.82L6.04,6.91C5.95,6.74 5.74,6.68 5.57,6.78C5.4,6.87 5.35,7.08 5.44,7.25L7.1,10.13C4.25,11.69 2.29,14.58 2,18H22C21.72,14.59 19.77,11.7 16.91,10.14H16.91Z"/>
</vector>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#FFAAAAAA"
android:pathData="M16.61,15.15C16.15,15.15 15.77,14.78 15.77,14.32S16.15,13.5 16.61,13.5H16.61C17.07,13.5 17.45,13.86 17.45,14.32C17.45,14.78 17.07,15.15 16.61,15.15M7.41,15.15C6.95,15.15 6.57,14.78 6.57,14.32C6.57,13.86 6.95,13.5 7.41,13.5H7.41C7.87,13.5 8.24,13.86 8.24,14.32C8.24,14.78 7.87,15.15 7.41,15.15M16.91,10.14L18.58,7.26C18.67,7.09 18.61,6.88 18.45,6.79C18.28,6.69 18.07,6.75 18,6.92L16.29,9.83C14.95,9.22 13.5,8.9 12,8.91C10.47,8.91 9,9.24 7.73,9.82L6.04,6.91C5.95,6.74 5.74,6.68 5.57,6.78C5.4,6.87 5.35,7.08 5.44,7.25L7.1,10.13C4.25,11.69 2.29,14.58 2,18H22C21.72,14.59 19.77,11.7 16.91,10.14H16.91Z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="36dp"
android:height="36dp"
android:viewportHeight="1024"
android:viewportWidth="1024">
<path
android:fillColor="#fff"
android:pathData="M847.53,307.03L597.5,307.03c-8.54,0.17 -13.66,-11.26 -13.66,-19.97 0.17,-8.7 5.12,-14.17 13.66,-14.17h250.02c30.21,-0.34 31.41,34.14 0,34.14zM736.6,428.71c-6.14,6.32 -16.05,6.32 -22.02,0.17l-128.34,-130.56c-5.98,-6.14 -5.8,-16.22 0.17,-22.53l122.37,-124.76c6.14,-6.31 16.05,-6.31 22.02,-0.34 5.98,6.14 5.81,16.22 -0.34,22.36L623.1,289.62l113.5,116.22a16.33,16.33 0,0 1,0 22.87zM833.02,717.99c-18.78,-12.63 -122.37,-64.85 -141.99,-77.14 -2.05,0 -7.34,0.68 -14.85,4.43 -8.02,4.1 -31.23,16.9 -63.66,34.99l-25.26,14.16 -23.9,-16.38c-17.75,-12.11 -56.32,-41.3 -115.03,-98.64 -58.88,-57.69 -88.58,-95.23 -101.04,-112.47l-16.72,-23.38L345.09,418.82c13.99,-23.9 30.72,-52.9 35.84,-62.46 4.1,-7.51 4.44,-12.63 4.44,-14.17v-0.51C374.27,324.44 303.27,219.65 290.3,201.22c-1.88,-0.34 -5.8,0 -10.75,3.42 -40.28,28.5 -82.43,68.95 -88.41,84.65C195.24,373.42 270.85,491.52 404.48,622.25c133.8,130.73 251.22,205.49 336.9,209.41 16.22,-5.63 62.81,-52.05 91.65,-91.14 2.05,-2.9 3.24,-3.58 3.24,-6.99 0,-0.51 -3.07,-15.02 -3.24,-15.53zM867.5,770.73c-0.68,1.02 -81.58,108.03 -126.12,106.67 -125.1,-3.93 -265.73,-128.86 -366.94,-227.84 -101.38,-98.99 -225.45,-238.25 -229.38,-360.96v-1.02c0,-43.01 124.76,-128 125.78,-128.69 19.62,-13.14 36.35,-13.82 52.39,10.41 7.85,10.92 87.73,123.9 96.94,138.58 3.92,6.49 11.09,25.94 11.09,34.48 0,10.92 -3.24,23.21 -9.73,34.98 -6.31,11.61 -26.62,46.59 -36.69,63.83 10.92,15.19 46.76,61.44 103.94,117.25 56.83,55.63 85.16,72.19 100.69,82.77 17.58,-9.73 53.42,-29.7 65.2,-35.67 22.18,-11.44 44.37,-12.8 59.39,-3.42 14.16,8.7 136.02,88.41 147.79,96.6 10.93,7.68 16.9,21.67 16.9,36.69 0.17,11.78 -3.58,24.41 -11.26,35.33z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="36dp"
android:height="36dp"
android:viewportHeight="1024"
android:viewportWidth="1024">
<path
android:fillColor="#fff"
android:pathData="M861.86,307.03L614.4,307.03c-31.06,-0.17 -29.86,-34.48 0,-34.14h247.46c8.54,0.17 13.31,5.46 13.49,14.17 0,8.87 -4.95,20.14 -13.49,19.97zM872.96,298.5l-126.98,130.56c-5.98,6.14 -15.7,5.98 -21.85,-0.17 -6.14,-6.32 -6.14,-16.38 -0.17,-22.36l112.3,-116.22L730.11,173.74c-6.14,-6.31 -6.14,-16.38 -0.17,-22.35 5.97,-6.14 15.7,-5.98 21.84,0.34L872.96,276.48c5.8,5.8 5.98,15.87 0,22.02zM833.02,717.99c-18.78,-12.63 -122.37,-64.85 -141.99,-77.14 -2.05,0 -7.34,0.68 -14.85,4.43 -8.02,4.1 -31.23,16.9 -63.66,34.99l-25.26,14.16 -23.9,-16.38c-17.75,-12.11 -56.32,-41.3 -115.03,-98.64 -58.88,-57.69 -88.41,-95.23 -100.86,-112.47L330.75,443.56l14.5,-24.74c14,-23.9 30.72,-52.9 35.84,-62.46 4.1,-7.51 4.44,-12.63 4.44,-14.17v-0.51C374.44,324.44 303.45,219.65 290.3,201.22c-1.88,-0.34 -5.8,0 -10.75,3.42 -40.28,28.5 -82.43,68.95 -88.41,84.65C195.24,373.42 270.85,491.52 404.48,622.25c133.63,130.73 251.05,205.49 336.9,209.41 16.22,-5.63 62.81,-52.05 91.65,-91.14 2.05,-2.9 3.24,-3.58 3.24,-6.99 0,-0.51 -3.07,-15.02 -3.24,-15.53zM867.5,770.73c-0.68,1.02 -81.58,108.03 -126.12,106.67 -125.1,-3.93 -265.56,-128.86 -366.94,-227.84 -101.38,-98.99 -225.45,-238.25 -229.38,-360.96v-1.02c0,-43.01 124.76,-128 125.78,-128.69 19.62,-13.14 36.35,-13.82 52.39,10.41 7.85,10.92 87.73,123.9 96.94,138.58 4.1,6.49 11.09,25.94 11.09,34.48 0,10.92 -3.24,23.21 -9.73,34.98 -6.14,11.61 -26.62,46.59 -36.69,63.83 10.75,15.19 46.76,61.44 103.94,117.25 56.83,55.63 85.16,72.19 100.69,82.77 17.58,-9.73 53.42,-29.7 65.2,-35.67 22.18,-11.44 44.37,-12.8 59.39,-3.42 14.16,8.7 136.19,88.41 147.79,96.6 10.93,7.68 16.9,21.67 16.9,36.69 0.17,11.78 -3.58,24.41 -11.26,35.33z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
android:viewportHeight="1024"
android:viewportWidth="1024">
<path
android:fillColor="#201f1f"
android:pathData="M841.22,856.06c185.86,-185.86 185.86,-487.42 0,-673.79C655.36,-3.58 353.79,-3.58 167.42,182.27c-185.86,185.86 -185.86,487.42 0,673.79 186.37,185.86 487.94,185.86 673.79,0zM218.62,495.1c0,-47.62 111.1,-113.66 285.7,-113.66 175.1,0 285.7,66.05 285.7,113.66 0,40.96 10.75,102.4 -73.73,93.18 -84.48,-9.22 -78.85,-40.96 -78.85,-83.46 0,-29.7 -68.61,-36.35 -133.12,-36.35 -65.02,0 -133.12,6.66 -133.12,36.35 0,42.5 5.63,74.24 -78.85,83.46 -84.99,9.22 -73.73,-51.71 -73.73,-93.18z" />
</vector>

View File

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
android:viewportHeight="1024"
android:viewportWidth="1024">
<path
android:fillColor="#FFFFFF"
android:pathData="M277.9,742s167.9,-294.1 465.3,-465.3C575.7,577.8 277.9,742 277.9,742z" />
<path
android:fillColor="#FFFFFF"
android:pathData="M743.1,742S575.2,447.9 277.8,276.7C445.3,577.8 743.1,742 743.1,742z" />
<path
android:fillColor="#FFFFFF"
android:pathData="M284.1,343m-49,0a49,49 0,1 0,98 0,49 49,0 1,0 -98,0Z" />
<path
android:fillColor="#FFFFFF"
android:pathData="M284.1,515.5m-49,0a49,49 0,1 0,98 0,49 49,0 1,0 -98,0Z" />
<path
android:fillColor="#FFFFFF"
android:pathData="M284.1,683.5m-49,0a49,49 0,1 0,98 0,49 49,0 1,0 -98,0Z" />
<path
android:fillColor="#FFFFFF"
android:pathData="M808.4,341.6s-208.5,-61.2 -420,0c211.5,64.8 420,0 420,0zM808.4,516.6s-208.5,-61.2 -420,0c211.5,64.8 420,0 420,0zM808.4,684.6s-208.5,-61.2 -420,0c211.5,64.8 420,0 420,0z" />
<path
android:fillColor="#0EC469"
android:pathData="M512,512m-448,0a448,448 0,1 0,896 0,448 448,0 1,0 -896,0Z" />
<path
android:fillColor="#FFFFFF"
android:pathData="M701.4,786.8h-0.3c-3.2,-0.3 -6.4,-0.8 -9.5,-1.4C290,725.2 237.2,331.5 237.2,331.5h0.1c-5.9,-27.8 0.8,-56.8 22.5,-78.5 9.5,-9.5 22.5,-18.1 31.3,-19.2l111.6,111.6c-1.1,8.8 -9.6,21.7 -19.1,31.2 -8.5,8.5 -17.9,14.4 -28.4,18.6 57.7,214.5 272.1,271.5 272.1,271.5l0.3,0.2c4.2,-10.5 9.6,-19.3 18.1,-27.8 9.5,-9.5 22.6,-18.1 31.4,-19.2l111.6,111.6c-1.1,8.8 -9.6,21.7 -19.1,31.2 -18.9,19 -43.4,26.3 -68.2,24.1z" />
</vector>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="180"
android:endColor="#FFFFFFFF"
android:startColor="#FFFFFFFF"
android:type="linear" />
<corners android:radius="10dp" />
</shape>

View File

@ -0,0 +1,28 @@
<?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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<EditText
android:id="@+id/phone_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入电话号码"/>
<Button
android:id="@+id/dial_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="拨号"/>
<TextView
android:id="@+id/call_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"/>
</LinearLayout>

View File

@ -0,0 +1,22 @@
<?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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<EditText
android:id="@+id/phone_number_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter phone number" />
<Button
android:id="@+id/dial_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Dial" />
</LinearLayout>

View File

@ -0,0 +1,27 @@
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/activitymainToolbar1"/>
<androidx.viewpager.widget.ViewPager
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0"
android:id="@+id/activitymainViewPager1"/>
<com.google.android.material.tabs.TabLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:id="@+id/activitymainTabLayout1"/>
</LinearLayout>

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".phonecallui.PhoneCallActivity">
<RelativeLayout
android:id="@+id/rl_user_info"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="@color/colorPrimaryDark">
<TextView
android:id="@+id/tv_call_number_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/tv_call_number"
android:layout_marginBottom="16dp"
android:gravity="center"
android:text="来电号码"
android:textColor="@android:color/white"
android:textSize="18sp" />
<TextView
android:id="@+id/tv_call_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textAlignment="center"
android:textColor="@android:color/white"
android:textSize="28sp"
android:textStyle="bold"
android:layout_centerInParent="true"
tools:text="133-9527-9527" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white">
<TextView
android:id="@+id/tv_phone_calling_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="24dp"
android:text="通话中01:33"
android:textColor="@android:color/black"
android:textSize="18sp"
android:visibility="gone"
tools:visibility="visible" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
<TextView
android:id="@+id/tv_phone_hang_up"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="16dp"
android:drawableTop="@drawable/ic_phone_hang_up"
android:foreground="?android:attr/selectableItemBackground"
android:gravity="center"
android:padding="8dp"
android:text="挂 断"
android:textColor="@android:color/black"
tools:visibility="visible" />
<TextView
android:id="@+id/tv_phone_pick_up"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="50dp"
android:layout_toRightOf="@id/tv_phone_hang_up"
android:drawablePadding="16dp"
android:drawableTop="@drawable/ic_phone_pick_up"
android:foreground="?android:attr/selectableItemBackground"
android:gravity="center"
android:padding="8dp"
android:text="接 听"
android:textColor="@android:color/black"
android:visibility="gone"
tools:visibility="visible" />
</RelativeLayout>
</RelativeLayout>
</LinearLayout>

View File

@ -0,0 +1,51 @@
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/activitymainToolbar1"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="应用权限设置:"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="悬浮窗设置"
android:id="@+id/activitysettingsButton2"
android:onClick="onCanDrawOverlays"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="默认拨号设置"
android:id="@+id/activitysettingsButton1"
android:onClick="onDefaultPhone"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,29 @@
<?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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:layout_width="0dp"
android:ems="10"
android:layout_height="wrap_content"
android:layout_weight="1.0"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Text"
android:id="@+id/page_text"/>
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,15 @@
<?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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Text"
android:id="@+id/page_text"/>
</LinearLayout>

View File

@ -0,0 +1,12 @@
<?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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<cc.winboll.studio.libappbase.LogView
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="@+id/logview"/>
</LinearLayout>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rl_user_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary">
<TextView
android:id="@+id/tv_call_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="30dp"
android:gravity="center"
android:textAlignment="center"
android:textColor="@android:color/white"
android:textSize="18sp"
tools:text="133-8892-9579" />
<Button
android:id="@+id/btn_open_app"
style="@style/Base.Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="match_parent"
android:textColor="@android:color/white"
android:layout_height="wrap_content"
android:layout_below="@id/tv_call_number"
android:gravity="center"
android:text="打开 Phone Call App"
android:textAlignment="center"
android:textSize="16sp" />
</RelativeLayout>

View File

@ -0,0 +1,32 @@
<?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="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_gradient"
android:gravity="center"
android:orientation="vertical"
android:padding="10dp">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_launcher"/>
<TextView
android:id="@android:id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:textColor="#FF000000"
android:textSize="16sp"/>
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,15 @@
<?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:orientation="vertical"
android:layout_width="40dp"
android:layout_height="40dp">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:id="@+id/widgetlayoutImageView1"/>
</LinearLayout>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/item_call"
android:title="CallActivity"/>
<item
android:id="@+id/item_settings"
android:title="SettingsActivity"/>
</menu>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- WinBoll 默认方案 -->
<color name="colorPrimary">#FF196ABC</color>
<color name="colorPrimaryDark">#FF002B57</color>
<color name="colorAccent">#FF80BFFF</color>
</resources>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Contacts</string>
</resources>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="MyAppTheme" parent="APPBaseTheme">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowContentOverlay">@null</item>
</style>
<style name="GlobalCrashActivityTheme" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar">
<item name="colorTittle">@color/colorAccent</item>
<item name="colorTittleBackgound">@color/colorPrimary</item>
<item name="colorText">@color/colorAccent</item>
<item name="colorTextBackgound">@color/colorPrimaryDark</item>
</style>
</resources>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="40dp"
android:minHeight="40dp"
android:updatePeriodMillis="0"
android:initialLayout="@layout/widget_layout"
android:resizeMode="none">
</appwidget-provider>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external_storage_root"
path="." />
<files-path
name="files_path"
path="." />
<cache-path
name="cache_path"
path="." />
<!--/storage/emulated/0/Android/data/...-->
<external-files-path
name="external_file_path"
path="." />
<!--代表app 外部存储区域根目录下的文件 Context.getExternalCacheDir目录下的目录-->
<external-cache-path
name="external_cache_path"
path="." />
<!--配置root-path。这样子可以读取到sd卡和一些应用分身的目录否则微信分身保存的图片就会导致 java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/999/tencent/MicroMsg/WeiXin/export1544062754693.jpg在小米6的手机上微信分身有这个crash华为没有
-->
<root-path
name="root_path"
path="" />
</paths>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" >
<application>
<!-- Put flavor specific code here -->
</application>
</manifest>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Put flavor specific strings here -->
</resources>

View File

@ -20,13 +20,27 @@ android {
} }
dependencies { dependencies {
api 'com.github.getActivity:ToastUtils:10.5'
api 'androidx.appcompat:appcompat:1.3.1'
api 'androidx.vectordrawable:vectordrawable:1.1.0'
api 'androidx.vectordrawable:vectordrawable-animated:1.1.0'
api 'androidx.fragment:fragment:1.1.0'
api 'com.google.android.material:material:1.1.0'
api fileTree(dir: 'libs', include: ['*.jar']) api fileTree(dir: 'libs', include: ['*.jar'])
// SSH
implementation 'com.jcraft:jsch:0.1.55'
// Html
implementation 'org.jsoup:jsoup:1.13.1'
//
implementation 'com.google.zxing:core:3.4.1'
implementation 'com.journeyapps:zxing-android-embedded:3.6.0'
//
implementation 'io.github.medyo:android-about-page:2.0.0'
//
implementation 'com.github.getActivity:ToastUtils:10.5'
//
implementation 'com.squareup.okhttp3:okhttp:4.4.1'
// Android
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.viewpager:viewpager:1.0.0'
implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
implementation 'androidx.vectordrawable:vectordrawable-animated:1.1.0'
implementation 'androidx.fragment:fragment:1.1.0'
implementation 'com.google.android.material:material:1.4.0'
} }

View File

@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Tue Feb 25 16:51:09 HKT 2025 #Sun Mar 09 09:15:24 HKT 2025
stageCount=3 stageCount=6
libraryProject=libappbase libraryProject=libappbase
baseVersion=2.0 baseVersion=2.1
publishVersion=2.0.2 publishVersion=2.1.5
buildCount=0 buildCount=0
baseBetaVersion=2.0.3 baseBetaVersion=2.1.6

View File

@ -73,6 +73,18 @@
</receiver> </receiver>
<service android:name="cc.winboll.studio.libappbase.sos.SOSCenter"/>
<receiver android:name="cc.winboll.studio.libappbase.sos.SOSCenterServiceReceiver">
<intent-filter>
<action android:name="cc.winboll.studio.libappbase.sos.SOSCenterServiceReceiver"/>
</intent-filter>
</receiver>
</application> </application>
</manifest> </manifest>

View File

@ -1,24 +0,0 @@
package cc.winboll.studio.libappbase;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2025/02/04 10:20:16
* @Describe WinBoll Activity 接口
*/
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libappbase.bean.APPInfo;
public interface IWinBollActivity {
public static final String TAG = "IWinBollActivity";
// 获取当前具有 IWinBoll 特征的 AppCompatActivity 活动窗口
AppCompatActivity getActivity();
abstract public APPInfo getAppInfo();
abstract public String getTag();
abstract Toolbar initToolBar();
abstract boolean isEnableDisplayHomeAsUp();
abstract boolean isAddWinBollToolBar();
}

View File

@ -1,68 +0,0 @@
package cc.winboll.studio.libappbase;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2024/08/12 15:07:58
* @Describe WinBoll 应用日志窗口
*/
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.bean.APPInfo;
import cc.winboll.studio.libappbase.R;
public class LogActivity extends AppCompatActivity implements IWinBollActivity {
public static final String TAG = "LogActivity";
LogView mLogView;
@Override
public AppCompatActivity getActivity() {
return this;
}
@Override
public APPInfo getAppInfo() {
return null;
}
@Override
public String getTag() {
return TAG;
}
@Override
public Toolbar initToolBar() {
return null;
}
@Override
public boolean isEnableDisplayHomeAsUp() {
return false;
}
@Override
public boolean isAddWinBollToolBar() {
return false;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
LogUtils.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_log);
mLogView = findViewById(R.id.logview);
if (GlobalApplication.isDebuging()) { mLogView.start(); }
}
@Override
protected void onResume() {
LogUtils.d(TAG, "onResume");
super.onResume();
mLogView.start();
}
}

View File

@ -38,7 +38,7 @@ public class LogUtils {
static volatile boolean _IsInited = false; static volatile boolean _IsInited = false;
static Context _mContext; static Context _mContext;
// 日志显示时间格式 // 日志显示时间格式
static SimpleDateFormat mSimpleDateFormat = new SimpleDateFormat("[yyyyMMdd_HHmmSS]", Locale.getDefault()); static SimpleDateFormat mSimpleDateFormat = new SimpleDateFormat("[yyyyMMdd_HHmmss_SSS]", Locale.getDefault());
// 应用日志文件夹 // 应用日志文件夹
static File _mfLogCacheDir; static File _mfLogCacheDir;
static File _mfLogDataDir; static File _mfLogDataDir;

View File

@ -1,57 +0,0 @@
package cc.winboll.studio.libappbase;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/13 21:09:36
* @Describe SOS 组件
*/
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import cc.winboll.studio.libappbase.bean.APPSOSBean;
import java.util.ArrayList;
public class SOS {
public static final String TAG = "SOS";
public static final String ACTION_SOS = SOS.class.getName() + ".ACTION_SOS";
public static final String ACTION_BIND = SOS.class.getName() + ".ACTION_BIND";
public static final String ACTION_SERVICE_ENABLE = SOS.class.getName() + ".ACTION_SERVICE_ENABLE";
public static final String ACTION_SERVICE_DISABLE = SOS.class.getName() + ".ACTION_SERVICE_DISENABLE";
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";
} else {
szToPackage = "cc.winboll.studio.appbase";
}
intent.setPackage(szToPackage);
context.sendBroadcast(intent);
LogUtils.d(TAG, String.format("Send ACTION_SOS To WinBoll. (szToPackage : %s)", szToPackage));
//ToastUtils.show("SOS Send To WinBoll");
}
public static void bindToAPPService(Context context, APPSOSBean bean) {
Intent intent = new Intent(ACTION_BIND);
intent.putExtra("SOS", "Service");
intent.putExtra("APPSOSBean", bean.toString());
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("Send ACTION_BIND To WinBoll. (szToPackage : %s)", szToPackage));
}
}

View File

@ -1,32 +0,0 @@
package cc.winboll.studio.libappbase;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/12 23:44:57
* @Describe 简单信号通信中心接收器
*/
public class SOSCSBroadcastReceiver extends BroadcastReceiver {
public static final String TAG = "SOSCSBroadcastReceiver";
public static final String ACTION_SOS = SOSCSBroadcastReceiver.class.getName() + ".ACTION_SOS";
//ISOSAPP mISOSAPP;
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);
} else {
LogUtils.d(TAG, String.format("%s", action));
}
}
}

View File

@ -0,0 +1,3 @@
package cc.winboll.studio.libappbase;

View File

@ -1,142 +0,0 @@
package cc.winboll.studio.libappbase.bean;
/**
* @Author ZhanGSKen@QQ.COM
* @Date 2025/01/20 14:19:02
* @Describe 应用信息类
*/
import cc.winboll.studio.libappbase.R;
import java.io.Serializable;
public class APPInfo implements Serializable {
public static final String TAG = "APPInfo";
// 应用名称
String appName;
// 应用图标
int appIcon;
// 应用描述
String appDescription;
// 应用Git仓库地址
String appGitName;
// 应用Git仓库拥有者
String appGitOwner;
// 应用Git仓库分支
String appGitAPPBranch;
// 应用Git仓库子项目文件夹
String appGitAPPSubProjectFolder;
// 应用主页
String appHomePage;
// 应用包名称
String appAPKName;
// 应用包存储文件夹名称
String appAPKFolderName;
public APPInfo(String appName, int appIcon, String appDescription, String appGitName, String appGitOwner, String appGitAPPBranch, String appGitAPPSubProjectFolder, String appHomePage, String appAPKName, String appAPKFolderName) {
this.appName = appName;
this.appIcon = appIcon;
this.appDescription = appDescription;
this.appGitName = appGitName;
this.appGitOwner = appGitOwner;
this.appGitAPPBranch = appGitAPPBranch;
this.appGitAPPSubProjectFolder = appGitAPPSubProjectFolder;
this.appHomePage = appHomePage;
this.appAPKName = appAPKName;
this.appAPKFolderName = appAPKFolderName;
}
public APPInfo() {
this.appName = "WinBoll-APP";
this.appIcon = R.drawable.ic_launcher;
this.appDescription = "WinBoll APP";
this.appGitName = "APP";
this.appGitOwner = "Studio";
this.appGitAPPBranch = "app";
this.appGitAPPSubProjectFolder = "app";
this.appHomePage = "https://www.winboll.cc/studio/details.php?app=APP";
this.appAPKName = "APP";
this.appAPKFolderName = "APP";
}
public void setAppGitOwner(String appGitOwner) {
this.appGitOwner = appGitOwner;
}
public String getAppGitOwner() {
return appGitOwner;
}
public void setAppGitAPPBranch(String appGitAPPBranch) {
this.appGitAPPBranch = appGitAPPBranch;
}
public String getAppGitAPPBranch() {
return appGitAPPBranch;
}
public void setAppGitAPPSubProjectFolder(String appGitAPPSubProjectFolder) {
this.appGitAPPSubProjectFolder = appGitAPPSubProjectFolder;
}
public String getAppGitAPPSubProjectFolder() {
return appGitAPPSubProjectFolder;
}
public void setAppIcon(int appIcon) {
this.appIcon = appIcon;
}
public int getAppIcon() {
return appIcon;
}
public void setAppDescription(String appDescription) {
this.appDescription = appDescription;
}
public String getAppDescription() {
return appDescription;
}
public void setAppAPKFolderName(String appAPKFolderName) {
this.appAPKFolderName = appAPKFolderName;
}
public String getAppAPKFolderName() {
return appAPKFolderName;
}
public void setAppName(String appName) {
this.appName = appName;
}
public String getAppName() {
return appName;
}
public void setAppGitName(String appGitName) {
this.appGitName = appGitName;
}
public String getAppGitName() {
return appGitName;
}
public void setAppHomePage(String appHomePage) {
this.appHomePage = appHomePage;
}
public String getAppHomePage() {
return appHomePage;
}
public void setAppAPKName(String appAPKName) {
this.appAPKName = appAPKName;
}
public String getAppAPKName() {
return appAPKName;
}
}

View File

@ -1,87 +0,0 @@
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,86 @@
package cc.winboll.studio.libappbase.sos;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/03/02 10:28:08
* @Describe APPModel
*/
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException;
public class APPModel extends BaseBean {
public static final String TAG = "APPModel";
String appPackageName;
String appMainServiveName;
public APPModel() {
this.appPackageName = "";
this.appMainServiveName = "";
}
public APPModel(String appPackageName, String appMainServiveName) {
this.appPackageName = appPackageName;
this.appMainServiveName = appMainServiveName;
}
public void setAppPackageName(String appPackageName) {
this.appPackageName = appPackageName;
}
public String getAppPackageName() {
return appPackageName;
}
public void setAppMainServiveName(String appMainServiveName) {
this.appMainServiveName = appMainServiveName;
}
public String getAppMainServiveName() {
return appMainServiveName;
}
@Override
public String getName() {
return APPModel.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
jsonWriter.name("appPackageName").value(getAppPackageName());
jsonWriter.name("appMainServiveName").value(getAppMainServiveName());
}
@Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
if (name.equals("appPackageName")) {
setAppPackageName(jsonReader.nextString());
} else if (name.equals("appMainServiveName")) {
setAppMainServiveName(jsonReader.nextString());
} else {
return false;
}
}
return true;
}
@Override
public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException {
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String name = jsonReader.nextName();
if (!initObjectsFromJsonReader(jsonReader, name)) {
jsonReader.skipValue();
}
}
// 结束 JSON 对象
jsonReader.endObject();
return this;
}
}

View File

@ -0,0 +1,59 @@
package cc.winboll.studio.libappbase.sos;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/03/02 09:36:29
* @Describe WinBoll 应用 SOS 机理保护类
*/
import android.content.Context;
import android.content.Intent;
import cc.winboll.studio.libappbase.LogUtils;
import java.io.IOException;
public class SOS {
public static final String TAG = "SOS";
public static final String ACTION_SOS = SOS.class.getName() + ".ACTION_SOS";
public static final String EXTRA_OBJECT = "EXTRA_OBJECT";
public static void sosToAppBase(Context context, String sosService) {
LogUtils.d(TAG, "sosToAppBase()");
String szToPackage = "cc.winboll.studio.appbase";
sos(context, szToPackage, sosService);
}
public static void sosToAppBaseBeta(Context context, String sosService) {
LogUtils.d(TAG, "sosToAppBaseBeta()");
String szToPackage = "cc.winboll.studio.appbase.beta";
sos(context, szToPackage, sosService);
}
static void sos(Context context, String szToPackage, String sosService) {
LogUtils.d(TAG, "sos(...)");
Intent intent = new Intent(ACTION_SOS);
intent.putExtra(EXTRA_OBJECT, genSOSObject(context.getPackageName(), sosService));
intent.setPackage(szToPackage);
LogUtils.d(TAG, String.format("ACTION_SOS :\nTo Package : %sSOS Service : %s\n", szToPackage, sosService));
context.sendBroadcast(intent);
}
public static SOSObject parseSOSObject(String szSOSObject) {
try {
return SOSObject.parseStringToBean(szSOSObject, SOSObject.class);
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
return null;
}
public static String sosObjectToString(SOSObject object) {
return object.toString();
}
public static String genSOSObject(String objectPackageName, String objectServiveName) {
return (new SOSObject(objectPackageName, objectServiveName)).toString();
}
}

View File

@ -1,10 +1,10 @@
package cc.winboll.studio.libappbase; package cc.winboll.studio.libappbase.sos;
/** /**
* @Author ZhanGSKen@AliYun.Com * @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/12 11:12:25 * @Date 2025/02/27 14:00:21
* @Describe 简单信号服务中心 * @Describe Simple Operate Signal Service Center.
* 简单操作信号服务中心
*/ */
import android.app.Service; import android.app.Service;
import android.content.Context; import android.content.Context;
@ -13,18 +13,19 @@ import android.os.IBinder;
import android.os.IInterface; import android.os.IInterface;
import android.os.Parcel; import android.os.Parcel;
import android.os.RemoteException; import android.os.RemoteException;
import cc.winboll.studio.libappbase.bean.SimpleOperateSignalCenterServiceBean;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import cc.winboll.studio.libappbase.LogUtils;
public class SimpleOperateSignalCenterService extends Service { public class SOSCenterService extends Service {
public static final String TAG = "SimpleOperateSignalCenterService"; public static final String TAG = "SOSCenterService";
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(); private final IBinder binder =(IBinder)new SOSBinder();
SimpleOperateSignalCenterServiceBean mSimpleOperateSignalCenterServiceBean; SOSCenterServiceModel mSOSCenterServiceModel;
static MainThread _MainThread; static MainThread _MainThread;
public static synchronized MainThread getMainThreadInstance() { public static synchronized MainThread getMainThreadInstance() {
if (_MainThread == null) { if (_MainThread == null) {
@ -83,8 +84,8 @@ public class SimpleOperateSignalCenterService extends Service {
} }
public static final String TAG = "SOSBinder"; public static final String TAG = "SOSBinder";
SimpleOperateSignalCenterService getService() { SOSCenterService getService() {
return SimpleOperateSignalCenterService.this; return SOSCenterService.this;
} }
} }
@ -92,10 +93,10 @@ public class SimpleOperateSignalCenterService extends Service {
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
LogUtils.d(TAG, "onCreate"); LogUtils.d(TAG, "onCreate");
mSimpleOperateSignalCenterServiceBean = SimpleOperateSignalCenterServiceBean.loadBean(this, SimpleOperateSignalCenterServiceBean.class); mSOSCenterServiceModel = SOSCenterServiceModel.loadBean(this, SOSCenterServiceModel.class);
if(mSimpleOperateSignalCenterServiceBean == null) { if(mSOSCenterServiceModel == null) {
mSimpleOperateSignalCenterServiceBean = new SimpleOperateSignalCenterServiceBean(); mSOSCenterServiceModel = new SOSCenterServiceModel();
SimpleOperateSignalCenterServiceBean.saveBean(this, mSimpleOperateSignalCenterServiceBean); SOSCenterServiceModel.saveBean(this, mSOSCenterServiceModel);
} }
runMainThread(); runMainThread();
} }
@ -103,21 +104,15 @@ public class SimpleOperateSignalCenterService extends Service {
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
LogUtils.d(TAG, "onStartCommand"); LogUtils.d(TAG, "onStartCommand");
// if (intent.getBooleanExtra(ISOSService.EXTRA_ENABLE, false)) {
// LogUtils.d(TAG, "onStartCommand enable service");
// mSimpleOperateSignalCenterServiceBean.setIsEnable(true);
// SimpleOperateSignalCenterServiceBean.saveBean(this, mSimpleOperateSignalCenterServiceBean);
// }
runMainThread(); runMainThread();
//return super.onStartCommand(intent, flags, startId); return mSOSCenterServiceModel.isEnable() ? Service.START_STICKY: super.onStartCommand(intent, flags, startId);
return mSimpleOperateSignalCenterServiceBean.isEnable() ? Service.START_STICKY: super.onStartCommand(intent, flags, startId);
} }
void runMainThread() { void runMainThread() {
mSimpleOperateSignalCenterServiceBean = SimpleOperateSignalCenterServiceBean.loadBean(this, SimpleOperateSignalCenterServiceBean.class); mSOSCenterServiceModel = mSOSCenterServiceModel.loadBean(this, SOSCenterServiceModel.class);
if (mSimpleOperateSignalCenterServiceBean.isEnable() if (mSOSCenterServiceModel.isEnable()
&& _MainThread == null) { && _MainThread == null) {
getMainThreadInstance().start(); getMainThreadInstance().start();
} }
@ -127,9 +122,9 @@ public class SimpleOperateSignalCenterService extends Service {
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
LogUtils.d(TAG, "onDestroy"); LogUtils.d(TAG, "onDestroy");
mSimpleOperateSignalCenterServiceBean = SimpleOperateSignalCenterServiceBean.loadBean(this, SimpleOperateSignalCenterServiceBean.class); mSOSCenterServiceModel = SOSCenterServiceModel.loadBean(this, SOSCenterServiceModel.class);
if (mSimpleOperateSignalCenterServiceBean.isEnable()) { if (mSOSCenterServiceModel.isEnable()) {
LogUtils.d(TAG, "mSimpleOperateSignalCenterServiceBean.isEnable()"); LogUtils.d(TAG, "mSOSCenterServiceModel.isEnable()");
// ISOSAPP iSOSAPP = (ISOSAPP)getApplication(); // ISOSAPP iSOSAPP = (ISOSAPP)getApplication();
// iSOSAPP.helpISOSService(getISOSServiceIntentWhichAskForHelp()); // iSOSAPP.helpISOSService(getISOSServiceIntentWhichAskForHelp());
} }
@ -141,22 +136,22 @@ public class SimpleOperateSignalCenterService extends Service {
public static void stopISOSService(Context context) { public static void stopISOSService(Context context) {
LogUtils.d(TAG, "stopISOSService"); LogUtils.d(TAG, "stopISOSService");
SimpleOperateSignalCenterServiceBean bean = new SimpleOperateSignalCenterServiceBean(); SOSCenterServiceModel bean = new SOSCenterServiceModel();
bean.setIsEnable(false); bean.setIsEnable(false);
SimpleOperateSignalCenterServiceBean.saveBean(context, bean); SOSCenterServiceModel.saveBean(context, bean);
context.stopService(new Intent(context, SimpleOperateSignalCenterService.class)); context.stopService(new Intent(context, SOSCenterServiceModel.class));
} }
public static void startISOSService(Context context) { public static void startISOSService(Context context) {
LogUtils.d(TAG, "startISOSService"); LogUtils.d(TAG, "startISOSService");
SimpleOperateSignalCenterServiceBean bean = new SimpleOperateSignalCenterServiceBean(); SOSCenterServiceModel bean = new SOSCenterServiceModel();
bean.setIsEnable(true); bean.setIsEnable(true);
SimpleOperateSignalCenterServiceBean.saveBean(context, bean); SOSCenterServiceModel.saveBean(context, bean);
context.startService(new Intent(context, SimpleOperateSignalCenterService.class)); context.startService(new Intent(context, SOSCenterServiceModel.class));
} }
public String getMessage() { public String getMessage() {
return "Hello from SimpleOperateSignalCenterService"; return "Hello from SOSCenterServiceModel";
} }
static class MainThread extends Thread { static class MainThread extends Thread {

View File

@ -0,0 +1,69 @@
package cc.winboll.studio.libappbase.sos;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/03/02 09:49:45
* @Describe SOSCenterServiceModel
* Simple Operate Signal Service Model.
*/
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException;
public class SOSCenterServiceModel extends BaseBean {
public static final String TAG = "SOSCenterServiceModel";
boolean isEnable;
public SOSCenterServiceModel() {
this.isEnable = false;
}
public void setIsEnable(boolean isEnable) {
this.isEnable = isEnable;
}
public boolean isEnable() {
return isEnable;
}
@Override
public String getName() {
return SOSCenterServiceModel.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
jsonWriter.name("isEnable").value(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,29 @@
package cc.winboll.studio.libappbase.sos;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/27 14:04:35
* @Describe SOSCenterServiceReceiver
*/
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import cc.winboll.studio.libappbase.LogUtils;
public class SOSCenterServiceReceiver extends BroadcastReceiver {
public static final String TAG = "SOSCenterServiceReceiver";
public static final String ACTION_SOS = SOSCenterServiceReceiver.class.getName() + ".ACTION_SOS";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(ACTION_SOS)) {
// 处理接收到的广播消息
LogUtils.d(TAG, String.format("Action %s \n%s\n%s", action));
} else {
LogUtils.d(TAG, String.format("%s", action));
}
}
}

View File

@ -0,0 +1,86 @@
package cc.winboll.studio.libappbase.sos;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/27 14:12:05
* @Describe SOSBean
*/
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException;
public class SOSObject extends BaseBean {
public static final String TAG = "SOSObject";
String objectPackageName;
String objectServiveName;
public SOSObject() {
this.objectPackageName = "";
this.objectServiveName = "";
}
public SOSObject(String objectPackageName, String objectServiveName) {
this.objectPackageName = objectPackageName;
this.objectServiveName = objectServiveName;
}
public void setObjectPackageName(String objectPackageName) {
this.objectPackageName = objectPackageName;
}
public String getObjectPackageName() {
return objectPackageName;
}
public void setObjectServiveName(String objectServiveName) {
this.objectServiveName = objectServiveName;
}
public String getObjectServiveName() {
return objectServiveName;
}
@Override
public String getName() {
return SOSObject.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
jsonWriter.name("objectPackageName").value(getObjectPackageName());
jsonWriter.name("objectServiveName").value(getObjectServiveName());
}
@Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
if (name.equals("objectPackageName")) {
setObjectPackageName(jsonReader.nextString());
} else if (name.equals("objectServiveName")) {
setObjectServiveName(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;
}
}

Some files were not shown because too many files have changed in this diff Show More