Compare commits
95 Commits
appbase-v1
...
mymessagem
Author | SHA1 | Date | |
---|---|---|---|
![]() |
33b7b65239 | ||
![]() |
664d14ad84 | ||
![]() |
47cb393f76 | ||
![]() |
6495f1c66e | ||
![]() |
f0c52d1e02 | ||
![]() |
d948f31331 | ||
![]() |
e1b3087020 | ||
![]() |
03e21ab81c | ||
![]() |
ac72132969 | ||
![]() |
cedb5f521b | ||
![]() |
396df6713c | ||
![]() |
90e66889a9 | ||
![]() |
3031c9bfe0 | ||
![]() |
51acbb1f54 | ||
![]() |
26fc0b4684 | ||
![]() |
ecb67edec1 | ||
![]() |
3b30acfdec | ||
![]() |
c633e1663b | ||
![]() |
40589ad879 | ||
![]() |
0357fcf6b3 | ||
![]() |
c56fdaf14d | ||
![]() |
9b1264234e | ||
![]() |
d207a9ea9b | ||
![]() |
404239de23 | ||
![]() |
c16b80ffae | ||
![]() |
ca16a8677a | ||
![]() |
bb089a4eb1 | ||
![]() |
0c00ace869 | ||
![]() |
e06b642b70 | ||
![]() |
5e107028de | ||
![]() |
3bcfc5a5da | ||
![]() |
e849e54960 | ||
![]() |
8b2866419c | ||
![]() |
22a4a71203 | ||
![]() |
292f7c553f | ||
![]() |
df9970c6df | ||
![]() |
0312ca50d2 | ||
![]() |
56187b588f | ||
![]() |
d91372af52 | ||
![]() |
288725eca0 | ||
![]() |
bd728b83a3 | ||
![]() |
d4f9fc3561 | ||
![]() |
e7c614ebec | ||
![]() |
c226a92ffe | ||
![]() |
358e8b3522 | ||
![]() |
83ab4f9417 | ||
![]() |
26cdacf1c6 | ||
![]() |
6378433424 | ||
![]() |
7b05d613e4 | ||
![]() |
691f9bbd1c | ||
![]() |
7a8d3329d4 | ||
![]() |
bbac0c7306 | ||
![]() |
8d2b325172 | ||
![]() |
825dfb944e | ||
![]() |
419244b12a | ||
![]() |
39fda1b5da | ||
![]() |
464f2da89f | ||
![]() |
4f37b6f0e3 | ||
![]() |
f91cd0c9c3 | ||
![]() |
d09f0783a4 | ||
![]() |
accca716d4 | ||
![]() |
dfd09eb647 | ||
![]() |
79547adcb3 | ||
![]() |
be39eef6e7 | ||
![]() |
50490096b4 | ||
![]() |
3dd4c84602 | ||
![]() |
311bc8e339 | ||
![]() |
6467bcd675 | ||
![]() |
206c804b4d | ||
![]() |
7a4df0444e | ||
![]() |
3c827a56cf | ||
![]() |
36af7947e8 | ||
![]() |
805edcf9c4 | ||
![]() |
11005e3356 | ||
![]() |
75361b2313 | ||
![]() |
1d29ce81e8 | ||
![]() |
0297e81090 | ||
![]() |
df7203e985 | ||
![]() |
8c4e8b8e23 | ||
![]() |
d9c02f55e3 | ||
![]() |
a9cb6b471b | ||
![]() |
e694063867 | ||
![]() |
0ee13986dc | ||
![]() |
3239778922 | ||
![]() |
13510f45cf | ||
![]() |
49d300dd33 | ||
![]() |
c42f677d48 | ||
![]() |
9052a3924b | ||
![]() |
9642ad1966 | ||
![]() |
6686da0e8f | ||
![]() |
9e7aff09d1 | ||
![]() |
494b2b7fbc | ||
![]() |
b1f9b74e28 | ||
![]() |
32287e17c0 | ||
![]() |
8a0605c12e |
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
1
.idea/.name
generated
Normal file
1
.idea/.name
generated
Normal file
@@ -0,0 +1 @@
|
||||
appbase
|
6
.idea/compiler.xml
generated
Normal file
6
.idea/compiler.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="17" />
|
||||
</component>
|
||||
</project>
|
10
.idea/deploymentTargetDropDown.xml
generated
Normal file
10
.idea/deploymentTargetDropDown.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="deploymentTargetDropDown">
|
||||
<value>
|
||||
<entry key="appbase">
|
||||
<State />
|
||||
</entry>
|
||||
</value>
|
||||
</component>
|
||||
</project>
|
10
.idea/migrations.xml
generated
Normal file
10
.idea/migrations.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectMigrations">
|
||||
<option name="MigrateToGradleLocalJavaHome">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
10
.idea/misc.xml
generated
Normal file
10
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
@@ -18,18 +18,18 @@ def genVersionName(def versionName){
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 32
|
||||
buildToolsVersion "33.0.3"
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion "30.0.3"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "cc.winboll.studio.appbase"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
minSdkVersion 26
|
||||
targetSdkVersion 29
|
||||
versionCode 1
|
||||
// versionName 更新后需要手动设置
|
||||
// .winboll/winbollBuildProps.properties 文件的 stageCount=0
|
||||
// Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
|
||||
versionName "1.2"
|
||||
versionName "2.0"
|
||||
if(true) {
|
||||
versionName = genVersionName("${versionName}")
|
||||
}
|
||||
@@ -41,11 +41,6 @@ android {
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Sun Feb 09 15:09:34 HKT 2025
|
||||
stageCount=4
|
||||
#Tue Feb 25 16:51:17 HKT 2025
|
||||
stageCount=3
|
||||
libraryProject=libappbase
|
||||
baseVersion=1.2
|
||||
publishVersion=1.2.3
|
||||
baseVersion=2.0
|
||||
publishVersion=2.0.2
|
||||
buildCount=0
|
||||
baseBetaVersion=1.2.4
|
||||
baseBetaVersion=2.0.3
|
||||
|
@@ -21,15 +21,76 @@
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES"/>
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<activity android:name=".GlobalApplication$CrashActivity"/>
|
||||
|
||||
<service
|
||||
android:name=".MyTileService"
|
||||
android:label="@string/tileservice_name"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
|
||||
|
||||
<intent-filter>
|
||||
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE"/>
|
||||
|
||||
</intent-filter>
|
||||
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".services.MainService"
|
||||
android:exported="true"/>
|
||||
|
||||
<service android:name=".services.AssistantService"/>
|
||||
|
||||
<receiver android:name="cc.winboll.studio.appbase.receivers.MainReceiver">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="cc.winboll.studio.appbase.receivers.MainReceiver"/>
|
||||
</intent-filter>
|
||||
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".widgets.SOSWidget"
|
||||
android:exported="true">
|
||||
|
||||
<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="android.appwidget.action.APPWIDGET_UPDATE"/>
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.appwidget.provider"
|
||||
android:resource="@xml/widget_provider_info_sos"/>
|
||||
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".widgets.SOSWidgetClickListener">
|
||||
|
||||
<intent-filter>
|
||||
|
||||
<action android:name="cc.winboll.studio.appbase.widgets.SOSWidgetClickListener.ACTION_PRE"/>
|
||||
|
||||
<action android:name="cc.winboll.studio.appbase.widgets.SOSWidgetClickListener.ACTION_NEXT"/>
|
||||
|
||||
</intent-filter>
|
||||
|
||||
</receiver>
|
||||
|
||||
<meta-data
|
||||
android:name="android.max_aspect"
|
||||
android:value="4.0"/>
|
||||
|
||||
<activity android:name=".GlobalApplication$CrashActivity"/>
|
||||
|
||||
</application>
|
||||
|
||||
|
@@ -6,11 +6,22 @@ package cc.winboll.studio.appbase;
|
||||
* @Describe APPbase 应用类
|
||||
*/
|
||||
import cc.winboll.studio.libappbase.GlobalApplication;
|
||||
import cc.winboll.studio.libappbase.SOSCSBroadcastReceiver;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
public class App extends GlobalApplication {
|
||||
|
||||
|
||||
public static final String TAG = "App";
|
||||
|
||||
SOSCSBroadcastReceiver mSOSCSBroadcastReceiver;
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
GlobalApplication.setIsDebuging(this, BuildConfig.DEBUG);
|
||||
mSOSCSBroadcastReceiver = new SOSCSBroadcastReceiver();
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(SOSCSBroadcastReceiver.ACTION_SOS);
|
||||
registerReceiver(mSOSCSBroadcastReceiver, intentFilter);
|
||||
}
|
||||
}
|
||||
|
@@ -1,23 +1,116 @@
|
||||
package cc.winboll.studio.appbase;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import cc.winboll.studio.appbase.R;
|
||||
import cc.winboll.studio.appbase.services.MainService;
|
||||
import cc.winboll.studio.libappbase.GlobalApplication;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.LogView;
|
||||
import cc.winboll.studio.libappbase.SOS;
|
||||
import cc.winboll.studio.libappbase.SimpleOperateSignalCenterService;
|
||||
import cc.winboll.studio.libappbase.bean.APPSOSBean;
|
||||
import cc.winboll.studio.libappbase.services.TestService;
|
||||
import cc.winboll.studio.libappbase.widgets.StatusWidget;
|
||||
import com.hjq.toast.ToastUtils;
|
||||
|
||||
public class MainActivity extends Activity {
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
public static final String TAG = "MainActivity";
|
||||
|
||||
LogView mLogView;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
ToastUtils.show("onCreate");
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
Toolbar toolbar = findViewById(R.id.activitymainToolbar1);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
CheckBox cbIsDebugMode = findViewById(R.id.activitymainCheckBox1);
|
||||
cbIsDebugMode.setChecked(GlobalApplication.isDebuging());
|
||||
mLogView = findViewById(R.id.activitymainLogView1);
|
||||
|
||||
if (GlobalApplication.isDebuging()) { mLogView.start(); }
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
Intent intentAPPWidget = new Intent(this, StatusWidget.class);
|
||||
intentAPPWidget.setAction(StatusWidget.ACTION_STATUS_UPDATE);
|
||||
sendBroadcast(intentAPPWidget);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
LogUtils.d(TAG, "onResume");
|
||||
super.onResume();
|
||||
mLogView.start();
|
||||
}
|
||||
|
||||
public void onSwitchDebugMode(View view) {
|
||||
GlobalApplication.setIsDebuging(this, ((CheckBox)view).isChecked());
|
||||
}
|
||||
|
||||
public void onStartCenter(View view) {
|
||||
MainService.startMainService(this);
|
||||
}
|
||||
|
||||
public void onStopCenter(View view) {
|
||||
MainService.stopMainService(this);
|
||||
}
|
||||
|
||||
public void onTestStopWithoutSettingEnable(View view) {
|
||||
LogUtils.d(TAG, "onTestStopWithoutSettingEnable");
|
||||
stopService(new Intent(this, SimpleOperateSignalCenterService.class));
|
||||
}
|
||||
|
||||
public void onTestStartWithString(View view) {
|
||||
LogUtils.d(TAG, "onTestStartWithString");
|
||||
|
||||
// 目标服务的包名和类名
|
||||
String packageName = this.getPackageName();
|
||||
String serviceClassName = SimpleOperateSignalCenterService.class.getName();
|
||||
|
||||
// 构建Intent
|
||||
Intent intentService = new Intent();
|
||||
intentService.setComponent(new ComponentName(packageName, serviceClassName));
|
||||
|
||||
startService(intentService);
|
||||
}
|
||||
|
||||
public void onSOS(View view) {
|
||||
Intent intent = new Intent(this, TestService.class);
|
||||
stopService(intent);
|
||||
SOS.sosWinBollService(this, new APPSOSBean(getPackageName(), TestService.class.getName()));
|
||||
}
|
||||
|
||||
public void onStartTestService(View view) {
|
||||
Intent intent = new Intent(this, TestService.class);
|
||||
intent.setAction(SOS.ACTION_SERVICE_ENABLE);
|
||||
startService(intent);
|
||||
|
||||
}
|
||||
|
||||
public void onStopTestService(View view) {
|
||||
Intent intent = new Intent(this, TestService.class);
|
||||
intent.setAction(SOS.ACTION_SERVICE_DISABLE);
|
||||
startService(intent);
|
||||
|
||||
Intent intentStop = new Intent(this, TestService.class);
|
||||
stopService(intentStop);
|
||||
}
|
||||
|
||||
public void onStopTestServiceNoSettings(View view) {
|
||||
Intent intent = new Intent(this, TestService.class);
|
||||
stopService(intent);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,79 @@
|
||||
package cc.winboll.studio.appbase;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/13 19:30:10
|
||||
*/
|
||||
import android.content.Context;
|
||||
import android.service.quicksettings.Tile;
|
||||
import android.service.quicksettings.TileService;
|
||||
import cc.winboll.studio.appbase.beans.MainServiceBean;
|
||||
import cc.winboll.studio.appbase.services.MainService;
|
||||
|
||||
public class MyTileService extends TileService {
|
||||
public static final String TAG = "MyTileService";
|
||||
|
||||
volatile static MyTileService _MyTileService;
|
||||
|
||||
@Override
|
||||
public void onStartListening() {
|
||||
super.onStartListening();
|
||||
_MyTileService = this;
|
||||
Tile tile = getQsTile();
|
||||
MainServiceBean bean = MainServiceBean.loadBean(this, MainServiceBean.class);
|
||||
if (bean != null && bean.isEnable()) {
|
||||
//MainService.startMainService(context);
|
||||
tile.setState(Tile.STATE_ACTIVE);
|
||||
tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud));
|
||||
} else {
|
||||
//MainService.stopMainService(context);
|
||||
tile.setState(Tile.STATE_INACTIVE);
|
||||
tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud_outline));
|
||||
}
|
||||
tile.updateTile();
|
||||
// Tile tile = getQsTile();
|
||||
// tile.setState(Tile.STATE_INACTIVE);
|
||||
// tile.setLabel(getString(R.string.tileservice_name));
|
||||
// tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud_outline));
|
||||
// tile.updateTile();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
super.onClick();
|
||||
Tile tile = getQsTile();
|
||||
MainServiceBean bean = MainServiceBean.loadBean(this, MainServiceBean.class);
|
||||
if (bean == null) {
|
||||
bean = new MainServiceBean();
|
||||
}
|
||||
|
||||
if (tile.getState() == Tile.STATE_ACTIVE) {
|
||||
bean.setIsEnable(false);
|
||||
MainServiceBean.saveBean(this, bean);
|
||||
MainService.stopMainService(this);
|
||||
} else if (tile.getState() == Tile.STATE_INACTIVE) {
|
||||
bean.setIsEnable(true);
|
||||
MainServiceBean.saveBean(this, bean);
|
||||
MainService.startMainService(this);
|
||||
}
|
||||
updateServiceIconStatus(this);
|
||||
}
|
||||
|
||||
public static void updateServiceIconStatus(Context context) {
|
||||
if (_MyTileService == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tile tile = _MyTileService.getQsTile();
|
||||
MainServiceBean bean = MainServiceBean.loadBean(context, MainServiceBean.class);
|
||||
if (bean != null && bean.isEnable()) {
|
||||
tile.setState(Tile.STATE_ACTIVE);
|
||||
tile.setIcon(android.graphics.drawable.Icon.createWithResource(context, R.drawable.ic_cloud));
|
||||
} else {
|
||||
tile.setState(Tile.STATE_INACTIVE);
|
||||
tile.setIcon(android.graphics.drawable.Icon.createWithResource(context, R.drawable.ic_cloud_outline));
|
||||
}
|
||||
tile.updateTile();
|
||||
}
|
||||
}
|
@@ -0,0 +1,68 @@
|
||||
package cc.winboll.studio.appbase.beans;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/13 07:06:13
|
||||
*/
|
||||
import android.util.JsonReader;
|
||||
import android.util.JsonWriter;
|
||||
import cc.winboll.studio.libappbase.BaseBean;
|
||||
import java.io.IOException;
|
||||
|
||||
public class MainServiceBean extends BaseBean {
|
||||
|
||||
public static final String TAG = "MainServiceBean";
|
||||
|
||||
boolean isEnable;
|
||||
|
||||
public MainServiceBean() {
|
||||
this.isEnable = false;
|
||||
}
|
||||
|
||||
public void setIsEnable(boolean isEnable) {
|
||||
this.isEnable = isEnable;
|
||||
}
|
||||
|
||||
public boolean isEnable() {
|
||||
return isEnable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return MainServiceBean.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
|
||||
super.writeThisToJsonWriter(jsonWriter);
|
||||
MainServiceBean bean = this;
|
||||
jsonWriter.name("isEnable").value(bean.isEnable());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
|
||||
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
|
||||
if (name.equals("isEnable")) {
|
||||
setIsEnable(jsonReader.nextBoolean());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException {
|
||||
jsonReader.beginObject();
|
||||
while (jsonReader.hasNext()) {
|
||||
String name = jsonReader.nextName();
|
||||
if (!initObjectsFromJsonReader(jsonReader, name)) {
|
||||
jsonReader.skipValue();
|
||||
}
|
||||
}
|
||||
// 结束 JSON 对象
|
||||
jsonReader.endObject();
|
||||
return this;
|
||||
}
|
||||
}
|
@@ -0,0 +1,72 @@
|
||||
package cc.winboll.studio.appbase.beans;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/17 10:05:09
|
||||
* @Describe APPSOSReportBean
|
||||
*/
|
||||
import android.util.JsonReader;
|
||||
import android.util.JsonWriter;
|
||||
import cc.winboll.studio.libappbase.BaseBean;
|
||||
import java.io.IOException;
|
||||
|
||||
public class SOSReportBean extends BaseBean {
|
||||
|
||||
public static final String TAG = "APPSOSReportBean";
|
||||
|
||||
protected String sosReport;
|
||||
|
||||
public SOSReportBean() {
|
||||
this.sosReport = "";
|
||||
}
|
||||
|
||||
public SOSReportBean(String sosReport) {
|
||||
this.sosReport = sosReport;
|
||||
}
|
||||
|
||||
public void setSosReport(String sosReport) {
|
||||
this.sosReport = sosReport;
|
||||
}
|
||||
|
||||
public String getSosReport() {
|
||||
return sosReport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return SOSReportBean.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
|
||||
super.writeThisToJsonWriter(jsonWriter);
|
||||
jsonWriter.name("sosReport").value(getSosReport());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
|
||||
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
|
||||
if (name.equals("sosReport")) {
|
||||
setSosReport(jsonReader.nextString());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException {
|
||||
jsonReader.beginObject();
|
||||
while (jsonReader.hasNext()) {
|
||||
String name = jsonReader.nextName();
|
||||
if (!initObjectsFromJsonReader(jsonReader, name)) {
|
||||
jsonReader.skipValue();
|
||||
}
|
||||
}
|
||||
// 结束 JSON 对象
|
||||
jsonReader.endObject();
|
||||
return this;
|
||||
}
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
package cc.winboll.studio.appbase.handlers;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/14 03:51:40
|
||||
*/
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import cc.winboll.studio.appbase.services.MainService;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class MainServiceHandler extends Handler {
|
||||
public static final String TAG = "MainServiceHandler";
|
||||
|
||||
public static final int MSG_REMINDTHREAD = 0;
|
||||
|
||||
WeakReference<MainService> serviceWeakReference;
|
||||
public MainServiceHandler(MainService service) {
|
||||
serviceWeakReference = new WeakReference<MainService>(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_REMINDTHREAD: // 处理下载完成消息,更新UI
|
||||
{
|
||||
// 显示提醒消息
|
||||
//
|
||||
//LogUtils.d(TAG, "显示提醒消息");
|
||||
MainService mainService = serviceWeakReference.get();
|
||||
if (mainService != null) {
|
||||
mainService.appenMessage((String)msg.obj);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,132 @@
|
||||
package cc.winboll.studio.appbase.receivers;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/13 06:58:04
|
||||
* @Describe 主要广播接收器
|
||||
*/
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import cc.winboll.studio.appbase.beans.SOSReportBean;
|
||||
import cc.winboll.studio.appbase.services.MainService;
|
||||
import cc.winboll.studio.appbase.widgets.SOSWidget;
|
||||
import cc.winboll.studio.libappbase.AppUtils;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.SOS;
|
||||
import cc.winboll.studio.libappbase.bean.APPSOSBean;
|
||||
import com.hjq.toast.ToastUtils;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class MainReceiver extends BroadcastReceiver {
|
||||
|
||||
public static final String TAG = "MainReceiver";
|
||||
public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
|
||||
WeakReference<MainService> mwrService;
|
||||
// 存储电量指示值,
|
||||
// 用于校验电量消息时的电量变化
|
||||
static volatile int _mnTheQuantityOfElectricityOld = -1;
|
||||
static volatile boolean _mIsCharging = false;
|
||||
|
||||
public MainReceiver(MainService service) {
|
||||
mwrService = new WeakReference<MainService>(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String szAction = intent.getAction();
|
||||
if (szAction.equals(ACTION_BOOT_COMPLETED)) {
|
||||
ToastUtils.show("ACTION_BOOT_COMPLETED");
|
||||
} else if (szAction.equals(SOS.ACTION_BIND)) {
|
||||
LogUtils.d(TAG, "ACTION_BIND");
|
||||
LogUtils.d(TAG, String.format("context.getPackageName() %s", context.getPackageName()));
|
||||
LogUtils.d(TAG, String.format("intent.getAction() %s", intent.getAction()));
|
||||
String SOS = intent.getStringExtra("SOS");
|
||||
LogUtils.d(TAG, String.format("SOS %s", SOS));
|
||||
if (SOS != null && SOS.equals("Service")) {
|
||||
String szAPPSOSBean = intent.getStringExtra("APPSOSBean");
|
||||
LogUtils.d(TAG, String.format("szAPPSOSBean %s", szAPPSOSBean));
|
||||
if (szAPPSOSBean != null && !szAPPSOSBean.equals("")) {
|
||||
try {
|
||||
APPSOSBean bean = APPSOSBean.parseStringToBean(szAPPSOSBean, APPSOSBean.class);
|
||||
if (bean != null) {
|
||||
String sosPackage = bean.getSosPackage();
|
||||
LogUtils.d(TAG, String.format("sosPackage %s", sosPackage));
|
||||
String sosClassName = bean.getSosClassName();
|
||||
LogUtils.d(TAG, String.format("sosClassName %s", sosClassName));
|
||||
mwrService.get().bindSOSConnection(bean);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (intent.getAction().equals(SOS.ACTION_SOS)) {
|
||||
LogUtils.d(TAG, "ACTION_SOS");
|
||||
LogUtils.d(TAG, String.format("context.getPackageName() %s", context.getPackageName()));
|
||||
LogUtils.d(TAG, String.format("intent.getAction() %s", intent.getAction()));
|
||||
String SOS = intent.getStringExtra("SOS");
|
||||
LogUtils.d(TAG, String.format("SOS %s", SOS));
|
||||
if (SOS != null && SOS.equals("Service")) {
|
||||
String szAPPSOSBean = intent.getStringExtra("APPSOSBean");
|
||||
LogUtils.d(TAG, String.format("szAPPSOSBean %s", szAPPSOSBean));
|
||||
if (szAPPSOSBean != null && !szAPPSOSBean.equals("")) {
|
||||
try {
|
||||
APPSOSBean bean = APPSOSBean.parseStringToBean(szAPPSOSBean, APPSOSBean.class);
|
||||
if (bean != null) {
|
||||
String sosPackage = bean.getSosPackage();
|
||||
LogUtils.d(TAG, String.format("sosPackage %s", sosPackage));
|
||||
String sosClassName = bean.getSosClassName();
|
||||
LogUtils.d(TAG, String.format("sosClassName %s", sosClassName));
|
||||
|
||||
Intent intentService = new Intent();
|
||||
intentService.setComponent(new ComponentName(sosPackage, sosClassName));
|
||||
context.startService(intentService);
|
||||
|
||||
String appName = AppUtils.getAppNameByPackageName(context, sosPackage);
|
||||
LogUtils.d(TAG, String.format("appName %s", appName));
|
||||
SOSReportBean appSOSReportBean = new SOSReportBean(appName);
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
|
||||
String currentTime = sdf.format(new Date());
|
||||
StringBuilder sbLine = new StringBuilder();
|
||||
sbLine.append("[");
|
||||
sbLine.append(currentTime);
|
||||
sbLine.append("] Power to ");
|
||||
sbLine.append(appName);
|
||||
appSOSReportBean.setSosReport(sbLine.toString());
|
||||
|
||||
SOSWidget.addAPPSOSReportBean(context, appSOSReportBean);
|
||||
|
||||
Intent intentWidget = new Intent(context, SOSWidget.class);
|
||||
intentWidget.setAction(SOSWidget.ACTION_RELOAD_REPORT);
|
||||
context.sendBroadcast(intentWidget);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ToastUtils.show(szAction);
|
||||
}
|
||||
}
|
||||
|
||||
// 注册 Receiver
|
||||
//
|
||||
public void registerAction(MainService service) {
|
||||
IntentFilter filter=new IntentFilter();
|
||||
filter.addAction(ACTION_BOOT_COMPLETED);
|
||||
filter.addAction(SOS.ACTION_SOS);
|
||||
filter.addAction(SOS.ACTION_BIND);
|
||||
filter.addAction(SOS.ACTION_SERVICE_ENABLE);
|
||||
filter.addAction(SOS.ACTION_SERVICE_DISABLE);
|
||||
//filter.addAction(Intent.ACTION_BATTERY_CHANGED);
|
||||
service.registerReceiver(this, filter);
|
||||
}
|
||||
}
|
@@ -0,0 +1,138 @@
|
||||
package cc.winboll.studio.appbase.services;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/14 03:38:31
|
||||
* @Describe 守护进程服务
|
||||
*/
|
||||
import android.app.Service;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.IBinder;
|
||||
import cc.winboll.studio.appbase.beans.MainServiceBean;
|
||||
import cc.winboll.studio.appbase.services.AssistantService;
|
||||
import cc.winboll.studio.appbase.services.MainService;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import android.os.Binder;
|
||||
|
||||
public class AssistantService extends Service {
|
||||
|
||||
public static final String TAG = "AssistantService";
|
||||
|
||||
MainServiceBean mMainServiceBean;
|
||||
MyServiceConnection mMyServiceConnection;
|
||||
MainService mMainService;
|
||||
boolean isBound = false;
|
||||
volatile boolean isThreadAlive = false;
|
||||
|
||||
public synchronized void setIsThreadAlive(boolean isThreadAlive) {
|
||||
LogUtils.d(TAG, "setIsThreadAlive(...)");
|
||||
LogUtils.d(TAG, String.format("isThreadAlive %s", isThreadAlive));
|
||||
this.isThreadAlive = isThreadAlive;
|
||||
}
|
||||
|
||||
public boolean isThreadAlive() {
|
||||
return isThreadAlive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return new MyBinder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
LogUtils.d(TAG, "onCreate");
|
||||
super.onCreate();
|
||||
|
||||
//mMyBinder = new MyBinder();
|
||||
if (mMyServiceConnection == null) {
|
||||
mMyServiceConnection = new MyServiceConnection();
|
||||
}
|
||||
// 设置运行参数
|
||||
setIsThreadAlive(false);
|
||||
assistantService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
LogUtils.d(TAG, "call onStartCommand(...)");
|
||||
assistantService();
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
//LogUtils.d(TAG, "onDestroy");
|
||||
setIsThreadAlive(false);
|
||||
// 解除绑定
|
||||
if (isBound) {
|
||||
unbindService(mMyServiceConnection);
|
||||
isBound = false;
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
// 运行服务内容
|
||||
//
|
||||
void assistantService() {
|
||||
LogUtils.d(TAG, "assistantService()");
|
||||
mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class);
|
||||
LogUtils.d(TAG, String.format("mMainServiceBean.isEnable() %s", mMainServiceBean.isEnable()));
|
||||
if (mMainServiceBean.isEnable()) {
|
||||
LogUtils.d(TAG, String.format("mIsThreadAlive %s", isThreadAlive()));
|
||||
if (isThreadAlive() == false) {
|
||||
// 设置运行状态
|
||||
setIsThreadAlive(true);
|
||||
// 唤醒和绑定主进程
|
||||
wakeupAndBindMain();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 唤醒和绑定主进程
|
||||
//
|
||||
void wakeupAndBindMain() {
|
||||
LogUtils.d(TAG, "wakeupAndBindMain()");
|
||||
// 绑定服务的Intent
|
||||
Intent intent = new Intent(this, MainService.class);
|
||||
startService(new Intent(this, MainService.class));
|
||||
bindService(intent, mMyServiceConnection, Context.BIND_IMPORTANT);
|
||||
|
||||
// startService(new Intent(this, MainService.class));
|
||||
// bindService(new Intent(AssistantService.this, MainService.class), mMyServiceConnection, Context.BIND_IMPORTANT);
|
||||
}
|
||||
|
||||
// 主进程与守护进程连接时需要用到此类
|
||||
//
|
||||
class MyServiceConnection implements ServiceConnection {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
LogUtils.d(TAG, "onServiceConnected(...)");
|
||||
MainService.MyBinder binder = (MainService.MyBinder) service;
|
||||
mMainService = binder.getService();
|
||||
isBound = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
LogUtils.d(TAG, "onServiceDisconnected(...)");
|
||||
mMainServiceBean = MainServiceBean.loadBean(AssistantService.this, MainServiceBean.class);
|
||||
if (mMainServiceBean.isEnable()) {
|
||||
wakeupAndBindMain();
|
||||
}
|
||||
isBound = false;
|
||||
mMainService = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 用于返回服务实例的Binder
|
||||
public class MyBinder extends Binder {
|
||||
AssistantService getService() {
|
||||
LogUtils.d(TAG, "AssistantService MyBinder getService()");
|
||||
return AssistantService.this;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,326 @@
|
||||
package cc.winboll.studio.appbase.services;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/13 06:56:41
|
||||
* @Describe 拨号主服务
|
||||
* 参考:
|
||||
* 进程保活-双进程守护的正确姿势
|
||||
* https://blog.csdn.net/sinat_35159441/article/details/75267380
|
||||
* Android Service之onStartCommand方法研究
|
||||
* https://blog.csdn.net/cyp331203/article/details/38920491
|
||||
*/
|
||||
import android.app.Service;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import cc.winboll.studio.appbase.MyTileService;
|
||||
import cc.winboll.studio.appbase.beans.MainServiceBean;
|
||||
import cc.winboll.studio.appbase.handlers.MainServiceHandler;
|
||||
import cc.winboll.studio.appbase.receivers.MainReceiver;
|
||||
import cc.winboll.studio.appbase.services.AssistantService;
|
||||
import cc.winboll.studio.appbase.threads.MainServiceThread;
|
||||
import cc.winboll.studio.appbase.widgets.SOSWidget;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.bean.APPSOSBean;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class MainService extends Service {
|
||||
|
||||
public static final String TAG = "MainService";
|
||||
|
||||
public static final int MSG_UPDATE_STATUS = 0;
|
||||
|
||||
static MainService _mControlCenterService;
|
||||
|
||||
volatile boolean isServiceRunning;
|
||||
|
||||
MainServiceBean mMainServiceBean;
|
||||
MainServiceThread mMainServiceThread;
|
||||
MainServiceHandler mMainServiceHandler;
|
||||
MyServiceConnection mMyServiceConnection;
|
||||
AssistantService mAssistantService;
|
||||
boolean isBound = false;
|
||||
MainReceiver mMainReceiver;
|
||||
ArrayList<SOSConnection> mSOSConnectionList;
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return new MyBinder();
|
||||
}
|
||||
|
||||
public MainServiceThread getRemindThread() {
|
||||
return mMainServiceThread;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
LogUtils.d(TAG, "onCreate()");
|
||||
mSOSConnectionList = new ArrayList<SOSConnection>();
|
||||
|
||||
_mControlCenterService = MainService.this;
|
||||
isServiceRunning = false;
|
||||
mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class);
|
||||
|
||||
if (mMyServiceConnection == null) {
|
||||
mMyServiceConnection = new MyServiceConnection();
|
||||
}
|
||||
mMainServiceHandler = new MainServiceHandler(this);
|
||||
|
||||
// 运行服务内容
|
||||
mainService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
LogUtils.d(TAG, "onStartCommand(...)");
|
||||
// 运行服务内容
|
||||
mainService();
|
||||
return (mMainServiceBean.isEnable()) ? START_STICKY : super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
|
||||
// 运行服务内容
|
||||
//
|
||||
void mainService() {
|
||||
LogUtils.d(TAG, "mainService()");
|
||||
mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class);
|
||||
if (mMainServiceBean.isEnable() && isServiceRunning == false) {
|
||||
LogUtils.d(TAG, "mainService() start running");
|
||||
isServiceRunning = true;
|
||||
// 唤醒守护进程
|
||||
wakeupAndBindAssistant();
|
||||
|
||||
if (mMainReceiver == null) {
|
||||
// 注册广播接收器
|
||||
mMainReceiver = new MainReceiver(this);
|
||||
mMainReceiver.registerAction(this);
|
||||
}
|
||||
|
||||
// 启动小部件
|
||||
Intent intentTimeWidget = new Intent(this, SOSWidget.class);
|
||||
intentTimeWidget.setAction(SOSWidget.ACTION_RELOAD_REPORT);
|
||||
this.sendBroadcast(intentTimeWidget);
|
||||
|
||||
startMainServiceThread();
|
||||
|
||||
MyTileService.updateServiceIconStatus(this);
|
||||
|
||||
LogUtils.i(TAG, "Main Service Is Start.");
|
||||
}
|
||||
}
|
||||
|
||||
// 唤醒和绑定守护进程
|
||||
//
|
||||
void wakeupAndBindAssistant() {
|
||||
LogUtils.d(TAG, "wakeupAndBindAssistant()");
|
||||
// if (ServiceUtils.isServiceAlive(getApplicationContext(), AssistantService.class.getName()) == false) {
|
||||
// startService(new Intent(MainService.this, AssistantService.class));
|
||||
// //LogUtils.d(TAG, "call wakeupAndBindAssistant() : Binding... AssistantService");
|
||||
// bindService(new Intent(MainService.this, AssistantService.class), mMyServiceConnection, Context.BIND_IMPORTANT);
|
||||
// }
|
||||
Intent intent = new Intent(this, AssistantService.class);
|
||||
startService(intent);
|
||||
// 绑定服务的Intent
|
||||
//Intent intent = new Intent(this, AssistantService.class);
|
||||
bindService(intent, mMyServiceConnection, Context.BIND_IMPORTANT);
|
||||
|
||||
// Intent intent = new Intent(this, AssistantService.class);
|
||||
// startService(intent);
|
||||
// LogUtils.d(TAG, "startService(intent)");
|
||||
// bindService(new Intent(this, AssistantService.class), mMyServiceConnection, Context.BIND_IMPORTANT);
|
||||
}
|
||||
|
||||
// 开启提醒铃声线程
|
||||
//
|
||||
public void startMainServiceThread() {
|
||||
LogUtils.d(TAG, "startMainServiceThread");
|
||||
if (mMainServiceThread == null) {
|
||||
mMainServiceThread = new MainServiceThread(this, mMainServiceHandler);
|
||||
LogUtils.d(TAG, "new MainServiceThread");
|
||||
} else {
|
||||
if (mMainServiceThread.isExist() == true) {
|
||||
mMainServiceThread = new MainServiceThread(this, mMainServiceHandler);
|
||||
LogUtils.d(TAG, "renew MainServiceThread");
|
||||
} else {
|
||||
// 提醒进程正在进行中就更新状态后退出
|
||||
LogUtils.d(TAG, "A mMainServiceThread running.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
mMainServiceThread.start();
|
||||
}
|
||||
|
||||
public void stopRemindThread() {
|
||||
if (mMainServiceThread != null) {
|
||||
mMainServiceThread.setIsExist(true);
|
||||
mMainServiceThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
//LogUtils.d(TAG, "onDestroy");
|
||||
mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class);
|
||||
if (mMainServiceBean.isEnable() == false) {
|
||||
// 设置运行状态
|
||||
isServiceRunning = false;// 解除绑定
|
||||
if (isBound) {
|
||||
unbindService(mMyServiceConnection);
|
||||
isBound = false;
|
||||
}
|
||||
// 停止守护进程
|
||||
Intent intent = new Intent(this, AssistantService.class);
|
||||
stopService(intent);
|
||||
// 停止Receiver
|
||||
if (mMainReceiver != null) {
|
||||
unregisterReceiver(mMainReceiver);
|
||||
mMainReceiver = null;
|
||||
}
|
||||
// 停止前台通知栏
|
||||
stopForeground(true);
|
||||
// 停止消息提醒进程
|
||||
stopRemindThread();
|
||||
|
||||
MyTileService.updateServiceIconStatus(this);
|
||||
|
||||
super.onDestroy();
|
||||
//LogUtils.d(TAG, "onDestroy done");
|
||||
}
|
||||
}
|
||||
|
||||
public void bindSOSConnection(APPSOSBean bean) {
|
||||
LogUtils.d(TAG, "bindSOSConnection(...)");
|
||||
// 清理旧的绑定链接
|
||||
for (int i = mSOSConnectionList.size() - 1; i > -1; i--) {
|
||||
SOSConnection item = mSOSConnectionList.get(i);
|
||||
if (item.isBindToAPPSOSBean(bean)) {
|
||||
LogUtils.d(TAG, "Bind Servive exist.");
|
||||
unbindService(item);
|
||||
mSOSConnectionList.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
// 绑定服务
|
||||
SOSConnection sosConnection = new SOSConnection();
|
||||
Intent intentService = new Intent();
|
||||
intentService.setComponent(new ComponentName(bean.getSosPackage(), bean.getSosClassName()));
|
||||
bindService(intentService, sosConnection, Context.BIND_IMPORTANT);
|
||||
mSOSConnectionList.add(sosConnection);
|
||||
|
||||
Intent intentWidget = new Intent(this, SOSWidget.class);
|
||||
intentWidget.setAction(SOSWidget.ACTION_WAKEUP_SERVICE);
|
||||
APPSOSBean appSOSBean = new APPSOSBean(bean.getSosPackage(), bean.getSosClassName());
|
||||
intentWidget.putExtra("APPSOSBean", appSOSBean.toString());
|
||||
sendBroadcast(intentWidget);
|
||||
}
|
||||
|
||||
public class SOSConnection implements ServiceConnection {
|
||||
|
||||
ComponentName mComponentName;
|
||||
|
||||
boolean isBindToAPPSOSBean(APPSOSBean bean) {
|
||||
return mComponentName != null
|
||||
&& mComponentName.getClassName().equals(bean.getSosClassName())
|
||||
&& mComponentName.getPackageName().equals(bean.getSosPackage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
LogUtils.d(TAG, "onServiceConnected(...)");
|
||||
mComponentName = name;
|
||||
LogUtils.d(TAG, String.format("onServiceConnected : \ngetClassName %s\ngetPackageName %s", name.getClassName(), name.getPackageName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
LogUtils.d(TAG, "onServiceDisconnected(...)");
|
||||
LogUtils.d(TAG, String.format("onServiceDisconnected : \ngetClassName %s\ngetPackageName %s", name.getClassName(), name.getPackageName()));
|
||||
|
||||
// 尝试无参数启动一下服务
|
||||
String sosPackage = mComponentName.getPackageName();
|
||||
LogUtils.d(TAG, String.format("sosPackage %s", sosPackage));
|
||||
String sosClassName = mComponentName.getClassName();
|
||||
LogUtils.d(TAG, String.format("sosClassName %s", sosClassName));
|
||||
|
||||
Intent intentService = new Intent();
|
||||
intentService.setComponent(new ComponentName(sosPackage, sosClassName));
|
||||
startService(intentService);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 主进程与守护进程连接时需要用到此类
|
||||
//
|
||||
private class MyServiceConnection implements ServiceConnection {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
LogUtils.d(TAG, "onServiceConnected(...)");
|
||||
AssistantService.MyBinder binder = (AssistantService.MyBinder) service;
|
||||
mAssistantService = binder.getService();
|
||||
isBound = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
LogUtils.d(TAG, "onServiceDisconnected(...)");
|
||||
|
||||
if (mMainServiceBean.isEnable()) {
|
||||
// 唤醒守护进程
|
||||
wakeupAndBindAssistant();
|
||||
}
|
||||
isBound = false;
|
||||
mAssistantService = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 用于返回服务实例的Binder
|
||||
public class MyBinder extends Binder {
|
||||
MainService getService() {
|
||||
LogUtils.d(TAG, "MainService MyBinder getService()");
|
||||
return MainService.this;
|
||||
}
|
||||
}
|
||||
|
||||
// //
|
||||
// // 启动服务
|
||||
// //
|
||||
// public static void startControlCenterService(Context context) {
|
||||
// Intent intent = new Intent(context, MainService.class);
|
||||
// context.startForegroundService(intent);
|
||||
// }
|
||||
//
|
||||
// //
|
||||
// // 停止服务
|
||||
// //
|
||||
// public static void stopControlCenterService(Context context) {
|
||||
// Intent intent = new Intent(context, MainService.class);
|
||||
// context.stopService(intent);
|
||||
// }
|
||||
|
||||
public void appenMessage(String message) {
|
||||
LogUtils.d(TAG, String.format("Message : %s", message));
|
||||
}
|
||||
|
||||
public static void stopMainService(Context context) {
|
||||
LogUtils.d(TAG, "stopMainService");
|
||||
MainServiceBean bean = new MainServiceBean();
|
||||
bean.setIsEnable(false);
|
||||
MainServiceBean.saveBean(context, bean);
|
||||
context.stopService(new Intent(context, MainService.class));
|
||||
}
|
||||
|
||||
public static void startMainService(Context context) {
|
||||
LogUtils.d(TAG, "startMainService");
|
||||
MainServiceBean bean = new MainServiceBean();
|
||||
bean.setIsEnable(true);
|
||||
MainServiceBean.saveBean(context, bean);
|
||||
context.startService(new Intent(context, MainService.class));
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,54 @@
|
||||
package cc.winboll.studio.appbase.threads;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/14 03:46:44
|
||||
*/
|
||||
import android.content.Context;
|
||||
import cc.winboll.studio.appbase.handlers.MainServiceHandler;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class MainServiceThread extends Thread {
|
||||
|
||||
public static final String TAG = "MainServiceThread";
|
||||
|
||||
Context mContext;
|
||||
|
||||
// 控制线程是否退出的标志
|
||||
volatile boolean isExist = false;
|
||||
|
||||
// 服务Handler, 用于线程发送消息使用
|
||||
WeakReference<MainServiceHandler> mwrMainServiceHandler;
|
||||
|
||||
public void setIsExist(boolean isExist) {
|
||||
this.isExist = isExist;
|
||||
}
|
||||
|
||||
public boolean isExist() {
|
||||
return isExist;
|
||||
}
|
||||
|
||||
public MainServiceThread(Context context, MainServiceHandler handler) {
|
||||
mContext = context;
|
||||
mwrMainServiceHandler = new WeakReference<MainServiceHandler>(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
LogUtils.d(TAG, "run()");
|
||||
|
||||
while (!isExist()) {
|
||||
//ToastUtils.show("run()");
|
||||
//LogUtils.d(TAG, "run()");
|
||||
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
|
||||
}
|
||||
}
|
||||
LogUtils.d(TAG, "run() exit.");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,184 @@
|
||||
package cc.winboll.studio.appbase.widgets;
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/15 14:41:25
|
||||
* @Describe TimeWidget
|
||||
*/
|
||||
import android.app.PendingIntent;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProvider;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.widget.RemoteViews;
|
||||
import cc.winboll.studio.appbase.R;
|
||||
import cc.winboll.studio.appbase.beans.SOSReportBean;
|
||||
import cc.winboll.studio.libappbase.AppUtils;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.bean.APPSOSBean;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
||||
public class SOSWidget extends AppWidgetProvider {
|
||||
|
||||
public static final String TAG = "SOSWidget";
|
||||
|
||||
public static final String ACTION_WAKEUP_SERVICE = "cc.winboll.studio.appbase.widgets.SOSWidget.ACTION_WAKEUP_SERVICE";
|
||||
public static final String ACTION_RELOAD_REPORT = "cc.winboll.studio.appbase.widgets.SOSWidget.ACTION_RELOAD_REPORT";
|
||||
|
||||
|
||||
volatile static ArrayList<SOSReportBean> _SOSReportBeanList;
|
||||
final static int _MAX_PAGES = 10;
|
||||
final static int _OnePageLinesCount = 5;
|
||||
volatile static int _CurrentPageIndex = 0;
|
||||
|
||||
@Override
|
||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
||||
initAPPSOSReportBeanList(context);
|
||||
for (int appWidgetId : appWidgetIds) {
|
||||
updateAppWidget(context, appWidgetManager, appWidgetId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
super.onReceive(context, intent);
|
||||
initAPPSOSReportBeanList(context);
|
||||
if (intent.getAction().equals(ACTION_RELOAD_REPORT)) {
|
||||
LogUtils.d(TAG, "ACTION_RELOAD_REPORT");
|
||||
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
||||
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, SOSWidget.class));
|
||||
for (int appWidgetId : appWidgetIds) {
|
||||
updateAppWidget(context, appWidgetManager, appWidgetId);
|
||||
}
|
||||
}else if (intent.getAction().equals(ACTION_WAKEUP_SERVICE)) {
|
||||
LogUtils.d(TAG, "ACTION_WAKEUP_SERVICE");
|
||||
String szAPPSOSBean = intent.getStringExtra("APPSOSBean");
|
||||
LogUtils.d(TAG, String.format("szAPPSOSBean %s", szAPPSOSBean));
|
||||
if (szAPPSOSBean != null && !szAPPSOSBean.equals("")) {
|
||||
try {
|
||||
APPSOSBean bean = APPSOSBean.parseStringToBean(szAPPSOSBean, APPSOSBean.class);
|
||||
if (bean != null) {
|
||||
String sosPackage = bean.getSosPackage();
|
||||
LogUtils.d(TAG, String.format("sosPackage %s", sosPackage));
|
||||
String sosClassName = bean.getSosClassName();
|
||||
LogUtils.d(TAG, String.format("sosClassName %s", sosClassName));
|
||||
|
||||
|
||||
String appName = AppUtils.getAppNameByPackageName(context, sosPackage);
|
||||
LogUtils.d(TAG, String.format("appName %s", appName));
|
||||
SOSReportBean appSOSReportBean = new SOSReportBean(appName);
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
|
||||
String currentTime = sdf.format(new Date());
|
||||
StringBuilder sbLine = new StringBuilder();
|
||||
sbLine.append("[");
|
||||
sbLine.append(currentTime);
|
||||
sbLine.append("] Wake up ");
|
||||
sbLine.append(appName);
|
||||
appSOSReportBean.setSosReport(sbLine.toString());
|
||||
|
||||
addAPPSOSReportBean(context, appSOSReportBean);
|
||||
|
||||
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
||||
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, SOSWidget.class));
|
||||
for (int appWidgetId : appWidgetIds) {
|
||||
updateAppWidget(context, appWidgetManager, appWidgetId);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 加入新报告信息
|
||||
//
|
||||
public synchronized static void addAPPSOSReportBean(Context context, SOSReportBean bean) {
|
||||
initAPPSOSReportBeanList(context);
|
||||
_SOSReportBeanList.add(0, bean);
|
||||
// 控制记录总数
|
||||
while (_SOSReportBeanList.size() > _MAX_PAGES * _OnePageLinesCount) {
|
||||
_SOSReportBeanList.remove(_SOSReportBeanList.size() - 1);
|
||||
}
|
||||
SOSReportBean.saveBeanList(context, _SOSReportBeanList, SOSReportBean.class);
|
||||
}
|
||||
|
||||
synchronized static void initAPPSOSReportBeanList(Context context) {
|
||||
if (_SOSReportBeanList == null) {
|
||||
_SOSReportBeanList = new ArrayList<SOSReportBean>();
|
||||
SOSReportBean.loadBeanList(context, _SOSReportBeanList, SOSReportBean.class);
|
||||
}
|
||||
if (_SOSReportBeanList == null) {
|
||||
_SOSReportBeanList = new ArrayList<SOSReportBean>();
|
||||
SOSReportBean.saveBeanList(context, _SOSReportBeanList, SOSReportBean.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
|
||||
LogUtils.d(TAG, "updateAppWidget(...)");
|
||||
|
||||
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_sos);
|
||||
//设置按钮点击事件
|
||||
Intent intentPre = new Intent(context, SOSWidgetClickListener.class);
|
||||
intentPre.setAction(SOSWidgetClickListener.ACTION_PRE);
|
||||
PendingIntent pendingIntentPre = PendingIntent.getBroadcast(context, 0, intentPre, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
views.setOnClickPendingIntent(R.id.widget_button_pre, pendingIntentPre);
|
||||
Intent intentNext = new Intent(context, SOSWidgetClickListener.class);
|
||||
intentNext.setAction(SOSWidgetClickListener.ACTION_NEXT);
|
||||
PendingIntent pendingIntentNext = PendingIntent.getBroadcast(context, 0, intentNext, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
views.setOnClickPendingIntent(R.id.widget_button_next, pendingIntentNext);
|
||||
|
||||
views.setTextViewText(R.id.infoTextView, getPageInfo());
|
||||
views.setTextViewText(R.id.sosReportTextView, getMessage());
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views);
|
||||
}
|
||||
|
||||
public static String getMessage() {
|
||||
ArrayList<String> msgTemp = new ArrayList<String>();
|
||||
if (_SOSReportBeanList != null) {
|
||||
int start = _OnePageLinesCount * _CurrentPageIndex;
|
||||
start = _SOSReportBeanList.size() > start ? start : _SOSReportBeanList.size() - 1;
|
||||
for (int i = start, j = 0; i < _SOSReportBeanList.size() && j < _OnePageLinesCount && start > -1; i++, j++) {
|
||||
msgTemp.add(_SOSReportBeanList.get(i).getSosReport());
|
||||
}
|
||||
String message = String.join("\n", msgTemp);
|
||||
return message;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static void prePage(Context context) {
|
||||
if (_SOSReportBeanList != null) {
|
||||
if (_CurrentPageIndex > 0) {
|
||||
_CurrentPageIndex = _CurrentPageIndex - 1;
|
||||
}
|
||||
Intent intentWidget = new Intent(context, SOSWidget.class);
|
||||
intentWidget.setAction(SOSWidget.ACTION_RELOAD_REPORT);
|
||||
context.sendBroadcast(intentWidget);
|
||||
}
|
||||
}
|
||||
|
||||
public static void nextPage(Context context) {
|
||||
if (_SOSReportBeanList != null) {
|
||||
if ((_CurrentPageIndex + 1) * _OnePageLinesCount < _SOSReportBeanList.size()) {
|
||||
_CurrentPageIndex = _CurrentPageIndex + 1;
|
||||
}
|
||||
Intent intentWidget = new Intent(context, SOSWidget.class);
|
||||
intentWidget.setAction(SOSWidget.ACTION_RELOAD_REPORT);
|
||||
context.sendBroadcast(intentWidget);
|
||||
}
|
||||
}
|
||||
|
||||
String getPageInfo() {
|
||||
if (_SOSReportBeanList == null) {
|
||||
return "0/0";
|
||||
}
|
||||
int leftCount = _SOSReportBeanList.size() % _OnePageLinesCount;
|
||||
int currentPageCount = _SOSReportBeanList.size() / _OnePageLinesCount + (leftCount == 0 ?0: 1);
|
||||
return String.format("%d/%d", _CurrentPageIndex + 1, currentPageCount);
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
package cc.winboll.studio.appbase.widgets;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/15 17:20:46
|
||||
* @Describe WidgetButtonClickListener
|
||||
*/
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
|
||||
public class SOSWidgetClickListener extends BroadcastReceiver {
|
||||
|
||||
public static final String TAG = "SOSWidgetClickListener";
|
||||
public static final String ACTION_PRE = "cc.winboll.studio.appbase.widgets.SOSWidgetClickListener.ACTION_PRE";
|
||||
public static final String ACTION_NEXT = "cc.winboll.studio.appbase.widgets.SOSWidgetClickListener.ACTION_NEXT";
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (action == null) {
|
||||
LogUtils.d(TAG, String.format("action %s", action));
|
||||
return;
|
||||
}
|
||||
if (action.equals(ACTION_PRE)) {
|
||||
LogUtils.d(TAG, "ACTION_PRE");
|
||||
SOSWidget.prePage(context);
|
||||
} else if (action.equals(ACTION_NEXT)) {
|
||||
LogUtils.d(TAG, "ACTION_NEXT");
|
||||
SOSWidget.nextPage(context);
|
||||
} else {
|
||||
LogUtils.d(TAG, String.format("action %s", action));
|
||||
}
|
||||
}
|
||||
}
|
11
appbase/src/main/res/drawable/ic_cloud.xml
Normal file
11
appbase/src/main/res/drawable/ic_cloud.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?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="#ff000000"
|
||||
android:pathData="M6.5,20Q4.22,20 2.61,18.43 1,16.85 1,14.58 1,12.63 2.17,11.1 3.35,9.57 5.25,9.15 5.88,6.85 7.75,5.43 9.63,4 12,4 14.93,4 16.96,6.04 19,8.07 19,11 20.73,11.2 21.86,12.5 23,13.78 23,15.5 23,17.38 21.69,18.69 20.38,20 18.5,20Z"/>
|
||||
|
||||
</vector>
|
11
appbase/src/main/res/drawable/ic_cloud_outline.xml
Normal file
11
appbase/src/main/res/drawable/ic_cloud_outline.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?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="#ff000000"
|
||||
android:pathData="M6.5,20Q4.22,20 2.61,18.43 1,16.85 1,14.58 1,12.63 2.17,11.1 3.35,9.57 5.25,9.15 5.88,6.85 7.75,5.43 9.63,4 12,4 14.93,4 16.96,6.04 19,8.07 19,11 20.73,11.2 21.86,12.5 23,13.78 23,15.5 23,17.38 21.69,18.69 20.38,20 18.5,20M6.5,18H18.5Q19.55,18 20.27,17.27 21,16.55 21,15.5 21,14.45 20.27,13.73 19.55,13 18.5,13H17V11Q17,8.93 15.54,7.46 14.08,6 12,6 9.93,6 8.46,7.46 7,8.93 7,11H6.5Q5.05,11 4.03,12.03 3,13.05 3,14.5 3,15.95 4.03,17 5.05,18 6.5,18M12,12Z"/>
|
||||
|
||||
</vector>
|
@@ -7,31 +7,141 @@
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello, WinBoll!"/>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="right|center_vertical">
|
||||
android:id="@+id/activitymainToolbar1"/>
|
||||
|
||||
<CheckBox
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1.0"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Debug Mode"
|
||||
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_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
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
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="StartTestService"
|
||||
android:textAllCaps="false"
|
||||
android:onClick="onStartTestService"/>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="StopTestService"
|
||||
android:textAllCaps="false"
|
||||
android:onClick="onStopTestService"/>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="StopTestServiceNoSettings"
|
||||
android:textAllCaps="false"
|
||||
android:onClick="onStopTestServiceNoSettings"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="StartCenter"
|
||||
android:textAllCaps="false"
|
||||
android:onClick="onStartCenter"/>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="StopCenter"
|
||||
android:textAllCaps="false"
|
||||
android:onClick="onStopCenter"/>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="TestStopWithoutSettingEnable"
|
||||
android:textAllCaps="false"
|
||||
android:onClick="onTestStopWithoutSettingEnable"/>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="TestStartWithString"
|
||||
android:textAllCaps="false"
|
||||
android:onClick="onTestStartWithString"/>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="SOS"
|
||||
android:textAllCaps="false"
|
||||
android:onClick="onSOS"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<cc.winboll.studio.libappbase.LogView
|
||||
android:layout_weight="1.0"
|
||||
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"/>
|
||||
android:layout_height="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/activitymainLogView1"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
42
appbase/src/main/res/layout/widget_sos.xml
Normal file
42
appbase/src/main/res/layout/widget_sos.xml
Normal file
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="#FFFFFFFF">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="right">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/infoTextView"/>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="⇦"
|
||||
android:id="@+id/widget_button_pre"/>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="⇨"
|
||||
android:id="@+id/widget_button_next"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:id="@+id/sosReportTextView"
|
||||
android:layout_weight="1.0"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
@@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorTextColor">#006D26C0</color>
|
||||
<color name="colorPrimary">#001BDCC0</color>
|
||||
<color name="colorPrimaryDark">#0028C025</color>
|
||||
<color name="colorAccent">#002985CC</color>
|
||||
<color name="colorPrimary">#005800FF</color>
|
||||
<color name="colorPrimaryDark">#005800FF</color>
|
||||
<color name="colorAccent">#005800FF</color>
|
||||
</resources>
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">AppBase</string>
|
||||
</resources>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">AppBase</string>
|
||||
<string name="tileservice_name">WinBoll</string>
|
||||
</resources>
|
||||
|
@@ -1,5 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="AppTheme" parent="@android:style/Theme.Material.Light.DarkActionBar">
|
||||
<style name="AppTheme" parent="APPBaseTheme">
|
||||
<item name="attrColorPrimary">@color/colorPrimary</item>
|
||||
<item name="themeGlobalCrashActivity">@style/MyGlobalCrashActivityTheme</item>
|
||||
</style>
|
||||
|
||||
<style name="MyGlobalCrashActivityTheme" parent="GlobalCrashActivityTheme">
|
||||
<item name="colorTittle">#FFFFFFFF</item>
|
||||
<item name="colorTittleBackgound">#FF00A4B3</item>
|
||||
<item name="colorText">#FFFFFFFF</item>
|
||||
<item name="colorTextBackgound">#FF000000</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
7
appbase/src/main/res/xml/widget_provider_info_sos.xml
Normal file
7
appbase/src/main/res/xml/widget_provider_info_sos.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:minWidth="200dp"
|
||||
android:minHeight="100dp"
|
||||
android:updatePeriodMillis="1000"
|
||||
android:initialLayout="@layout/widget_sos">
|
||||
</appwidget-provider>
|
40
build.gradle
40
build.gradle
@@ -1,8 +1,21 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
maven { url 'https://maven.aliyun.com/repository/public/' }
|
||||
maven { url 'https://maven.aliyun.com/repository/google/' }
|
||||
maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' }
|
||||
maven { url 'https://dl.bintray.com/ppartisan/maven/' }
|
||||
maven { url "https://clojars.org/repo/" }
|
||||
maven { url "https://jitpack.io" }
|
||||
mavenCentral()
|
||||
google()
|
||||
mavenLocal()
|
||||
// Nexus Maven 库地址
|
||||
// "WinBoll Release"
|
||||
maven { url "https://nexus.winboll.cc/repository/maven-public/" }
|
||||
// "WinBoll Snapshot"
|
||||
maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" }
|
||||
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.2.1'
|
||||
@@ -13,11 +26,12 @@ buildscript {
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
// Nexus Maven 库地址
|
||||
// "WinBoll Release"
|
||||
maven { url "https://nexus.winboll.cc/repository/maven-public/" }
|
||||
// "WinBoll Snapshot"
|
||||
maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" }
|
||||
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/google/' }
|
||||
@@ -28,6 +42,12 @@ allprojects {
|
||||
mavenCentral()
|
||||
google()
|
||||
mavenLocal()
|
||||
// Nexus Maven 库地址
|
||||
// "WinBoll Release"
|
||||
maven { url "https://nexus.winboll.cc/repository/maven-public/" }
|
||||
// "WinBoll Snapshot"
|
||||
maven { url "https://nexus.winboll.cc/repository/maven-snapshots/" }
|
||||
|
||||
}
|
||||
ext {
|
||||
// 定义全局变量,常用于版本管理
|
||||
@@ -69,6 +89,14 @@ allprojects {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
subprojects {
|
||||
tasks.withType(JavaCompile) {
|
||||
options.compilerArgs << "-parameters"
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
|
@@ -6,7 +6,7 @@
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx2048m
|
||||
org.gradle.jvmargs=-Xmx4096m
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
@@ -18,7 +18,9 @@ android.useAndroidX=true
|
||||
# Automatically convert third-party libraries to use AndroidX
|
||||
android.enableJetifier=true
|
||||
|
||||
#org.gradle.caching=true
|
||||
org.gradle.caching=true
|
||||
|
||||
android.disableAutomaticComponentCreation=true
|
||||
|
||||
android.injected.testOnly=false
|
||||
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl = https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
|
||||
distributionUrl = https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
@@ -4,14 +4,12 @@ apply from: '../.winboll/winboll_lib_build.gradle'
|
||||
apply from: '../.winboll/winboll_lint_build.gradle'
|
||||
|
||||
android {
|
||||
namespace 'cc.winboll.studio.libappbase'
|
||||
|
||||
compileSdkVersion 32
|
||||
buildToolsVersion "33.0.3"
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion "30.0.3"
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
minSdkVersion 26
|
||||
targetSdkVersion 29
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
@@ -19,12 +17,16 @@ android {
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
}
|
||||
|
||||
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'])
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Sun Feb 09 15:09:34 HKT 2025
|
||||
stageCount=4
|
||||
#Tue Feb 25 16:51:09 HKT 2025
|
||||
stageCount=3
|
||||
libraryProject=libappbase
|
||||
baseVersion=1.2
|
||||
publishVersion=1.2.3
|
||||
baseVersion=2.0
|
||||
publishVersion=2.0.2
|
||||
buildCount=0
|
||||
baseBetaVersion=1.2.4
|
||||
baseBetaVersion=2.0.3
|
||||
|
@@ -1,17 +1,78 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="cc.winboll.studio.libappbase" >
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="cc.winboll.studio.libappbase">
|
||||
|
||||
<!-- 拥有完全的网络访问权限 -->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
<!-- 发送持久广播 -->
|
||||
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
|
||||
|
||||
<application>
|
||||
|
||||
<activity
|
||||
android:name=".CrashHandler$CrashActiviy"
|
||||
android:label="CrashActiviy"
|
||||
android:name=".CrashHandler$CrashActivity"
|
||||
android:label="CrashActivity"
|
||||
android:launchMode="standard"/>
|
||||
|
||||
<activity
|
||||
android:name=".CrashHandler$GlobalCrashActiviy"
|
||||
android:label="GlobalCrashActiviy"
|
||||
android:name=".GlobalCrashActivity"
|
||||
android:label="GlobalCrashActivity"
|
||||
android:launchMode="standard"/>
|
||||
|
||||
<activity android:name=".LogActivity"/>
|
||||
|
||||
<service
|
||||
android:name=".SimpleOperateSignalCenterService"
|
||||
android:exported="true">
|
||||
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".services.TestService"
|
||||
android:exported="true"/>
|
||||
|
||||
<receiver android:name=".receiver.MyBroadcastReceiver">
|
||||
|
||||
<intent-filter>
|
||||
|
||||
<action android:name="cc.winboll.studio.libappbase.action.SOS"/>
|
||||
|
||||
</intent-filter>
|
||||
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".widgets.StatusWidget"
|
||||
android:exported="true">
|
||||
|
||||
<intent-filter>
|
||||
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
|
||||
|
||||
<action android:name="cc.winboll.studio.libappbase.widgets.StatusWidget.ACTION_STATUS_UPDATE"/>
|
||||
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.appwidget.provider"
|
||||
android:resource="@xml/widget_provider_info_status"/>
|
||||
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".widgets.StatusWidgetClickListener"
|
||||
android:exported="true">
|
||||
|
||||
<intent-filter>
|
||||
|
||||
<action android:name="cc.winboll.studio.libappbase.widgets.StatusWidgetClickListener.ACTION_IVAPP"/>
|
||||
|
||||
</intent-filter>
|
||||
|
||||
</receiver>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
|
@@ -0,0 +1,28 @@
|
||||
package cc.winboll.studio.libappbase;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/15 20:05:03
|
||||
* @Describe AppUtils
|
||||
*/
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
|
||||
public class AppUtils {
|
||||
|
||||
public static final String TAG = "AppUtils";
|
||||
|
||||
public static String getAppNameByPackageName(Context context, String packageName) {
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
try {
|
||||
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName, 0);
|
||||
return (String) packageManager.getApplicationLabel(applicationInfo);
|
||||
} catch (NameNotFoundException e) {
|
||||
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -118,7 +118,11 @@ public abstract class BaseBean<T extends BaseBean> {
|
||||
|
||||
public static <T extends BaseBean> boolean parseStringToBeanList(String szBeanList, ArrayList<T> beanList, Class<T> clazz) {
|
||||
try {
|
||||
beanList.clear();
|
||||
if(beanList == null) {
|
||||
beanList = new ArrayList<T>();
|
||||
} else {
|
||||
beanList.clear();
|
||||
}
|
||||
StringReader stringReader = new StringReader(szBeanList);
|
||||
JsonReader jsonReader = new JsonReader(stringReader);
|
||||
jsonReader.beginArray();
|
||||
|
@@ -17,6 +17,7 @@ import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@@ -53,7 +54,7 @@ public final class CrashHandler {
|
||||
|
||||
public static final String TITTLE = "CrashReport";
|
||||
|
||||
private static final String EXTRA_CRASH_INFO = "crashInfo";
|
||||
public static final String EXTRA_CRASH_INFO = "crashInfo";
|
||||
|
||||
final static String PREFS = CrashHandler.class.getName() + "PREFS";
|
||||
final static String PREFS_CRASHHANDLER_ISCRASHHAPPEN = "PREFS_CRASHHANDLER_ISCRASHHAPPEN";
|
||||
@@ -130,7 +131,7 @@ public final class CrashHandler {
|
||||
LogUtils.d(TAG, "gotoCrashActiviy: ");
|
||||
if (AppCrashSafetyWire.getInstance().isAppCrashSafetyWireOK()) {
|
||||
LogUtils.d(TAG, "gotoCrashActiviy: isAppCrashSafetyWireOK");
|
||||
intent.setClass(app, GlobalCrashActiviy.class);
|
||||
intent.setClass(app, GlobalCrashActivity.class);
|
||||
intent.putExtra(EXTRA_CRASH_INFO, errorLog);
|
||||
// 如果发生了 CrashHandler 内部崩溃, 就调用基础的应用崩溃显示类
|
||||
// intent.setClass(app, GlobalCrashActiviy.class);
|
||||
@@ -138,7 +139,7 @@ public final class CrashHandler {
|
||||
} else {
|
||||
LogUtils.d(TAG, "gotoCrashActiviy: else");
|
||||
// 正常状态调用进阶的应用崩溃显示页
|
||||
intent.setClass(app, CrashActiviy.class);
|
||||
intent.setClass(app, CrashActivity.class);
|
||||
intent.putExtra(EXTRA_CRASH_INFO, errorLog);
|
||||
}
|
||||
|
||||
@@ -263,22 +264,6 @@ public final class CrashHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean resumeSafetyLevel() {
|
||||
LogUtils.d(TAG, "resumeSafetyLevel()");
|
||||
// 崩溃计数进入崩溃保险值
|
||||
int safeLevel = loadCurrentSafetyLevel();
|
||||
if (isSafetyWireWorking(safeLevel)) {
|
||||
// 如果保险丝未熔断, 就增加一次熔断值
|
||||
LogUtils.d(TAG, "resumeSafetyLevel() resume 1");
|
||||
saveCurrentSafetyLevel(safeLevel + 1);
|
||||
return isSafetyWireWorking(safeLevel + 1);
|
||||
} else {
|
||||
LogUtils.d(TAG, "resumeSafetyLevel() resume immediately");
|
||||
resumeToMaximumImmediately();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isSafetyWireWorking(int safetyLevel) {
|
||||
LogUtils.d(TAG, "isSafetyWireOK()");
|
||||
//safetyLevel = _MINI;
|
||||
@@ -302,16 +287,6 @@ public final class CrashHandler {
|
||||
AppCrashSafetyWire.getInstance().saveCurrentSafetyLevel(_MAX);
|
||||
}
|
||||
|
||||
// boolean resumeToMaximum(int safetyLevel) {
|
||||
// if (safetyLevel + 1 < _MAX
|
||||
// && safetyLevel >= _MINI
|
||||
// && isSafetyWireWorking(safetyLevel + 1)) {
|
||||
// AppCrashSafetyWire.getInstance().saveCurrentSafetyLevel(currentSafetyLevel + 1);
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
void off() {
|
||||
LogUtils.d(TAG, "off()");
|
||||
saveCurrentSafetyLevel(_MINI);
|
||||
@@ -341,19 +316,7 @@ public final class CrashHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public static String getAppName(Context context) {
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
try {
|
||||
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(
|
||||
context.getPackageName(), 0);
|
||||
return (String) packageManager.getApplicationLabel(applicationInfo);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static final class CrashActiviy extends Activity implements MenuItem.OnMenuItemClickListener {
|
||||
public static final class CrashActivity extends Activity implements MenuItem.OnMenuItemClickListener {
|
||||
private static final int MENUITEM_COPY = 0;
|
||||
private static final int MENUITEM_RESTART = 1;
|
||||
|
||||
@@ -363,7 +326,7 @@ public final class CrashHandler {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
AppCrashSafetyWire.getInstance().postResumeCrashSafetyWireHandler(getApplicationContext());
|
||||
|
||||
|
||||
mLog = getIntent().getStringExtra(EXTRA_CRASH_INFO);
|
||||
setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar);
|
||||
setContentView: {
|
||||
@@ -437,149 +400,5 @@ public final class CrashHandler {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class GlobalCrashActiviy extends Activity implements MenuItem.OnMenuItemClickListener {
|
||||
|
||||
private static final int MENUITEM_COPY = 0;
|
||||
private static final int MENUITEM_RESTART = 1;
|
||||
|
||||
private String mLog;
|
||||
int mTitleTextColor;
|
||||
int mStartColor;
|
||||
int mCenterColor;
|
||||
int mEndColor;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
AppCrashSafetyWire.getInstance().postResumeCrashSafetyWireHandler(getApplicationContext());
|
||||
|
||||
mLog = getIntent().getStringExtra(EXTRA_CRASH_INFO);
|
||||
setTheme(android.R.style.Theme_DeviceDefault_NoActionBar);
|
||||
// TypedArray a = obtainStyledAttributes(attrs, R.styleable.ASupportToolbar, R.attr.aSupportToolbar, 0);
|
||||
// mTitleTextColor = a.getColor(R.style.AppTheme.attrs.colo, Color.GREEN);
|
||||
// mStartColor = a.getColor(R.styleable.ASupportToolbar_attrASupportToolbarStartColor, Color.BLUE);
|
||||
// mCenterColor = a.getColor(R.styleable.ASupportToolbar_attrASupportToolbarCenterColor, Color.RED);
|
||||
// mEndColor = a.getColor(R.styleable.ASupportToolbar_attrASupportToolbarEndColor, Color.YELLOW);
|
||||
// // 返回一个绑定资源结束的信号给资源
|
||||
// a.recycle();
|
||||
|
||||
setContentView: {
|
||||
// LinearLayout contentView = new LinearLayout(this);
|
||||
// contentView.setOrientation(LinearLayout.VERTICAL);
|
||||
// contentView.setBackgroundColor(Color.BLUE);
|
||||
// LinearLayout llTitle = new LinearLayout(this);
|
||||
// TextView title = new TextView(this); {
|
||||
// int padding = dp2px(16);
|
||||
// title.setPadding(padding, padding, padding, padding);
|
||||
// title.setText("GlobalCrashActiviy");
|
||||
// title.setTextColor(Color.WHITE);
|
||||
// }
|
||||
// llTitle.addView(title, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
// contentView.addView(llTitle, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
//
|
||||
// ScrollView svContent = new ScrollView(this);
|
||||
// svContent.setFillViewport(true);
|
||||
//
|
||||
// HorizontalScrollView hw = new HorizontalScrollView(this);
|
||||
// hw.setBackgroundColor(Color.WHITE);
|
||||
// TextView message = new TextView(this); {
|
||||
// int padding = dp2px(16);
|
||||
// message.setPadding(padding, padding, padding, padding);
|
||||
// message.setText(mLog);
|
||||
// message.setTextIsSelectable(true);
|
||||
// }
|
||||
// hw.addView(message);
|
||||
// svContent.addView(hw, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.FILL_PARENT);
|
||||
// contentView.addView(svContent, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.FILL_PARENT);
|
||||
//
|
||||
// setContentView(contentView);
|
||||
setContentView(R.layout.activity_globalcrash);
|
||||
LinearLayout llMain = findViewById(R.id.activityglobalcrashLinearLayout1);
|
||||
llMain.setBackgroundColor(Color.GRAY);
|
||||
Toolbar toolbar = findViewById(R.id.activityglobalcrashToolbar1);
|
||||
toolbar.setBackgroundColor(Color.BLACK);
|
||||
toolbar.setTitleTextColor(Color.WHITE);
|
||||
toolbar.setSubtitleTextColor(Color.WHITE);
|
||||
setActionBar(toolbar);
|
||||
TextView tvLog = findViewById(R.id.activityglobalcrashTextView1);
|
||||
tvLog.setText(mLog);
|
||||
tvLog.setTextColor(Color.BLACK);
|
||||
tvLog.setBackgroundColor(Color.GRAY);
|
||||
// // 内部崩溃测试
|
||||
// tvLog.setOnClickListener(new View.OnClickListener(){
|
||||
// @Override
|
||||
// public void onClick(View view) {
|
||||
// for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
|
||||
// getString(i);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
getActionBar().setTitle(TITTLE);
|
||||
getActionBar().setSubtitle(getAppName(getApplicationContext()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
restart();
|
||||
}
|
||||
|
||||
private void restart() {
|
||||
PackageManager pm = getPackageManager();
|
||||
Intent intent = pm.getLaunchIntentForPackage(getPackageName());
|
||||
if (intent != null) {
|
||||
intent.addFlags(
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
| Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
);
|
||||
startActivity(intent);
|
||||
}
|
||||
finish();
|
||||
android.os.Process.killProcess(android.os.Process.myPid());
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
private int dp2px(final float dpValue) {
|
||||
final float scale = Resources.getSystem().getDisplayMetrics().density;
|
||||
return (int) (dpValue * scale + 0.5f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENUITEM_COPY:
|
||||
ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
cm.setPrimaryClip(ClipData.newPlainText(getPackageName(), mLog));
|
||||
Toast.makeText(getApplication(), "The text is copied.", Toast.LENGTH_SHORT).show();
|
||||
break;
|
||||
case MENUITEM_RESTART:
|
||||
AppCrashSafetyWire.getInstance().resumeToMaximumImmediately();
|
||||
restart();
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
menu.add(0, MENUITEM_COPY, 0, "Copy").setOnMenuItemClickListener(this)
|
||||
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
||||
menu.add(0, MENUITEM_RESTART, 0, "Restart").setOnMenuItemClickListener(this)
|
||||
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
||||
|
||||
// 设置菜单文本颜色
|
||||
for (int i = 0; i < menu.size(); i++) {
|
||||
MenuItem item = menu.getItem(i);
|
||||
SpannableString spanString = new SpannableString(item.getTitle().toString());
|
||||
spanString.setSpan(new ForegroundColorSpan(Color.WHITE), 0, spanString.length(), 0);
|
||||
item.setTitle(spanString);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@@ -6,18 +6,17 @@ package cc.winboll.studio.libappbase;
|
||||
* @Describe 全局应用类
|
||||
*/
|
||||
import android.app.Application;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import android.view.Gravity;
|
||||
import com.hjq.toast.ToastUtils;
|
||||
import com.hjq.toast.style.WhiteToastStyle;
|
||||
|
||||
public class GlobalApplication extends Application {
|
||||
|
||||
@@ -60,13 +59,13 @@ public class GlobalApplication extends Application {
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
GlobalApplication.isDebuging = true;
|
||||
GlobalApplication.setIsDebuging(this, true);
|
||||
//GlobalApplication.isDebuging = true;
|
||||
//GlobalApplication.setIsDebuging(this, true);
|
||||
LogUtils.init(this);
|
||||
LogUtils.setLogLevel(LogUtils.LOG_LEVEL.Debug);
|
||||
//LogUtils.setLogLevel(LogUtils.LOG_LEVEL.Debug);
|
||||
//LogUtils.setTAGListEnable(GlobalApplication.TAG, true);
|
||||
LogUtils.setALlTAGListEnable(true);
|
||||
LogUtils.d(TAG, "LogUtils init");
|
||||
//LogUtils.setALlTAGListEnable(true);
|
||||
//LogUtils.d(TAG, "LogUtils init");
|
||||
|
||||
// 设置应用异常处理窗口
|
||||
CrashHandler.init(this);
|
||||
@@ -75,44 +74,46 @@ public class GlobalApplication extends Application {
|
||||
//SharedPreferences sharedPreferences = getSharedPreferences(PREFS, Context.MODE_PRIVATE);
|
||||
//GlobalApplication.isDebuging = sharedPreferences.getBoolean(PREFS_ISDEBUGING, GlobalApplication.isDebuging);
|
||||
|
||||
// 初始化 Toast 框架
|
||||
ToastUtils.init(this);
|
||||
// 设置 Toast 布局样式
|
||||
//ToastUtils.setView(R.layout.toast_custom_view);
|
||||
ToastUtils.setStyle(new WhiteToastStyle());
|
||||
ToastUtils.setGravity(Gravity.BOTTOM, 0, 200);
|
||||
}
|
||||
|
||||
public static void write(InputStream input, OutputStream output) throws IOException {
|
||||
byte[] buf = new byte[1024 * 8];
|
||||
int len;
|
||||
while ((len = input.read(buf)) != -1) {
|
||||
output.write(buf, 0, len);
|
||||
}
|
||||
}
|
||||
|
||||
public static void write(File file, byte[] data) throws IOException {
|
||||
File parent = file.getParentFile();
|
||||
if (parent != null && !parent.exists()) parent.mkdirs();
|
||||
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(data);
|
||||
FileOutputStream output = new FileOutputStream(file);
|
||||
public static String getAppName(Context context) {
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
try {
|
||||
write(input, output);
|
||||
} finally {
|
||||
closeIO(input, output);
|
||||
}
|
||||
}
|
||||
|
||||
public static String toString(InputStream input) throws IOException {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
write(input, output);
|
||||
try {
|
||||
return output.toString("UTF-8");
|
||||
} finally {
|
||||
closeIO(input, output);
|
||||
}
|
||||
}
|
||||
|
||||
public static void closeIO(Closeable... closeables) {
|
||||
for (Closeable closeable : closeables) {
|
||||
try {
|
||||
if (closeable != null) closeable.close();
|
||||
} catch (IOException ignored) {}
|
||||
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(
|
||||
context.getPackageName(), 0);
|
||||
return (String) packageManager.getApplicationLabel(applicationInfo);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
//
|
||||
// @Override
|
||||
// public void helpISOSService(Intent intent) {
|
||||
// String szServiceName = intent.getStringExtra(EXTRA_SERVICE);
|
||||
// String szPackageName = intent.getStringExtra(EXTRA_PACKAGE);
|
||||
// if (szServiceName != null && !szServiceName.equals("")
|
||||
// && szPackageName != null && !szPackageName.equals("")) {
|
||||
// LogUtils.d(TAG, "szPackageName " + szPackageName);
|
||||
// LogUtils.d(TAG, "szServiceName " + szServiceName);
|
||||
//
|
||||
// // 目标服务的包名和类名
|
||||
// //String packageName = this.getPackageName();
|
||||
// //String serviceClassName = SimpleOperateSignalCenterService.class.getName();
|
||||
//
|
||||
// // 构建Intent
|
||||
// Intent intentService = new Intent();
|
||||
// intentService.setComponent(new ComponentName(szPackageName, szServiceName));
|
||||
// intentService.putExtra(ISOSService.EXTRA_ENABLE, true);
|
||||
// startService(intentService);
|
||||
// LogUtils.d(TAG, "startService(intentService)");
|
||||
// }
|
||||
// LogUtils.d(TAG, "helpISOSService");
|
||||
// }
|
||||
}
|
||||
|
@@ -0,0 +1,119 @@
|
||||
package cc.winboll.studio.libappbase;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/11 00:14:05
|
||||
*/
|
||||
import android.app.Activity;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.SpannableString;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import cc.winboll.studio.libappbase.R;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
public final class GlobalCrashActivity extends AppCompatActivity implements MenuItem.OnMenuItemClickListener {
|
||||
|
||||
private static final int MENUITEM_COPY = 0;
|
||||
private static final int MENUITEM_RESTART = 1;
|
||||
|
||||
GlobalCrashReportView mGlobalCrashReportView;
|
||||
String mLog;
|
||||
|
||||
|
||||
public static final String TAG = "GlobalCrashActivity";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
CrashHandler.AppCrashSafetyWire.getInstance().postResumeCrashSafetyWireHandler(getApplicationContext());
|
||||
|
||||
mLog = getIntent().getStringExtra(CrashHandler.EXTRA_CRASH_INFO);
|
||||
//setTheme(android.R.style.Theme_Holo_Light_NoActionBar);
|
||||
//setTheme(R.style.APPBaseTheme);
|
||||
setContentView(R.layout.activity_globalcrash);
|
||||
mGlobalCrashReportView = findViewById(R.id.activityglobalcrashGlobalCrashReportView1);
|
||||
mGlobalCrashReportView.setReport(mLog);
|
||||
setSupportActionBar(mGlobalCrashReportView.getToolbar());
|
||||
|
||||
getSupportActionBar().setTitle(CrashHandler.TITTLE);
|
||||
getSupportActionBar().setSubtitle(GlobalApplication.getAppName(getApplicationContext()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
restart();
|
||||
}
|
||||
|
||||
private void restart() {
|
||||
PackageManager pm = getPackageManager();
|
||||
Intent intent = pm.getLaunchIntentForPackage(getPackageName());
|
||||
if (intent != null) {
|
||||
intent.addFlags(
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
| Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
);
|
||||
startActivity(intent);
|
||||
}
|
||||
finish();
|
||||
android.os.Process.killProcess(android.os.Process.myPid());
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENUITEM_COPY:
|
||||
ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
cm.setPrimaryClip(ClipData.newPlainText(getPackageName(), mLog));
|
||||
Toast.makeText(getApplication(), "The text is copied.", Toast.LENGTH_SHORT).show();
|
||||
break;
|
||||
case MENUITEM_RESTART:
|
||||
CrashHandler.AppCrashSafetyWire.getInstance().resumeToMaximumImmediately();
|
||||
restart();
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
menu.add(0, MENUITEM_COPY, 0, "Copy").setOnMenuItemClickListener(this)
|
||||
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
||||
menu.add(0, MENUITEM_RESTART, 0, "Restart").setOnMenuItemClickListener(this)
|
||||
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
||||
|
||||
// 更新菜单文字风格
|
||||
mGlobalCrashReportView.updateMenuStyle();
|
||||
return true;
|
||||
}
|
||||
|
||||
void joinQQGroup(String key) {
|
||||
// 创建Intent
|
||||
Intent intent = new Intent();
|
||||
// 设置动作
|
||||
intent.setAction("android.intent.action.VIEW");
|
||||
// 设置数据为网址的URI
|
||||
Uri content_url = Uri.parse("https://www.winboll.cc");
|
||||
intent.setData(content_url);
|
||||
// 添加标志
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
// 设置类名和活动名
|
||||
intent.setClassName("com.android.browser", "com.android.browser.BrowserActivity");
|
||||
// 启动Activity
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
@@ -0,0 +1,138 @@
|
||||
package cc.winboll.studio.libappbase;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/11 20:18:30
|
||||
* @Describe 应用崩溃报告视图
|
||||
*/
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.text.SpannableString;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import cc.winboll.studio.libappbase.R;
|
||||
|
||||
public class GlobalCrashReportView extends LinearLayout {
|
||||
|
||||
public static final String TAG = "GlobalCrashReportView";
|
||||
|
||||
Context mContext;
|
||||
Toolbar mToolbar;
|
||||
int colorTittle;
|
||||
int colorTittleBackground;
|
||||
int colorText;
|
||||
int colorTextBackground;
|
||||
TextView mtvReport;
|
||||
|
||||
public GlobalCrashReportView(Context context) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
//initView();
|
||||
}
|
||||
|
||||
public GlobalCrashReportView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mContext = context;
|
||||
initView(attrs);
|
||||
}
|
||||
|
||||
public GlobalCrashReportView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mContext = context;
|
||||
//initView();
|
||||
}
|
||||
|
||||
public GlobalCrashReportView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
mContext = context;
|
||||
//initView();
|
||||
}
|
||||
|
||||
public void setColorTittle(int colorTittle) {
|
||||
this.colorTittle = colorTittle;
|
||||
}
|
||||
|
||||
public int getColorTittle() {
|
||||
return colorTittle;
|
||||
}
|
||||
|
||||
public void setColorTittleBackground(int colorTittleBackground) {
|
||||
this.colorTittleBackground = colorTittleBackground;
|
||||
}
|
||||
|
||||
public int getColorTittleBackground() {
|
||||
return colorTittleBackground;
|
||||
}
|
||||
|
||||
public void setColorText(int colorText) {
|
||||
this.colorText = colorText;
|
||||
}
|
||||
|
||||
public int getColorText() {
|
||||
return colorText;
|
||||
}
|
||||
|
||||
public void setColorTextBackground(int colorTextBackground) {
|
||||
this.colorTextBackground = colorTextBackground;
|
||||
}
|
||||
|
||||
public int getColorTextBackground() {
|
||||
return colorTextBackground;
|
||||
}
|
||||
|
||||
void initView(AttributeSet attrs) {
|
||||
TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.GlobalCrashActivity, R.attr.themeGlobalCrashActivity, 0);
|
||||
this.colorTittle = a.getColor(R.styleable.GlobalCrashActivity_colorTittle, Color.WHITE);
|
||||
this.colorTittleBackground = a.getColor(R.styleable.GlobalCrashActivity_colorTittleBackgound, Color.BLACK);
|
||||
this.colorText = a.getColor(R.styleable.GlobalCrashActivity_colorText, Color.BLACK);
|
||||
this.colorTextBackground = a.getColor(R.styleable.GlobalCrashActivity_colorTextBackgound, Color.WHITE);
|
||||
// 返回一个绑定资源结束的信号给资源
|
||||
a.recycle();
|
||||
|
||||
/*this.colorTittle = Color.WHITE;
|
||||
this.colorTittleBackground = Color.BLACK;
|
||||
this.colorText = Color.BLACK;
|
||||
this.colorTextBackground = Color.WHITE;
|
||||
*/
|
||||
|
||||
inflate(mContext, R.layout.view_globalcrashreport, this);
|
||||
|
||||
LinearLayout llMain = findViewById(R.id.viewglobalcrashreportLinearLayout1);
|
||||
llMain.setBackgroundColor(this.colorTextBackground);
|
||||
mToolbar = findViewById(R.id.viewglobalcrashreportToolbar1);
|
||||
mToolbar.setBackgroundColor(this.colorTittleBackground);
|
||||
mToolbar.setTitleTextColor(this.colorTittle);
|
||||
mToolbar.setSubtitleTextColor(this.colorTittle);
|
||||
mtvReport = findViewById(R.id.viewglobalcrashreportTextView1);
|
||||
mtvReport.setTextColor(this.colorText);
|
||||
mtvReport.setBackgroundColor(this.colorTextBackground);
|
||||
}
|
||||
|
||||
public void setReport(String report) {
|
||||
mtvReport.setText(report);
|
||||
}
|
||||
|
||||
public Toolbar getToolbar() {
|
||||
return mToolbar;
|
||||
}
|
||||
|
||||
//
|
||||
// 更新菜单文字风格
|
||||
//
|
||||
public void updateMenuStyle() {
|
||||
// 设置菜单文本颜色
|
||||
Menu menu = mToolbar.getMenu();
|
||||
for (int i = 0; i < menu.size(); i++) {
|
||||
MenuItem item = menu.getItem(i);
|
||||
SpannableString spanString = new SpannableString(item.getTitle().toString());
|
||||
spanString.setSpan(new ForegroundColorSpan(this.colorTittle), 0, spanString.length(), 0);
|
||||
item.setTitle(spanString);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
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();
|
||||
}
|
@@ -0,0 +1,68 @@
|
||||
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();
|
||||
}
|
||||
}
|
@@ -0,0 +1,387 @@
|
||||
package cc.winboll.studio.libappbase;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@QQ.COM
|
||||
* @Date 2024/08/12 14:36:18
|
||||
* @Describe 日志视图类,继承 RelativeLayout 类。
|
||||
*/
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.R;
|
||||
import java.text.Collator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class LogView extends RelativeLayout {
|
||||
|
||||
public static final String TAG = "LogView";
|
||||
|
||||
public volatile boolean mIsHandling;
|
||||
public volatile boolean mIsAddNewLog;
|
||||
|
||||
Context mContext;
|
||||
ScrollView mScrollView;
|
||||
TextView mTextView;
|
||||
CheckBox mSelectableCheckBox;
|
||||
CheckBox mSelectAllTAGCheckBox;
|
||||
TAGListAdapter mTAGListAdapter;
|
||||
LogViewThread mLogViewThread;
|
||||
LogViewHandler mLogViewHandler;
|
||||
Spinner mLogLevelSpinner;
|
||||
ArrayAdapter<CharSequence> mLogLevelSpinnerAdapter;
|
||||
// 标签列表
|
||||
RecyclerView recyclerView;
|
||||
|
||||
public LogView(Context context) {
|
||||
super(context);
|
||||
initView(context);
|
||||
}
|
||||
|
||||
public LogView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initView(context);
|
||||
}
|
||||
|
||||
public LogView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
initView(context);
|
||||
}
|
||||
|
||||
public LogView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
initView(context);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
mLogViewThread = new LogViewThread(LogView.this);
|
||||
mLogViewThread.start();
|
||||
// 显示日志
|
||||
showAndScrollLogView();
|
||||
}
|
||||
|
||||
public void scrollLogUp() {
|
||||
mScrollView.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
|
||||
// 日志显示结束
|
||||
mLogViewHandler.setIsHandling(false);
|
||||
// 检查是否添加了新日志
|
||||
if (mLogViewHandler.isAddNewLog()) {
|
||||
// 有新日志添加,先更改新日志标志
|
||||
mLogViewHandler.setIsAddNewLog(false);
|
||||
// 再次发送显示日志的显示
|
||||
Message message = mLogViewHandler.obtainMessage(LogViewHandler.MSG_LOGVIEW_UPDATE);
|
||||
mLogViewHandler.sendMessage(message);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void initView(Context context) {
|
||||
mContext = context;
|
||||
mLogViewHandler = new LogViewHandler();
|
||||
// 加载视图布局
|
||||
addView(inflate(mContext, cc.winboll.studio.libappbase.R.layout.view_log, null));
|
||||
// 初始化日志子控件视图
|
||||
//
|
||||
mScrollView = findViewById(cc.winboll.studio.libappbase.R.id.viewlogScrollViewLog);
|
||||
mTextView = findViewById(cc.winboll.studio.libappbase.R.id.viewlogTextViewLog);
|
||||
// 获取Log Level spinner实例
|
||||
mLogLevelSpinner = findViewById(cc.winboll.studio.libappbase.R.id.viewlogSpinner1);
|
||||
|
||||
(findViewById(cc.winboll.studio.libappbase.R.id.viewlogButtonClean)).setOnClickListener(new View.OnClickListener(){
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LogUtils.cleanLog();
|
||||
LogUtils.d(TAG, "Log is cleaned.");
|
||||
}
|
||||
});
|
||||
(findViewById(cc.winboll.studio.libappbase.R.id.viewlogButtonCopy)).setOnClickListener(new View.OnClickListener(){
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
||||
ClipboardManager cm = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
cm.setPrimaryClip(ClipData.newPlainText(mContext.getPackageName(), LogUtils.loadLog()));
|
||||
LogUtils.d(TAG, "Log is copied.");
|
||||
}
|
||||
});
|
||||
mSelectableCheckBox = findViewById(cc.winboll.studio.libappbase.R.id.viewlogCheckBoxSelectable);
|
||||
mSelectableCheckBox.setOnClickListener(new View.OnClickListener(){
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (mSelectableCheckBox.isChecked()) {
|
||||
setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
|
||||
} else {
|
||||
setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 设置日志级别列表
|
||||
ArrayList<String> adapterItems = new ArrayList<>();
|
||||
for (LogUtils.LOG_LEVEL e : LogUtils.LOG_LEVEL.values()) {
|
||||
adapterItems.add(e.name());
|
||||
}
|
||||
// 假设你有一个字符串数组作为选项列表
|
||||
//String[] options = {"Option 1", "Option 2", "Option 3"};
|
||||
// 创建一个ArrayAdapter来绑定数据到spinner
|
||||
mLogLevelSpinnerAdapter = ArrayAdapter.createFromResource(
|
||||
context, cc.winboll.studio.libappbase.R.array.enum_loglevel_array, android.R.layout.simple_spinner_item);
|
||||
mLogLevelSpinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
|
||||
// 设置适配器并将它应用到spinner上
|
||||
mLogLevelSpinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); // 设置下拉视图样式
|
||||
mLogLevelSpinner.setAdapter(mLogLevelSpinnerAdapter);
|
||||
// 为Spinner添加监听器
|
||||
mLogLevelSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
//String selectedOption = mLogLevelSpinnerAdapter.getItem(position);
|
||||
// 处理选中的选项...
|
||||
LogUtils.setLogLevel(LogUtils.LOG_LEVEL.values()[position]);
|
||||
}
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
// 如果没有选择,则执行此操作...
|
||||
}
|
||||
});
|
||||
// 获取默认值的索引
|
||||
int defaultValueIndex = LogUtils.getLogLevel().ordinal();
|
||||
|
||||
if (defaultValueIndex != -1) {
|
||||
// 如果找到了默认值,设置默认选项
|
||||
mLogLevelSpinner.setSelection(defaultValueIndex);
|
||||
}
|
||||
|
||||
// 加载标签列表
|
||||
Map<String, Boolean> mapTAGList = LogUtils.getMapTAGList();
|
||||
boolean isAllSelect = true;
|
||||
for (Map.Entry<String, Boolean> entry : mapTAGList.entrySet()) {
|
||||
if (entry.getValue() == false) {
|
||||
isAllSelect = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CheckBox cbALLTAG = findViewById(cc.winboll.studio.libappbase.R.id.viewlogCheckBox1);
|
||||
cbALLTAG.setChecked(isAllSelect);
|
||||
|
||||
// 加载标签表
|
||||
recyclerView = findViewById(cc.winboll.studio.libappbase.R.id.viewlogRecyclerView1);
|
||||
LinearLayoutManager layoutManager = new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false);
|
||||
recyclerView.setLayoutManager(layoutManager);
|
||||
mTAGListAdapter = new TAGListAdapter(mapTAGList);
|
||||
recyclerView.setAdapter(mTAGListAdapter);
|
||||
|
||||
// 可以添加点击监听器来处理勾选框状态变化后的逻辑,比如获取当前勾选情况等
|
||||
mTAGListAdapter.notifyDataSetChanged();
|
||||
|
||||
mSelectAllTAGCheckBox = findViewById(cc.winboll.studio.libappbase.R.id.viewlogCheckBox1);
|
||||
mSelectAllTAGCheckBox.setOnClickListener(new View.OnClickListener(){
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LogUtils.setALlTAGListEnable(mSelectAllTAGCheckBox.isChecked());
|
||||
//LogUtils.setALlTAGListEnable(false);
|
||||
//mTAGListAdapter.notifyDataSetChanged();
|
||||
mTAGListAdapter.reload();
|
||||
//ToastUtils.show(String.format("onClick\nmSelectAllTAGCheckBox.isChecked() : %s", mSelectAllTAGCheckBox.isChecked()));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// 设置滚动时不聚焦日志
|
||||
setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
|
||||
}
|
||||
|
||||
public void updateLogView() {
|
||||
if (mLogViewHandler.isHandling() == true) {
|
||||
// 正在处理日志显示,
|
||||
// 就先设置一个新日志标志位
|
||||
// 以便日志显示完后,再次显示新日志内容
|
||||
mLogViewHandler.setIsAddNewLog(true);
|
||||
} else {
|
||||
//LogUtils.d(TAG, "LogListener showLog(String path)");
|
||||
Message message = mLogViewHandler.obtainMessage(LogViewHandler.MSG_LOGVIEW_UPDATE);
|
||||
mLogViewHandler.sendMessage(message);
|
||||
mLogViewHandler.setIsAddNewLog(false);
|
||||
}
|
||||
}
|
||||
|
||||
void showAndScrollLogView() {
|
||||
mTextView.setText(LogUtils.loadLog());
|
||||
scrollLogUp();
|
||||
}
|
||||
|
||||
class LogViewHandler extends Handler {
|
||||
|
||||
final static int MSG_LOGVIEW_UPDATE = 0;
|
||||
volatile boolean isHandling;
|
||||
volatile boolean isAddNewLog;
|
||||
|
||||
public LogViewHandler() {
|
||||
setIsHandling(false);
|
||||
setIsAddNewLog(false);
|
||||
}
|
||||
|
||||
public void setIsHandling(boolean isHandling) {
|
||||
this.isHandling = isHandling;
|
||||
}
|
||||
|
||||
public boolean isHandling() {
|
||||
return isHandling;
|
||||
}
|
||||
|
||||
public void setIsAddNewLog(boolean isAddNewLog) {
|
||||
this.isAddNewLog = isAddNewLog;
|
||||
}
|
||||
|
||||
public boolean isAddNewLog() {
|
||||
return isAddNewLog;
|
||||
}
|
||||
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_LOGVIEW_UPDATE:{
|
||||
if (isHandling() == false) {
|
||||
setIsHandling(true);
|
||||
showAndScrollLogView();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
super.handleMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public class TAGItemModel {
|
||||
private String tag;
|
||||
private boolean isChecked;
|
||||
|
||||
public TAGItemModel(String tag, boolean isChecked) {
|
||||
this.tag = tag;
|
||||
this.isChecked = isChecked;
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
public void setTag(String tag) {
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
public boolean isChecked() {
|
||||
return isChecked;
|
||||
}
|
||||
|
||||
public void setChecked(boolean checked) {
|
||||
isChecked = checked;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class TAGListAdapter extends RecyclerView.Adapter<TAGListAdapter.ViewHolder> {
|
||||
|
||||
private Map<String, Boolean> mapOrigin;
|
||||
private List<TAGItemModel> itemList;
|
||||
|
||||
public TAGListAdapter(Map<String, Boolean> map) {
|
||||
mapOrigin = map;
|
||||
loadMap(mapOrigin);
|
||||
}
|
||||
|
||||
void loadMap(Map<String, Boolean> map) {
|
||||
itemList = new ArrayList<TAGItemModel>();
|
||||
for (Map.Entry<String, Boolean> entry : map.entrySet()) {
|
||||
itemList.add(new TAGItemModel(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
// 添加排序功能,按照tag进行升序排序
|
||||
Collections.sort(itemList, new SortMapEntryByKeyString(true));
|
||||
//Collections.sort(itemList, new SortMapEntryByKeyString(false));
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
loadMap(mapOrigin);
|
||||
super.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_logtag, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
final TAGItemModel item = itemList.get(position);
|
||||
holder.tvText.setText(item.getTag());
|
||||
holder.cbChecked.setChecked(item.isChecked());
|
||||
holder.cbChecked.setOnClickListener(new View.OnClickListener(){
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LogUtils.setTAGListEnable(item.getTag(), ((CheckBox)v).isChecked());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return itemList.size();
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView tvText;
|
||||
CheckBox cbChecked;
|
||||
|
||||
public ViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
tvText = itemView.findViewById(R.id.viewlogtagTextView1);
|
||||
cbChecked = itemView.findViewById(R.id.viewlogtagCheckBox1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SortMapEntryByKeyString implements Comparator<TAGItemModel> {
|
||||
private boolean mIsDesc = true;
|
||||
// isDesc 是否降序排列
|
||||
public SortMapEntryByKeyString(boolean isDesc) {
|
||||
mIsDesc = isDesc;
|
||||
}
|
||||
Collator cmp = Collator.getInstance(java.util.Locale.CHINA);
|
||||
@Override
|
||||
public int compare(TAGItemModel o1, TAGItemModel o2) {
|
||||
if (mIsDesc) {
|
||||
return o1.getTag().compareTo(o2.getTag());
|
||||
} else {
|
||||
return o2.getTag().compareTo(o1.getTag());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,80 @@
|
||||
package cc.winboll.studio.libappbase;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@QQ.COM
|
||||
* @Date 2024/08/12 14:43:50
|
||||
* @Describe 日志视图线程类
|
||||
*/
|
||||
import android.os.FileObserver;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class LogViewThread extends Thread {
|
||||
|
||||
public static final String TAG = "LogViewThread";
|
||||
|
||||
// 线程退出标志
|
||||
volatile boolean isExist = false;
|
||||
// 应用日志文件监听实例
|
||||
LogListener mLogListener;
|
||||
// 日志视图弱引用
|
||||
WeakReference<LogView> mwrLogView;
|
||||
|
||||
//
|
||||
// 构造函数
|
||||
// @logView : 日志显示输出视图类
|
||||
public LogViewThread(LogView logView) {
|
||||
mwrLogView = new WeakReference<LogView>(logView);
|
||||
|
||||
}
|
||||
|
||||
public void setIsExist(boolean isExist) {
|
||||
this.isExist = isExist;
|
||||
}
|
||||
|
||||
public boolean isExist() {
|
||||
return isExist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
String szLogDir = LogUtils.getLogCacheDir().getPath();
|
||||
mLogListener = new LogListener(szLogDir);
|
||||
mLogListener.startWatching();
|
||||
while (isExist() == false) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {}
|
||||
}
|
||||
mLogListener.stopWatching();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 日志文件监听类
|
||||
//
|
||||
class LogListener extends FileObserver {
|
||||
public LogListener(String path) {
|
||||
super(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(int event, String path) {
|
||||
int e = event & FileObserver.ALL_EVENTS;
|
||||
switch (e) {
|
||||
case FileObserver.CLOSE_WRITE:{
|
||||
if (mwrLogView.get() != null) {
|
||||
mwrLogView.get().updateLogView();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FileObserver.DELETE:{
|
||||
if (mwrLogView.get() != null) {
|
||||
mwrLogView.get().updateLogView();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,187 @@
|
||||
package cc.winboll.studio.libappbase;
|
||||
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/12 11:12:25
|
||||
* @Describe 简单信号服务中心
|
||||
*/
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.os.IInterface;
|
||||
import android.os.Parcel;
|
||||
import android.os.RemoteException;
|
||||
import cc.winboll.studio.libappbase.bean.SimpleOperateSignalCenterServiceBean;
|
||||
import java.io.FileDescriptor;
|
||||
|
||||
public class SimpleOperateSignalCenterService extends Service {
|
||||
|
||||
public static final String TAG = "SimpleOperateSignalCenterService";
|
||||
public static final String ACTION_ENABLE = SimpleOperateSignalCenterService.class.getName() + ".ACTION_ENABLE";
|
||||
public static final String ACTION_DISABLE = SimpleOperateSignalCenterService.class.getName() + ".ACTION_DISABLE";
|
||||
|
||||
private final IBinder binder =(IBinder)new SOSBinder();
|
||||
|
||||
SimpleOperateSignalCenterServiceBean mSimpleOperateSignalCenterServiceBean;
|
||||
static MainThread _MainThread;
|
||||
public static synchronized MainThread getMainThreadInstance() {
|
||||
if (_MainThread == null) {
|
||||
_MainThread = new MainThread();
|
||||
}
|
||||
return _MainThread;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return binder;
|
||||
}
|
||||
|
||||
public class SOSBinder implements IBinder {
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fileDescriptor, String[] string) throws RemoteException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpAsync(FileDescriptor fileDescriptor, String[] string) throws RemoteException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInterfaceDescriptor() throws RemoteException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBinderAlive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void linkToDeath(IBinder.DeathRecipient deathRecipient, int p) throws RemoteException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pingBinder() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IInterface queryLocalInterface(String string) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean transact(int p, Parcel parcel, Parcel parcel1, int p1) throws RemoteException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unlinkToDeath(IBinder.DeathRecipient deathRecipient, int p) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static final String TAG = "SOSBinder";
|
||||
SimpleOperateSignalCenterService getService() {
|
||||
return SimpleOperateSignalCenterService.this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
LogUtils.d(TAG, "onCreate");
|
||||
mSimpleOperateSignalCenterServiceBean = SimpleOperateSignalCenterServiceBean.loadBean(this, SimpleOperateSignalCenterServiceBean.class);
|
||||
if(mSimpleOperateSignalCenterServiceBean == null) {
|
||||
mSimpleOperateSignalCenterServiceBean = new SimpleOperateSignalCenterServiceBean();
|
||||
SimpleOperateSignalCenterServiceBean.saveBean(this, mSimpleOperateSignalCenterServiceBean);
|
||||
}
|
||||
runMainThread();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
LogUtils.d(TAG, "onStartCommand");
|
||||
// if (intent.getBooleanExtra(ISOSService.EXTRA_ENABLE, false)) {
|
||||
// LogUtils.d(TAG, "onStartCommand enable service");
|
||||
// mSimpleOperateSignalCenterServiceBean.setIsEnable(true);
|
||||
// SimpleOperateSignalCenterServiceBean.saveBean(this, mSimpleOperateSignalCenterServiceBean);
|
||||
// }
|
||||
|
||||
runMainThread();
|
||||
|
||||
//return super.onStartCommand(intent, flags, startId);
|
||||
return mSimpleOperateSignalCenterServiceBean.isEnable() ? Service.START_STICKY: super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
|
||||
void runMainThread() {
|
||||
mSimpleOperateSignalCenterServiceBean = SimpleOperateSignalCenterServiceBean.loadBean(this, SimpleOperateSignalCenterServiceBean.class);
|
||||
if (mSimpleOperateSignalCenterServiceBean.isEnable()
|
||||
&& _MainThread == null) {
|
||||
getMainThreadInstance().start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
LogUtils.d(TAG, "onDestroy");
|
||||
mSimpleOperateSignalCenterServiceBean = SimpleOperateSignalCenterServiceBean.loadBean(this, SimpleOperateSignalCenterServiceBean.class);
|
||||
if (mSimpleOperateSignalCenterServiceBean.isEnable()) {
|
||||
LogUtils.d(TAG, "mSimpleOperateSignalCenterServiceBean.isEnable()");
|
||||
// ISOSAPP iSOSAPP = (ISOSAPP)getApplication();
|
||||
// iSOSAPP.helpISOSService(getISOSServiceIntentWhichAskForHelp());
|
||||
}
|
||||
if (_MainThread != null) {
|
||||
_MainThread.isExist = true;
|
||||
_MainThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void stopISOSService(Context context) {
|
||||
LogUtils.d(TAG, "stopISOSService");
|
||||
SimpleOperateSignalCenterServiceBean bean = new SimpleOperateSignalCenterServiceBean();
|
||||
bean.setIsEnable(false);
|
||||
SimpleOperateSignalCenterServiceBean.saveBean(context, bean);
|
||||
context.stopService(new Intent(context, SimpleOperateSignalCenterService.class));
|
||||
}
|
||||
|
||||
public static void startISOSService(Context context) {
|
||||
LogUtils.d(TAG, "startISOSService");
|
||||
SimpleOperateSignalCenterServiceBean bean = new SimpleOperateSignalCenterServiceBean();
|
||||
bean.setIsEnable(true);
|
||||
SimpleOperateSignalCenterServiceBean.saveBean(context, bean);
|
||||
context.startService(new Intent(context, SimpleOperateSignalCenterService.class));
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return "Hello from SimpleOperateSignalCenterService";
|
||||
}
|
||||
|
||||
static class MainThread extends Thread {
|
||||
volatile boolean isExist = false;
|
||||
|
||||
public void setIsExist(boolean isExist) {
|
||||
this.isExist = isExist;
|
||||
}
|
||||
|
||||
public boolean isExist() {
|
||||
return isExist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
super.run();
|
||||
while (!isExist) {
|
||||
LogUtils.d(TAG, "run");
|
||||
try {
|
||||
sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,142 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,87 @@
|
||||
package cc.winboll.studio.libappbase.bean;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/17 00:29:29
|
||||
* @Describe APPSOSReportBean
|
||||
*/
|
||||
import android.util.JsonReader;
|
||||
import android.util.JsonWriter;
|
||||
import cc.winboll.studio.libappbase.BaseBean;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class APPSOSBean extends BaseBean {
|
||||
|
||||
public static final String TAG = "APPSOSBean";
|
||||
|
||||
protected String sosPackage;
|
||||
protected String sosClassName;
|
||||
|
||||
public APPSOSBean() {
|
||||
this.sosPackage = "";
|
||||
this.sosClassName = "";
|
||||
}
|
||||
|
||||
public APPSOSBean(String sosPackage, String sosClassName) {
|
||||
this.sosPackage = sosPackage;
|
||||
this.sosClassName = sosClassName;
|
||||
}
|
||||
|
||||
public void setSosPackage(String sosPackage) {
|
||||
this.sosPackage = sosPackage;
|
||||
}
|
||||
|
||||
public String getSosPackage() {
|
||||
return sosPackage;
|
||||
}
|
||||
|
||||
public void setSosClassName(String sosClassName) {
|
||||
this.sosClassName = sosClassName;
|
||||
}
|
||||
|
||||
public String getSosClassName() {
|
||||
return sosClassName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return APPSOSBean.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
|
||||
super.writeThisToJsonWriter(jsonWriter);
|
||||
jsonWriter.name("sosPackage").value(getSosPackage());
|
||||
jsonWriter.name("sosClassName").value(getSosClassName());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
|
||||
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
|
||||
if (name.equals("sosPackage")) {
|
||||
setSosPackage(jsonReader.nextString());
|
||||
} else if (name.equals("sosClassName")) {
|
||||
setSosClassName(jsonReader.nextString());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException {
|
||||
jsonReader.beginObject();
|
||||
while (jsonReader.hasNext()) {
|
||||
String name = jsonReader.nextName();
|
||||
if (!initObjectsFromJsonReader(jsonReader, name)) {
|
||||
jsonReader.skipValue();
|
||||
}
|
||||
}
|
||||
// 结束 JSON 对象
|
||||
jsonReader.endObject();
|
||||
return this;
|
||||
}
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
package cc.winboll.studio.libappbase.bean;
|
||||
import android.util.JsonReader;
|
||||
import android.util.JsonWriter;
|
||||
import cc.winboll.studio.libappbase.BaseBean;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/13 04:27:42
|
||||
*/
|
||||
public class SimpleOperateSignalCenterServiceBean extends BaseBean {
|
||||
|
||||
public static final String TAG = "SimpleOperateSignalCenterServiceBean";
|
||||
|
||||
boolean isEnable;
|
||||
|
||||
public SimpleOperateSignalCenterServiceBean() {
|
||||
this.isEnable = false;
|
||||
}
|
||||
|
||||
public void setIsEnable(boolean isEnable) {
|
||||
this.isEnable = isEnable;
|
||||
}
|
||||
|
||||
public boolean isEnable() {
|
||||
return isEnable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return SimpleOperateSignalCenterServiceBean.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;
|
||||
}
|
||||
}
|
@@ -0,0 +1,67 @@
|
||||
package cc.winboll.studio.libappbase.bean;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/19 13:34:52
|
||||
* @Describe TestServiceBean
|
||||
*/
|
||||
import android.util.JsonReader;
|
||||
import android.util.JsonWriter;
|
||||
import cc.winboll.studio.libappbase.BaseBean;
|
||||
import java.io.IOException;
|
||||
|
||||
public class TestServiceBean extends BaseBean {
|
||||
|
||||
public static final String TAG = "TestServiceBean";
|
||||
|
||||
boolean isEnable;
|
||||
|
||||
public TestServiceBean() {
|
||||
this.isEnable = false;
|
||||
}
|
||||
|
||||
public void setIsEnable(boolean isEnable) {
|
||||
this.isEnable = isEnable;
|
||||
}
|
||||
|
||||
public boolean isEnable() {
|
||||
return isEnable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return TestServiceBean.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;
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package cc.winboll.studio.libappbase.receiver;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/13 21:19:09
|
||||
* @Describe MyBroadcastReceiver
|
||||
*/
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.R;
|
||||
|
||||
public class MyBroadcastReceiver extends BroadcastReceiver {
|
||||
|
||||
public static final String TAG = "MyBroadcastReceiver";
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (context.getString(R.string.action_sos).equals(intent.getAction())) {
|
||||
String message = intent.getStringExtra("message");
|
||||
String sosPackage = intent.getStringExtra("sosPackage");
|
||||
|
||||
// 处理接收到的广播消息
|
||||
LogUtils.d(TAG, String.format("MyBroadcastReceiver action %s \n%s\n%s", intent.getAction(), sosPackage, message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,149 @@
|
||||
package cc.winboll.studio.libappbase.services;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/15 20:48:36
|
||||
* @Describe TestService
|
||||
*/
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.SOS;
|
||||
import cc.winboll.studio.libappbase.bean.APPSOSBean;
|
||||
import cc.winboll.studio.libappbase.bean.TestServiceBean;
|
||||
|
||||
public class TestService extends Service {
|
||||
|
||||
public static final String TAG = "TestService";
|
||||
|
||||
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 TestService getService() {
|
||||
return TestService.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(...)");
|
||||
TestServiceBean bean = TestServiceBean.loadBean(this, TestServiceBean.class);
|
||||
if (bean == null) {
|
||||
bean = new TestServiceBean();
|
||||
}
|
||||
if (intent.getAction() != null && intent.getAction().equals(SOS.ACTION_SERVICE_ENABLE)) {
|
||||
bean.setIsEnable(true);
|
||||
TestServiceBean.saveBean(this, bean);
|
||||
run();
|
||||
} else if (intent.getAction() != null && intent.getAction().equals(SOS.ACTION_SERVICE_DISABLE)) {
|
||||
bean.setIsEnable(false);
|
||||
TestServiceBean.saveBean(this, bean);
|
||||
}
|
||||
LogUtils.d(TAG, String.format("TestServiceBean.saveBean setIsEnable %s", bean.isEnable()));
|
||||
return (bean.isEnable()) ? START_STICKY : super.onStartCommand(intent, flags, startId);
|
||||
//return super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
|
||||
void run() {
|
||||
LogUtils.d(TAG, "run()");
|
||||
TestServiceBean bean = TestServiceBean.loadBean(this, TestServiceBean.class);
|
||||
if (bean == null) {
|
||||
bean = new TestServiceBean();
|
||||
TestServiceBean.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()");
|
||||
TestThread.getInstance(this).setIsExit(true);
|
||||
|
||||
_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");
|
||||
SOS.bindToAPPService(mContext, new APPSOSBean(mContext.getPackageName(), TestService.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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
package cc.winboll.studio.libappbase.utils;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/17 19:38:20
|
||||
* @Describe 服务工具集
|
||||
*/
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import java.util.List;
|
||||
|
||||
public class ServiceUtils {
|
||||
|
||||
public static final String TAG = "ServiceUtils";
|
||||
|
||||
/**
|
||||
* 检查指定服务是否正在运行
|
||||
* @param context 上下文
|
||||
* @param serviceClass 服务类
|
||||
* @return true 如果服务正在运行,否则返回 false
|
||||
*/
|
||||
public static boolean isServiceRunning(Context context, String serviceClassName) {
|
||||
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
if (activityManager == null) {
|
||||
return false;
|
||||
}
|
||||
List<ActivityManager.RunningServiceInfo> runningServices;
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
// Intent intent = new Intent(context, serviceClass);
|
||||
// runningServices = activityManager.getRunningServices(100, intent);
|
||||
// } else {
|
||||
runningServices = activityManager.getRunningServices(100);
|
||||
//}
|
||||
for (ActivityManager.RunningServiceInfo serviceInfo : runningServices) {
|
||||
if (serviceClassName.equals(serviceInfo.service.getClassName())) {
|
||||
LogUtils.d(TAG, "Service is running: " + serviceInfo.service.getClassName());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
LogUtils.d(TAG, "Service is not running: " + serviceClassName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,63 @@
|
||||
package cc.winboll.studio.libappbase.widgets;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/17 20:32:12
|
||||
*/
|
||||
import android.app.PendingIntent;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProvider;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.widget.RemoteViews;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.R;
|
||||
import cc.winboll.studio.libappbase.utils.ServiceUtils;
|
||||
import com.hjq.toast.ToastUtils;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.IBinder;
|
||||
import cc.winboll.studio.libappbase.services.TestService;
|
||||
|
||||
public class StatusWidget extends AppWidgetProvider {
|
||||
|
||||
public static final String TAG = "StatusWidget";
|
||||
|
||||
public static final String ACTION_STATUS_UPDATE = "cc.winboll.studio.libappbase.widgets.APPWidget.ACTION_STATUS_UPDATE";
|
||||
|
||||
@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_UPDATE)) {
|
||||
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
||||
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, StatusWidget.class));
|
||||
for (int appWidgetId : appWidgetIds) {
|
||||
updateAppWidget(context, appWidgetManager, appWidgetId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
|
||||
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_status);
|
||||
//设置按钮点击事件
|
||||
Intent intentAppButton = new Intent(context, StatusWidgetClickListener.class);
|
||||
intentAppButton.setAction(StatusWidgetClickListener.ACTION_IVAPP);
|
||||
PendingIntent pendingIntentAppButton = PendingIntent.getBroadcast(context, 0, intentAppButton, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
views.setOnClickPendingIntent(R.id.ivapp, pendingIntentAppButton);
|
||||
|
||||
boolean isActive = ServiceUtils.isServiceRunning(context, TestService.class.getName());
|
||||
if (isActive) {
|
||||
views.setImageViewResource(R.id.ivapp, cc.winboll.studio.libappbase.R.drawable.ic_launcher);
|
||||
} else {
|
||||
views.setImageViewResource(R.id.ivapp, cc.winboll.studio.libappbase.R.drawable.ic_launcher_disable);
|
||||
}
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views);
|
||||
}
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
package cc.winboll.studio.libappbase.widgets;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@AliYun.Com
|
||||
* @Date 2025/02/17 20:33:53
|
||||
* @Describe APPWidgetClickListener
|
||||
*/
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import com.hjq.toast.ToastUtils;
|
||||
|
||||
public class StatusWidgetClickListener extends BroadcastReceiver {
|
||||
|
||||
public static final String TAG = "APPWidgetClickListener";
|
||||
|
||||
public static final String ACTION_IVAPP = "cc.winboll.studio.libappbase.widgets.StatusWidgetClickListener.ACTION_IVAPP";
|
||||
|
||||
@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_IVAPP)) {
|
||||
ToastUtils.show("ACTION_LAUNCHER");
|
||||
} else {
|
||||
LogUtils.d(TAG, String.format("action %s", action));
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 9.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 5.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 14 KiB |
Binary file not shown.
Before Width: | Height: | Size: 19 KiB |
41
libappbase/src/main/res/drawable/bg_shadow.xml
Normal file
41
libappbase/src/main/res/drawable/bg_shadow.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<!-- 阴影部分 -->
|
||||
<!-- 个人觉得更形象的表达:top代表下边的阴影高度,left代表右边的阴影宽度。其实也就是相对应的offset,solid中的颜色是阴影的颜色,也可以设置角度等等 -->
|
||||
<item
|
||||
android:left="2dp"
|
||||
android:top="2dp"
|
||||
android:right="2dp"
|
||||
android:bottom="2dp">
|
||||
<shape android:shape="rectangle" >
|
||||
<gradient
|
||||
android:angle="270"
|
||||
android:endColor="#0F000000"
|
||||
android:startColor="#0F000000" />
|
||||
<corners
|
||||
android:bottomLeftRadius="6dip"
|
||||
android:bottomRightRadius="6dip"
|
||||
android:topLeftRadius="6dip"
|
||||
android:topRightRadius="6dip" />
|
||||
</shape>
|
||||
</item>
|
||||
<!-- 背景部分 -->
|
||||
<!-- 形象的表达:bottom代表背景部分在上边缘超出阴影的高度,right代表背景部分在左边超出阴影的宽度(相对应的offset) -->
|
||||
<item
|
||||
android:left="3dp"
|
||||
android:top="3dp"
|
||||
android:right="3dp"
|
||||
android:bottom="5dp">
|
||||
<shape android:shape="rectangle" >
|
||||
<gradient
|
||||
android:angle="270"
|
||||
android:endColor="@color/colorAccent"
|
||||
android:startColor="@color/colorAccent" />
|
||||
<corners
|
||||
android:bottomLeftRadius="6dip"
|
||||
android:bottomRightRadius="6dip"
|
||||
android:topLeftRadius="6dip"
|
||||
android:topRightRadius="6dip" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
13
libappbase/src/main/res/drawable/ic_launcher.xml
Normal file
13
libappbase/src/main/res/drawable/ic_launcher.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:clickable="true"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp">
|
||||
<item android:drawable="@drawable/ic_launcher_background"/>
|
||||
<item
|
||||
android:left="0dp"
|
||||
android:top="0dp"
|
||||
android:right="0dp"
|
||||
android:bottom="0dp"
|
||||
android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</layer-list>
|
170
libappbase/src/main/res/drawable/ic_launcher_background.xml
Normal file
170
libappbase/src/main/res/drawable/ic_launcher_background.xml
Normal 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="#FF005C12"
|
||||
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>
|
13
libappbase/src/main/res/drawable/ic_launcher_disable.xml
Normal file
13
libappbase/src/main/res/drawable/ic_launcher_disable.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:clickable="true"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp">
|
||||
<item android:drawable="@drawable/ic_launcher_background"/>
|
||||
<item
|
||||
android:left="0dp"
|
||||
android:top="0dp"
|
||||
android:right="0dp"
|
||||
android:bottom="0dp"
|
||||
android:drawable="@drawable/ic_launcher_foreground_disable"/>
|
||||
</layer-list>
|
10
libappbase/src/main/res/drawable/ic_launcher_foreground.xml
Normal file
10
libappbase/src/main/res/drawable/ic_launcher_foreground.xml
Normal 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>
|
@@ -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="#FF808080"
|
||||
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>
|
8
libappbase/src/main/res/drawable/view_border.xml
Normal file
8
libappbase/src/main/res/drawable/view_border.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="#000000" /> <!-- 这里可调整边框宽度和颜色 -->
|
||||
<solid android:color="@android:color/transparent" />
|
||||
</shape>
|
@@ -2,34 +2,14 @@
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/activityglobalcrashLinearLayout1">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.widget.Toolbar
|
||||
<cc.winboll.studio.libappbase.GlobalCrashReportView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/activityglobalcrashToolbar1"/>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1.0">
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/activityglobalcrashTextView1"
|
||||
android:background="#FFFFFFFF"/>
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
</ScrollView>
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/activityglobalcrashGlobalCrashReportView1"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
16
libappbase/src/main/res/layout/activity_log.xml
Normal file
16
libappbase/src/main/res/layout/activity_log.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<?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:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1.0"
|
||||
android:id="@+id/logview"/>
|
||||
|
||||
</LinearLayout>
|
35
libappbase/src/main/res/layout/view_globalcrashreport.xml
Normal file
35
libappbase/src/main/res/layout/view_globalcrashreport.xml
Normal file
@@ -0,0 +1,35 @@
|
||||
<?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:id="@+id/viewglobalcrashreportLinearLayout1">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/viewglobalcrashreportToolbar1"/>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1.0">
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#FFFFFFFF"
|
||||
android:id="@+id/viewglobalcrashreportTextView1"/>
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
121
libappbase/src/main/res/layout/view_log.xml
Normal file
121
libappbase/src/main/res/layout/view_log.xml
Normal file
@@ -0,0 +1,121 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#FF000000">
|
||||
|
||||
<RelativeLayout
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:layout_alignParentTop="true"
|
||||
android:background="@drawable/bg_shadow"
|
||||
android:id="@+id/viewlogRelativeLayoutToolbar">
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="36dp"
|
||||
android:text="Clean"
|
||||
android:textSize="14dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:id="@+id/viewlogButtonClean"
|
||||
android:layout_marginLeft="5dp"/>
|
||||
|
||||
<TextView
|
||||
android:background="#FF000000"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:text="LV:"
|
||||
android:layout_toRightOf="@+id/viewlogButtonClean"
|
||||
android:layout_centerVertical="true"
|
||||
android:id="@+id/viewlogTextView1"
|
||||
android:textColor="#FFFFFFFF"/>
|
||||
|
||||
<Spinner
|
||||
android:background="#FFFFFFFF"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:layout_toRightOf="@+id/viewlogTextView1"
|
||||
android:layout_centerVertical="true"
|
||||
android:id="@+id/viewlogSpinner1"/>
|
||||
|
||||
<CheckBox
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:layout_toLeftOf="@+id/viewlogButtonCopy"
|
||||
android:layout_centerVertical="true"
|
||||
android:text="Selectable"
|
||||
android:background="#FFFFFFFF"
|
||||
android:paddingRight="10dp"
|
||||
android:textSize="16dp"
|
||||
android:id="@+id/viewlogCheckBoxSelectable"/>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="36dp"
|
||||
android:text="Copy"
|
||||
android:layout_alignParentRight="true"
|
||||
android:textSize="14dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:id="@+id/viewlogButtonCopy"
|
||||
android:layout_marginRight="5dp"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:background="@drawable/bg_shadow"
|
||||
android:layout_below="@+id/viewlogRelativeLayoutToolbar"
|
||||
android:id="@+id/viewlogLinearLayout1"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<CheckBox
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="ALL"
|
||||
android:id="@+id/viewlogCheckBox1"/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/view_border"
|
||||
android:id="@+id/viewlogRecyclerView1"
|
||||
android:layout_weight="1.0"
|
||||
android:layout_marginRight="5dp"
|
||||
android:padding="2dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.0"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_below="@+id/viewlogLinearLayout1">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#FF000000"
|
||||
android:id="@+id/viewlogScrollViewLog">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="Text"
|
||||
android:textColor="#FF00FF00"
|
||||
android:textIsSelectable="true"
|
||||
android:id="@+id/viewlogTextViewLog"/>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
32
libappbase/src/main/res/layout/view_logtag.xml
Normal file
32
libappbase/src/main/res/layout/view_logtag.xml
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView
|
||||
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"
|
||||
app:cardBackgroundColor="#F5F5F5"
|
||||
app:cardElevation="4dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
android:id="@+id/listviewauthinfoCardView1"
|
||||
android:layout_marginLeft="0dp"
|
||||
android:layout_marginRight="5dp">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:id="@+id/viewlogtagTextView1"/>
|
||||
|
||||
<CheckBox
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:id="@+id/viewlogtagCheckBox1"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
15
libappbase/src/main/res/layout/widget_status.xml
Normal file
15
libappbase/src/main/res/layout/widget_status.xml
Normal 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/ivapp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="AppTheme" parent="@android:style/Theme.Material.Light">
|
||||
</style>
|
||||
</resources>
|
11
libappbase/src/main/res/values/array.xml
Normal file
11
libappbase/src/main/res/values/array.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<array name="enum_loglevel_array">
|
||||
<item>Off</item>
|
||||
<item>Error</item>
|
||||
<item>Warn</item>
|
||||
<item>Info</item>
|
||||
<item>Debug</item>
|
||||
<item>Verbose</item>
|
||||
</array>
|
||||
</resources>
|
@@ -1,7 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<attr name="attrTextColor" format="color" />
|
||||
<attr name="attrPrimaryColor" format="color" />
|
||||
<attr name="attrPrimaryDarkColor" format="color" />
|
||||
<attr name="attrAccentColor" format="color" />
|
||||
|
||||
<attr name="attrColorPrimary" format="color" />
|
||||
|
||||
<attr name="themeGlobalCrashActivity" format="reference"/>
|
||||
|
||||
<declare-styleable name="GlobalCrashActivity">
|
||||
<attr name="colorTittle" format="color" />
|
||||
<attr name="colorTittleBackgound" format="color" />
|
||||
<attr name="colorText" format="color" />
|
||||
<attr name="colorTextBackgound" format="color" />
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#FF03AB4E</color>
|
||||
<color name="colorPrimaryDark">#FF027C39</color>
|
||||
<color name="colorAccent">#FF3DDC84</color>
|
||||
<color name="colorText">#FF000000</color>
|
||||
<color name="colorPrimary">#FF00B322</color>
|
||||
<color name="colorPrimaryDark">#FF005C12</color>
|
||||
<color name="colorAccent">#FF8DFFA2</color>
|
||||
<color name="colorText">#FFFFFB8D</color>
|
||||
</resources>
|
||||
|
@@ -3,5 +3,5 @@
|
||||
|
||||
<string name="lib_name">libappbase</string>
|
||||
<string name="hello_world">Hello world!</string>
|
||||
|
||||
<string name="action_sos">cc.winboll.studio.libappbase.action.SOS</string>
|
||||
</resources>
|
||||
|
@@ -1,9 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="AppTheme" parent="@android:style/Theme.Holo.Light">
|
||||
<item name="attrTextColor">#FF000000</item>
|
||||
<item name="attrPrimaryColor">@color/colorPrimary</item>
|
||||
<item name="attrPrimaryDarkColor">@color/colorPrimaryDark</item>
|
||||
<item name="attrAccentColor">@color/colorAccent</item>
|
||||
|
||||
<style name="APPBaseTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<item name="themeGlobalCrashActivity">@style/GlobalCrashActivityTheme</item>
|
||||
</style>
|
||||
|
||||
<style name="GlobalCrashActivityTheme" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar">
|
||||
<item name="colorTittle">#FFFFF600</item>
|
||||
<item name="colorTittleBackgound">#FF00B322</item>
|
||||
<item name="colorText">#FF00B322</item>
|
||||
<item name="colorTextBackgound">#FF000000</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
@@ -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="1000"
|
||||
android:initialLayout="@layout/widget_status"
|
||||
android:resizeMode="none">
|
||||
</appwidget-provider>
|
1
mymessagemanager/.gitignore
vendored
Normal file
1
mymessagemanager/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
45
mymessagemanager/README.md
Normal file
45
mymessagemanager/README.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# MyMessageManager
|
||||
|
||||
#### 介绍
|
||||
用正则表达式方法自定义短信过滤和语音播报的短信应用。
|
||||
|
||||
#### 软件架构
|
||||
软件架构说明
|
||||
|
||||
|
||||
#### 安装教程
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
|
||||
#### 使用说明
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
|
||||
#### 参与贡献
|
||||
|
||||
1. Fork 本仓库
|
||||
2. 新建 Feat_xxx 分支
|
||||
3. 提交代码:ZhanGSKen(ZhanGSKen@QQ.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/)
|
||||
|
||||
#### 参考文档
|
||||
|
||||
使用GitHub Actions实现Android自动打包apk
|
||||
https://blog.csdn.net/ZZL23333/article/details/115798615?app_version=6.0.0&code=app_1562916241&csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22115798615%22%2C%22source%22%3A%22weixin_38986226%22%7D&uLinkId=usr1mkqgl919blen&utm_source=app
|
||||
|
||||
Android中assets的使用(用于读取内容)
|
||||
https://blog.csdn.net/qq_27664947/article/details/103924058?app_version=6.0.0&code=app_1562916241&csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22103924058%22%2C%22source%22%3A%22weixin_38986226%22%7D&uLinkId=usr1mkqgl919blen&utm_source=app
|
1
mymessagemanager/app_update_description.txt
Normal file
1
mymessagemanager/app_update_description.txt
Normal file
@@ -0,0 +1 @@
|
||||
|
69
mymessagemanager/build.gradle
Normal file
69
mymessagemanager/build.gradle
Normal file
@@ -0,0 +1,69 @@
|
||||
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 30
|
||||
buildToolsVersion "30.0.3"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "cc.winboll.studio.mymessagemanager"
|
||||
minSdkVersion 26
|
||||
targetSdkVersion 29
|
||||
versionCode 8
|
||||
// versionName 更新后需要手动设置
|
||||
// .winboll/winbollBuildProps.properties 文件的 stageCount=0
|
||||
// Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
|
||||
versionName "4.1"
|
||||
if(true) {
|
||||
versionName = genVersionName("${versionName}")
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api 'cc.winboll.studio:winboll-shared:1.6.4'
|
||||
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.0.0'
|
||||
api 'androidx.fragment:fragment:1.0.0'
|
||||
api 'com.google.android.material:material:1.0.0'
|
||||
|
||||
// 权限请求框架:https://github.com/getActivity/XXPermissions
|
||||
api 'com.github.getActivity:XXPermissions:18.63'
|
||||
api 'com.baoyz.pullrefreshlayout:library:1.2.0'
|
||||
|
||||
api 'androidx.appcompat:appcompat:1.0.0'
|
||||
api 'androidx.fragment:fragment:1.0.0'
|
||||
api 'com.google.android.material:material:1.0.0'
|
||||
|
||||
api 'cc.winboll.studio:libaes:7.6.0'
|
||||
|
||||
api fileTree(dir: 'libs', include: ['*.jar'])
|
||||
}
|
8
mymessagemanager/build.properties
Normal file
8
mymessagemanager/build.properties
Normal file
@@ -0,0 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Sat Mar 01 14:11:49 HKT 2025
|
||||
stageCount=19
|
||||
libraryProject=
|
||||
baseVersion=4.1
|
||||
publishVersion=4.1.18
|
||||
buildCount=0
|
||||
baseBetaVersion=4.1.19
|
17
mymessagemanager/proguard-rules.pro
vendored
Normal file
17
mymessagemanager/proguard-rules.pro
vendored
Normal 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 *;
|
||||
#}
|
23
mymessagemanager/src/beta/AndroidManifest.xml
Normal file
23
mymessagemanager/src/beta/AndroidManifest.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?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 -->
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="cc.winboll.studio.mymessagemanager.beta.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_provider"/>
|
||||
|
||||
</provider>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
6
mymessagemanager/src/beta/res/values-zh/strings.xml
Normal file
6
mymessagemanager/src/beta/res/values-zh/strings.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="app_name">我的短信管家 ☆</string>
|
||||
|
||||
</resources>
|
6
mymessagemanager/src/beta/res/values/strings.xml
Normal file
6
mymessagemanager/src/beta/res/values/strings.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="app_name">My Message Manager +</string>
|
||||
|
||||
</resources>
|
233
mymessagemanager/src/main/AndroidManifest.xml
Normal file
233
mymessagemanager/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,233 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="cc.winboll.studio.mymessagemanager">
|
||||
|
||||
<!-- 发送短信 -->
|
||||
<uses-permission android:name="android.permission.SEND_SMS"/>
|
||||
|
||||
<!-- 接收讯息(短信) -->
|
||||
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
|
||||
|
||||
<!-- 读取短信 -->
|
||||
<uses-permission android:name="android.permission.READ_SMS"/>
|
||||
|
||||
<!-- WRITE_SMS -->
|
||||
<uses-permission android:name="android.permission.WRITE_SMS"/>
|
||||
|
||||
<!-- 接收讯息(彩信) -->
|
||||
<uses-permission android:name="android.permission.RECEIVE_MMS"/>
|
||||
|
||||
<!-- 开机启动 -->
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
|
||||
<!-- 运行前台服务 -->
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
|
||||
<!-- 读取联系人 -->
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
|
||||
<!-- 读取您共享存储空间中的内容 -->
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
|
||||
<!-- 修改或删除您共享存储空间中的内容 -->
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
|
||||
<!-- 接收讯息 (WAP) -->
|
||||
<uses-permission android:name="android.permission.RECEIVE_WAP_PUSH"/>
|
||||
|
||||
<!-- MANAGE_EXTERNAL_STORAGE -->
|
||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
|
||||
|
||||
<!-- 此应用可显示在其他应用上方 -->
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||
|
||||
<queries>
|
||||
|
||||
<intent>
|
||||
|
||||
<action android:name="android.intent.action.TTS_SERVICE"/>
|
||||
|
||||
</intent>
|
||||
|
||||
</queries>
|
||||
|
||||
<application
|
||||
android:name=".GlobalApplication"
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:roundIcon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/WinBoll.SupportThemeNoActionBar"
|
||||
android:persistent="true"
|
||||
android:resizeableActivity="true"
|
||||
android:supportsRtl="true"
|
||||
android:requestLegacyExternalStorage="true">
|
||||
|
||||
<activity
|
||||
android:name=".activitys.SMSActivity"
|
||||
android:process=":sms"/>
|
||||
|
||||
<activity
|
||||
android:name=".activitys.SMSReceiveRuleActivity"
|
||||
android:process=":smsars">
|
||||
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activitys.SharedJSONReceiveActivity"
|
||||
android:process=":smssjr"
|
||||
android:exported="true">
|
||||
|
||||
<intent-filter>
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
|
||||
<action android:name="android.intent.action.SEND"/>
|
||||
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
|
||||
<action android:name="android.intent.action.EDIT"/>
|
||||
|
||||
<data android:mimeType="application/json"/>
|
||||
|
||||
<data android:mimeType="text/x-json"/>
|
||||
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activitys.TTSPlayRuleActivity"
|
||||
android:process=":ttsrule"/>
|
||||
|
||||
<activity
|
||||
android:name=".activitys.AboutActivity"
|
||||
android:process=":about"/>
|
||||
|
||||
<activity
|
||||
android:name=".activitys.MainActivity"
|
||||
android:exported="true"
|
||||
android:process=":main">
|
||||
|
||||
<intent-filter>
|
||||
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activitys.ComposeSMSActivity"
|
||||
android:exported="true"
|
||||
android:process=":csms">
|
||||
|
||||
<intent-filter>
|
||||
|
||||
<action android:name="android.intent.action.SEND"/>
|
||||
|
||||
<action android:name="android.intent.action.SENDTO"/>
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
|
||||
<data android:scheme="sms"/>
|
||||
|
||||
<data android:scheme="smsto"/>
|
||||
|
||||
<data android:scheme="mms"/>
|
||||
|
||||
<data android:scheme="mmsto"/>
|
||||
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<activity android:name=".activitys.AppSettingsActivity"/>
|
||||
|
||||
<service android:name=".services.TTSPlayService"/>
|
||||
|
||||
<service android:name=".services.MainService"/>
|
||||
|
||||
<service android:name=".services.AssistantService"/>
|
||||
|
||||
<service
|
||||
android:name=".services.DefaultSMSManagerService"
|
||||
android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
|
||||
android:exported="true">
|
||||
|
||||
<intent-filter>
|
||||
|
||||
<action android:name="android.intent.action.RESPOND_VIA_MESSAGE"/>
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
|
||||
<data android:scheme="sms"/>
|
||||
|
||||
<data android:scheme="smsto"/>
|
||||
|
||||
<data android:scheme="mms"/>
|
||||
|
||||
<data android:scheme="mmsto"/>
|
||||
|
||||
</intent-filter>
|
||||
|
||||
</service>
|
||||
|
||||
<receiver
|
||||
android:name=".receivers.MainReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:directBootAware="true">
|
||||
|
||||
<intent-filter>
|
||||
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
|
||||
</intent-filter>
|
||||
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".receivers.SMSRecevier"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BROADCAST_SMS">
|
||||
|
||||
<intent-filter android:priority="1">
|
||||
|
||||
<action android:name="android.provider.Telephony.SMS_DELIVER"/>
|
||||
|
||||
</intent-filter>
|
||||
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".receivers.MmsReceiver"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BROADCAST_WAP_PUSH">
|
||||
|
||||
<intent-filter>
|
||||
|
||||
<action android:name="android.provider.Telephony.WAP_PUSH_DELIVER"/>
|
||||
|
||||
<data android:mimeType="application/vnd.wap.mms-message"/>
|
||||
|
||||
</intent-filter>
|
||||
|
||||
</receiver>
|
||||
|
||||
<meta-data
|
||||
android:name="android.max_aspect"
|
||||
android:value="4.0"/>
|
||||
|
||||
<activity android:name="cc.winboll.studio.mymessagemanager.activitys.SMSRecycleActivity"/>
|
||||
|
||||
<activity android:name="cc.winboll.studio.mymessagemanager.unittest.UnitTestActivity"/>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"userId": -1,
|
||||
"ruleData": ".*",
|
||||
"isEnable": true
|
||||
}
|
||||
]
|
@@ -0,0 +1,38 @@
|
||||
[
|
||||
{
|
||||
"userId": 1,
|
||||
"ruleName": "规则1",
|
||||
"demoSMSText": "【短信应用A】验证码123456",
|
||||
"patternText": "^(【.*】)验证码(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)$",
|
||||
"ttdRuleText": "$1验证码是($2)($3)($4)($5)($6)($7)。",
|
||||
"isSimpleView": false,
|
||||
"isEnable": true
|
||||
},
|
||||
{
|
||||
"userId": 1,
|
||||
"ruleName": "规则2",
|
||||
"demoSMSText": "[短信应用A]验证码123456",
|
||||
"patternText": "^(\\[.*\\])验证码(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)$",
|
||||
"ttdRuleText": "$1验证码是($2)($3)($4)($5)($6)($7)。",
|
||||
"isSimpleView": false,
|
||||
"isEnable": true
|
||||
},
|
||||
{
|
||||
"userId": 1,
|
||||
"ruleName": "规则3",
|
||||
"demoSMSText": "【短信应用A】验证码123456",
|
||||
"patternText": ".*(【.+】).*",
|
||||
"ttdRuleText": "短信来自$1。",
|
||||
"isSimpleView": false,
|
||||
"isEnable": true
|
||||
},
|
||||
{
|
||||
"userId": 1,
|
||||
"ruleName": "规则4",
|
||||
"demoSMSText": "[短信应用A]验证码123456",
|
||||
"patternText": ".*(\\[.*\\]).*",
|
||||
"ttdRuleText": "短信来自$1。",
|
||||
"isSimpleView": false,
|
||||
"isEnable": true
|
||||
}
|
||||
]
|
@@ -0,0 +1,52 @@
|
||||
package cc.winboll.studio.mymessagemanager;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@QQ.COM
|
||||
* @Date 2023/07/24 01:46:59
|
||||
* @Describe 全局应用类
|
||||
*/
|
||||
import android.view.Gravity;
|
||||
import cc.winboll.studio.mymessagemanager.R;
|
||||
import cc.winboll.studio.shared.app.WinBollApplication;
|
||||
import cc.winboll.studio.shared.log.LogUtils;
|
||||
import com.hjq.toast.ToastUtils;
|
||||
import java.io.File;
|
||||
|
||||
public class GlobalApplication extends WinBollApplication {
|
||||
|
||||
public static final String TAG = "GlobalApplication";
|
||||
|
||||
static String _mszAppExternalFilesDir;
|
||||
static String _mszConfigUtilFileName = "ConfigUtil.json";
|
||||
static String _mszConfigUtilPath;
|
||||
static String _mszSMSReceiveRuleUtilFileName = "SMSReceiveRuleUtil.json";
|
||||
static String _mszSMSReceiveRuleUtilPath;
|
||||
|
||||
public static final int USER_ID = -1;
|
||||
Long mszVersionName = 1L;
|
||||
Long mszDataVersionName = 1L;
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
//setIsDebug(cc.winboll.studio.mymessagemanager.BuildConfig.DEBUG);
|
||||
|
||||
// 初始化 Toast 框架
|
||||
ToastUtils.init(this);
|
||||
// 设置 Toast 布局样式
|
||||
ToastUtils.setView(R.layout.toast_custom_view);
|
||||
//ToastUtils.setStyle(new WhiteToastStyle());
|
||||
ToastUtils.setGravity(Gravity.BOTTOM, 0, 200);
|
||||
|
||||
//LogUtils.d(TAG, "BuildConfig.DEBUG " + Boolean.toString(BuildConfig.DEBUG));
|
||||
|
||||
_mszAppExternalFilesDir = getExternalFilesDir(TAG).toString();
|
||||
_mszConfigUtilPath = _mszAppExternalFilesDir + File.separator + _mszConfigUtilFileName;
|
||||
_mszSMSReceiveRuleUtilPath = _mszAppExternalFilesDir + File.separator + _mszSMSReceiveRuleUtilFileName;
|
||||
}
|
||||
|
||||
public static void showApplicationMessage(String szMessage) {
|
||||
LogUtils.i(TAG, szMessage);
|
||||
}
|
||||
}
|
@@ -0,0 +1,74 @@
|
||||
package cc.winboll.studio.mymessagemanager.activitys;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@QQ.COM
|
||||
* @Date 2024/07/14 13:20:33
|
||||
* @Describe 应用关于对话窗口
|
||||
*/
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import cc.winboll.studio.mymessagemanager.R;
|
||||
import cc.winboll.studio.shared.app.WinBollActivity;
|
||||
import cc.winboll.studio.shared.app.WinBollActivityManager;
|
||||
import com.hjq.toast.ToastUtils;
|
||||
import cc.winboll.studio.libaes.utils.AESThemeUtil;
|
||||
import android.content.Context;
|
||||
|
||||
final public class AboutActivity extends WinBollActivity {
|
||||
|
||||
public static final String TAG = "AboutActivity";
|
||||
|
||||
Context mContext;
|
||||
|
||||
@Override
|
||||
public String getTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnableDisplayHomeAsUp() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(AESThemeUtil.getThemeTypeID(getApplicationContext()));
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_about);
|
||||
mContext = getApplicationContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
setTitle(mContext.getString(R.string.text_about) + mContext.getString(R.string.app_name));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAddWinBollToolBar() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Toolbar initToolBar() {
|
||||
return findViewById(R.id.activityaboutASupportToolbar1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.toolbar_about, menu);
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
/*if (item.getItemId() == R.id.item_help) {
|
||||
ToastUtils.show("R.id.item_help");
|
||||
} else */if (item.getItemId() == android.R.id.home) {
|
||||
WinBollActivityManager.getInstance(getApplicationContext()).finish(this);
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
@@ -0,0 +1,99 @@
|
||||
package cc.winboll.studio.mymessagemanager.activitys;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen@QQ.COM
|
||||
* @Date 2024/05/12 20:03:42
|
||||
* @Describe 应用设置窗口
|
||||
*/
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Switch;
|
||||
import android.widget.Toast;
|
||||
import cc.winboll.studio.libaes.views.AOHPCTCSeekBar;
|
||||
import cc.winboll.studio.libaes.views.AToolbar;
|
||||
import cc.winboll.studio.mymessagemanager.R;
|
||||
import cc.winboll.studio.mymessagemanager.utils.AppConfigUtil;
|
||||
import cc.winboll.studio.mymessagemanager.utils.PermissionUtil;
|
||||
|
||||
public class AppSettingsActivity extends BaseActivity {
|
||||
|
||||
public static final String TAG = "AppSettingsActivity";
|
||||
|
||||
AppConfigUtil mAppConfigUtil;
|
||||
AToolbar mAToolbar;
|
||||
AOHPCTCSeekBar mAOHPCTCSeekBar;
|
||||
EditText metTTSPlayDelayTimes;
|
||||
EditText metPhoneMergePrefix;
|
||||
Switch mswMergePrefixPhone;
|
||||
Switch mswSMSRecycleProtectMode;
|
||||
EditText metProtectModerRefuseChars;
|
||||
EditText metProtectModerReplaceChars;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_appsettings);
|
||||
|
||||
// 初始化属性
|
||||
mAppConfigUtil = AppConfigUtil.getInstance(this);
|
||||
int nTtsPlayDelayTimes = mAppConfigUtil.mAppConfigBean.getTtsPlayDelayTimes();
|
||||
metTTSPlayDelayTimes = findViewById(R.id.activityappsettingsEditText1);
|
||||
metTTSPlayDelayTimes.setText(Integer.toString(nTtsPlayDelayTimes / 1000));
|
||||
|
||||
// 初始化标题栏
|
||||
mAToolbar = findViewById(R.id.activityappsettingsAToolbar1);
|
||||
mAToolbar.setSubtitle(getString(R.string.activity_name_appsettings));
|
||||
setActionBar(mAToolbar);
|
||||
|
||||
metPhoneMergePrefix = findViewById(R.id.activityappsettingsEditText2);
|
||||
metPhoneMergePrefix.setText(mAppConfigUtil.mAppConfigBean.getCountryCode());
|
||||
|
||||
mswMergePrefixPhone = findViewById(R.id.activityappsettingsSwitch1);
|
||||
mswMergePrefixPhone.setChecked(mAppConfigUtil.mAppConfigBean.isMergeCountryCodePrefix());
|
||||
|
||||
mswSMSRecycleProtectMode = findViewById(R.id.activityappsettingsSwitch3);
|
||||
mswSMSRecycleProtectMode.setChecked(mAppConfigUtil.mAppConfigBean.isSMSRecycleProtectMode());
|
||||
|
||||
metProtectModerRefuseChars = findViewById(R.id.activityappsettingsEditText3);
|
||||
metProtectModerRefuseChars.setText(mAppConfigUtil.mAppConfigBean.getProtectModerRefuseChars());
|
||||
|
||||
metProtectModerReplaceChars = findViewById(R.id.activityappsettingsEditText4);
|
||||
metProtectModerReplaceChars.setText(mAppConfigUtil.mAppConfigBean.getProtectModerReplaceChars());
|
||||
|
||||
mAOHPCTCSeekBar = findViewById(R.id.activityappsettingsAOHPCTCSeekBar1);
|
||||
mAOHPCTCSeekBar.setThumb(getDrawable(R.drawable.cursor_pointer));
|
||||
mAOHPCTCSeekBar.setThumbOffset(0);
|
||||
mAOHPCTCSeekBar.setOnOHPCListener(new AOHPCTCSeekBar.OnOHPCListener(){
|
||||
|
||||
@Override
|
||||
public void onOHPCommit() {
|
||||
mAppConfigUtil.reLoadConfig();
|
||||
mAppConfigUtil.mAppConfigBean.setIsSMSRecycleProtectMode(mswSMSRecycleProtectMode.isChecked());
|
||||
mAppConfigUtil.mAppConfigBean.setProtectModerRefuseChars(metProtectModerRefuseChars.getText().toString());
|
||||
mAppConfigUtil.mAppConfigBean.setProtectModerReplaceChars(metProtectModerReplaceChars.getText().toString());
|
||||
mAppConfigUtil.mAppConfigBean.setCountryCode(metPhoneMergePrefix.getText().toString());
|
||||
mAppConfigUtil.mAppConfigBean.setIsMergeCountryCodePrefix(mswMergePrefixPhone.isChecked());
|
||||
int nTtsPlayDelayTimes = 1000 * Integer.parseInt(metTTSPlayDelayTimes.getText().toString());
|
||||
mAppConfigUtil.mAppConfigBean.setTtsPlayDelayTimes(nTtsPlayDelayTimes);
|
||||
mAppConfigUtil.saveConfig();
|
||||
Toast.makeText(getApplication(), "App config data is saved.", Toast.LENGTH_SHORT).show();
|
||||
//LogUtils.d(TAG, "TTS Play Delay Times is setting to : " + Integer.toString(mAppConfigData.getTtsPlayDelayTimes()));Toast.makeText(getApplication(), "onOHPCommit", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
public void onOpenSystemDefaultAppSettings(View view) {
|
||||
Intent intent = new Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
public void onCheckAndGetAppPermission(View view) {
|
||||
//LogUtils.d(TAG, "onCheckAndGetAppPermission");
|
||||
if (PermissionUtil.checkAndGetAppPermission(this)) {
|
||||
Toast.makeText(getApplication(), "应用已获得所需权限。", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,113 @@
|
||||
package cc.winboll.studio.mymessagemanager.activitys;
|
||||
|
||||
import cc.winboll.studio.mymessagemanager.R;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import cc.winboll.studio.libaes.utils.AESThemeUtil;
|
||||
import cc.winboll.studio.shared.log.LogUtils;
|
||||
import com.hjq.toast.ToastUtils;
|
||||
import cc.winboll.studio.libaes.beans.AESThemeBean;
|
||||
|
||||
abstract public class BaseActivity extends AppCompatActivity {
|
||||
|
||||
public static final String TAG = "BaseActivity";
|
||||
|
||||
IOnActivityMessageReceived mIOnActivityMessageReceived;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
//AppConfigUtil configUtil = AppConfigUtil.getInstance(this);
|
||||
//setTheme(configUtil.mAppConfigBean.getAppThemeID());
|
||||
LogUtils.d(TAG, "AESThemeUtil.getThemeTypeID(this) is : " + Integer.toString(AESThemeUtil.getThemeTypeID(this)));
|
||||
setTheme(AESThemeUtil.getThemeTypeID(this));
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
public void sendActivityMessage(Message msg) {
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
protected void setOnActivityMessageReceived(IOnActivityMessageReceived iOnActivityMessageReceived) {
|
||||
mIOnActivityMessageReceived = iOnActivityMessageReceived;
|
||||
}
|
||||
|
||||
Handler mHandler = new Handler(){
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
super.handleMessage(msg);
|
||||
if (mIOnActivityMessageReceived != null) {
|
||||
mIOnActivityMessageReceived.onActivityMessageReceived(msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
protected interface IOnActivityMessageReceived {
|
||||
void onActivityMessageReceived(Message msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
AESThemeUtil.inflateMenu(this, menu);
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
/*if (AESThemeUtil.onAppCompatThemeItemSelected(this, item)) {
|
||||
ToastUtils.show("onAppCompatThemeItemSelected");
|
||||
recreate();
|
||||
}*/
|
||||
|
||||
/*int nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.DEFAULT);
|
||||
if (R.id.item_depththeme == item.getItemId()) {
|
||||
nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.DEPTH);
|
||||
AESThemeUtil.saveThemeStyleID(this, nThemeStyleID);
|
||||
recreate();
|
||||
} else if (R.id.item_skytheme == item.getItemId()) {
|
||||
nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.SKY);
|
||||
AESThemeUtil.saveThemeStyleID(this, nThemeStyleID);
|
||||
recreate();
|
||||
} else if (R.id.item_goldentheme == item.getItemId()) {
|
||||
nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.GOLDEN);
|
||||
AESThemeUtil.saveThemeStyleID(this, nThemeStyleID);
|
||||
recreate();
|
||||
} else if (R.id.item_taotheme == item.getItemId()) {
|
||||
nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.TAO);
|
||||
AESThemeUtil.saveThemeStyleID(this, nThemeStyleID);
|
||||
recreate();
|
||||
} else if (R.id.item_defaulttheme == item.getItemId()) {
|
||||
nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.DEFAULT);
|
||||
AESThemeUtil.saveThemeStyleID(this, nThemeStyleID);
|
||||
recreate();
|
||||
}*/
|
||||
|
||||
//int nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.DEFAULT);
|
||||
if (R.id.item_depththeme == item.getItemId()) {
|
||||
AESThemeUtil.saveThemeStyleID(this, R.style.MyDepthAESTheme);
|
||||
recreate();
|
||||
} else if (R.id.item_skytheme == item.getItemId()) {
|
||||
AESThemeUtil.saveThemeStyleID(this, R.style.MySkyAESTheme);
|
||||
recreate();
|
||||
} else if (R.id.item_goldentheme == item.getItemId()) {
|
||||
AESThemeUtil.saveThemeStyleID(this, R.style.MyGoldenAESTheme);
|
||||
recreate();
|
||||
} else if (R.id.item_memortheme == item.getItemId()) {
|
||||
AESThemeUtil.saveThemeStyleID(this, R.style.MyMemorAESTheme);
|
||||
recreate();
|
||||
} else if (R.id.item_taotheme == item.getItemId()) {
|
||||
AESThemeUtil.saveThemeStyleID(this, R.style.MyTaoAESTheme);
|
||||
recreate();
|
||||
} else if (R.id.item_defaulttheme == item.getItemId()) {
|
||||
AESThemeUtil.saveThemeStyleID(this, R.style.MyDefaultAESTheme);
|
||||
recreate();
|
||||
}
|
||||
//ToastUtils.show("nThemeStyleID " + Integer.toString(nThemeStyleID));
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
@@ -0,0 +1,192 @@
|
||||
package cc.winboll.studio.mymessagemanager.activitys;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ListView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.SimpleAdapter;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import android.widget.Toolbar;
|
||||
import cc.winboll.studio.libaes.views.AOHPCTCSeekBar;
|
||||
import cc.winboll.studio.mymessagemanager.R;
|
||||
import cc.winboll.studio.mymessagemanager.activitys.ComposeSMSActivity;
|
||||
import cc.winboll.studio.mymessagemanager.beans.PhoneBean;
|
||||
import cc.winboll.studio.mymessagemanager.utils.PhoneUtil;
|
||||
import cc.winboll.studio.mymessagemanager.utils.SMSUtil;
|
||||
import com.hjq.toast.ToastUtils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ComposeSMSActivity extends BaseActivity {
|
||||
|
||||
public static String TAG = "ComposeSMSActivity";
|
||||
|
||||
public static String EXTRA_SMSBODY = "sms_body";
|
||||
|
||||
static String MAP_NAME = "NAME";
|
||||
static String MAP_PHONE = "PHONE";
|
||||
|
||||
String mszSMSBody;
|
||||
String mszScheme;
|
||||
String mszPhoneTo;
|
||||
EditText metTO;
|
||||
EditText metSMSBody;
|
||||
SimpleAdapter mSimpleAdapter;
|
||||
List<Map<String,Object>> mAdapterData = new ArrayList<>();
|
||||
ListView mlvContracts;
|
||||
List<PhoneBean> mListPhoneBeanContracts;
|
||||
Toolbar mToolbar;
|
||||
AOHPCTCSeekBar mAOHPCTCSeekBar;
|
||||
RelativeLayout mrlContracts;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_composesms);
|
||||
mszSMSBody = getIntent().getStringExtra(EXTRA_SMSBODY);
|
||||
mszScheme = getIntent().getData().getScheme();
|
||||
mszPhoneTo = getIntent().getData().getSchemeSpecificPart();
|
||||
if (!mszScheme.equals("smsto")) {
|
||||
// 其他方式未支持就退出
|
||||
finish();
|
||||
}
|
||||
// 初始化视图
|
||||
initView();
|
||||
// 设置适配器
|
||||
initAdapter();
|
||||
// 设置搜索到的匹配位置
|
||||
setListViewPrePosition();
|
||||
}
|
||||
|
||||
//
|
||||
// 初始化视图
|
||||
//
|
||||
void initView() {
|
||||
//Drawable drawableFrame = AppCompatResources.getDrawable(this, R.drawable.bg_frame);
|
||||
|
||||
// 初始化标题栏
|
||||
mToolbar = findViewById(R.id.activitycomposesmsASupportToolbar1);
|
||||
mToolbar.setSubtitle(getString(R.string.activity_name_composesms));
|
||||
setActionBar(mToolbar);
|
||||
|
||||
// 初始化联系人栏目框
|
||||
mrlContracts = findViewById(R.id.activitycomposesmsRelativeLayout1);
|
||||
//mrlContracts.setBackground(drawableFrame);
|
||||
|
||||
// 初始化联系人列表
|
||||
mlvContracts = findViewById(R.id.activitycomposesmsListView1);
|
||||
|
||||
// 初始化联系人输入框
|
||||
metTO = findViewById(R.id.activitycomposesmsEditText1);
|
||||
metTO.setText(mszPhoneTo);
|
||||
metTO.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
setListViewPrePosition();
|
||||
}
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
}
|
||||
});
|
||||
|
||||
// 初始化发送拉动控件
|
||||
mAOHPCTCSeekBar = findViewById(R.id.viewsmssendpart1AOHPCTCSeekBar1);
|
||||
mAOHPCTCSeekBar.setThumb(getDrawable(R.drawable.ic_message));
|
||||
mAOHPCTCSeekBar.setThumbOffset(20);
|
||||
mAOHPCTCSeekBar.setOnOHPCListener(new AOHPCTCSeekBar.OnOHPCListener() {
|
||||
@Override
|
||||
public void onOHPCommit() {
|
||||
// 空号码不发送
|
||||
mszPhoneTo = metTO.getText().toString();
|
||||
if (mszPhoneTo.trim().equals("")) {
|
||||
ToastUtils.show("没有设置接收号码。");
|
||||
return;
|
||||
}
|
||||
// 空消息不发送
|
||||
mszSMSBody = metSMSBody.getText().toString();
|
||||
if (mszSMSBody.equals("")) {
|
||||
ToastUtils.show("没有消息内容可发送。");
|
||||
return;
|
||||
}
|
||||
// 发送消息
|
||||
if (SMSUtil.sendMessageByInterface2(ComposeSMSActivity.this, mszPhoneTo, mszSMSBody)) {
|
||||
ComposeSMSActivity.this.finish();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 初始化提示框
|
||||
TextView tvAOHPCTCSeekBarMSG = findViewById(R.id.viewsmssendpart1TextView1);
|
||||
tvAOHPCTCSeekBarMSG.setText(R.string.msg_100sendmsg);
|
||||
|
||||
// 初始化发送消息框
|
||||
metSMSBody = findViewById(R.id.viewsmssendpart1EditText1);
|
||||
//metSMSBody.setBackground(drawableFrame);
|
||||
metSMSBody.setText(mszSMSBody);
|
||||
}
|
||||
|
||||
//
|
||||
// 设置搜索到的匹配位置
|
||||
//
|
||||
void setListViewPrePosition() {
|
||||
int nPrePosition = getContractsDataPrePosition(metTO.getText().toString());
|
||||
mlvContracts.setSelected(false);
|
||||
mlvContracts.setSelection(nPrePosition);
|
||||
}
|
||||
|
||||
//
|
||||
// 返回搜索到的匹配位置
|
||||
//
|
||||
int getContractsDataPrePosition(String szPhone) {
|
||||
for (int i = 0; i < mListPhoneBeanContracts.size(); i++) {
|
||||
if (mListPhoneBeanContracts.get(i).getTelPhone().compareTo(szPhone) > -1) {
|
||||
return i;
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// 初始化适配器
|
||||
//
|
||||
void initAdapter() {
|
||||
// 初始化联系人数据适配器
|
||||
mAdapterData = new ArrayList<>();
|
||||
// 读取联系人数据
|
||||
PhoneUtil phoneUtils = new PhoneUtil(this);
|
||||
mListPhoneBeanContracts = phoneUtils.getPhoneList();
|
||||
// 映射联系人数据给适配器数据对象
|
||||
for (int i = 0;i < mListPhoneBeanContracts.size();i++) {
|
||||
Map<String,Object> map =new HashMap<>();
|
||||
map.put(MAP_NAME, mListPhoneBeanContracts.get(i).getName());
|
||||
map.put(MAP_PHONE, mListPhoneBeanContracts.get(i).getTelPhone());
|
||||
mAdapterData.add(map);
|
||||
}
|
||||
// 绑定适配器与数据
|
||||
mSimpleAdapter = new SimpleAdapter(ComposeSMSActivity.this, mAdapterData, R.layout.listview_contracts
|
||||
, new String[]{MAP_NAME, MAP_PHONE}
|
||||
, new int[]{R.id.listviewcontractsTextView1, R.id.listviewcontractsTextView2});
|
||||
mSimpleAdapter.setDropDownViewResource(R.layout.listview_contracts);
|
||||
mlvContracts.setAdapter(mSimpleAdapter);
|
||||
mlvContracts.setOnItemClickListener(new ListView.OnItemClickListener() {
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
metTO.setText(mAdapterData.get(position).get(MAP_PHONE).toString());
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,338 @@
|
||||
package cc.winboll.studio.mymessagemanager.activitys;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Message;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.ScrollView;
|
||||
import cc.winboll.studio.libaes.views.AToolbar;
|
||||
import cc.winboll.studio.mymessagemanager.BuildConfig;
|
||||
import cc.winboll.studio.mymessagemanager.R;
|
||||
import cc.winboll.studio.mymessagemanager.activitys.MainActivity;
|
||||
import cc.winboll.studio.mymessagemanager.adapters.PhoneArrayAdapter;
|
||||
import cc.winboll.studio.mymessagemanager.services.MainService;
|
||||
import cc.winboll.studio.mymessagemanager.utils.AppConfigUtil;
|
||||
import cc.winboll.studio.mymessagemanager.utils.AppGoToSettingsUtil;
|
||||
import cc.winboll.studio.mymessagemanager.utils.NotificationUtil;
|
||||
import cc.winboll.studio.mymessagemanager.utils.PermissionUtil;
|
||||
import cc.winboll.studio.mymessagemanager.utils.SMSUtil;
|
||||
import cc.winboll.studio.mymessagemanager.utils.ThemeUtil;
|
||||
import cc.winboll.studio.mymessagemanager.utils.ViewUtil;
|
||||
import cc.winboll.studio.mymessagemanager.views.ConfirmSwitchView;
|
||||
import cc.winboll.studio.mymessagemanager.views.PhoneListViewForScrollView;
|
||||
import cc.winboll.studio.shared.log.LogUtils;
|
||||
import cc.winboll.studio.shared.log.LogView;
|
||||
import com.baoyz.widget.PullRefreshLayout;
|
||||
import java.util.ArrayList;
|
||||
import cc.winboll.studio.libaes.utils.AESThemeUtil;
|
||||
import cc.winboll.studio.libaes.views.ASupportToolbar;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import cc.winboll.studio.mymessagemanager.unittest.UnitTestActivity;
|
||||
|
||||
public class MainActivity extends BaseActivity {
|
||||
|
||||
public final static String TAG = "MainActivity";
|
||||
|
||||
public static final int ACTIVITY_RESULT_APP_SETTINGS = -1;
|
||||
|
||||
public final static int MSG_RELOADSMS = 0;
|
||||
|
||||
public static final int PERMISSION_SETTING_FOR_RESULT = 0;
|
||||
public static final int MY_PERMISSIONS_REQUEST = 0;
|
||||
|
||||
static MainActivity _mMainActivity;
|
||||
LogView mLogView;
|
||||
AppConfigUtil mAppConfigUtil;
|
||||
ConfirmSwitchView msvEnableService;
|
||||
ConfirmSwitchView msvOnlyReceiveContacts;
|
||||
ConfirmSwitchView msvEnableTTS;
|
||||
ConfirmSwitchView msvEnableTTSRuleMode;
|
||||
PhoneListViewForScrollView mListViewPhone;
|
||||
Toolbar mToolbar;
|
||||
PhoneArrayAdapter mPhoneArrayAdapter;
|
||||
AppGoToSettingsUtil mAppGoToSettingsUtil;
|
||||
String[] mPermissionList = {Manifest.permission.READ_CONTACTS,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.READ_SMS};
|
||||
ArrayList<String> listPerms;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
_mMainActivity = MainActivity.this;
|
||||
|
||||
mAppConfigUtil = AppConfigUtil.getInstance(this);
|
||||
initView();
|
||||
|
||||
// 调用调试检查函数
|
||||
onOnceAndroidStory(null);
|
||||
}
|
||||
|
||||
//
|
||||
// 这是一个测试函数,
|
||||
// 用于调试读取 string.xml string-array使用。
|
||||
//
|
||||
public void onOnceAndroidStory(View view) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
// 获取strings.xml文件中的tab_names数组
|
||||
String[] tab_names = getResources().getStringArray(R.array.strings_OnceAndroidStory);
|
||||
// 这里R.array.tab_names是你在XML文件中定义的数组资源ID
|
||||
// 例如,在strings.xml中可能这样定义:
|
||||
/*/ <!-- strings.xml -->
|
||||
<resources>
|
||||
<string-array name="tab_names">
|
||||
<item>Tab 1</item>
|
||||
<item>Tab 2</item>
|
||||
<item>Tab 3</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
*/
|
||||
// 现在你可以遍历这个数组来访问每个元素
|
||||
for (int i = 0; i < tab_names.length; i++) {
|
||||
// 创建Random实例并传入任意非负种子(这里是1)
|
||||
java.util.Random r = new java.util.Random(1);
|
||||
// 调用nextInt(6),范围是0到5(包括0和5),加1后得到1到5
|
||||
int randomNum = r.nextInt(6) + 1;
|
||||
System.out.println("Random number between 1 and 5: " + randomNum);
|
||||
LogUtils.d("OnceAndroidStory", tab_names[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void scrollScrollView() {
|
||||
ScrollView sv = findViewById(R.id.activitymainScrollView1);
|
||||
ViewUtil.scrollScrollView(sv);
|
||||
}
|
||||
|
||||
void genTestData() {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
SMSUtil.saveReceiveSms(this, "13172887736", "调试阶段生成的短信" + Integer.toString(i), "0", -1, "inbox");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 初始化视图控件
|
||||
//
|
||||
void initView() {
|
||||
// 设置调试日志
|
||||
mLogView = findViewById(R.id.logview);
|
||||
mLogView.start();
|
||||
|
||||
// 设置消息处理函数
|
||||
setOnActivityMessageReceived(mIOnActivityMessageReceived);
|
||||
|
||||
// 设置标题栏
|
||||
mToolbar = findViewById(R.id.activitymainASupportToolbar1);
|
||||
mToolbar.setSubtitle(getString(R.string.activity_name_main));
|
||||
setSupportActionBar(mToolbar);
|
||||
|
||||
// 创建通知频道
|
||||
NotificationUtil nu = new NotificationUtil();
|
||||
nu.createServiceNotificationChannel(MainActivity.this);
|
||||
nu.createSMSNotificationChannel(MainActivity.this);
|
||||
|
||||
boolean isEnableService = mAppConfigUtil.mAppConfigBean.isEnableService();
|
||||
msvEnableService = findViewById(R.id.activitymainSwitchView1);
|
||||
msvEnableService.setChecked(isEnableService);
|
||||
msvEnableService.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
boolean isEnable = ((ConfirmSwitchView)v).isChecked();
|
||||
mAppConfigUtil.reLoadConfig();
|
||||
mAppConfigUtil.mAppConfigBean.setIsEnableService(isEnable);
|
||||
mAppConfigUtil.saveConfig();
|
||||
initService(isEnable);
|
||||
}
|
||||
});
|
||||
|
||||
boolean isOnlyReceiveContacts = mAppConfigUtil.mAppConfigBean.isEnableOnlyReceiveContacts();
|
||||
msvOnlyReceiveContacts = findViewById(R.id.activitymainSwitchView2);
|
||||
msvOnlyReceiveContacts.setChecked(isOnlyReceiveContacts);
|
||||
msvOnlyReceiveContacts.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
boolean isEnable = ((ConfirmSwitchView)v).isChecked();
|
||||
mAppConfigUtil.reLoadConfig();
|
||||
mAppConfigUtil.mAppConfigBean.setIsEnableOnlyReceiveContacts(isEnable);
|
||||
mAppConfigUtil.saveConfig();
|
||||
}
|
||||
});
|
||||
|
||||
boolean isEnableTTS = mAppConfigUtil.mAppConfigBean.isEnableTTS();
|
||||
msvEnableTTS = findViewById(R.id.activitymainSwitchView3);
|
||||
msvEnableTTS.setChecked(isEnableTTS);
|
||||
msvEnableTTS.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
boolean isEnable = ((ConfirmSwitchView)v).isChecked();
|
||||
mAppConfigUtil.reLoadConfig();
|
||||
mAppConfigUtil.mAppConfigBean.setIsEnableTTS(isEnable);
|
||||
mAppConfigUtil.saveConfig();
|
||||
}
|
||||
});
|
||||
|
||||
boolean isEnableTTSRuleMode = mAppConfigUtil.mAppConfigBean.isEnableTTSRuleMode();
|
||||
msvEnableTTSRuleMode = findViewById(R.id.activitymainSwitchView4);
|
||||
msvEnableTTSRuleMode.setChecked(isEnableTTSRuleMode);
|
||||
msvEnableTTSRuleMode.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
boolean isEnable = ((ConfirmSwitchView)v).isChecked();
|
||||
mAppConfigUtil.reLoadConfig();
|
||||
mAppConfigUtil.mAppConfigBean.setIsEnableTTSRuleMode(isEnable);
|
||||
mAppConfigUtil.saveConfig();
|
||||
}
|
||||
});
|
||||
|
||||
initService(isEnableService);
|
||||
|
||||
// 短信发送窗口按钮
|
||||
Button btnSendSMS = findViewById(R.id.activitymainButton1);
|
||||
btnSendSMS.setOnClickListener(new View.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Uri uri = Uri.parse("smsto:");
|
||||
Intent it = new Intent(Intent.ACTION_SENDTO, uri);
|
||||
it.putExtra("sms_body", "");
|
||||
startActivity(it);
|
||||
}
|
||||
});
|
||||
|
||||
mListViewPhone = (PhoneListViewForScrollView) findViewById(R.id.activitymainListView1);
|
||||
//准备数据
|
||||
mPhoneArrayAdapter = new PhoneArrayAdapter(MainActivity.this);
|
||||
|
||||
final PullRefreshLayout layout = (PullRefreshLayout) findViewById(R.id.activitymainPullRefreshLayout1);
|
||||
//将适配器加载到控件中
|
||||
mListViewPhone.setAdapter(mPhoneArrayAdapter);
|
||||
|
||||
// listen refresh event
|
||||
layout.setOnRefreshListener(new PullRefreshLayout.OnRefreshListener() {
|
||||
@Override
|
||||
public void onRefresh() {
|
||||
// start refresh
|
||||
reloadSMS();
|
||||
layout.setRefreshing(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void initService(boolean isEnableService) {
|
||||
if (isEnableService) {
|
||||
Intent service = new Intent(this, MainService.class);
|
||||
startService(service);
|
||||
} else {
|
||||
Intent service = new Intent(this, MainService.class);
|
||||
stopService(service);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 定义应用内消息处理函数
|
||||
//
|
||||
IOnActivityMessageReceived mIOnActivityMessageReceived = new IOnActivityMessageReceived(){
|
||||
|
||||
@Override
|
||||
public void onActivityMessageReceived(Message msg) {
|
||||
switch (msg.arg1) {
|
||||
case MSG_RELOADSMS : {
|
||||
LogUtils.d(TAG, "MSG_RELOADSMS");
|
||||
if (PermissionUtil.checkAppPermission(MainActivity.this)) {
|
||||
mPhoneArrayAdapter.loadData();
|
||||
mPhoneArrayAdapter.notifyDataSetChanged();
|
||||
} else {
|
||||
LogUtils.i(TAG, "遇到应用权限问题,请打开应用设置检查一下应用权限。");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean onCreatePanelMenu(int featureId, Menu menu) {
|
||||
return super.onCreatePanelMenu(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
reloadSMS();
|
||||
mLogView.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
//return super.onCreateOptionsMenu(menu);
|
||||
getMenuInflater().inflate(R.menu.toolbar_main, menu);
|
||||
|
||||
/*ThemeUtil.BaseTheme baseTheme = ThemeUtil.getTheme(mAppConfigUtil.mAppConfigBean.getAppThemeID());
|
||||
if (baseTheme == ThemeUtil.BaseTheme.DEFAULT) {
|
||||
menu.findItem(R.id.app_defaulttheme).setChecked(true);
|
||||
} else if (baseTheme == ThemeUtil.BaseTheme.SKY) {
|
||||
menu.findItem(R.id.app_skytheme).setChecked(true);
|
||||
} else if (baseTheme == ThemeUtil.BaseTheme.GOLDEN) {
|
||||
menu.findItem(R.id.app_goldentheme).setChecked(true);
|
||||
}*/
|
||||
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
public static void reloadSMS() {
|
||||
if (_mMainActivity != null) {
|
||||
Message msg = new Message();
|
||||
msg.arg1 = MSG_RELOADSMS;
|
||||
_mMainActivity.sendActivityMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int nItemId = item.getItemId();
|
||||
if (nItemId == R.id.app_ttsrule) {
|
||||
Intent i = new Intent(MainActivity.this, TTSPlayRuleActivity.class);
|
||||
i.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(i);
|
||||
} else if (nItemId == R.id.app_smsrule) {
|
||||
Intent i = new Intent(MainActivity.this, SMSReceiveRuleActivity.class);
|
||||
i.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(i);
|
||||
} else if (nItemId == R.id.app_appsettings) {
|
||||
Intent i = new Intent(MainActivity.this, AppSettingsActivity.class);
|
||||
i.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(i);
|
||||
} else if (nItemId == R.id.app_unittest) {
|
||||
Intent i = new Intent(MainActivity.this, UnitTestActivity.class);
|
||||
i.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(i);
|
||||
} else if (nItemId == R.id.app_crashtest) {
|
||||
for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
|
||||
getString(i);
|
||||
}
|
||||
} else if (nItemId == R.id.app_about) {
|
||||
Intent i = new Intent(MainActivity.this, AboutActivity.class);
|
||||
i.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(i);
|
||||
} else if (nItemId == R.id.app_smsrecycle) {
|
||||
Intent i = new Intent(MainActivity.this, SMSRecycleActivity.class);
|
||||
i.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(i);
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,228 @@
|
||||
package cc.winboll.studio.mymessagemanager.activitys;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import android.widget.Toolbar;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import cc.winboll.studio.libaes.views.AOHPCTCSeekBar;
|
||||
import cc.winboll.studio.mymessagemanager.R;
|
||||
import cc.winboll.studio.mymessagemanager.activitys.SMSActivity;
|
||||
import cc.winboll.studio.mymessagemanager.adapters.SMSArrayAdapter;
|
||||
import cc.winboll.studio.mymessagemanager.utils.AddressUtils;
|
||||
import cc.winboll.studio.mymessagemanager.utils.SMSUtil;
|
||||
import cc.winboll.studio.mymessagemanager.utils.ViewUtil;
|
||||
import cc.winboll.studio.mymessagemanager.views.SMSListViewForScrollView;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class SMSActivity extends BaseActivity {
|
||||
public static String TAG = "SMSActivity";
|
||||
|
||||
public static final String ACTION_NOTIFY_SMS_CHANGED = "cc.winboll.studio.mymessagemanager.activitys.SMSActivity.ACTION_NOTIFY_SMS_CHANGED";
|
||||
|
||||
public static final String EXTRA_PHONE = "Phone";
|
||||
final static int MSG_SET_FOCUS = 0;
|
||||
|
||||
SMSListViewForScrollView mlvSMS;
|
||||
Toolbar mToolbar;
|
||||
String mszPhoneTo;
|
||||
SMSArrayAdapter mSMSArrayAdapter;
|
||||
ScrollView mScrollView;
|
||||
EditText metSMSBody;
|
||||
SMSActivityBroadcastReceiver mSMSActivityBroadcastReceiver;
|
||||
Handler mSetFocusHandler;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_sms);
|
||||
|
||||
initView();
|
||||
mSetFocusHandler = new MyHandler(SMSActivity.this);
|
||||
scrollScrollView();
|
||||
|
||||
// 每隔一定时间设置输入框获得焦点
|
||||
//
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(1500);
|
||||
} catch (InterruptedException e) {}
|
||||
Message message = mSetFocusHandler.obtainMessage(MSG_SET_FOCUS);
|
||||
mSetFocusHandler.sendMessage(message);
|
||||
}
|
||||
}}.start();
|
||||
}
|
||||
|
||||
//
|
||||
// 设置输入框获得焦点的类
|
||||
//
|
||||
static class MyHandler extends Handler {
|
||||
WeakReference<SMSActivity> mActivity;
|
||||
MyHandler(SMSActivity activity) {
|
||||
mActivity = new WeakReference<SMSActivity>(activity);
|
||||
}
|
||||
public void handleMessage(Message msg) {
|
||||
SMSActivity theActivity = mActivity.get();
|
||||
switch (msg.what) {
|
||||
case MSG_SET_FOCUS:
|
||||
theActivity.metSMSBody.setFocusable(true);
|
||||
theActivity.metSMSBody.requestFocus();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
super.handleMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mSMSActivityBroadcastReceiver);
|
||||
}
|
||||
|
||||
void initView() {
|
||||
// 发送端空号码退出
|
||||
mszPhoneTo = getIntent().getStringExtra(EXTRA_PHONE);
|
||||
if (mszPhoneTo == null || mszPhoneTo.trim().equals("")) {
|
||||
finish();
|
||||
}
|
||||
|
||||
// 初始化标题栏
|
||||
mToolbar = findViewById(R.id.activitysmsASupportToolbar1);
|
||||
mToolbar.setSubtitle(getString(R.string.activity_name_smsinphone) + " < Phone : " + AddressUtils.getFormattedAddress(mszPhoneTo) + " >");
|
||||
setActionBar(mToolbar);
|
||||
|
||||
// 初始化滚动窗口
|
||||
mScrollView = findViewById(R.id.activitysmsinphoneScrollView1);
|
||||
|
||||
// 初始化发送消息框
|
||||
//Drawable drawableFrame = AppCompatResources.getDrawable(this, R.drawable.bg_frame);
|
||||
metSMSBody = findViewById(R.id.viewsmssendpart1EditText1);
|
||||
//metSMSBody.setBackground(drawableFrame);
|
||||
|
||||
// 初始化发送拉动控件
|
||||
final AOHPCTCSeekBar aOHPCTCSeekBar = findViewById(R.id.viewsmssendpart1AOHPCTCSeekBar1);
|
||||
aOHPCTCSeekBar.setThumb(getDrawable(R.drawable.ic_message));
|
||||
aOHPCTCSeekBar.setThumbOffset(20);
|
||||
aOHPCTCSeekBar.setOnOHPCListener(
|
||||
new AOHPCTCSeekBar.OnOHPCListener(){
|
||||
@Override
|
||||
public void onOHPCommit() {
|
||||
//Toast.makeText(getApplication(), "Send", Toast.LENGTH_SHORT).show();
|
||||
sendSMS();
|
||||
}
|
||||
});
|
||||
|
||||
// 初始化提示框
|
||||
TextView tvAOHPCTCSeekBarMSG = findViewById(R.id.viewsmssendpart1TextView1);
|
||||
tvAOHPCTCSeekBarMSG.setText(R.string.msg_100sendmsg);
|
||||
|
||||
mlvSMS = (SMSListViewForScrollView) findViewById(R.id.activitysmsinphoneListView1);
|
||||
|
||||
// 准备数据
|
||||
mSMSArrayAdapter = new SMSArrayAdapter(SMSActivity.this, mszPhoneTo);
|
||||
mlvSMS.setAdapter(mSMSArrayAdapter);
|
||||
|
||||
// 设置短信列表滚动到底部就取消已发送的通知消息
|
||||
//
|
||||
mlvSMS.setOnScrollListener(new AbsListView.OnScrollListener() {
|
||||
@Override
|
||||
public void onScrollStateChanged(AbsListView view, int scrollState) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
|
||||
if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) {
|
||||
// 滑动到了底部
|
||||
mSMSArrayAdapter.cancelMessageNotification();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mSMSActivityBroadcastReceiver = new SMSActivityBroadcastReceiver();
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(ACTION_NOTIFY_SMS_CHANGED);
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(mSMSActivityBroadcastReceiver, intentFilter);
|
||||
|
||||
/*SMSView mSMSView = findViewById(R.id.viewsmssendSMSView1);
|
||||
mSMSView.setSMSType(SMSView.SMSType.SEND);*/
|
||||
}
|
||||
|
||||
//
|
||||
// 更新信息列表
|
||||
//
|
||||
public void updateSMSView() {
|
||||
mSMSArrayAdapter.reLoadSMSList(SMSActivity.this, mszPhoneTo);
|
||||
mSMSArrayAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
//
|
||||
// 滚动消息文本框
|
||||
//
|
||||
void scrollScrollView() {
|
||||
|
||||
ViewUtil.scrollScrollView(mScrollView);
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// 发送短信
|
||||
//
|
||||
void sendSMS() {
|
||||
// 空消息不发送
|
||||
String szSMSBody = metSMSBody.getText().toString();
|
||||
if (szSMSBody.equals("")) {
|
||||
Toast.makeText(getApplication(), "没有消息内容可发送。", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
// 发送短信
|
||||
if (SMSUtil.sendMessageByInterface2(this, mszPhoneTo, szSMSBody)) {
|
||||
metSMSBody.setText("");
|
||||
new Handler().postDelayed(new Runnable(){
|
||||
@Override
|
||||
public void run() {
|
||||
updateSMSView();
|
||||
ViewUtil.scrollScrollView(mScrollView);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
class SMSActivityBroadcastReceiver extends BroadcastReceiver {
|
||||
|
||||
public SMSActivityBroadcastReceiver() {
|
||||
//LogUtils.d(TAG, "SMSActivityBroadcastReceiver()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
switch (intent.getAction()) {
|
||||
case ACTION_NOTIFY_SMS_CHANGED :
|
||||
//Toast.makeText(context, "ACTION_NOTIFY_SMS_CHANGED", Toast.LENGTH_SHORT).show();
|
||||
updateSMSView();
|
||||
ViewUtil.scrollScrollView(mScrollView);
|
||||
//LogUtils.d(TAG, "ACTION_NOTIFY_SMS_CHANGED");
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected value: " + intent.getAction());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user