Compare commits

..

80 Commits

Author SHA1 Message Date
ZhanGSKen
ecb67edec1 <appbase>APK 2.0.1 release Publish. 2025-02-25 16:50:23 +08:00
ZhanGSKen
3b30acfdec <appbase>APK 2.0.0 release Publish. 2025-02-25 16:48:35 +08:00
ZhanGSKen
c633e1663b 2025-02-25 16:44:26 +08:00
ZhanGSKen
40589ad879 1641 2025-02-25 16:41:51 +08:00
ZhanGSKen
0357fcf6b3 0225_1615 2025-02-25 16:15:54 +08:00
ZhanGSKen
c56fdaf14d <libappbase>Library Release 2.0.0 2025-02-25 16:11:50 +08:00
ZhanGSKen
9b1264234e 设置版本号 2025-02-25 16:02:55 +08:00
ZhanGSKen
d207a9ea9b 更正com.android.tools.build:gradle:7.2.1'对应的Gradle版本设置 2025-02-25 15:59:48 +08:00
ZhanGSKen
404239de23 更新编译配置已对应Android10开发,API级别29。Java 使用版本为 Java 8。 2025-02-25 15:51:54 +08:00
ZhanGSKen
c16b80ffae 地图标记保存完成 2025-02-25 06:43:50 +08:00
ZhanGSKen
ca16a8677a 添加地图定位功能 2025-02-24 15:20:51 +08:00
ZhanGSKen
bb089a4eb1 整合SDK成功 2025-02-24 08:06:04 +08:00
ZhanGSKen
0c00ace869 注释问题代码 2025-02-24 04:30:26 +08:00
ZhanGSKen
e06b642b70 添加demo 2025-02-24 03:51:22 +08:00
ZhanGSKen
5e107028de 绘图与缩略完成 2025-02-22 19:43:11 +08:00
ZhanGSKen
3bcfc5a5da 添加Positions项目 2025-02-22 01:50:07 +08:00
ZhanGSKen
e849e54960 <libappbase>Library Release 1.5.6 2025-02-21 11:03:53 +08:00
ZhanGSKen
8b2866419c <appbase>APK 1.5.6 release Publish. 2025-02-21 10:58:04 +08:00
ZhanGSKen
22a4a71203 更新bean基础类 2025-02-21 10:56:13 +08:00
ZhanGSKen
292f7c553f <libappbase>Library Release 1.5.5 2025-02-20 11:24:38 +08:00
ZhanGSKen
df9970c6df <appbase>APK 1.5.5 release Publish. 2025-02-20 11:24:23 +08:00
ZhanGSKen
0312ca50d2 添加绑定服务的APP的唤醒记录在部件的提示 2025-02-20 11:22:34 +08:00
ZhanGSKen
56187b588f <libappbase>Library Release 1.5.4 2025-02-19 19:57:16 +08:00
ZhanGSKen
d91372af52 <appbase>APK 1.5.4 release Publish. 2025-02-19 19:57:00 +08:00
ZhanGSKen
288725eca0 不同应用包服务绑定逻辑完成 2025-02-19 19:55:03 +08:00
ZhanGSKen
bd728b83a3 <libappbase>Library Release 1.5.3 2025-02-19 03:19:17 +08:00
ZhanGSKen
d4f9fc3561 <appbase>APK 1.5.3 release Publish. 2025-02-19 03:18:52 +08:00
ZhanGSKen
e7c614ebec 重构主应用架构 2025-02-19 03:17:49 +08:00
ZhanGSKen
c226a92ffe <libappbase>Library Release 1.5.2 2025-02-17 12:10:10 +08:00
ZhanGSKen
358e8b3522 <appbase>APK 1.5.2 release Publish. 2025-02-17 12:09:50 +08:00
ZhanGSKen
83ab4f9417 添加用磁贴启动小部件功能 2025-02-17 12:07:52 +08:00
ZhanGSKen
26cdacf1c6 BugFix 2025-02-17 11:44:15 +08:00
ZhanGSKen
6378433424 sos报告部件重构 2025-02-17 11:13:09 +08:00
ZhanGSKen
7b05d613e4 完成小部件分页功能 2025-02-16 20:54:33 +08:00
ZhanGSKen
691f9bbd1c 基本救援设施铺设完成 2025-02-15 21:37:33 +08:00
ZhanGSKen
7a8d3329d4 完成摘要事件监控小部件 2025-02-15 19:53:24 +08:00
ZhanGSKen
bbac0c7306 添加WinBoll类 2025-02-15 12:46:23 +08:00
ZhanGSKen
8d2b325172 实现磁贴启动服务功能 2025-02-15 11:30:20 +08:00
ZhanGSKen
825dfb944e AssistantService 启动成功 2025-02-14 21:18:43 +08:00
ZhanGSKen
419244b12a 放弃使用aidl 2025-02-14 07:30:47 +08:00
ZhanGSKen
39fda1b5da Use android studio add aidl file. 2025-02-14 07:04:21 +08:00
ZhanGSKen
464f2da89f test 2025-02-14 06:25:35 +08:00
ZhanGSKen
4f37b6f0e3 test 2025-02-14 06:08:50 +08:00
ZhanGSKen
f91cd0c9c3 <appbase>Start New Stage Version. 2025-02-14 06:02:07 +08:00
ZhanGSKen
d09f0783a4 <appbase>Start New Stage Version. 2025-02-14 06:01:54 +08:00
ZhanGSKen
accca716d4 Test aidl 2025-02-14 06:01:16 +08:00
ZhanGSKen
dfd09eb647 <libappbase>Library Release 1.5.1 2025-02-14 03:01:05 +08:00
ZhanGSKen
79547adcb3 <appbase>APK 1.5.1 release Publish. 2025-02-14 03:00:46 +08:00
ZhanGSKen
be39eef6e7 添加调试信息 2025-02-14 02:59:52 +08:00
ZhanGSKen
50490096b4 SOS广播消息发送与接收完成 2025-02-13 21:31:33 +08:00
ZhanGSKen
3dd4c84602 添加磁贴模块 2025-02-13 20:42:58 +08:00
ZhanGSKen
311bc8e339 <libappbase>Library Release 1.5.0 2025-02-13 06:53:58 +08:00
ZhanGSKen
6467bcd675 <appbase>APK 1.5.0 release Publish. 2025-02-13 06:53:34 +08:00
ZhanGSKen
206c804b4d SOS 服务架构基本完成 2025-02-13 06:51:41 +08:00
ZhanGSKen
7a4df0444e 添加SOS广播接收 2025-02-13 03:46:55 +08:00
ZhanGSKen
3c827a56cf <libappbase>Library Release 1.4.1 2025-02-12 18:04:10 +08:00
ZhanGSKen
36af7947e8 <appbase>APK 1.4.1 release Publish. 2025-02-12 18:03:55 +08:00
ZhanGSKen
805edcf9c4 添加吐司控件 2025-02-12 16:43:57 +08:00
ZhanGSKen
11005e3356 <libappbase>Library Release 1.4.0 2025-02-12 15:01:51 +08:00
ZhanGSKen
75361b2313 <appbase>APK 1.4.0 release Publish. 2025-02-12 15:01:33 +08:00
ZhanGSKen
1d29ce81e8 编译测试 2025-02-12 14:59:38 +08:00
ZhanGSKen
0297e81090 精简配置 2025-02-12 14:59:00 +08:00
ZhanGSKen
df7203e985 更新类库 2025-02-12 14:57:50 +08:00
ZhanGSKen
8c4e8b8e23 <appbase>Start New Stage Version. 2025-02-12 14:14:36 +08:00
ZhanGSKen
d9c02f55e3 更新版本号 2025-02-12 14:14:15 +08:00
ZhanGSKen
a9cb6b471b <appbase>Start New Stage Version. 2025-02-12 14:10:53 +08:00
ZhanGSKen
e694063867 <appbase>Start New Stage Version. 2025-02-12 14:09:34 +08:00
ZhanGSKen
0ee13986dc <appbase>Start New Stage Version. 2025-02-12 14:09:05 +08:00
ZhanGSKen
3239778922 更新测试APP风格配置 2025-02-12 14:06:02 +08:00
ZhanGSKen
13510f45cf 应用风格架构基本完成 2025-02-12 13:28:58 +08:00
ZhanGSKen
49d300dd33 添加信号处理中心 2025-02-12 11:28:39 +08:00
ZhanGSKen
c42f677d48 <libappbase>Library Release 1.3.0 2025-02-11 13:11:35 +08:00
ZhanGSKen
9052a3924b <appbase>APK 1.3.0 release Publish. 2025-02-11 13:11:17 +08:00
ZhanGSKen
9642ad1966 精简代码 2025-02-11 13:09:33 +08:00
ZhanGSKen
6686da0e8f 调色架构1 2025-02-11 12:42:07 +08:00
ZhanGSKen
9e7aff09d1 <libappbase>Library Release 1.2.4 2025-02-11 00:32:09 +08:00
ZhanGSKen
494b2b7fbc <appbase>APK 1.2.4 release Publish. 2025-02-11 00:31:50 +08:00
ZhanGSKen
b1f9b74e28 源码重构整理,精简代码。 2025-02-11 00:27:54 +08:00
ZhanGSKen
32287e17c0 注释冗余代码 2025-02-09 19:05:27 +08:00
ZhanGSKen
8a0605c12e <libappbase>Library Release 1.2.3 2025-02-09 15:09:48 +08:00
304 changed files with 44299 additions and 360 deletions

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

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

