第一次提交

This commit is contained in:
xuhuixiang
2026-03-21 10:50:34 +08:00
commit b68b389cd4
91 changed files with 3527 additions and 0 deletions

1
app/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

71
app/build.gradle Normal file
View File

@@ -0,0 +1,71 @@
plugins {
id 'com.android.application'
}
ext {
miraclegardenlibVersion = '1.0'
}
android {
namespace 'com.miraclegarden.smsmessage'
compileSdk 32
defaultConfig {
applicationId "com.miraclegarden.smsmessage"
minSdk 24
targetSdk 32
versionCode 11
versionName "2.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
signingConfigs {
debug {
storeFile file('justlet.jks')
storePassword "123456"
keyAlias 'key0'
keyPassword "123456"
}
release {
storeFile file('justlet.jks')
storePassword "123456"
keyAlias 'key0'
keyPassword "123456"
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
lintOptions {
abortOnError false
}
buildFeatures {
viewBinding true
}
}
dependencies {
implementation "com.github.yingliangwei:MiracleGardenLib:1.0"
implementation 'androidx.databinding:viewbinding:7.3.0'
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.10'
implementation 'androidx.appcompat:appcompat:1.5.0'
implementation 'com.google.android.material:material:1.6.1'
implementation 'com.github.yingliangwei:MiracleGardenLib:1.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
api 'com.google.code.gson:gson:2.9.0'
}

BIN
app/justlet.jks Normal file

Binary file not shown.

21
app/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# 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

BIN
app/release/app-release.apk Normal file

Binary file not shown.

View File

@@ -0,0 +1,20 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.miraclegarden.smsmessage",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 11,
"versionName": "2.1",
"outputFile": "app-release.apk"
}
],
"elementType": "File"
}

View File

@@ -0,0 +1,26 @@
package com.miraclegarden.smsmessage;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.miraclegarden.smsmessage", appContext.getPackageName());
}
}

View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- <uses-permission android:name="android.permission.READ_SMS" />-->
<uses-permission android:name="android.permission.INTERNET" />
<!-- <uses-permission android:name="android.permission.RECEIVE_SMS" />&lt;!&ndash; 接收短信权限 &ndash;&gt;-->
<!-- 添加接收系统启动消息(用于开机启动)权限 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<!-- 下面这个也必须加,否则 Android 11+ 拿不到列表 -->
<queries>
<intent>
<action android:name="android.intent.action.MAIN" />
</intent>
<intent>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent>
</queries>
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/app_logo"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:preserveLegacyExternalStorage="true"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/app_logo"
android:supportsRtl="true"
android:theme="@style/Theme.SmsMessage"
tools:targetApi="31">
<activity
android:name=".Activity.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".Activity.NotificationActivity"
android:theme="@style/Theme.SmsMessage1"
android:exported="true" />
<activity
android:name=".Activity.SettingActivity"
android:theme="@style/Theme.SmsMessage1"
android:exported="true" />
<activity
android:name=".Activity.AppListActivity"
android:theme="@style/Theme.SmsMessage1"
android:exported="true" />
<!--通知栏获取短信-->
<service
android:name=".service.NotificationService"
android:exported="true"
android:label="通知监控"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
android:priority="1000">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
</application>
</manifest>

25
app/src/main/AppInfo.java Normal file
View File

@@ -0,0 +1,25 @@
/**
* **********************
*
* @Author bug machine
* 创建时间: 2026/3/20 15:29
* 用途
* **********************
*/
import android.graphics.drawable.Drawable;
public class AppInfo {
private String appName; // 应用名
private String packageName;// 包名
private Drawable icon; // 图标
public AppInfo(String appName, String packageName, Drawable icon) {
this.appName = appName;
this.packageName = packageName;
this.icon = icon;
}
public String getAppName() { return appName; }
public String getPackageName() { return packageName; }
public Drawable getIcon() { return icon; }
}

View File

@@ -0,0 +1,99 @@
package com.miraclegarden.smsmessage;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.miraclegarden.smsmessage.databinding.DialogActionConfirmBinding;
/**
* 通用弹窗
*/
public class ActionConfirmDialog extends Dialog {
private final Context context;
OnToActionListener onToActionListener;
AppInfo appInfo;
int index;
DialogActionConfirmBinding actionConfirmBinding;
public interface OnToActionListener {
void toSumbit(AppInfo appInfo);
void toCancel();
}
public void setOnToActionListener(OnToActionListener onNextCallListener) {
this.onToActionListener = onNextCallListener;
}
public ActionConfirmDialog(Context context, AppInfo appInfo) {
super(context, R.style.MaterialDesignDialog);
this.context = context;
this.appInfo = appInfo;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
actionConfirmBinding = DialogActionConfirmBinding.inflate(getLayoutInflater());
setContentView(actionConfirmBinding.getRoot());
actionConfirmBinding.ivIcon.setImageDrawable(appInfo.getIcon());
actionConfirmBinding.tvAppname.setText(appInfo.getAppName());
actionConfirmBinding.tvPackage.setText(appInfo.getPackageName());
if(!TextUtils.isEmpty(appInfo.getName())){
actionConfirmBinding.tvName.setText(appInfo.getName());
}
if(!TextUtils.isEmpty(appInfo.getCode())){
actionConfirmBinding.tvCode.setText(appInfo.getCode());
}
if(!TextUtils.isEmpty(appInfo.getRemark())){
actionConfirmBinding.tvRemark.setText(appInfo.getRemark());
}
actionConfirmBinding.sumbitTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(TextUtils.isEmpty(actionConfirmBinding.tvName.getText().toString().trim())){
Toast.makeText(context,"名称不能为空",Toast.LENGTH_SHORT).show();
return;
}
if(TextUtils.isEmpty(actionConfirmBinding.tvCode.getText().toString().trim())){
Toast.makeText(context,"Code不能为空",Toast.LENGTH_SHORT).show();
return;
}
appInfo.setName(actionConfirmBinding.tvName.getText().toString().trim());
appInfo.setCode(actionConfirmBinding.tvCode.getText().toString().trim());
appInfo.setRemark(actionConfirmBinding.tvRemark.getText().toString().trim());
if(onToActionListener!=null){
dismiss();
onToActionListener.toSumbit(appInfo);
}
}
});
actionConfirmBinding.cancelTv.setOnClickListener(view -> {
dismiss();
if(onToActionListener!=null){
onToActionListener.toCancel();
}
});
Window window = getWindow();
WindowManager.LayoutParams wlp = window.getAttributes();
wlp.gravity = Gravity.CENTER;
wlp.width = WindowManager.LayoutParams.WRAP_CONTENT;
wlp.height = WindowManager.LayoutParams.WRAP_CONTENT;
window.setAttributes(wlp);
}
}

