Compare commits
10 Commits
edef32dc07
...
acdd23567e
| Author | SHA1 | Date |
|---|---|---|
|
|
acdd23567e | |
|
|
e5d8b244d1 | |
|
|
b64cb19e17 | |
|
|
a5e081a0a1 | |
|
|
5fd4acf9fb | |
|
|
1ecf3998ad | |
|
|
d52b837175 | |
|
|
82d21d98be | |
|
|
cc4ef4939c | |
|
|
e59de5764e |
|
|
@ -67,6 +67,14 @@
|
|||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<service android:name=".service.MonitorService" />
|
||||
<service android:name=".service.MonitorService"/>
|
||||
<service android:name=".service.NotificationListener"
|
||||
android:label="NotificationListener"
|
||||
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.notification.NotificationListenerService" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
@ -11,8 +11,10 @@ import androidx.appcompat.app.AppCompatActivity;
|
|||
|
||||
import com.nbee.echolink.async.BatteryOptimizationTask;
|
||||
import com.nbee.echolink.service.MonitorService;
|
||||
import com.nbee.echolink.service.NotificationListener;
|
||||
import com.nbee.echolink.utils.BatteryOptimizationUtil;
|
||||
import com.nbee.echolink.utils.PermissionUtils;
|
||||
import com.nbee.echolink.utils.SharedPreferencesManager;
|
||||
import com.nbee.echolink.utils.ShellUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
|
|
@ -25,6 +27,7 @@ import timber.log.Timber;
|
|||
public class MainActivity extends AppCompatActivity {
|
||||
private final String TAG = "MainActivity";
|
||||
private PermissionUtils permissionUtils;
|
||||
private SharedPreferencesManager spManager;
|
||||
private TextView logTextView; // 将类型从 View 更改为 TextView
|
||||
|
||||
@Override
|
||||
|
|
@ -35,14 +38,31 @@ public class MainActivity extends AppCompatActivity {
|
|||
logTextView = findViewById(R.id.logTextView);
|
||||
updateLog("初始化日志...");
|
||||
|
||||
spManager = new SharedPreferencesManager(this);
|
||||
|
||||
if (isFirstRun()) {
|
||||
setupInitialDataAsync();
|
||||
spManager.putBoolean("isFirstRun", false);
|
||||
}
|
||||
|
||||
requestIgnoreBatteryAsync();
|
||||
permissionUtils = new PermissionUtils(this);
|
||||
permissionUtils.checkPermissions();
|
||||
if (permissionUtils.isNotificationServiceEnabled(this)) {
|
||||
// 拥有权限,可以执行相关操作
|
||||
} else {
|
||||
// 未获得权限,可能需要提示用户
|
||||
Intent intent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
// 启动MonitorService服务
|
||||
|
||||
Intent serviceIntent = new Intent(this, MonitorService.class);
|
||||
startService(serviceIntent);
|
||||
|
||||
//启动通知监听服务
|
||||
Intent serviceIntent1 = new Intent(this, NotificationListener.class);
|
||||
startService(serviceIntent1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -57,6 +77,20 @@ public class MainActivity extends AppCompatActivity {
|
|||
readLogFileAsync();
|
||||
}
|
||||
|
||||
private boolean isFirstRun() {
|
||||
// 默认值为 true,如果找不到该键值对
|
||||
return spManager.getBoolean("isFirstRun", true);
|
||||
}
|
||||
//设置通知监控的包名
|
||||
private void setupInitialDataAsync() {
|
||||
new Thread(() -> {
|
||||
// 在这里设置SharedPreferences中的包名和对应的应用名
|
||||
// 例如:
|
||||
spManager.putString("com.tencent.mm", "微信");
|
||||
Timber.d("写入SharedPreferences成功。");
|
||||
// 完成后,您可以在这里执行其他操作,如发送广播、更新UI等(确保在主线程中执行UI操作)
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void readLogFileAsync() {
|
||||
new AsyncTask<Void, Void, String>() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
package com.nbee.echolink.model;
|
||||
|
||||
public class WeChatMsg {
|
||||
private String packageName;
|
||||
private String appName;
|
||||
private String title;
|
||||
private String sender;
|
||||
private String message;
|
||||
|
||||
public String getCurrentTime() {
|
||||
return currentTime;
|
||||
}
|
||||
|
||||
public void setCurrentTime(String currentTime) {
|
||||
this.currentTime = currentTime;
|
||||
}
|
||||
|
||||
private String currentTime;
|
||||
|
||||
public String getPackageName() {
|
||||
return packageName;
|
||||
}
|
||||
|
||||
public void setPackageName(String packageName) {
|
||||
this.packageName = packageName;
|
||||
}
|
||||
|
||||
public String getAppName() {
|
||||
return appName;
|
||||
}
|
||||
|
||||
public void setAppName(String appName) {
|
||||
this.appName = appName;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getSender() {
|
||||
return sender;
|
||||
}
|
||||
|
||||
public void setSender(String sender) {
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public WeChatMsg() {
|
||||
}
|
||||
|
||||
public WeChatMsg(String packageName, String appName, String title, String sender, String message,String currentTime) {
|
||||
this.packageName = packageName;
|
||||
this.appName = appName;
|
||||
this.title = title;
|
||||
this.sender = sender;
|
||||
this.message = message;
|
||||
this.currentTime = currentTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WeChatMsg{" +
|
||||
"packageName='" + packageName + '\'' +
|
||||
", appName='" + appName + '\'' +
|
||||
", title='" + title + '\'' +
|
||||
", sender='" + sender + '\'' +
|
||||
", message='" + message + '\'' +
|
||||
", currentTime='" + currentTime + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@ import com.nbee.echolink.broadcast.HeartbeatAlarmReceiver;
|
|||
import com.nbee.echolink.model.CallInfo;
|
||||
import com.nbee.echolink.model.DeviceInfo;
|
||||
import com.nbee.echolink.model.SMSInfo;
|
||||
import com.nbee.echolink.model.WeChatMsg;
|
||||
import com.nbee.echolink.response.ApiResponse;
|
||||
import com.nbee.echolink.utils.DeviceInfoUtils;
|
||||
import com.nbee.echolink.utils.NetworkUtil;
|
||||
|
|
@ -104,6 +105,10 @@ public class MonitorService extends Service {
|
|||
networkUtil.postRequest(smsInfo);
|
||||
}
|
||||
|
||||
public void sendWeChatMsg(WeChatMsg weChatMsg){
|
||||
networkUtil.postRequest(weChatMsg);
|
||||
}
|
||||
|
||||
private boolean checkNullString(String a, String b){
|
||||
if (a == null || b == null){
|
||||
return true;
|
||||
|
|
@ -126,6 +131,7 @@ public class MonitorService extends Service {
|
|||
// 创建通知
|
||||
Notification notification = new NotificationCompat.Builder(this, "channel_id")
|
||||
.setContentTitle(getString(R.string.notification_title))
|
||||
//.setContentText("sdads")
|
||||
.setSmallIcon(R.drawable.ic_notification) // 确保您有这个图标
|
||||
.build();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
package com.nbee.echolink.service;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.os.Bundle;
|
||||
import android.service.notification.NotificationListenerService;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.util.Log;
|
||||
|
||||
import com.nbee.echolink.model.WeChatMsg;
|
||||
import com.nbee.echolink.utils.HandleNoticeUtils;
|
||||
import com.nbee.echolink.utils.NetworkUtil;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
|
||||
public class NotificationListener extends NotificationListenerService {
|
||||
private static final String TAG = "NotificationListener";
|
||||
private static final List<String> notAllowList = Arrays.asList("com.github.kr328.clash","com.google.android.dialer",
|
||||
"com.google.android.apps.messaging");
|
||||
private HandleNoticeUtils handleNoticeUtils;
|
||||
private NetworkUtil networkUtil;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
handleNoticeUtils = new HandleNoticeUtils(this);
|
||||
networkUtil = new NetworkUtil(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationPosted(StatusBarNotification sbn) {
|
||||
String packageName = sbn.getPackageName();
|
||||
if (notAllowList.contains(packageName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Bundle extras = sbn.getNotification().extras;
|
||||
String title = extras.getString(Notification.EXTRA_TITLE);
|
||||
String content = extras.getString(Notification.EXTRA_TEXT);
|
||||
String tickerText = sbn.getNotification().tickerText != null ? sbn.getNotification().tickerText.toString() : "";
|
||||
Timber.d("packageName: %s,title: %s,content: %s,tickerText: %s",packageName,title,content,tickerText);
|
||||
|
||||
String appName = handleNoticeUtils.messageHandle(packageName);
|
||||
if ("微信".equals(appName) && tickerText.contains(":")) {
|
||||
String[] parts = tickerText.split(":", 2);
|
||||
WeChatMsg weChatMsg = new WeChatMsg();
|
||||
weChatMsg.setPackageName(packageName);
|
||||
weChatMsg.setSender(parts[0]);
|
||||
weChatMsg.setMessage(parts.length > 1 ? parts[1] : "");
|
||||
weChatMsg.setTitle(title);
|
||||
weChatMsg.setAppName(appName);
|
||||
weChatMsg.setCurrentTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(new Date()));
|
||||
|
||||
Timber.d("准备发送微信消息: %s", weChatMsg);
|
||||
// 异步执行网络请求
|
||||
networkUtil.postRequest(weChatMsg);
|
||||
} else {
|
||||
Timber.d("非微信通知或TickerText格式不正确,已忽略");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onNotificationRemoved(StatusBarNotification sbn) {
|
||||
// 当通知被移除时调用
|
||||
Log.d(TAG, "通知被移除: " + sbn.getPackageName());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.nbee.echolink.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class HandleNoticeUtils {
|
||||
private SharedPreferencesManager spManager;
|
||||
private Context context;
|
||||
|
||||
public HandleNoticeUtils(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public String messageHandle(String packageName){
|
||||
String appName = null;
|
||||
spManager = new SharedPreferencesManager(context);
|
||||
String value = spManager.getString(packageName,"defaultValue");
|
||||
if (value.equals("defaultValue")){
|
||||
return appName;
|
||||
}
|
||||
appName = value;
|
||||
return appName;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import com.google.gson.Gson;
|
|||
import com.nbee.echolink.R;
|
||||
import com.nbee.echolink.model.CallInfo;
|
||||
import com.nbee.echolink.model.SMSInfo;
|
||||
import com.nbee.echolink.model.WeChatMsg;
|
||||
import com.nbee.echolink.response.ApiResponse;
|
||||
|
||||
|
||||
|
|
@ -22,6 +23,7 @@ public class NetworkUtil {
|
|||
private final String TAG = "NetworkUtil";
|
||||
private String callApiUrl;
|
||||
private String smsApiUrl;
|
||||
private String wechatApiUrl;
|
||||
private String accessToken;
|
||||
private Handler handler = new Handler();
|
||||
private static final int MAX_RETRIES = 3;
|
||||
|
|
@ -33,6 +35,7 @@ public class NetworkUtil {
|
|||
public NetworkUtil(Context context) {
|
||||
callApiUrl = context.getResources().getString(R.string.call_api_url);
|
||||
smsApiUrl = context.getResources().getString(R.string.message_api_url);
|
||||
wechatApiUrl= context.getResources().getString(R.string.send_wechat_msg_api_url);
|
||||
accessToken = context.getResources().getString(R.string.access_token);
|
||||
}
|
||||
|
||||
|
|
@ -42,6 +45,8 @@ public class NetworkUtil {
|
|||
postRequestWithRetry(dataObject, 0, callApiUrl);
|
||||
} else if (dataObject instanceof SMSInfo) {
|
||||
postRequestWithRetry(dataObject, 0, smsApiUrl);
|
||||
} else if (dataObject instanceof WeChatMsg){
|
||||
postRequestWithRetry(dataObject,0,wechatApiUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -73,6 +78,7 @@ public class NetworkUtil {
|
|||
// ... 处理响应 ...
|
||||
Gson gson1 = new Gson();
|
||||
ApiResponse apiResponse = gson1.fromJson(response.body().string(), ApiResponse.class);
|
||||
Timber.d("ApiResponse" + apiResponse);
|
||||
if (apiResponse.getCode().equals(0)){
|
||||
Timber.d("Received response from " + apiUrl + ": " + apiResponse.getCode() + " - " + apiResponse.getMsg());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ package com.nbee.echolink.utils;
|
|||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.provider.Settings;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.core.app.ActivityCompat;
|
||||
|
|
@ -17,7 +19,7 @@ import timber.log.Timber;
|
|||
|
||||
public class PermissionUtils {
|
||||
private static final int PERMISSION_REQUEST_CODE = 1;
|
||||
private Activity activity;
|
||||
private final Activity activity;
|
||||
|
||||
public PermissionUtils(Activity activity) {
|
||||
this.activity = activity;
|
||||
|
|
@ -30,11 +32,10 @@ public class PermissionUtils {
|
|||
Manifest.permission.READ_CALL_LOG,
|
||||
Manifest.permission.READ_CONTACTS,
|
||||
Manifest.permission.RECEIVE_SMS
|
||||
|
||||
};
|
||||
|
||||
if (!hasPermissions(permissions)) {
|
||||
Timber.d("请求以下权限:\n" + Arrays.toString(permissions));
|
||||
Timber.d("请求以下权限: %s", Arrays.toString(permissions));
|
||||
ActivityCompat.requestPermissions(activity, permissions, PERMISSION_REQUEST_CODE);
|
||||
}
|
||||
}
|
||||
|
|
@ -42,7 +43,7 @@ public class PermissionUtils {
|
|||
private boolean hasPermissions(String... permissions) {
|
||||
for (String permission : permissions) {
|
||||
if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
|
||||
Timber.d("缺少权限:\n" + permission);
|
||||
Timber.d("缺少权限: %s", permission);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -62,8 +63,8 @@ public class PermissionUtils {
|
|||
|
||||
if (deniedPermissions.length() > 0) {
|
||||
// 显示对话框
|
||||
Timber.d("权限被拒绝:" + deniedPermissions.toString());
|
||||
showAlert("以下权限被拒绝:\n" + deniedPermissions.toString());
|
||||
Timber.d("权限被拒绝:%s", deniedPermissions);
|
||||
showAlert("以下权限被拒绝:\n" + deniedPermissions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -71,15 +72,27 @@ public class PermissionUtils {
|
|||
private void showAlert(String message) {
|
||||
new AlertDialog.Builder(activity)
|
||||
.setMessage(message)
|
||||
.setPositiveButton("确认", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
})
|
||||
.setPositiveButton("确认", (dialog, which) -> dialog.dismiss())
|
||||
.create()
|
||||
.show();
|
||||
}
|
||||
private void showToast(String message) {
|
||||
Toast.makeText(activity, message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
public boolean isNotificationServiceEnabled(Context context) {
|
||||
String packageName = context.getPackageName();
|
||||
String flat = Settings.Secure.getString(context.getContentResolver(), "enabled_notification_listeners");
|
||||
if (flat != null && !flat.isEmpty()) {
|
||||
final String[] activeListeners = flat.split(":");
|
||||
for (String activeListener : activeListeners) {
|
||||
ComponentName cn = ComponentName.unflattenFromString(activeListener);
|
||||
if (cn != null && cn.getPackageName().equals(packageName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
package com.nbee.echolink.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
public class SharedPreferencesManager {
|
||||
|
||||
private static final String PREFS_NAME = "MyAppPrefs";
|
||||
private SharedPreferences sharedPreferences;
|
||||
|
||||
public SharedPreferencesManager(Context context) {
|
||||
this.sharedPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
public void putString(String key, String value) {
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putString(key, value);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public String getString(String key,String defaultValue) {
|
||||
return sharedPreferences.getString(key,defaultValue);
|
||||
}
|
||||
|
||||
public void putBoolean(String key, boolean value) {
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putBoolean(key, value);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public boolean getBoolean(String key, boolean defaultValue) {
|
||||
return sharedPreferences.getBoolean(key, defaultValue);
|
||||
}
|
||||
|
||||
public void putInt(String key, int value) {
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putInt(key, value);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public int getInt(String key, int defaultValue) {
|
||||
return sharedPreferences.getInt(key, defaultValue);
|
||||
}
|
||||
|
||||
// 添加更多的方法来处理其他类型,如 putLong, getLong, putFloat, getFloat 等。
|
||||
|
||||
public void remove(String key) {
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.remove(key);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public void clearAll() {
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.clear();
|
||||
editor.apply();
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
<string name="call_api_url">https://api.kimgo.cn/api/call</string>
|
||||
<string name="message_api_url">https://api.kimgo.cn/api/sms</string>
|
||||
<string name="heart_beat_url">https://api.kimgo.cn/heartbeat</string>
|
||||
<string name="send_wechat_msg_api_url">https://api.kimgo.cn/api/wechat</string>
|
||||
<string name="SN">XCCS3IK75OCM</string>
|
||||
<string name="access_token">gKGCDSgWV82XbU0H</string>
|
||||
<string name="notification_title">监控服务运行中</string>
|
||||
|
|
|
|||
Loading…
Reference in New Issue