1
.idea/.name generated Normal file
View File

@@ -0,0 +1 @@
appbase

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

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

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

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

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

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

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

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

View File

@@ -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 {

View File

@@ -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:50:23 HKT 2025
stageCount=2
libraryProject=libappbase
baseVersion=1.2
publishVersion=1.2.3
baseVersion=2.0
publishVersion=2.0.1
buildCount=0
baseBetaVersion=1.2.4
baseBetaVersion=2.0.2

View File

@@ -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>

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,68 @@
package cc.winboll.studio.appbase.beans;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/13 07:06:13
*/
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException;
public class MainServiceBean extends BaseBean {
public static final String TAG = "MainServiceBean";
boolean isEnable;
public MainServiceBean() {
this.isEnable = false;
}
public void setIsEnable(boolean isEnable) {
this.isEnable = isEnable;
}
public boolean isEnable() {
return isEnable;
}
@Override
public String getName() {
return MainServiceBean.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
MainServiceBean bean = this;
jsonWriter.name("isEnable").value(bean.isEnable());
}
@Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
if (name.equals("isEnable")) {
setIsEnable(jsonReader.nextBoolean());
} else {
return false;
}
}
return true;
}
@Override
public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException {
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String name = jsonReader.nextName();
if (!initObjectsFromJsonReader(jsonReader, name)) {
jsonReader.skipValue();
}
}
// 结束 JSON 对象
jsonReader.endObject();
return this;
}
}