View File

@@ -0,0 +1,125 @@
package com.miraclegarden.smsmessage.Activity;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.miraclegarden.library.app.MiracleGardenActivity;
import com.miraclegarden.smsmessage.ActionConfirmDialog;
import com.miraclegarden.smsmessage.App;
import com.miraclegarden.smsmessage.AppInfo;
import com.miraclegarden.smsmessage.AppListUtil;
import com.miraclegarden.smsmessage.R;
import com.miraclegarden.smsmessage.comm.CommonAdapter;
import com.miraclegarden.smsmessage.comm.ViewHolder;
import com.miraclegarden.smsmessage.databinding.AppListSettingBinding;
import java.util.ArrayList;
public class AppListActivity extends MiracleGardenActivity<AppListSettingBinding> {
public static SharedPreferences sp;
private ArrayList<AppInfo> appList = new ArrayList<>();
CommonAdapter userAdapter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sp = getSharedPreferences("server", MODE_PRIVATE);
initData();
}
@Override
protected void onResume() {
super.onResume();
new LoadAppTask().execute();
}
// 异步加载
private class LoadAppTask extends AsyncTask<Void, Void, ArrayList<AppInfo>> {
@Override
protected ArrayList<AppInfo> doInBackground(Void... voids) {
// 获取全部APP
return AppListUtil.getAllInstalledApps(AppListActivity.this);
}
@Override
protected void onPostExecute(ArrayList<AppInfo> result) {
super.onPostExecute(result);
appList.clear();
appList.addAll(result);
userAdapter.notifyDataSetChanged();
if(appList.size()<=1){
binding.oneLy.setVisibility(View.VISIBLE);
}else{
binding.oneLy.setVisibility(View.GONE);
}
binding.loadingLy.setVisibility(View.GONE);
}
}
private void initData() {
binding.backIv.setOnClickListener(view -> finish());
binding.recyclerview.setLayoutManager(new LinearLayoutManager(this));
userAdapter = new CommonAdapter<>(AppListActivity.this, R.layout.item_user, appList) {
@Override
public void convert(ViewHolder holder, AppInfo info, int index) {
info = App.getAppInfoByNotiList(AppListActivity.this,info);
((ImageView) holder.getView(R.id.iv_icon)).setImageDrawable(info.getIcon());
holder.setText(R.id.tv_appname, info.getAppName());
holder.setText(R.id.tv_package, info.getPackageName());
if (!TextUtils.isEmpty(info.getName())) {
holder.setText(R.id.tv_name, info.getName()+"/");
}else{
holder.setText(R.id.tv_name, "--/");
}
if (!TextUtils.isEmpty(info.getCode())) {
holder.setText(R.id.tv_code, info.getCode()+"/");
}else{
holder.setText(R.id.tv_code, "--/");
}
if (!TextUtils.isEmpty(info.getRemark())) {
holder.setText(R.id.tv_remark, info.getRemark());
}else{
holder.setText(R.id.tv_remark, "--");
}
AppInfo finalInfo = info;
holder.getView(R.id.layout_big).setOnClickListener(view -> {
ActionConfirmDialog actionConfirmDialog = new ActionConfirmDialog(AppListActivity.this, finalInfo);
actionConfirmDialog.setOnToActionListener(new ActionConfirmDialog.OnToActionListener() {
@Override
public void toSumbit(AppInfo appInfo) {
appList.set(index,appInfo);
userAdapter.notifyItemChanged(index,appInfo);
App.saveNotiBean(AppListActivity.this,appInfo);
}
@Override
public void toCancel() {
}
});
actionConfirmDialog.show();
});
}
};
binding.recyclerview.setAdapter(userAdapter);
}
}

View File

@@ -0,0 +1,73 @@
package com.miraclegarden.smsmessage.Activity;
import android.Manifest;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.miraclegarden.library.app.MiracleGardenActivity;
import com.miraclegarden.smsmessage.databinding.ActivityMainBinding;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends MiracleGardenActivity<ActivityMainBinding> {
public static SharedPreferences sp;
private static final String TAG = "MainActivity";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sp = getSharedPreferences("server", MODE_PRIVATE);
initData();
initView();
}
private void initData() {
if (sp == null) {
return;
}
binding.host.setText(sp.getString("host", ""));
}
private void initView() {
binding.yes.setOnClickListener(v -> {
if (sp == null) {
return;
}
binding.host.setText(sp.getString("host", "https://www.judy88.xin/api/bills/app-upload"));
if (binding.host.getText().toString().length() == 0) {
Toast.makeText(this, "服务器和添加参数不能为空", Toast.LENGTH_SHORT).show();
return;
}
if (!binding.host.getText().toString().startsWith("http")) {
Toast.makeText(this, "服务器地址错误", Toast.LENGTH_SHORT).show();
return;
}
SharedPreferences.Editor edit = sp.edit();
edit.putString("host", binding.host.getText().toString());
edit.apply();
startActivity(new Intent(MainActivity.this, NotificationActivity.class));
finish();
});
new Handler().postDelayed(() -> binding.yes.performClick(),2000);
}
}

View File

