first commit
This commit is contained in:
11
app/src/main/java/com/nbee/echolink/DeviceInfo.java
Normal file
11
app/src/main/java/com/nbee/echolink/DeviceInfo.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package com.nbee.echolink;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
public class DeviceInfo {
|
||||
|
||||
public static int getApiVersion() {
|
||||
return Build.VERSION.SDK_INT;
|
||||
}
|
||||
|
||||
}
|
||||
28
app/src/main/java/com/nbee/echolink/MainActivity.java
Normal file
28
app/src/main/java/com/nbee/echolink/MainActivity.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package com.nbee.echolink;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
import android.telephony.PhoneStateListener;
|
||||
import android.telephony.TelephonyManager;
|
||||
import com.nbee.echolink.broadcast.PhoneCallReceiver;
|
||||
import com.nbee.echolink.broadcast.SMSReceiver;
|
||||
import com.nbee.echolink.service.MonitorService;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
private final String TAG = "MainActivity";
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
// 启动MonitorService服务
|
||||
Intent serviceIntent = new Intent(this, MonitorService.class);
|
||||
startService(serviceIntent);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.nbee.echolink.broadcast;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.nbee.echolink.service.MonitorService;
|
||||
|
||||
public class BootCompletedReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
|
||||
// 启动您的服务或活动
|
||||
Intent serviceIntent = new Intent(context, MonitorService.class);
|
||||
context.startService(serviceIntent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.nbee.echolink.broadcast;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.telephony.PhoneStateListener;
|
||||
import android.telephony.TelephonyManager;
|
||||
|
||||
import com.nbee.echolink.service.MonitorService;
|
||||
|
||||
public class PhoneCallReceiver extends BroadcastReceiver {
|
||||
private static final String TAG = "PhoneCallReceiver";
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
if (tm != null) {
|
||||
tm.listen(new PhoneStateListener() {
|
||||
@Override
|
||||
public void onCallStateChanged(int state, String incomingNumber) {
|
||||
super.onCallStateChanged(state, incomingNumber);
|
||||
if (state == TelephonyManager.CALL_STATE_RINGING) {
|
||||
// 来电号码
|
||||
Intent serviceIntent = new Intent(context, MonitorService.class);
|
||||
serviceIntent.putExtra("incomingNumber", incomingNumber);
|
||||
context.startService(serviceIntent);
|
||||
}
|
||||
}
|
||||
}, PhoneStateListener.LISTEN_CALL_STATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.nbee.echolink.broadcast;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.telephony.SmsMessage;
|
||||
import android.util.Log;
|
||||
|
||||
import com.nbee.echolink.service.MonitorService;
|
||||
|
||||
public class SMSReceiver extends BroadcastReceiver {
|
||||
|
||||
private static final String TAG = "SMSReceiver";
|
||||
private static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (SMS_RECEIVED_ACTION.equals(intent.getAction())) {
|
||||
Bundle bundle = intent.getExtras();
|
||||
if (bundle != null) {
|
||||
Object[] pdus = (Object[]) bundle.get("pdus");
|
||||
if (pdus != null) {
|
||||
StringBuilder fullMessage = new StringBuilder();
|
||||
String sender = null;
|
||||
|
||||
for (Object pdu : pdus) {
|
||||
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdu);
|
||||
if (sender == null) {
|
||||
// 只需要从第一部分获取发件人号码
|
||||
sender = smsMessage.getDisplayOriginatingAddress();
|
||||
}
|
||||
// 拼接每个部分的消息内容
|
||||
fullMessage.append(smsMessage.getMessageBody());
|
||||
}
|
||||
|
||||
Log.d(TAG, "Sender: " + sender + ", Message: " + fullMessage.toString());
|
||||
// 在这里处理完整的短信内容
|
||||
Intent serviceIntent = new Intent(context, MonitorService.class);
|
||||
serviceIntent.putExtra("sender", sender);
|
||||
serviceIntent.putExtra("messageBody", fullMessage.toString());
|
||||
context.startService(serviceIntent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
40
app/src/main/java/com/nbee/echolink/model/CallInfo.java
Normal file
40
app/src/main/java/com/nbee/echolink/model/CallInfo.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package com.nbee.echolink.model;
|
||||
|
||||
|
||||
|
||||
public class CallInfo {
|
||||
private String phoneNumber;
|
||||
private String callTime;
|
||||
|
||||
public CallInfo() {
|
||||
}
|
||||
|
||||
public CallInfo(String phoneNumber, String callTime) {
|
||||
this.phoneNumber = phoneNumber;
|
||||
this.callTime = callTime;
|
||||
}
|
||||
|
||||
public String getPhoneNumber() {
|
||||
return phoneNumber;
|
||||
}
|
||||
|
||||
public void setPhoneNumber(String phoneNumber) {
|
||||
this.phoneNumber = phoneNumber;
|
||||
}
|
||||
|
||||
public String getCallTime() {
|
||||
return callTime;
|
||||
}
|
||||
|
||||
public void setCallTime(String callTime) {
|
||||
this.callTime = callTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CallInfo{" +
|
||||
"phoneNumber='" + phoneNumber + '\'' +
|
||||
", callTime='" + callTime + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
52
app/src/main/java/com/nbee/echolink/model/SMSInfo.java
Normal file
52
app/src/main/java/com/nbee/echolink/model/SMSInfo.java
Normal file
@@ -0,0 +1,52 @@
|
||||
package com.nbee.echolink.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
public class SMSInfo {
|
||||
private String smsNumber;
|
||||
private String smsAcceptanceTime;
|
||||
private String smsContent;
|
||||
|
||||
public SMSInfo() {
|
||||
}
|
||||
|
||||
public SMSInfo(String smsNumber, String smsAcceptanceTime, String smsContent) {
|
||||
this.smsNumber = smsNumber;
|
||||
this.smsAcceptanceTime = smsAcceptanceTime;
|
||||
this.smsContent = smsContent;
|
||||
}
|
||||
|
||||
public String getSmsNumber() {
|
||||
return smsNumber;
|
||||
}
|
||||
|
||||
public void setSmsNumber(String smsNumber) {
|
||||
this.smsNumber = smsNumber;
|
||||
}
|
||||
|
||||
public String getSmsAcceptanceTime() {
|
||||
return smsAcceptanceTime;
|
||||
}
|
||||
|
||||
public void setSmsAcceptanceTime(String smsAcceptanceTime) {
|
||||
this.smsAcceptanceTime = smsAcceptanceTime;
|
||||
}
|
||||
|
||||
public String getSmsContent() {
|
||||
return smsContent;
|
||||
}
|
||||
|
||||
public void setSmsContent(String smsContent) {
|
||||
this.smsContent = smsContent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SMSInfo{" +
|
||||
"smsNumber='" + smsNumber + '\'' +
|
||||
", smsAcceptanceTime='" + smsAcceptanceTime + '\'' +
|
||||
", smsContent='" + smsContent + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.nbee.echolink.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
public class ApiResponse<T> {
|
||||
private String code;
|
||||
|
||||
/** Response message. */
|
||||
private String msg;
|
||||
|
||||
/** Response timestamp. */
|
||||
private Long timestamp;
|
||||
|
||||
/** Response data. */
|
||||
private T data;
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public Long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(Long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(T data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ApiResponse{" +
|
||||
"code='" + code + '\'' +
|
||||
", msg='" + msg + '\'' +
|
||||
", timestamp=" + timestamp +
|
||||
", data=" + data +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
121
app/src/main/java/com/nbee/echolink/service/MonitorService.java
Normal file
121
app/src/main/java/com/nbee/echolink/service/MonitorService.java
Normal file
@@ -0,0 +1,121 @@
|
||||
package com.nbee.echolink.service;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import com.nbee.echolink.R;
|
||||
import com.nbee.echolink.model.CallInfo;
|
||||
import com.nbee.echolink.model.SMSInfo;
|
||||
import com.nbee.echolink.utils.NetworkUtil;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class MonitorService extends Service {
|
||||
private NetworkUtil networkUtil;
|
||||
private static final String TAG = "MonitorService";
|
||||
private String lastPhoneNumber = null;
|
||||
private long lastCallTime = 0;
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
startForegroundService();
|
||||
networkUtil = new NetworkUtil(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (intent != null) {
|
||||
if (intent.hasExtra("incomingNumber")) {
|
||||
String incomingNumber = intent.getStringExtra("incomingNumber");
|
||||
Log.i(TAG, "获取到来电信息,号码: "+ incomingNumber);
|
||||
sendCallInfoToServer(incomingNumber);
|
||||
} else if (intent.hasExtra("sender") && intent.hasExtra("messageBody")) {
|
||||
String sender = intent.getStringExtra("sender");
|
||||
String messageBody = intent.getStringExtra("messageBody");
|
||||
Log.i(TAG, "获取到短信信息,号码: "+ sender);
|
||||
sendSmsInfoToServer(sender, messageBody);
|
||||
}
|
||||
}
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
private void sendCallInfoToServer(String incomingNumber) {
|
||||
if (incomingNumber.equals("null") || incomingNumber == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
long currentTimeMillis = System.currentTimeMillis();
|
||||
if (incomingNumber.equals(lastPhoneNumber) && (currentTimeMillis - lastCallTime) < 70000) {
|
||||
// 如果电话号码与上次相同,且在70秒之内,则不执行请求
|
||||
Log.i(TAG, "sendCallInfoToServer: 电话号码与上次相同,且在70秒之内,不执行请求.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新存储的电话号码和时间戳
|
||||
lastPhoneNumber = incomingNumber;
|
||||
lastCallTime = currentTimeMillis;
|
||||
String currentTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
|
||||
|
||||
CallInfo callInfo = new CallInfo();
|
||||
callInfo.setCallTime(currentTime);
|
||||
callInfo.setPhoneNumber(incomingNumber);
|
||||
networkUtil.postRequest(callInfo);
|
||||
}
|
||||
|
||||
private void sendSmsInfoToServer(String sender,String messageBody){
|
||||
if (checkNullString(sender,messageBody)){
|
||||
return;
|
||||
}
|
||||
String currentTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
|
||||
SMSInfo smsInfo = new SMSInfo();
|
||||
smsInfo.setSmsNumber(sender);
|
||||
smsInfo.setSmsContent(messageBody);
|
||||
smsInfo.setSmsAcceptanceTime(currentTime);
|
||||
networkUtil.postRequest(smsInfo);
|
||||
}
|
||||
|
||||
private boolean checkNullString(String a, String b){
|
||||
if (a == null || b == null){
|
||||
return true;
|
||||
}
|
||||
if (a.equals("null") || b.equals("null")){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void startForegroundService() {
|
||||
// 创建通知频道(仅在API 26及以上版本中需要)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = new NotificationChannel("channel_id", "Channel Name", NotificationManager.IMPORTANCE_DEFAULT);
|
||||
NotificationManager notificationManager = getSystemService(NotificationManager.class);
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
// 创建通知
|
||||
Notification notification = new NotificationCompat.Builder(this, "channel_id")
|
||||
.setContentTitle("服务运行中")
|
||||
.setContentText("EchoLink正在运行")
|
||||
.setSmallIcon(R.drawable.ic_notification) // 确保您有这个图标
|
||||
.build();
|
||||
|
||||
// 启动前台服务
|
||||
startForeground(1, notification);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null; // 不提供绑定服务的接口
|
||||
}
|
||||
}
|
||||
95
app/src/main/java/com/nbee/echolink/utils/NetworkUtil.java
Normal file
95
app/src/main/java/com/nbee/echolink/utils/NetworkUtil.java
Normal file
@@ -0,0 +1,95 @@
|
||||
package com.nbee.echolink.utils;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
|
||||
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.response.ApiResponse;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
|
||||
public class NetworkUtil {
|
||||
private final String TAG = "NetworkUtil";
|
||||
private String callApiUrl;
|
||||
private String smsApiUrl;
|
||||
private String accessToken;
|
||||
private Handler handler = new Handler();
|
||||
private static final int MAX_RETRIES = 3;
|
||||
private static final long RETRY_DELAY_MS = 2000; // 重试延迟,例如2秒
|
||||
|
||||
// API URL
|
||||
public NetworkUtil(Context context) {
|
||||
callApiUrl = context.getResources().getString(R.string.call_api_url);
|
||||
smsApiUrl = context.getResources().getString(R.string.message_api_url);
|
||||
accessToken = context.getResources().getString(R.string.access_token);
|
||||
}
|
||||
|
||||
public <T> void postRequest(T dataObject) {
|
||||
if (dataObject instanceof CallInfo) {
|
||||
postRequestWithRetry(dataObject, 0,callApiUrl);
|
||||
} else if (dataObject instanceof SMSInfo) {
|
||||
postRequestWithRetry(dataObject, 0,smsApiUrl);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void postRequestWithRetry(T dataObject, int retryCount,String apiUrl) {
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
// ... 构建请求 ...
|
||||
Request request = buildRequest(dataObject,apiUrl);
|
||||
|
||||
client.newCall(request).enqueue(new okhttp3.Callback() {
|
||||
@Override
|
||||
public void onFailure(okhttp3.Call call, IOException e) {
|
||||
if (retryCount < MAX_RETRIES) {
|
||||
handler.postDelayed(() -> postRequestWithRetry(dataObject, retryCount + 1,apiUrl), RETRY_DELAY_MS);
|
||||
} else {
|
||||
Log.e(TAG, "onFailure: Failed after " + MAX_RETRIES + " attempts", e);
|
||||
// 超出重试次数,处理失败情况
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {
|
||||
if (!response.isSuccessful()) {
|
||||
// 在这里处理响应错误
|
||||
Log.d("onResponse", response.message());
|
||||
throw new IOException("Unexpected code " + response);
|
||||
}
|
||||
// ... 处理响应 ...
|
||||
Gson gson1 = new Gson();
|
||||
ApiResponse apiResponse = gson1.fromJson(response.body().string(), ApiResponse.class);
|
||||
if (apiResponse.getCode().equals(0)){
|
||||
Log.i(TAG, "onResponse ResponseCode: " + apiResponse.getCode() + "ResponseMessage" + apiResponse.getMsg());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private <T>Request buildRequest(T dataObject,String apiUrl){
|
||||
Gson gson = new Gson();
|
||||
// 将对象转换为JSON字符串
|
||||
String json = gson.toJson(dataObject);
|
||||
|
||||
// 创建请求体
|
||||
MediaType JSON = MediaType.get("application/json; charset=utf-8");
|
||||
RequestBody body = RequestBody.create(json, JSON);
|
||||
|
||||
// 构建请求,并设置请求头
|
||||
Request request = new Request.Builder()
|
||||
.url(apiUrl)
|
||||
.addHeader("accessToken", accessToken) // 使用加载的accessToken
|
||||
.addHeader("Content-Type", "application/json")
|
||||
.post(body)
|
||||
.build();
|
||||
|
||||
return request;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user