View File

@@ -0,0 +1,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;
}
}

View File

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

View File

@@ -0,0 +1,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);
}
}

View File

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

View File

@@ -0,0 +1,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));
}
}

View File

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

View File

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

View File

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

View 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>

View 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>

View File

@@ -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>

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#FFFFFFFF">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/infoTextView"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="⇦"
android:id="@+id/widget_button_pre"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="⇨"
android:id="@+id/widget_button_next"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="@+id/sosReportTextView"
android:layout_weight="1.0"/>
</LinearLayout>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="200dp"
android:minHeight="100dp"
android:updatePeriodMillis="1000"
android:initialLayout="@layout/widget_sos">
</appwidget-provider>

View File

@@ -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) {

View File

@@ -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

View File

@@ -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

View File

@@ -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'])
}

View File

@@ -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:50:23 HKT 2025
stageCount=2
libraryProject=libappbase
baseVersion=1.2
publishVersion=1.2.3
baseVersion=2.0
publishVersion=2.0.1
buildCount=0
baseBetaVersion=1.2.4
baseBetaVersion=2.0.2

View File

@@ -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>

View File

@@ -0,0 +1,28 @@
package cc.winboll.studio.libappbase;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/15 20:05:03
* @Describe AppUtils
*/
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
public class AppUtils {
public static final String TAG = "AppUtils";
public static String getAppNameByPackageName(Context context, String packageName) {
PackageManager packageManager = context.getPackageManager();
try {
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName, 0);
return (String) packageManager.getApplicationLabel(applicationInfo);
} catch (NameNotFoundException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
return "";
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,87 @@
package cc.winboll.studio.libappbase.bean;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/17 00:29:29
* @Describe APPSOSReportBean
*/
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException;
import java.io.Serializable;
public class APPSOSBean extends BaseBean {
public static final String TAG = "APPSOSBean";
protected String sosPackage;
protected String sosClassName;
public APPSOSBean() {
this.sosPackage = "";
this.sosClassName = "";
}
public APPSOSBean(String sosPackage, String sosClassName) {
this.sosPackage = sosPackage;
this.sosClassName = sosClassName;
}
public void setSosPackage(String sosPackage) {
this.sosPackage = sosPackage;
}
public String getSosPackage() {
return sosPackage;
}
public void setSosClassName(String sosClassName) {
this.sosClassName = sosClassName;
}
public String getSosClassName() {
return sosClassName;
}
@Override
public String getName() {
return APPSOSBean.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
jsonWriter.name("sosPackage").value(getSosPackage());
jsonWriter.name("sosClassName").value(getSosClassName());
}
@Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
if (name.equals("sosPackage")) {
setSosPackage(jsonReader.nextString());
} else if (name.equals("sosClassName")) {
setSosClassName(jsonReader.nextString());
} else {
return false;
}
}
return true;
}
@Override
public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException {
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String name = jsonReader.nextName();
if (!initObjectsFromJsonReader(jsonReader, name)) {
jsonReader.skipValue();
}
}
// 结束 JSON 对象
jsonReader.endObject();
return this;
}
}