@@ -0,0 +1,207 @@
package com.miraclegarden.smsmessage.Activity;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.provider.Settings;
import android.text.TextUtils;
import android.view.View;
import android.view.WindowManager;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.content.ContextCompat;
import androidx.core.widget.NestedScrollView;
import com.miraclegarden.library.app.MiracleGardenActivity;
import com.miraclegarden.smsmessage.AppInfo;
import com.miraclegarden.smsmessage.AppListUtil;
import com.miraclegarden.smsmessage.MessageInfo;
import com.miraclegarden.smsmessage.databinding.ActivityNotificationBinding;
import com.miraclegarden.smsmessage.service.NotificationService;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class NotificationActivity extends MiracleGardenActivity<ActivityNotificationBinding> {
private static final Handler handler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
String str = (String) msg.obj;
if (str != null) {
@SuppressLint("SimpleDateFormat") SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");
String t = format.format(new Date());
if (textView != null) {
textView.append(t + "" + str + "\n\r");
scrollView.post(() -> scrollView.fullScroll(ScrollView.FOCUS_DOWN));
}
}
}
};
public static SharedPreferences sharedPreferences;
public static void sendMessage(String str) {
Message message = new Message();
message.obj = str;
NotificationActivity.handler.sendMessage(message);
}
@SuppressLint("StaticFieldLeak")
private static TextView textView;
@SuppressLint("StaticFieldLeak")
private static NestedScrollView scrollView;
private final String[] permissions = new String[]{
Manifest.permission.RECEIVE_BOOT_COMPLETED
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sharedPreferences = getSharedPreferences("server", MODE_PRIVATE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
NotificationActivity.textView = binding.text;
NotificationActivity.scrollView = binding.scrollable;
initPermission();
initView();
}
private void initView() {
binding.button2.setOnClickListener(v -> {
//打开监听引用消息Notification access
Intent intent_s = new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS);
startActivity(intent_s);
});
binding.button.setOnClickListener(v -> {
AppInfo appInfo = AppListUtil.getAppByPackageName(NotificationActivity.this,"com.miraclegarden.smsmessage");
appInfo.setCode("111");
appInfo.setName("测试");
appInfo.setRemark("测试备注");
MessageInfo messageInfo = MessageInfo.AppInfoToMessageInfo(appInfo);
Submit(messageInfo,"我是标题","我是正文");
});
binding.button1.setOnClickListener(view -> {
if (textView != null) {
textView.setText("");
}
});
binding.toolbar.setOnLongClickListener(view -> {
// Toast.makeText(NotificationActivity.this,"点我干嘛",Toast.LENGTH_SHORT).show();
startActivity(new Intent(NotificationActivity.this,SettingActivity.class));
return false;
});
}
private void initPermission() {
checkPermission();
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
sendMessage("没有" + permission + "权限");
}
}
}
//打开设置界面
private void checkPermission() {
if (!isEnabled()) {
startActivity(new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"));
}
}
// 判断是否打开了通知监听权限
private boolean isEnabled() {
String pkgName = getPackageName();
final String flat = Settings.Secure.getString(getContentResolver(), "enabled_notification_listeners");
if (!TextUtils.isEmpty(flat)) {
final String[] names = flat.split(":");
for (String name : names) {
final ComponentName cn = ComponentName.unflattenFromString(name);
if (cn != null) {
if (TextUtils.equals(pkgName, cn.getPackageName())) {
return true;
}
}
}
}
return false;
}
public MediaType JSON = MediaType.parse("application/json; charset=utf-8");
public void Submit(MessageInfo messageInfo, String title, String context) {
OkHttpClient client = new OkHttpClient();
SharedPreferences sharedPreferences = getSharedPreferences("server", MODE_PRIVATE);
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", messageInfo.getName());
jsonObject.put("code", messageInfo.getCode());
jsonObject.put("remark", messageInfo.getRemark());
jsonObject.put("appName", messageInfo.getAppName());
jsonObject.put("packageName", messageInfo.getPackageName());
JSONObject jsonObject1 = new JSONObject();
jsonObject1.put("title", title);
jsonObject1.put("context", context);
jsonObject.put("data", jsonObject1);
String json = jsonObject.toString();
RequestBody body = RequestBody.create(json, JSON);
// 构建请求
Request request = new Request.Builder()
.url(sharedPreferences.getString("host", ""))
.post(body)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
NotificationActivity.sendMessage("提交失败:" + e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if (response.isSuccessful()) {
String str = response.body().string();
NotificationActivity.sendMessage(title + "提交成功:" + str);
return;
}
NotificationActivity.sendMessage("提交失败:");
}
});
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,151 @@
package com.miraclegarden.smsmessage.Activity;
import android.Manifest;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.miraclegarden.library.app.MiracleGardenActivity;
import com.miraclegarden.smsmessage.ActionConfirmDialog;
import com.miraclegarden.smsmessage.App;
import com.miraclegarden.smsmessage.AppInfo;
import com.miraclegarden.smsmessage.AppListUtil;
import com.miraclegarden.smsmessage.DeleteConfirmDialog;
import com.miraclegarden.smsmessage.MessageInfo;
import com.miraclegarden.smsmessage.R;
import com.miraclegarden.smsmessage.comm.CommonAdapter;
import com.miraclegarden.smsmessage.comm.ViewHolder;
import com.miraclegarden.smsmessage.databinding.ActivityMainBinding;
import com.miraclegarden.smsmessage.databinding.ActivitySettingBinding;
import java.util.ArrayList;
import java.util.List;
public class SettingActivity extends MiracleGardenActivity<ActivitySettingBinding> {
public static SharedPreferences sp;
private static final String TAG = "SettingActivity";
private ArrayList<MessageInfo> appList = new ArrayList<>();
CommonAdapter userAdapter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sp = getSharedPreferences("server", MODE_PRIVATE);
initData();
initList();
}
@Override
protected void onResume() {
super.onResume();
initChangeList();
}
private void initChangeList() {
List<MessageInfo> appList1 = App.getNotiList(SettingActivity.this);
if(appList1 == null){
appList = new ArrayList<>();
}else{
appList = (ArrayList<MessageInfo>) appList1;
}
userAdapter.setDates(appList);
if(appList.size()>0){
binding.recyclerview.setVisibility(View.VISIBLE);
binding.nodataIv.setVisibility(View.GONE);
}else{
binding.recyclerview.setVisibility(View.GONE);
binding.nodataIv.setVisibility(View.VISIBLE);
}
}
private void initData() {
binding.host.setText(sp.getString("host", "https://www.judy88.xin/api/bills/app-upload"));
binding.addBt.setOnClickListener(view -> startActivity(new Intent(SettingActivity.this,AppListActivity.class)));
binding.backIv.setOnClickListener(view -> finish());
binding.yes.setOnClickListener(v -> {
if (sp == null) {
return;
}
if (binding.host.getText().toString().length() == 0) {
Toast.makeText(this, "服务器和添加参数不能为空", Toast.LENGTH_SHORT).show();
return;
}
if (!binding.host.getText().toString().startsWith("http")) {
Toast.makeText(this, "服务器地址错误", Toast.LENGTH_SHORT).show();
return;
}
SharedPreferences.Editor edit = sp.edit();
edit.putString("host", binding.host.getText().toString());
edit.apply();
Toast.makeText(this, "服务器地址修改成功", Toast.LENGTH_SHORT).show();
});
}
private void initList() {
binding.recyclerview.setLayoutManager(new LinearLayoutManager(this));
userAdapter = new CommonAdapter<>(SettingActivity.this, R.layout.item_user, appList) {
@Override
public void convert(ViewHolder holder, MessageInfo info, int index) {
AppInfo appInfo = AppListUtil.getAppByPackageName(SettingActivity.this,info.getPackageName());
ImageView delete_img = holder.getView(R.id.delete_img);
delete_img.setVisibility(View.VISIBLE);
delete_img.setOnClickListener(view -> {
DeleteConfirmDialog deleteConfirmDialog = new DeleteConfirmDialog(SettingActivity.this,info);
deleteConfirmDialog.setOnToActionListener(() -> {
App.deleteNotiBean(SettingActivity.this,info);
initChangeList();
});
deleteConfirmDialog.show();
});
if(appInfo!=null){
((ImageView) holder.getView(R.id.iv_icon)).setImageDrawable(appInfo.getIcon());
}else{
((ImageView) holder.getView(R.id.iv_icon)).setImageResource(R.mipmap.app_logo);
}
holder.setText(R.id.tv_appname, info.getAppName());
holder.setText(R.id.tv_package, info.getPackageName());
if (!TextUtils.isEmpty(info.getName())) {
holder.setText(R.id.tv_name, info.getName()+"/");
}else{
holder.setText(R.id.tv_name, "--/");
}
if (!TextUtils.isEmpty(info.getCode())) {
holder.setText(R.id.tv_code, info.getCode()+"/");
}else{
holder.setText(R.id.tv_code, "--/");
}
if (!TextUtils.isEmpty(info.getRemark())) {
holder.setText(R.id.tv_remark, info.getRemark());
}else{
holder.setText(R.id.tv_remark, "--");
}
}
};
binding.recyclerview.setAdapter(userAdapter);
}
}