View File

@@ -0,0 +1,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;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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

View 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代表右边的阴影宽度。其实也就是相对应的offsetsolid中的颜色是阴影的颜色也可以设置角度等等 -->
<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>

View 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>

View File

@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#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>

View 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>

View File

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

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#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>

View 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>

View File

@@ -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>

View 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>

View 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>

View 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>

View 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>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="40dp"
android:layout_height="40dp">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:id="@+id/ivapp"/>
</LinearLayout>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="@android:style/Theme.Material.Light">
</style>
</resources>

View 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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

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

BIN
positions/.DS_Store vendored Normal file

Binary file not shown.

39
positions/README.md Normal file
View File

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

View File

84
positions/build.gradle Normal file
View File

@@ -0,0 +1,84 @@
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']
}
Properties properties = new Properties()
File localFile = project.rootProject.file('local.properties')
if (localFile.exists()) {
InputStream inputStream = localFile.newDataInputStream()
properties.load(inputStream)
}
def mapsdkkey = properties.getProperty('mapsdk.key', "")
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "cc.winboll.studio.positions"
minSdkVersion 26
targetSdkVersion 29
versionCode 1
// versionName 更新后需要手动设置
// 项目模块目录的 build.gradle 文件的 stageCount=0
// Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
versionName "1.0"
if(true) {
versionName = genVersionName("${versionName}")
}
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
manifestPlaceholders = ["TencentMapSDK_KEY": mapsdkkey]
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
// 定位服务
implementation 'com.google.android.gms:play-services-location:20.0.0'
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.viewpager:viewpager:1.0.0'
implementation 'androidx.fragment:fragment:1.0.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'pub.devrel:easypermissions:2.0.1'
// 地图
implementation 'com.tencent.map:tencent-map-vector-sdk:6.2.1.250120.3f971009.140342819'
// 基础库
implementation 'com.tencent.openmap:foundation:0.5.6.9be4e02'
implementation 'com.tencent.map:sdk-utilities:1.0.9'
implementation 'com.tencent.map.geolocation:TencentLocationSdk-openplatform:7.5.4.3'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'io.github.medyo:android-about-page:2.0.0'
implementation 'com.github.getActivity:ToastUtils:10.5'
implementation 'cc.winboll.studio:libapputils:9.3.2'
implementation 'cc.winboll.studio:libappbase:1.5.6'
}

View File

@@ -0,0 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Tue Feb 25 05:04:52 GMT 2025
stageCount=0
libraryProject=
baseVersion=1.0
publishVersion=1.0.0
buildCount=184
baseBetaVersion=1.0.1