View File

@@ -0,0 +1,162 @@
package com.miraclegarden.smsmessage;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class App extends Application {
private static final String TAG = "App";
public static String Hash_value;
@Override
public void onCreate() {
super.onCreate();
String packageName = getApplicationContext().getPackageName();
MessageDigest messageDigest = getMessageDigest();
String signature = getSignature(this, packageName);
Hash_value = getHashCode(packageName, messageDigest, signature);
}
public static MessageDigest getMessageDigest() {
MessageDigest messageDigest = null;
try {
messageDigest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "No Such Algorithm.", e);
}
return messageDigest;
}
public static String getSignature(Context context, String packageName) {
PackageManager packageManager = context.getPackageManager();
Signature[] signatureArrs;
try {
signatureArrs = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures;
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Package name inexistent.");
return "";
}
if (null == signatureArrs || 0 == signatureArrs.length) {
Log.e(TAG, "signature is null.");
return "";
}
return signatureArrs[0].toCharsString();
}
private String getHashCode(String packageName, MessageDigest messageDigest, String signature) {
String appInfo = packageName + " " + signature;
messageDigest.update(appInfo.getBytes(StandardCharsets.UTF_8));
byte[] hashSignature = messageDigest.digest();
hashSignature = Arrays.copyOfRange(hashSignature, 0, 9);
String base64Hash = Base64.encodeToString(hashSignature, Base64.NO_PADDING | Base64.NO_WRAP);
base64Hash = base64Hash.substring(0, 11);
return base64Hash;
}
public static void saveNotiList(Context context, String value) {
SharedPreferences sp = context.getSharedPreferences("server", Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString("saveNotiList", value);
editor.apply();
}
public static List<MessageInfo> getNotiList(Context context) {
SharedPreferences sp = context.getSharedPreferences("server", Activity.MODE_PRIVATE);
String messages = sp.getString("saveNotiList", "");
if (TextUtils.isEmpty(messages)) {
return null;
}
List<MessageInfo> messageInfos = GsonUtils.getListFromJSON(messages, MessageInfo.class);
return messageInfos;
}
public static void deleteNotiBean(Context context, MessageInfo appInfo) {
List<MessageInfo> messageInfos = getNotiList(context);
if (messageInfos == null) {
saveNotiList(context, "");
return;
}
for (int i = 0; i < messageInfos.size(); i++) {
if (messageInfos.get(i).getPackageName().equals(appInfo.getPackageName())) {
messageInfos.remove(i);
if (messageInfos.size() == 0) {
saveNotiList(context, "");
} else {
saveNotiList(context, GsonUtils.beanToJSONString(messageInfos));
}
break;
}
}
}
public static void saveNotiBean(Context context, AppInfo appInfo) {
List<MessageInfo> messageInfos = getNotiList(context);
if (messageInfos == null) {
messageInfos = new ArrayList<>();
messageInfos.add(MessageInfo.AppInfoToMessageInfo(appInfo));
saveNotiList(context, GsonUtils.beanToJSONString(messageInfos));
return;
}
boolean isAdd = true;
for (int i = 0; i < messageInfos.size(); i++) {
if (messageInfos.get(i).getPackageName().equals(appInfo.getPackageName())) {
messageInfos.get(i).setName(appInfo.getName());
messageInfos.get(i).setCode(appInfo.getCode());
messageInfos.get(i).setRemark(appInfo.getRemark());
isAdd = false;
}
}
if(isAdd){
messageInfos.add(MessageInfo.AppInfoToMessageInfo(appInfo));
}
saveNotiList(context, GsonUtils.beanToJSONString(messageInfos));
}
public static AppInfo getAppInfoByNotiList(Context context, AppInfo appInfo) {
List<MessageInfo> messageInfos = getNotiList(context);
if (messageInfos == null) {
return appInfo;
}
for (int i = 0; i < messageInfos.size(); i++) {
if (messageInfos.get(i).getPackageName().equals(appInfo.getPackageName())) {
appInfo.setName(messageInfos.get(i).getName());
appInfo.setCode(messageInfos.get(i).getCode());
appInfo.setRemark(messageInfos.get(i).getRemark());
return appInfo;
}
}
return appInfo;
}
public static MessageInfo getMessageByNotiList(Context context, String packageName) {
List<MessageInfo> messageInfos = getNotiList(context);
if (messageInfos == null) {
return null;
}
for (int i = 0; i < messageInfos.size(); i++) {
if (messageInfos.get(i).getPackageName().equals(packageName)) {
return messageInfos.get(i);
}
}
return null;
}
}

View File

@@ -0,0 +1,53 @@
package com.miraclegarden.smsmessage;
/**
* **********************
*
* @Author bug machine
* 创建时间: 2026/3/20 15:30
* 用途
* **********************
*/
import android.graphics.drawable.Drawable;
public class AppInfo {
private String appName; // 应用名
private String packageName;// 包名
private Drawable icon; // 图标
private String name;
private String code;
private String remark;
public AppInfo(String appName, String packageName, Drawable icon) {
this.appName = appName;
this.packageName = packageName;
this.icon = icon;
}
public String getAppName() { return appName; }
public String getPackageName() { return packageName; }
public Drawable getIcon() { return icon; }
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
}

View File

@@ -0,0 +1,91 @@
package com.miraclegarden.smsmessage;
/**
* **********************
*
* @Author bug machine
* 创建时间: 2026/3/20 15:30
* 用途
* **********************
*/
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
public class AppListUtil {
// 获取 所有已安装APP
public static ArrayList<AppInfo> getAllInstalledApps(Context context) {
ArrayList<AppInfo> list = new ArrayList<>();
PackageManager pm = context.getPackageManager();
// 获取全部应用
List<ApplicationInfo> apps = pm.getInstalledApplications(0);
Log.i("多少条数据","多少条数据:"+apps.size());
for (ApplicationInfo info : apps) {
// 只获取有桌面图标的应用(可去掉,获取全部)
if (pm.getLaunchIntentForPackage(info.packageName) != null) {
String name = info.loadLabel(pm).toString();
String pkg = info.packageName;
Drawable icon = info.loadIcon(pm);
boolean isSystem = (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
list.add(new AppInfo(name, pkg, icon));
}
}
return list;
}
// 只获取 第三方APP排除系统APP
public static ArrayList<AppInfo> getThirdPartyApps(Context context) {
ArrayList<AppInfo> list = new ArrayList<>();
PackageManager pm = context.getPackageManager();
List<ApplicationInfo> apps = pm.getInstalledApplications(0);
for (ApplicationInfo info : apps) {
// 非系统APP + 有启动图标
if ((info.flags & ApplicationInfo.FLAG_SYSTEM) == 0
&& pm.getLaunchIntentForPackage(info.packageName) != null) {
list.add(new AppInfo(
info.loadLabel(pm).toString(),
info.packageName,
info.loadIcon(pm)
));
}
}
return list;
}
/**
* 判断某个包名是否已安装,并返回应用信息
* @param context 上下文
* @param packageName 指定包名
* @return null = 未安装 / 无权限 / 找不到
*/
public static AppInfo getAppByPackageName(Context context, String packageName) {
try {
PackageManager pm = context.getPackageManager();
// ✅ 关键:直接查询指定包名(不会被系统限制)
PackageInfo packageInfo = pm.getPackageInfo(packageName, 0);
ApplicationInfo appInfo = packageInfo.applicationInfo;
String appName = appInfo.loadLabel(pm).toString();
Drawable icon = appInfo.loadIcon(pm);
return new AppInfo(appName, packageName, icon);
} catch (PackageManager.NameNotFoundException e) {
// 没安装
return null;
}
}
}

View File

@@ -0,0 +1,65 @@
package com.miraclegarden.smsmessage;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
import com.miraclegarden.smsmessage.databinding.DialogDeleteConfirmBinding;
/**
* 通用弹窗
*/
public class DeleteConfirmDialog extends Dialog {
DialogDeleteConfirmBinding dialogActionConfirmBinding;
OnToActionListener onToActionListener;
MessageInfo messageInfo;
public interface OnToActionListener {
void toSumbit();
}
public void setOnToActionListener(OnToActionListener onNextCallListener) {
this.onToActionListener = onNextCallListener;
}
public DeleteConfirmDialog(Context context, MessageInfo messageInfo) {
super(context, R.style.MaterialDesignDialog);
this.messageInfo = messageInfo;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dialogActionConfirmBinding = DialogDeleteConfirmBinding.inflate(getLayoutInflater());
setContentView(dialogActionConfirmBinding.getRoot());
dialogActionConfirmBinding.contentTv.setText("删除"+messageInfo.getAppName()+"监听");
dialogActionConfirmBinding.sumbitTv.setOnClickListener(v -> {
dismiss();
if(onToActionListener!=null){
onToActionListener.toSumbit();
}
});
dialogActionConfirmBinding.cancelTv.setOnClickListener(v -> {
dismiss();
});
Window window = getWindow();
WindowManager.LayoutParams wlp = window.getAttributes();
wlp.gravity = Gravity.CENTER;
wlp.width = WindowManager.LayoutParams.WRAP_CONTENT;
wlp.height = WindowManager.LayoutParams.WRAP_CONTENT;
window.setAttributes(wlp);
}
}

View File

@@ -0,0 +1,91 @@
package com.miraclegarden.smsmessage;
import android.text.TextUtils;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
/**
* json解析工具类 其实对于数组解析有一些问题
* @author
*/
public class GsonUtils {
public static Gson gson = new Gson();
/**
* 返回List对象
* @param str
* @param type new TypeToken<ArrayList<T>>(){}.getType()
* @param <T>
* @return
*/
public static <T> T getListFromJSON(String str, Type type) {
if (!TextUtils.isEmpty(str)) {
return gson.fromJson(str, type);
}
return null;
}
/**
* 返回List对象
* @param str
* @param cls
* @param <T>
* @return
*/
public static <T> List<T> getListFromJSON(String str, Class<T> cls)
{
Type type = new TypeToken<ArrayList<JsonObject>>()
{}.getType();
ArrayList<JsonObject> jsonObjects = gson.fromJson(str, type);
ArrayList<T> arrayList = new ArrayList<>();
for (JsonObject jsonObject : jsonObjects)
{
arrayList.add(gson.fromJson(jsonObject, cls));
}
return arrayList;
}
/**
* 返回对象
* @param str
* @param cls
* @param <T>
* @return
*/
public static <T> T getObjFromJSON(String str, Class<T> cls) {
try {
if (!TextUtils.isEmpty(str)) {
// LogUtils.i("参数:"+str);
return gson.fromJson(str, cls);
}
return null;
}catch (Exception e) {
return null;
}
}
/**
* 返回JsonString
* @return
*/
public static String beanToJSONString(Object bean) {
return new Gson().toJson(bean);
}
public static String JSONTokener(String in) {
// consume an optional byte order mark (BOM) if it exists
if (in != null && in.startsWith("\ufeff")) {
in = in.substring(1);
}
return in;
}
}

View File

@@ -0,0 +1,79 @@
package com.miraclegarden.smsmessage;
/**
* **********************
*
* @Author bug machine
* 创建时间: 2026/3/20 15:30
* 用途
* **********************
*/
public class MessageInfo {
private String appName; // 应用名
private String packageName;// 包名
private String name;
private String code;
private String remark;
public MessageInfo() {
}
public MessageInfo(String appName, String packageName, String name, String code, String remark) {
this.appName = appName;
this.packageName = packageName;
this.name = name;
this.code = code;
this.remark = remark;
}
public static MessageInfo AppInfoToMessageInfo(AppInfo appInfo) {
MessageInfo messageInfo = new MessageInfo();
messageInfo.appName = appInfo.getAppName();
messageInfo.packageName = appInfo.getPackageName();
messageInfo.name = appInfo.getName();
messageInfo.code = appInfo.getCode();
messageInfo.remark = appInfo.getRemark();
return messageInfo;
}
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName = appName;
}
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
}