41
positions/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,41 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# 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 *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}
-dontwarn com.tencent.tmsqmsp.**
-keep public class com.tencent.tmsqmsp.**{*;}
-dontwarn com.tencent.tmsbeacon.**
-keep public class com.tencent.tmsbeacon.**{*;}
-dontwarn com.tencent.map.**
-keep public class com.tencent.map.** {*;}
-dontwarn com.tencent.mapsdk.**
-keep public class com.tencent.mapsdk.** {*;}
-dontwarn com.tencent.tencentmap.**
-keep public class com.tencent.tencentmap.** {*;}
-dontwarn com.tencent.lbssearch.**
-keep public class com.tencent.lbssearch.** {*;}

BIN
positions/src/.DS_Store vendored Normal file

Binary file not shown.

View File

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

View File

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

BIN
positions/src/main/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,741 @@
<?xml version='1.0' encoding='utf-8'?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="cc.winboll.studio.positions">
<!-- 拥有完全的网络访问权限 -->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- 查看网络连接 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!-- 查看WLAN连接 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!-- 修改或删除您共享存储空间中的内容 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 读取您共享存储空间中的内容 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- 读取手机状态和身份 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<!-- 只能在前台获取精确的位置信息 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- 只能在前台获取大概位置(基于网络) -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!-- 连接WLAN网络和断开连接 -->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<!-- 更改网络连接性 -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<application
android:name=".App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/MyAppTheme"
android:usesCleartextTraffic="true"
android:requestLegacyExternalStorage="true"
tools:ignore="AllowBackup,GoogleAppIndexingWarning"
tools:targetApi="q">
<activity android:name=".MainSimpleActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".MainActivity2">
</activity>
<activity android:name="com.tencent.map.vector.demo.DemoMainActivity">
</activity>
<activity
android:name="com.tencent.map.vector.demo.basic.MapViewActivity"
android:description="@string/demo_description_show_map"
android:label="@string/demo_label_show_map">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_basic"/>
</activity>
<activity
android:name=".basic.SetMapTypeActivity"
android:description="@string/demo_description_map_type"
android:label="@string/demo_label_map_type">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_basic"/>
</activity>
<activity
android:name=".basic.MapRenderLayerActivity"
android:description="@string/demo_description_show_mapRenderLayer"
android:label="@string/demo_label_show_mapRenderLayer">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_basic"/>
</activity>
<activity
android:name=".location.LocationLayerActivity"
android:description="@string/demo_description_show_location"
android:label="@string/demo_label_show_location">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_location"/>
</activity>
<activity
android:name=".location.LocationPointActivity"
android:description="@string/demo_description_change_location_style"
android:label="@string/demo_label_change_location_style">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_location"/>
</activity>
<activity
android:name=".basic.IndoorMapActivity"
android:description="@string/demo_description_indoor_map"
android:label="@string/demo_label_indoor_map">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_basic"/>
</activity>
<activity
android:name=".basic.OverseaMapActivity"
android:description="@string/demo_description_oversea"
android:label="@string/demo_label_oversea">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_basic"/>
</activity>
<activity
android:name=".basic.MapStyleDemoActivity"
android:description="@string/demo_description_style"
android:label="@string/demo_label_style">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_basic"/>
</activity>
<activity
android:name=".basic.UiSettingsActivity"
android:description="@string/demo_description_ui"
android:label="@string/demo_label_ui">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_interactive"/>
</activity>
<activity
android:name=".gesture.GestureSettingsActivity"
android:description="@string/demo_description_gesture"
android:label="@string/demo_label_gesture">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_interactive"/>
</activity>
<activity
android:name=".transaction.ZoomMapActivity"
android:description="@string/demo_description_modify_zoom"
android:label="@string/demo_label_modify_zoom">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_interactive"/>
</activity>
<activity
android:name=".camera.MapCameraCenterActivity"
android:description="@string/demo_description_modify_map_center"
android:label="@string/demo_label_modify_map_center">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_interactive"/>
</activity>
<activity
android:name=".camera.MapBoundActivity"
android:description="@string/demo_description_map_bound"
android:label="@string/demo_label_map_bound">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_interactive"/>
</activity>
<activity
android:name=".poi.PoiClickActivity"
android:description="@string/demo_description_click_poi"
android:label="@string/demo_label_click_poi">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_interactive"/>
</activity>
<activity
android:name=".transaction.AnimateCameraActivity"
android:description="@string/demo_description_animate_camera"
android:label="@string/demo_label_animate_camera">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_interactive"/>
</activity>
<activity
android:name=".camera.MapAnchorZoomActivity"
android:description="@string/demo_description_map_camera_anchor"
android:label="@string/demo_label_map_camera_anchor">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_interactive"/>
</activity>
<activity
android:name=".transaction.ScollMapActivity"
android:description="@string/demo_description_camera_translation"
android:label="@string/demo_label_camera_translation">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_transformation"/>
</activity>
<activity
android:name=".transaction.RotateMapActivity"
android:description="@string/demo_description_camera_rotation"
android:label="@string/demo_label_camera_rotation">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_transformation"/>
</activity>
<activity
android:name=".transaction.ZoomCalulateActivity"
android:description="@string/demo_description_camera_include_points"
android:label="@string/demo_label_camera_include_points">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_transformation"/>
</activity>
<activity
android:name=".transaction.MoveCameraActivity"
android:description="@string/demo_description_camera_change_listener"
android:label="@string/demo_label_camera_change_listener">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_transformation"/>
</activity>
<activity
android:name=".gesture.MapListenActivity"
android:description="@string/demo_description_map_click_listener"
android:label="@string/demo_label_map_click_listener">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_transformation"/>
</activity>
<activity
android:name=".gesture.MapLongClickActivity"
android:description="@string/demo_description_map_long_click_listener"
android:label="@string/demo_label_map_long_click_listener">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_transformation"/>
</activity>
<activity
android:name=".marker.SimpleMarkerActivity"
android:description="@string/demo_description_simple_marker"
android:label="@string/demo_label_simple_marker">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_marker"/>
</activity>
<activity
android:name=".marker.MarkerCollisions"
android:description="@string/demo_description_collisions_marker"
android:label="@string/demo_label_collisions_marker">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_marker"/>
</activity>
<activity
android:name=".marker.MarkerOptionsActivity"
android:description="@string/demo_description_marker_options"
android:label="@string/demo_label_marker_options">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_marker"/>
</activity>
<activity
android:name=".marker.MarkerClickActivity"
android:description="@string/demo_description_marker_click_listener"
android:label="@string/demo_label_marker_click_listener">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_marker"/>
</activity>
<activity
android:name=".marker.MarkerDragActivity"
android:description="@string/demo_description_marker_drag_listener"
android:label="@string/demo_label_marker_drag_listener">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_marker"/>
</activity>
<activity
android:name=".marker.MarkerInfoWindowActivity"
android:description="@string/demo_description_infowindow_click_listener"
android:label="@string/demo_label_infowindow_click_listener">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_marker"/>
</activity>
<activity
android:name=".marker.MarkerClusterActivity"
android:description="@string/demo_description_marker_cluster"
android:label="@string/demo_label_marker_cluster">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_marker"/>
</activity>
<activity
android:name=".marker.MarkerAnimation"
android:description="@string/demo_description_marker_animation"
android:label="@string/demo_label_marker_animation">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_marker"/>
</activity>
<activity
android:name=".heatoverlay.DrawHeatOverlayActivity"
android:description="@string/demo_description_heat_map"
android:label="@string/demo_label_heat_map">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_draw"/>
</activity>
<activity
android:name=".polygon.TileOverlayActivity"
android:description="@string/demo_description_tileOverlay_map"
android:label="@string/demo_label_tileOverlay_map">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_draw"/>
</activity>
<activity
android:name=".polyline.DrawLineActivity"
android:description="@string/demo_description_polyline"
android:label="@string/demo_label_polyline">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_draw"/>
</activity>
<activity
android:name=".polyline.MutablePolylineActivity"
android:description="@string/demo_description_mutable_polyline"
android:label="@string/demo_label_mutable_polyline">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_draw"/>
</activity>
<activity
android:name=".polygon.DrawPolygonActivity"
android:description="@string/demo_description_polygon"
android:label="@string/demo_label_polygon">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_draw"/>
</activity>
<activity
android:name=".circle.DrawCircleActivity"
android:description="@string/demo_description_circle"
android:label="@string/demo_label_circle">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_draw"/>
</activity>
<activity
android:name=".circle.ArcActivity"
android:description="@string/demo_description_arc"
android:label="@string/demo_label_arc">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_draw"/>
</activity>
<activity
android:name=".search.WalkingRouteActivity"
android:description="@string/demo_description_walking_plan"
android:label="@string/demo_label_walking_plan">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_route_plan"/>
</activity>
<activity
android:name=".search.DrivingRouteActivity"
android:description="@string/demo_description_driving_plan"
android:label="@string/demo_label_driving_plan">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_route_plan"/>
</activity>
<activity
android:name=".search.TransitRouteActivity"
android:description="@string/demo_description_transit_plan"
android:label="@string/demo_label_transit_plan">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_route_plan"/>
</activity>
<activity
android:name=".search.TruckingRouteActivity"
android:description="@string/demo_description_truking_plan"
android:label="@string/demo_label_truking_plan">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_route_plan"/>
</activity>
<activity
android:name=".search.SearchBasicActivity"
android:description="@string/demo_description_basic_search"
android:label="@string/demo_label_basic_search">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_search"/>
</activity>
<activity
android:name=".search.GeoCoderActivity"
android:description="@string/demo_description_geocoder"
android:label="@string/demo_label_geocoder">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_search"/>
</activity>
<activity
android:name=".search.DistrictActivity"
android:description="@string/demo_description_district"
android:label="@string/demo_label_district">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_search"/>
</activity>
<activity
android:name=".polyline.LineTextActivity"
android:description="@string/demo_description_line_text"
android:label="@string/demo_label_line_text">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_special"/>
</activity>
<activity
android:name=".utils.BitMapActivity"
android:description="@string/demo_description_bitmap"
android:enabled="false"
android:label="@string/demo_label_bitmap">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_tools"/>
</activity>
<activity
android:name=".utils.SnapshotActivity"
android:description="@string/demo_description_map_snapshot"
android:label="@string/demo_label_map_snapshot">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_tools"/>
</activity>
<activity
android:name=".utils.CoordinateActivity"
android:description="@string/demo_description_projection"
android:label="@string/demo_label_projection">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_tools"/>
</activity>
<activity android:name=".basic.SupportMapFragmentActivity"/>
<activity
android:name=".marker.CustomRenderActivity"
android:description="@string/demo_description_opengl"
android:label="@string/demo_label_opengl">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_draw"/>
</activity>
<activity
android:name=".marker.GroundOverlayActivity"
android:description="@string/demo_description_overlay"
android:label="@string/demo_label_ground_overlay">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_draw"/>
</activity>
<activity
android:name=".marker.AoiLayerActivity"
android:description="@string/demo_description_aoi"
android:label="@string/demo_label_aoi">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_draw"/>
</activity>
<activity
android:name=".heatoverlay.VectorHeatMapActivity"
android:description="@string/demo_description_vectorheatmap"
android:label="@string/demo_label_vectorheatmap">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_draw"/>
</activity>
<activity
android:name=".heatoverlay.ArcLineLayerActivity"
android:description="@string/demo_description_arcline"
android:label="@string/demo_label_arcline_map">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_draw"/>
</activity>
<activity
android:name=".heatoverlay.HeatMapVectorOverlayActivity"
android:description="@string/demo_description_3dheatmap"
android:label="@string/demo_label_3d_heat_map">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_draw"/>
</activity>
<activity
android:name=".heatoverlay.AggregationOverlayActivity"
android:description="@string/demo_description_AggregationOverlay"
android:label="@string/demo_label_3d_aggregationOverlay_map">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_draw"/>
</activity>
<activity
android:name=".heatoverlay.ScatterPlotOverlayActivity"
android:description="@string/demo_description_ScatterPlotOverlay"
android:label="@string/demo_label_3d_scatterplotoverlay_map">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_draw"/>
</activity>
<activity
android:name=".heatoverlay.TrailOverlayActivity"
android:description="@string/demo_description_TrailOverlay"
android:label="@string/demo_label_3d_railoverltay_map">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_draw"/>
</activity>
<activity
android:name=".heatoverlay.GLModelActivity"
android:description="@string/demo_description_glModel"
android:label="@string/demo_label_glModel">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_draw"/>
</activity>
<activity
android:name=".basic.RecyclerListActivity"
android:description="@string/demo_description_recycler_map"
android:label="@string/demo_label_recycler_map">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_basic"/>
</activity>
<activity
android:name=".smooth.SmoothMoveActivity"
android:description="@string/demo_description_smooth_move"
android:label="@string/demo_label_smooth_move">
<meta-data
android:name="@string/demo_type"
android:value="@string/demo_type_draw"/>
</activity>
<meta-data
android:name="TencentMapSDK"
android:value="SCYBZ-EC5Y4-XMHUI-FX2PU-ZYMMS-IBB7P"/>
<activity android:name="cc.winboll.studio.positions.activities.TestMapViewActivity"/>
</application>
</manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@@ -0,0 +1,50 @@
31.23037 121.4737 40.07733 116.60039 45.0
30.5702 104.06476 40.07733 116.60039 45.0
22.54286 114.05956 40.07733 116.60039 45.0
23.12908 113.26436 40.07733 116.60039 45.0
29.56471 106.55073 40.07733 116.60039 45.0
30.27415 120.15515 40.07733 116.60039 45.0
24.87966 102.83322 40.07733 116.60039 45.0
34.32932 108.70929 40.07733 116.60039 45.0
45.80216 126.5358 40.07733 116.60039 45.0
28.22778 112.93886 40.07733 116.60039 45.0
18.25248 109.51209 40.07733 116.60039 45.0
43.82663 87.61688 40.07733 116.60039 45.0
30.59276 114.30525 40.07733 116.60039 45.0
22.27534 114.16546 40.07733 116.60039 45.0
26.64702 106.63024 40.07733 116.60039 45.0
24.47951 118.08948 40.07733 116.60039 45.0
20.04422 110.19989 40.07733 116.60039 45.0
28.68202 115.85794 40.07733 116.60039 45.0
43.81602 125.32357 40.07733 116.60039 45.0
36.06623 120.38299 40.07733 116.60039 45.0
22.81673 108.3669 40.07733 116.60039 45.0
26.07421 119.29647 40.07733 116.60039 45.0
38.91369 121.61476 40.07733 116.60039 45.0
41.80563 123.43236 40.07733 116.60039 45.0
32.05838 118.79647 40.07733 116.60039 45.0
36.06138 103.83417 40.07733 116.60039 45.0
38.48644 106.23248 40.07733 116.60039 45.0
27.99492 120.69939 40.07733 116.60039 45.0
37.46353 121.44801 40.07733 116.60039 45.0
22.27073 113.57668 40.07733 116.60039 45.0
29.87386 121.55027 40.07733 116.60039 45.0
31.82057 117.22901 40.07733 116.60039 45.0
34.34127 108.93984 40.07733 116.60039 45.0
49.21163 119.76584 40.07733 116.60039 45.0
40.84149 111.75199 40.07733 116.60039 45.0
37.87059 112.55067 40.07733 116.60039 45.0
46.58758 125.10307 40.07733 116.60039 45.0
25.27361 110.29002 40.07733 116.60039 45.0
31.46751 104.6796 40.07733 116.60039 45.0
24.87389 118.67587 40.07733 116.60039 45.0
30.69186 111.28642 40.07733 116.60039 45.0
23.54972 116.37271 40.07733 116.60039 45.0
40.65781 109.84021 40.07733 116.60039 45.0
37.51348 122.12171 40.07733 116.60039 45.0
31.49099 120.31237 40.07733 116.60039 45.0
22.18684 113.54294 40.07733 116.60039 45.0
34.74725 113.62493 40.07733 116.60039 45.0
34.61812 112.45361 40.07733 116.60039 45.0
36.50204 102.104287 40.07733 116.60039 45.0
24.954708 121.48068 40.07733 116.60039 45.0

View File

@@ -0,0 +1,10 @@
39.90469 116.40717 29.56471 106.55073 30.0
39.90469 116.40717 39.53775 116.68376 30.0
39.90469 116.40717 31.23037 121.4737 30.0
39.90469 116.40717 23.12908 113.26436 30.0
39.90469 116.40717 28.22778 112.93886 30.0
29.56471 106.55073 39.90469 116.40717 60.0
18.25248 109.51209 39.90469 116.40717 60.0
31.23037 121.4737 39.90469 116.40717 60.0
23.12908 113.26436 39.90469 116.40717 60.0
39.53775 116.68376 39.90469 116.40717 60.0

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