View File

@@ -0,0 +1,68 @@
package com.miraclegarden.smsmessage.comm;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
/**
* 通用列表适配器
* @param <T>
*/
public abstract class CommonAdapter<T> extends RecyclerView.Adapter<ViewHolder> {
protected Context mContext;
protected int mLayoutId;
protected List<T> mDatas;
protected LayoutInflater mInflater;
ViewHolder viewHolder;
public CommonAdapter(Context context, int layoutId, List<T> datas) {
mContext = context;
mInflater = LayoutInflater.from(context);
mLayoutId = layoutId;
mDatas = datas;
}
public void setDates(List<T> dates){
this.mDatas=dates;
// notifyItemRangeChanged(0,mDatas.size());
notifyDataSetChanged();
}
public void addDates(List<T> dates){
this.mDatas.addAll(dates);
notifyDataSetChanged();
}
public void addDates(int localSize){
int size=mDatas.size();
notifyItemRangeChanged(size,localSize);
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
viewHolder = ViewHolder.get(mContext, parent, mLayoutId);
return viewHolder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
convert(holder, mDatas.get(position),position);
}
public abstract void convert(ViewHolder holder, T t,int index);
@Override
public int getItemCount() {
return mDatas.size();
}
}

View File

@@ -0,0 +1,60 @@
package com.miraclegarden.smsmessage.comm;
import android.content.Context;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
/**
* 通用列表ViewHolder
*/
public class ViewHolder extends RecyclerView.ViewHolder {
private SparseArray<View> mViews;
private View mConvertView;
private Context mContext;
public ViewHolder(Context context, View itemView, ViewGroup parent) {
super(itemView);
mContext = context;
mConvertView = itemView;
mViews = new SparseArray<View>();
}
public static ViewHolder get(Context context, ViewGroup parent, int layoutId) {
View itemView = LayoutInflater.from(context).inflate(layoutId, parent,
false);
ViewHolder holder = new ViewHolder(context, itemView, parent);
return holder;
}
public <T extends View> T getView(int viewId) {
View view = mViews.get(viewId);
if (view == null) {
view = mConvertView.findViewById(viewId);
mViews.put(viewId, view);
}
return (T) view;
}
public ViewHolder setText(int viewId, String text)
{
TextView tv = getView(viewId);
tv.setText(text);
return this;
}
public ViewHolder setOnClickListener(int viewId, View.OnClickListener listener) {
View view = getView(viewId);
view.setOnClickListener(listener);
return this;
}
}

View File

@@ -0,0 +1,157 @@
package com.miraclegarden.smsmessage.service;
import android.annotation.SuppressLint;
import android.app.Notification;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import com.miraclegarden.smsmessage.Activity.NotificationActivity;
import com.miraclegarden.smsmessage.App;
import com.miraclegarden.smsmessage.MessageInfo;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class NotificationService extends NotificationListenerService {
private static final String TAG = "NotificationService";
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
NotificationActivity.sendMessage("监听服务成功!");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onNotificationPosted(StatusBarNotification sbn) {
getSbnByNotificatinList(sbn);
}
public void getSbnByNotificatinList(StatusBarNotification sbn) {
MessageInfo messageInfo = App.getMessageByNotiList(this, sbn.getPackageName());
if (messageInfo != null) {
initData(messageInfo, sbn);
}
}
private String text = "";
private void initData(MessageInfo messageInfo, StatusBarNotification sbn) {
Bundle bundle = sbn.getNotification().extras;
String title = bundle.getString(Notification.EXTRA_TITLE, "获取标题失败!");
String context = bundle.getString(Notification.EXTRA_TEXT, "获取内容失败!");
if (context.equals("获取内容失败!")) {
if (sbn.getNotification().tickerText != null) {
context = sbn.getNotification().tickerText.toString();
}
}
NotificationActivity.sendMessage(title + " " + context);
if (!text.equals(context)) {
if (!title.equals("获取标题失败!") && !context.equals("获取内容失败!") && !title.contains("正在运行")) {
NotificationActivity.sendMessage("准备发送服务器:成功");
Submit(messageInfo,title, context);
}
}
}
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
public void Submit(MessageInfo messageInfo,String title, String context) {
OkHttpClient client = new OkHttpClient();
SharedPreferences sharedPreferences = getSharedPreferences("server", MODE_PRIVATE);
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", messageInfo.getName());
jsonObject.put("code", messageInfo.getCode());
jsonObject.put("remark", messageInfo.getRemark());
jsonObject.put("appName", messageInfo.getAppName());
jsonObject.put("packageName", messageInfo.getPackageName());
JSONObject jsonObject1 = new JSONObject();
jsonObject1.put("title", title+System.currentTimeMillis());
jsonObject1.put("context", context+System.currentTimeMillis());
jsonObject.put("data", jsonObject1);
String json = jsonObject.toString();
RequestBody body = RequestBody.create(json, JSON);
// 构建请求
Request request = new Request.Builder()
.url(sharedPreferences.getString("host", ""))
.post(body)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
NotificationActivity.sendMessage("提交失败:" + e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if (response.isSuccessful()) {
String str = response.body().string();
NotificationActivity.sendMessage(title + "提交成功:" + str);
text = context;
return;
}
NotificationActivity.sendMessage("提交失败:");
}
});
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
/**
* 监听断开
*/
@Override
public void onListenerDisconnected() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// 通知侦听器断开连接 - 请求重新绑定
requestRebind(new ComponentName(this, NotificationListenerService.class));
}
}
/**
* @param context 反正第二次启动失败
*/
public static void toggleNotificationListenerService(Context context) {
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(new ComponentName(context, NotificationService.class),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
pm.setComponentEnabledSetting(new ComponentName(context, NotificationService.class),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
}
}

View File

@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF"
android:alpha="0.8">
<path
android:fillColor="@android:color/white"
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

View File

@@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

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="#3DDC84"
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,27 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:color="@color/white"
tools:ignore="NewApi">
<item android:id="@android:id/mask"
tools:ignore="NewApi">
<shape>
<solid android:color="@android:color/transparent" />
<corners android:radius="5dp" />
</shape>
</item>
<!-- 默认显⽰效果-->
<item>
<shape android:shape="rectangle">
<gradient
android:angle="180"
android:startColor="#EEEEEE"
android:endColor="#EEEEEE"
android:type="linear"
android:useLevel="true" />
<corners
android:radius="5dp" />
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<animated-rotate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
>
<shape
android:shape="ring"
android:innerRadiusRatio="3"
android:thicknessRatio="8"
android:useLevel="false"
>
<gradient
android:type="sweep"
android:useLevel="false"
android:startColor="@color/purple_700"
android:centerColor="@color/purple_500"
android:endColor="#FFFFFF"
android:centerY="0.50" />
</shape>
</animated-rotate>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<corners android:radius="12dp" />
<solid android:color="@color/white" />
</shape>

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/top_ab"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="MissingConstraints">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:title="@string/app_name"
app:titleTextColor="@color/white" />
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/top_ab"
android:orientation="vertical"
android:padding="10dp">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="服务器地址http://xxx.xxx.xxx/xxx"
tools:ignore="HardcodedText">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/host"
android:text="https://www.judy88.xin/api/bills/app-upload"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/yes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="保存参数"
tools:ignore="HardcodedText" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="@color/purple_500">
<ImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:src="@mipmap/app_logo" />
</LinearLayout>
</RelativeLayout>

View File

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:title="@string/app_name"
app:titleTextColor="@color/white" />
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_weight="1"
android:textColor="@color/white"
android:text="开启监听"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_weight="1"
android:text="测试接口"
android:textColor="@color/white"
tools:ignore="HardcodedText" />
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_weight="1"
android:text="清理数据"
android:textColor="@color/white"
tools:ignore="HardcodedText" />
</LinearLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/scrollable"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textIsSelectable="true" />
</androidx.core.widget.NestedScrollView>
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,115 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/top_ab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="MissingConstraints">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:title=""
app:titleTextColor="@color/white" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/back_iv"
android:src="@drawable/ic_action_back"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="设置"
android:textSize="18sp"
android:textColor="@color/white"/>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/top_ab"
android:orientation="vertical"
android:padding="10dp">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="服务器地址:"
tools:ignore="HardcodedText">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/host"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/yes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="保存"
android:textColor="@color/white"
tools:ignore="HardcodedText" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:text="监听App列表"
android:textColor="@color/black" />
<Button
android:id="@+id/add_bt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="添加"
android:textColor="@color/white"
tools:ignore="HardcodedText" />
</LinearLayout>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#DDDDDD" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableTop="@mipmap/no_data"
android:id="@+id/nodata_iv"
android:visibility="gone"
android:textColor="@color/black"
android:textSize="16sp"
android:gravity="center_horizontal"
android:drawablePadding="10dp"
android:text="暂无监听"/>
</androidx.appcompat.widget.LinearLayoutCompat>
</LinearLayout>
</RelativeLayout>

View File

@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/top_ab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="MissingConstraints">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:titleTextColor="@color/white" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/back_iv"
android:src="@drawable/ic_action_back"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="本机App列表"
android:textSize="18sp"
android:textColor="@color/white"/>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/top_ab"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:id="@+id/recyclerview"/>
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/one_ly"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/recyclerview"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:background="#DDDDDD"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="获取所有app列表失败 你可以:"
android:layout_marginTop="10dp"
android:textStyle="bold"
android:layout_marginStart="10dp"
android:textColor="@color/black"
android:gravity="center_vertical"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:src="@mipmap/get_list"
android:adjustViewBounds="true"/>
</androidx.appcompat.widget.LinearLayoutCompat>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:layout_below="@id/top_ab"
android:gravity="center"
android:id="@+id/loading_ly"
android:orientation="vertical">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:indeterminateDrawable="@drawable/pass_word_bg1" />
</LinearLayout>
</RelativeLayout>

View File

@@ -0,0 +1,158 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/shape_dialog_bg3"
android:orientation="vertical">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="285dp"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/content_tv"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_weight="1"
android:gravity="center"
android:text="添加监听"
android:lineSpacingExtra="4dp"
android:textColor="@color/black"
android:textSize="16sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:padding="12dp">
<ImageView
android:id="@+id/iv_icon"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@mipmap/app_logo" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginStart="12dp">
<TextView
android:id="@+id/tv_appname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textColor="@color/black"
android:text="111111"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_package"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
android:text="2222222"
android:textColor="#888888" />
</LinearLayout>
</LinearLayout>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:orientation="vertical">
<EditText
android:id="@+id/tv_name"
android:layout_width="match_parent"
android:layout_height="35dp"
android:textSize="12sp"
android:text=""
android:hint="请输入名称"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:textColorHint="#333333"
android:background="@drawable/pass_word_bg"
android:textColor="@color/black" />
<EditText
android:id="@+id/tv_code"
android:layout_width="match_parent"
android:layout_height="35dp"
android:textSize="12sp"
android:layout_marginTop="10dp"
android:background="@drawable/pass_word_bg"
android:text=""
android:hint="请输入Code"
android:paddingStart="10dp"
android:textColorHint="#333333"
android:paddingEnd="10dp"
android:inputType="number"
android:textColor="@color/black" />
<EditText
android:id="@+id/tv_remark"
android:layout_width="match_parent"
android:layout_height="40dp"
android:textSize="12sp"
android:layout_marginTop="10dp"
android:background="@drawable/pass_word_bg"
android:hint="请输入备注"
android:textColorHint="#333333"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:text=""
android:textColor="@color/black" />
</androidx.appcompat.widget.LinearLayoutCompat>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginTop="10dp"
android:background="#DDDDDD" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_gravity="center_horizontal"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/cancel_tv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="取消"
android:textColor="@color/black"
android:textSize="16sp" />
<View
android:id="@+id/line_v"
android:layout_width="0.5dp"
android:layout_height="50dp"
android:background="#DDDDDD" />
<TextView
android:id="@+id/sumbit_tv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="添加"
android:textColor="@color/purple_500"
android:textSize="16sp" />
</LinearLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
</LinearLayout>

View File

@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_dialog_bg3"
android:orientation="vertical">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="285dp"
android:layout_height="wrap_content"
android:minHeight="144dp"
android:orientation="vertical">
<TextView
android:id="@+id/content_tv"
android:layout_width="245dp"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:layout_marginTop="30dp"
android:layout_marginBottom="30dp"
android:layout_weight="1"
android:gravity="center"
android:text="删除消息监听"
android:lineSpacingExtra="4dp"
android:textColor="@color/black"
android:textSize="16sp" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#DDDDDD" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_gravity="center_horizontal"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/cancel_tv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:textColor="@color/black"
android:text="取消"
android:textSize="16sp" />
<View
android:id="@+id/line_v"
android:layout_width="1px"
android:layout_height="match_parent"
android:background="#DDDDDD" />
<TextView
android:id="@+id/sumbit_tv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="删除"
android:textColor="@color/purple_500"
android:textSize="16sp" />
</LinearLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
</LinearLayout>

View File

@@ -0,0 +1,97 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:id="@+id/layout_big"
android:paddingTop="12dp"
android:paddingBottom="12dp">
<ImageView
android:id="@+id/iv_icon"
android:layout_width="70dp"
android:layout_height="70dp"
android:src="@mipmap/app_logo" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginStart="12dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_appname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="16sp"
android:text="111111"
android:textStyle="bold" />
<ImageView
android:id="@+id/delete_img"
android:visibility="invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/delete_img"/>
</LinearLayout>
<TextView
android:id="@+id/tv_package"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
android:text="2222222"
android:textColor="#888888" />
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="25dp"
android:gravity="center_vertical"
android:paddingStart="5dp"
android:id="@+id/show_more"
android:paddingEnd="5dp"
android:background="@drawable/pass_word_bg"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
android:text="11"
android:textColor="#888888" />
<TextView
android:id="@+id/tv_code"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
android:text="22"
android:textColor="#888888" />
<TextView
android:id="@+id/tv_remark"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
android:text="33"
android:textColor="#888888" />
</androidx.appcompat.widget.LinearLayoutCompat>
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#DDDDDD"/>
</LinearLayout>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -0,0 +1,20 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.SmsMessage" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/purple_700</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_200</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorOnPrimary</item>
<!-- Customize your theme here. -->
<item name="android:navigationBarColor">@color/purple_500</item>
<item name="android:windowBackground">@color/purple_500</item>
<item name="android:windowIsTranslucent">true</item>
</style>
</resources>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

View File

@@ -0,0 +1,4 @@
<resources>
<string name="app_name">通知管理</string>
<string name="key">#$%^*()XCVBNM</string>
</resources>

View File

@@ -0,0 +1,53 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.SmsMessage" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_500</item>
<item name="colorOnPrimary">@color/purple_500</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
<item name="android:navigationBarColor">@color/purple_500</item>
<item name="android:windowIsTranslucent">true</item>
</style>
<style name="Theme.SmsMessage1" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_500</item>
<item name="colorOnPrimary">@color/purple_500</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
<item name="android:navigationBarColor">@color/white</item>
<item name="android:windowBackground">@color/white</item>
</style>
<style name="MaterialDesignDialog" parent="@style/Theme.AppCompat.Dialog">
<!-- 背景透明 -->
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
<!-- 浮于Activity之上 -->
<item name="android:windowIsFloating">true</item>
<!-- 边框 -->
<item name="android:windowFrame">@null</item>
<!-- Dialog以外的区域模糊效果 -->
<item name="android:backgroundDimEnabled">true</item>
<!-- 无标题 -->
<item name="android:windowNoTitle">true</item>
<!-- 半透明 -->
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowCloseOnTouchOutside">true</item>
</style>
</resources>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample backup rules file; uncomment and customize as necessary.
See https://developer.android.com/guide/topics/data/autobackup
for details.
Note: This file is ignored for devices older that API 31
See https://developer.android.com/about/versions/12/backup-restore
-->
<full-backup-content>
<!--
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
-->
</full-backup-content>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample data extraction rules file; uncomment and customize as necessary.
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
for details.
-->
<data-extraction-rules>
<cloud-backup>
<!-- TODO: Use <include> and <exclude> to control what is backed up.
<include .../>
<exclude .../>
-->
</cloud-backup>
<!--
<device-transfer>
<include .../>
<exclude .../>
</device-transfer>
-->
</data-extraction-rules>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config xmlns:tools="http://schemas.android.com/tools">
<base-config cleartextTrafficPermitted="true"
tools:ignore="InsecureBaseConfiguration" />
</network-security-config>

View File

@@ -0,0 +1,17 @@
package com.miraclegarden.smsmessage;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}