mirror of
https://github.com/pppscn/SmsForwarder
synced 2025-08-03 01:17:41 +08:00
新增:smshub主被动模式
This commit is contained in:
parent
88768342c2
commit
ff61e2a735
343
app/build.gradle
343
app/build.gradle
@ -1,170 +1,173 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
def keyProps = new Properties()
|
def keyProps = new Properties()
|
||||||
def keyPropsFile = rootProject.file('keystore/keystore.properties')
|
def keyPropsFile = rootProject.file('keystore/keystore.properties')
|
||||||
if (keyPropsFile.exists()) {
|
if (keyPropsFile.exists()) {
|
||||||
keyProps.load(new FileInputStream(keyPropsFile))
|
keyProps.load(new FileInputStream(keyPropsFile))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 读取version.properties
|
// 读取version.properties
|
||||||
def versionProps = new Properties()
|
def versionProps = new Properties()
|
||||||
def versionPropsFile = rootProject.file('version.properties')
|
def versionPropsFile = rootProject.file('version.properties')
|
||||||
if (versionPropsFile.exists()) {
|
if (versionPropsFile.exists()) {
|
||||||
versionProps.load(new FileInputStream(versionPropsFile))
|
versionProps.load(new FileInputStream(versionPropsFile))
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
buildToolsVersion '30.0.3'
|
buildToolsVersion '30.0.3'
|
||||||
compileSdkVersion 30
|
compileSdkVersion 30
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility 11
|
sourceCompatibility 11
|
||||||
targetCompatibility 11
|
targetCompatibility 11
|
||||||
}
|
}
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.idormy.sms.forwarder"
|
applicationId "com.idormy.sms.forwarder"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode versionProps['versionCode'].toInteger()
|
versionCode versionProps['versionCode'].toInteger()
|
||||||
versionName versionProps['versionName']
|
versionName versionProps['versionName']
|
||||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||||
}
|
}
|
||||||
lintOptions {
|
lintOptions {
|
||||||
checkReleaseBuilds false
|
checkReleaseBuilds false
|
||||||
}
|
}
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
release {
|
release {
|
||||||
keyAlias keyProps['keyAlias']
|
keyAlias keyProps['keyAlias']
|
||||||
keyPassword keyProps['keyPassword']
|
keyPassword keyProps['keyPassword']
|
||||||
storeFile keyProps['storeFile'] ? file(keyProps['storeFile']) : null
|
storeFile keyProps['storeFile'] ? file(keyProps['storeFile']) : null
|
||||||
storePassword keyProps['storePassword']
|
storePassword keyProps['storePassword']
|
||||||
}
|
}
|
||||||
debug {
|
debug {
|
||||||
keyAlias keyProps['keyAlias']
|
keyAlias keyProps['keyAlias']
|
||||||
keyPassword keyProps['keyPassword']
|
keyPassword keyProps['keyPassword']
|
||||||
storeFile keyProps['storeFile'] ? file(keyProps['storeFile']) : null
|
storeFile keyProps['storeFile'] ? file(keyProps['storeFile']) : null
|
||||||
storePassword keyProps['storePassword']
|
storePassword keyProps['storePassword']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
signingConfig signingConfigs.release
|
signingConfig signingConfigs.release
|
||||||
}
|
}
|
||||||
debug {
|
debug {
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
signingConfig signingConfigs.debug
|
signingConfig signingConfigs.debug
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//apk file name
|
//apk file name
|
||||||
android.applicationVariants.all { variant ->
|
android.applicationVariants.all { variant ->
|
||||||
variant.outputs.all {
|
variant.outputs.all {
|
||||||
//def date = new Date().format("yyyyMMdd" , TimeZone.getTimeZone("Asia/Shanghai"))
|
//def date = new Date().format("yyyyMMdd" , TimeZone.getTimeZone("Asia/Shanghai"))
|
||||||
def date = new Date().format("yyyyMMdd", TimeZone.getTimeZone("GMT+08"))
|
def date = new Date().format("yyyyMMdd", TimeZone.getTimeZone("GMT+08"))
|
||||||
if (variant.buildType.name == 'debug') {
|
if (variant.buildType.name == 'debug') {
|
||||||
outputFileName = "SmsForwarder_debug_${date}_${versionName}.apk"
|
outputFileName = "SmsForwarder_debug_${date}_${versionName}.apk"
|
||||||
}
|
}
|
||||||
if (variant.buildType.name == 'release') {
|
if (variant.buildType.name == 'release') {
|
||||||
outputFileName = "SmsForwarder_release_${date}_${versionName}.apk"
|
outputFileName = "SmsForwarder_release_${date}_${versionName}.apk"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
packagingOptions {
|
packagingOptions {
|
||||||
exclude 'META-INF/DEPENDENCIES.txt'
|
exclude 'META-INF/DEPENDENCIES.txt'
|
||||||
exclude 'META-INF/LICENSE.txt'
|
exclude 'META-INF/LICENSE.txt'
|
||||||
exclude 'META-INF/NOTICE.txt'
|
exclude 'META-INF/NOTICE.txt'
|
||||||
exclude 'META-INF/NOTICE'
|
exclude 'META-INF/NOTICE'
|
||||||
exclude 'META-INF/LICENSE'
|
exclude 'META-INF/LICENSE'
|
||||||
exclude 'META-INF/DEPENDENCIES'
|
exclude 'META-INF/DEPENDENCIES'
|
||||||
exclude 'META-INF/notice.txt'
|
exclude 'META-INF/notice.txt'
|
||||||
exclude 'META-INF/license.txt'
|
exclude 'META-INF/license.txt'
|
||||||
exclude 'META-INF/dependencies.txt'
|
exclude 'META-INF/dependencies.txt'
|
||||||
exclude 'META-INF/LGPL2.1'
|
exclude 'META-INF/LGPL2.1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
task upgradeVersion {
|
task upgradeVersion {
|
||||||
group 'help'
|
group 'help'
|
||||||
description '构建新版本'
|
description '构建新版本'
|
||||||
doLast {
|
doLast {
|
||||||
println("---自动升级版本号---\n")
|
println("---自动升级版本号---\n")
|
||||||
String oldVersionCode = versionProps['versionCode']
|
String oldVersionCode = versionProps['versionCode']
|
||||||
String oldVersionName = versionProps['versionName']
|
String oldVersionName = versionProps['versionName']
|
||||||
if (oldVersionCode == null || oldVersionName == null ||
|
if (oldVersionCode == null || oldVersionName == null ||
|
||||||
oldVersionCode.isEmpty() || oldVersionName.isEmpty()) {
|
oldVersionCode.isEmpty() || oldVersionName.isEmpty()) {
|
||||||
println("error:版本号不能为空")
|
println("error:版本号不能为空")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
versionProps['versionCode'] = String.valueOf(versionProps['versionCode'].toInteger() + 1)
|
versionProps['versionCode'] = String.valueOf(versionProps['versionCode'].toInteger() + 1)
|
||||||
String str = versionProps['versionName'].toString()
|
String str = versionProps['versionName'].toString()
|
||||||
versionProps['versionName'] = str.substring(0, str.lastIndexOf('.') + 1) +
|
versionProps['versionName'] = str.substring(0, str.lastIndexOf('.') + 1) +
|
||||||
(str.substring(str.lastIndexOf('.') + 1).toInteger() + 1)
|
(str.substring(str.lastIndexOf('.') + 1).toInteger() + 1)
|
||||||
String tip =
|
String tip =
|
||||||
"版本号从$oldVersionName($oldVersionCode)升级到${versionProps['versionName']}(${versionProps['versionCode']})"
|
"版本号从$oldVersionName($oldVersionCode)升级到${versionProps['versionName']}(${versionProps['versionCode']})"
|
||||||
println(tip)
|
println(tip)
|
||||||
|
|
||||||
def writer = new FileWriter(versionPropsFile)
|
def writer = new FileWriter(versionPropsFile)
|
||||||
versionProps.store(writer, null)
|
versionProps.store(writer, null)
|
||||||
writer.flush()
|
writer.flush()
|
||||||
writer.close()
|
writer.close()
|
||||||
def tag = "v${versionProps['versionName']}"
|
def tag = "v${versionProps['versionName']}"
|
||||||
cmdExecute("git pull")
|
cmdExecute("git pull")
|
||||||
cmdExecute("git add version.properties")
|
cmdExecute("git add version.properties")
|
||||||
cmdExecute("git commit -m \"版本号升级为:$tag\"")
|
cmdExecute("git commit -m \"版本号升级为:$tag\"")
|
||||||
cmdExecute("git push origin")
|
cmdExecute("git push origin")
|
||||||
cmdExecute("git tag $tag")
|
cmdExecute("git tag $tag")
|
||||||
cmdExecute("git push origin $tag")
|
cmdExecute("git push origin $tag")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmdExecute(String cmd) {
|
void cmdExecute(String cmd) {
|
||||||
println "\n执行$cmd"
|
println "\n执行$cmd"
|
||||||
println cmd.execute().text
|
println cmd.execute().text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
|
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
|
||||||
implementation 'com.google.firebase:firebase-crashlytics-buildtools:2.5.2'
|
implementation 'com.google.firebase:firebase-crashlytics-buildtools:2.5.2'
|
||||||
testImplementation 'junit:junit:4.+'
|
testImplementation 'junit:junit:4.+'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||||
|
|
||||||
//okhttp
|
//okhttp
|
||||||
implementation 'com.squareup.okhttp3:okhttp:4.9.1'
|
implementation 'com.squareup.okhttp3:okhttp:4.9.1'
|
||||||
implementation 'com.squareup.okio:okio:2.10.0'
|
implementation 'com.squareup.okio:okio:2.10.0'
|
||||||
|
|
||||||
//fastjson
|
//fastjson
|
||||||
implementation "com.alibaba:fastjson:1.2.78"
|
implementation "com.alibaba:fastjson:1.2.78"
|
||||||
|
|
||||||
//友盟统计SDK
|
//友盟统计SDK
|
||||||
implementation 'com.umeng.umsdk:common:9.4.4'// 必选
|
implementation 'com.umeng.umsdk:common:9.4.4'// 必选
|
||||||
implementation 'com.umeng.umsdk:asms:1.4.1'// 必选
|
implementation 'com.umeng.umsdk:asms:1.4.1'// 必选
|
||||||
//implementation 'com.umeng.umsdk:apm:1.4.2' // 错误分析升级为独立SDK,看crash数据请一定集成,可选
|
//implementation 'com.umeng.umsdk:apm:1.4.2' // 错误分析升级为独立SDK,看crash数据请一定集成,可选
|
||||||
|
|
||||||
//XUpdate
|
//XUpdate
|
||||||
implementation 'com.github.xuexiangjys:XUpdate:2.1.1'
|
implementation 'com.github.xuexiangjys:XUpdate:2.1.1'
|
||||||
implementation 'com.github.xuexiangjys.XUpdateAPI:xupdate-easy:1.0.1'
|
implementation 'com.github.xuexiangjys.XUpdateAPI:xupdate-easy:1.0.1'
|
||||||
implementation 'com.github.xuexiangjys.XUpdateAPI:xupdate-downloader-aria:1.0.1'
|
implementation 'com.github.xuexiangjys.XUpdateAPI:xupdate-downloader-aria:1.0.1'
|
||||||
|
|
||||||
//EmailKit
|
//EmailKit
|
||||||
implementation 'com.github.mailhu:emailkit:4.2.2'
|
implementation 'com.github.mailhu:emailkit:4.2.2'
|
||||||
|
|
||||||
//Lombok
|
//Lombok
|
||||||
//noinspection AnnotationProcessorOnCompilePath
|
//noinspection AnnotationProcessorOnCompilePath
|
||||||
compileOnly 'org.projectlombok:lombok:1.18.20'
|
compileOnly 'org.projectlombok:lombok:1.18.20'
|
||||||
annotationProcessor 'org.projectlombok:lombok:1.18.20'
|
annotationProcessor 'org.projectlombok:lombok:1.18.20'
|
||||||
|
|
||||||
//RxJava
|
//RxJava
|
||||||
implementation 'io.reactivex.rxjava3:rxjava:3.1.1'
|
implementation 'io.reactivex.rxjava3:rxjava:3.1.1'
|
||||||
|
|
||||||
//AndroidAsync
|
//AndroidAsync
|
||||||
implementation 'com.koushikdutta.async:androidasync:3.1.0'
|
implementation 'com.koushikdutta.async:androidasync:3.1.0'
|
||||||
|
|
||||||
// 权限请求框架:https://github.com/getActivity/XXPermissions
|
// 权限请求框架:https://github.com/getActivity/XXPermissions
|
||||||
implementation 'com.github.getActivity:XXPermissions:13.2'
|
implementation 'com.github.getActivity:XXPermissions:13.2'
|
||||||
}
|
//jetty
|
||||||
|
implementation "org.eclipse.jetty:jetty-server:$jetty_version"
|
||||||
|
implementation "org.eclipse.jetty:jetty-servlet:$jetty_version"
|
||||||
|
}
|
||||||
|
@ -12,11 +12,11 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
import com.idormy.sms.forwarder.receiver.RebootBroadcastReceiver;
|
import com.idormy.sms.forwarder.receiver.RebootBroadcastReceiver;
|
||||||
|
import com.idormy.sms.forwarder.sender.HttpServer;
|
||||||
import com.idormy.sms.forwarder.utils.LogUtil;
|
import com.idormy.sms.forwarder.utils.LogUtil;
|
||||||
import com.idormy.sms.forwarder.utils.NetUtil;
|
import com.idormy.sms.forwarder.utils.NetUtil;
|
||||||
|
import com.idormy.sms.forwarder.utils.SettingUtil;
|
||||||
import com.idormy.sms.forwarder.view.IPEditText;
|
import com.idormy.sms.forwarder.view.IPEditText;
|
||||||
import com.koushikdutta.async.http.WebSocket;
|
|
||||||
import com.koushikdutta.async.http.server.AsyncHttpServer;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
@ -25,8 +25,6 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import okhttp3.Call;
|
import okhttp3.Call;
|
||||||
@ -38,9 +36,8 @@ import okhttp3.Response;
|
|||||||
public class CloneActivity extends AppCompatActivity {
|
public class CloneActivity extends AppCompatActivity {
|
||||||
private final String TAG = "CloneActivity";
|
private final String TAG = "CloneActivity";
|
||||||
private Context context;
|
private Context context;
|
||||||
private boolean isRunning = false;
|
|
||||||
private String serverIp;
|
private String serverIp;
|
||||||
private final String DATABASE_NAME = "sms_forwarder.db";
|
public static final String DATABASE_NAME = "sms_forwarder.db";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
@ -62,47 +59,46 @@ public class CloneActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
IPEditText textServerIp = findViewById(R.id.textServerIp);
|
IPEditText textServerIp = findViewById(R.id.textServerIp);
|
||||||
|
|
||||||
List<WebSocket> _sockets = new ArrayList<>();
|
|
||||||
AsyncHttpServer server = new AsyncHttpServer();
|
|
||||||
|
|
||||||
TextView sendTxt = findViewById(R.id.sendTxt);
|
TextView sendTxt = findViewById(R.id.sendTxt);
|
||||||
TextView receiveTxt = findViewById(R.id.receiveTxt);
|
TextView receiveTxt = findViewById(R.id.receiveTxt);
|
||||||
|
|
||||||
Button sendBtn = findViewById(R.id.sendBtn);
|
Button sendBtn = findViewById(R.id.sendBtn);
|
||||||
|
serverIp = NetUtil.getLocalIp(CloneActivity.this);
|
||||||
|
TextView ipText = findViewById(R.id.ipText);
|
||||||
|
ipText.setText(serverIp);
|
||||||
|
if (HttpServer.asRunning()) {
|
||||||
|
sendBtn.setText(R.string.stop);
|
||||||
|
sendTxt.setText(R.string.server_has_started);
|
||||||
|
textServerIp.setIP(serverIp);
|
||||||
|
} else {
|
||||||
|
sendBtn.setText(R.string.send);
|
||||||
|
sendTxt.setText(R.string.server_has_stopped);
|
||||||
|
}
|
||||||
sendBtn.setOnClickListener(v -> {
|
sendBtn.setOnClickListener(v -> {
|
||||||
if (NetUtil.NETWORK_WIFI != NetUtil.getNetWorkStatus()) {
|
if (!HttpServer.asRunning() && NetUtil.NETWORK_WIFI != NetUtil.getNetWorkStatus()) {
|
||||||
Toast.makeText(CloneActivity.this, R.string.no_wifi_network, Toast.LENGTH_SHORT).show();
|
Toast.makeText(CloneActivity.this, R.string.no_wifi_network, Toast.LENGTH_SHORT).show();
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
serverIp = NetUtil.getLocalIp(CloneActivity.this);
|
|
||||||
TextView ipText = findViewById(R.id.ipText);
|
|
||||||
ipText.setText(getString(R.string.local_ip) + serverIp);
|
|
||||||
}
|
}
|
||||||
if (!isRunning) {
|
SettingUtil.switchEnableHttpServer(!SettingUtil.getSwitchEnableHttpServer());
|
||||||
isRunning = true;
|
if (!HttpServer.update()) {
|
||||||
server.get("/", (request, response) -> {
|
SettingUtil.switchEnableHttpServer(!SettingUtil.getSwitchEnableHttpServer());
|
||||||
File file = context.getDatabasePath(DATABASE_NAME);
|
return;
|
||||||
response.getHeaders().add("Content-Disposition", "attachment;filename=" + DATABASE_NAME);
|
}
|
||||||
response.sendFile(file);
|
if (!HttpServer.asRunning()) {
|
||||||
});
|
|
||||||
server.listen(5000);
|
|
||||||
Toast.makeText(CloneActivity.this, R.string.server_has_started, Toast.LENGTH_SHORT).show();
|
|
||||||
sendTxt.setText(R.string.server_has_started);
|
|
||||||
textServerIp.setIP(serverIp);
|
|
||||||
sendBtn.setText(R.string.stop);
|
|
||||||
} else {
|
|
||||||
isRunning = false;
|
|
||||||
server.stop();
|
|
||||||
Toast.makeText(CloneActivity.this, R.string.server_has_stopped, Toast.LENGTH_SHORT).show();
|
|
||||||
sendTxt.setText(R.string.server_has_stopped);
|
sendTxt.setText(R.string.server_has_stopped);
|
||||||
textServerIp.setIP("");
|
textServerIp.setIP("");
|
||||||
sendBtn.setText(R.string.send);
|
sendBtn.setText(R.string.send);
|
||||||
|
} else {
|
||||||
|
sendTxt.setText(R.string.server_has_started);
|
||||||
|
textServerIp.setIP(serverIp);
|
||||||
|
sendBtn.setText(R.string.stop);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Button receiveBtn = findViewById(R.id.receiveBtn);
|
Button receiveBtn = findViewById(R.id.receiveBtn);
|
||||||
receiveBtn.setOnClickListener(v -> {
|
receiveBtn.setOnClickListener(v -> {
|
||||||
if (isRunning) {
|
if (HttpServer.asRunning()) {
|
||||||
receiveTxt.setText(R.string.sender_cannot_receive);
|
receiveTxt.setText(R.string.sender_cannot_receive);
|
||||||
Toast.makeText(CloneActivity.this, R.string.sender_cannot_receive, Toast.LENGTH_SHORT).show();
|
Toast.makeText(CloneActivity.this, R.string.sender_cannot_receive, Toast.LENGTH_SHORT).show();
|
||||||
return;
|
return;
|
||||||
|
@ -4,9 +4,7 @@ import android.annotation.SuppressLint;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.*;
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
@ -23,21 +21,15 @@ import androidx.appcompat.app.AppCompatActivity;
|
|||||||
|
|
||||||
import com.idormy.sms.forwarder.adapter.LogAdapter;
|
import com.idormy.sms.forwarder.adapter.LogAdapter;
|
||||||
import com.idormy.sms.forwarder.model.vo.LogVo;
|
import com.idormy.sms.forwarder.model.vo.LogVo;
|
||||||
|
import com.idormy.sms.forwarder.sender.HttpServer;
|
||||||
|
import com.idormy.sms.forwarder.sender.SmsHubApiTask;
|
||||||
import com.idormy.sms.forwarder.service.BatteryService;
|
import com.idormy.sms.forwarder.service.BatteryService;
|
||||||
import com.idormy.sms.forwarder.service.FrontService;
|
import com.idormy.sms.forwarder.service.FrontService;
|
||||||
import com.idormy.sms.forwarder.utils.CommonUtil;
|
import com.idormy.sms.forwarder.utils.*;
|
||||||
import com.idormy.sms.forwarder.utils.KeepAliveUtils;
|
|
||||||
import com.idormy.sms.forwarder.utils.LogUtil;
|
|
||||||
import com.idormy.sms.forwarder.utils.NetUtil;
|
|
||||||
import com.idormy.sms.forwarder.utils.PhoneUtils;
|
|
||||||
import com.idormy.sms.forwarder.utils.SettingUtil;
|
|
||||||
import com.idormy.sms.forwarder.utils.SmsUtil;
|
|
||||||
import com.idormy.sms.forwarder.utils.TimeUtil;
|
|
||||||
import com.umeng.analytics.MobclickAgent;
|
import com.umeng.analytics.MobclickAgent;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity implements RefreshListView.IRefreshListener {
|
public class MainActivity extends AppCompatActivity implements RefreshListView.IRefreshListener {
|
||||||
|
|
||||||
@ -69,6 +61,10 @@ public class MainActivity extends AppCompatActivity implements RefreshListView.I
|
|||||||
SmsUtil.init(this);
|
SmsUtil.init(this);
|
||||||
NetUtil.init(this);
|
NetUtil.init(this);
|
||||||
|
|
||||||
|
HttpUtil.init(this);
|
||||||
|
SmsHubApiTask.init(this);
|
||||||
|
HttpServer.init(this);
|
||||||
|
|
||||||
//前台服务
|
//前台服务
|
||||||
try {
|
try {
|
||||||
serviceIntent = new Intent(MainActivity.this, FrontService.class);
|
serviceIntent = new Intent(MainActivity.this, FrontService.class);
|
||||||
@ -86,6 +82,12 @@ public class MainActivity extends AppCompatActivity implements RefreshListView.I
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "BatteryService:", e);
|
Log.e(TAG, "BatteryService:", e);
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
SmsHubApiTask.updateTimer();
|
||||||
|
HttpServer.update();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "SmsHubApiTask:", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -23,10 +23,8 @@ import androidx.annotation.RequiresApi;
|
|||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
import com.idormy.sms.forwarder.utils.CommonUtil;
|
import com.idormy.sms.forwarder.sender.SmsHubApiTask;
|
||||||
import com.idormy.sms.forwarder.utils.DbHelper;
|
import com.idormy.sms.forwarder.utils.*;
|
||||||
import com.idormy.sms.forwarder.utils.KeepAliveUtils;
|
|
||||||
import com.idormy.sms.forwarder.utils.SettingUtil;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -85,6 +83,38 @@ public class SettingActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
EditText textSmsTemplate = findViewById(R.id.text_sms_template);
|
EditText textSmsTemplate = findViewById(R.id.text_sms_template);
|
||||||
editSmsTemplate(textSmsTemplate);
|
editSmsTemplate(textSmsTemplate);
|
||||||
|
|
||||||
|
editSmsHubConfig(findViewById(R.id.switch_enable_sms_hub),findViewById(R.id.editText_text_sms_hub_url));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("UseSwitchCompatOrMaterialCode")
|
||||||
|
private void editSmsHubConfig(Switch switch_enable_send_sms, EditText editText_text_send_sms) {
|
||||||
|
switch_enable_send_sms.setChecked(SettingUtil.getSwitchEnableSmsHubApi());
|
||||||
|
switch_enable_send_sms.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||||
|
if (isChecked && editText_text_send_sms.getText() != null && editText_text_send_sms.getText().length() < 1) {
|
||||||
|
HttpUtil.Toast(TAG, "url为空无法启用");
|
||||||
|
switch_enable_send_sms.setChecked(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SettingUtil.switchEnableSmsHubApi(isChecked);
|
||||||
|
Log.d(TAG, "switchEnableSendApi:" + isChecked);
|
||||||
|
SmsHubApiTask.updateTimer();
|
||||||
|
});
|
||||||
|
editText_text_send_sms.setText(SettingUtil.getSmsHubApiUrl());
|
||||||
|
editText_text_send_sms.addTextChangedListener(new TextWatcher() {
|
||||||
|
@Override
|
||||||
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable s) {
|
||||||
|
SettingUtil.smsHubApiUrl(editText_text_send_sms.getText().toString().trim());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//设置转发短信
|
//设置转发短信
|
||||||
|
@ -0,0 +1,117 @@
|
|||||||
|
package com.idormy.sms.forwarder.model.vo;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.idormy.sms.forwarder.sender.SmsHubApiTask;
|
||||||
|
import com.idormy.sms.forwarder.utils.*;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class SmsHubVo implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public SmsHubVo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public SmsHubVo(Type type, Integer simId, String content, String target) {
|
||||||
|
this.msgId = UUID.randomUUID().toString();
|
||||||
|
if (channel != null) {
|
||||||
|
String simInfo = simId == 2 ? SettingUtil.getAddExtraSim2() : SettingUtil.getAddExtraSim1(); //自定义备注优先
|
||||||
|
if (!simInfo.isEmpty()) {
|
||||||
|
simInfo = "SIM" + simId + ":" + simInfo;
|
||||||
|
} else {
|
||||||
|
simInfo = SimUtil.getSimInfo(simId);
|
||||||
|
}
|
||||||
|
this.channel = simInfo;
|
||||||
|
}
|
||||||
|
this.content = content;
|
||||||
|
this.target = target;
|
||||||
|
this.action = Action.receive.code();
|
||||||
|
this.type = type.code;
|
||||||
|
}
|
||||||
|
|
||||||
|
//唯一id
|
||||||
|
private String msgId;
|
||||||
|
//心跳数据时发送的设备名
|
||||||
|
private String deviceInfo;
|
||||||
|
//卡槽信息
|
||||||
|
private String channel;
|
||||||
|
//消息内容
|
||||||
|
private String content;
|
||||||
|
//错误消息
|
||||||
|
private String errMsg;
|
||||||
|
//手机号(;分隔)或包名
|
||||||
|
private String target;
|
||||||
|
//状态或操作
|
||||||
|
private String action;
|
||||||
|
//消息类型
|
||||||
|
private String type;
|
||||||
|
//时间戳
|
||||||
|
private String ts;
|
||||||
|
//两次交互之间接收到的消息
|
||||||
|
private List<SmsHubVo> children;
|
||||||
|
|
||||||
|
public static SmsHubVo heartbeatInstance() {
|
||||||
|
SmsHubVo smsHubVo = new SmsHubVo();
|
||||||
|
HashMap<String, String> deviInfoMap = getDevInfoMap(false);
|
||||||
|
smsHubVo.setDeviceInfo(JSON.toJSONString(deviInfoMap));
|
||||||
|
smsHubVo.setChannel("SIM1:" + SimUtil.getSimInfo(1) + SettingUtil.getAddExtraSim1() + ";SIM2:" + SimUtil.getSimInfo(2) + SettingUtil.getAddExtraSim2());
|
||||||
|
smsHubVo.setTs(Long.toString(System.currentTimeMillis()));
|
||||||
|
smsHubVo.setAction(SmsHubVo.Action.heartbeat.code());
|
||||||
|
return smsHubVo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, Object> cache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static HashMap<String, String> getDevInfoMap(boolean reflush) {
|
||||||
|
String key = "deviceInfo";
|
||||||
|
if (reflush || !cache.containsKey(key)) {
|
||||||
|
HashMap<String, String> deviInfoMap = new HashMap<>();
|
||||||
|
deviInfoMap.put("mark", SettingUtil.getAddExtraDeviceMark());
|
||||||
|
deviInfoMap.put("simOperatorName", PhoneUtils.getSimOperatorName());
|
||||||
|
deviInfoMap.put("phoneNumber", PhoneUtils.getPhoneNumber());
|
||||||
|
deviInfoMap.put("imei", PhoneUtils.getIMEI());
|
||||||
|
deviInfoMap.put("SDKVersion", PhoneUtils.getSDKVersion() + "");
|
||||||
|
deviInfoMap.put("Version", SettingUtil.getVersionName());
|
||||||
|
deviInfoMap.put("heartbeat", SmsHubApiTask.DELAY_SECONDS + "");
|
||||||
|
cache.put(key, deviInfoMap);
|
||||||
|
return deviInfoMap;
|
||||||
|
}
|
||||||
|
return (HashMap<String, String>) cache.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Action {
|
||||||
|
send("0"), receive("1"), suessces("2"), failure("3"), heartbeat("-1");
|
||||||
|
|
||||||
|
Action(String code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
|
||||||
|
public String code() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
app("app"), phone("phone"), sms("sms"), battery("battery");
|
||||||
|
|
||||||
|
Type(String code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
|
||||||
|
public String code() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,172 @@
|
|||||||
|
package com.idormy.sms.forwarder.receiver;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.util.IOUtils;
|
||||||
|
import com.idormy.sms.forwarder.CloneActivity;
|
||||||
|
import com.idormy.sms.forwarder.model.vo.SmsHubVo;
|
||||||
|
import com.idormy.sms.forwarder.utils.SmsHubActionHandler;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||||
|
import org.eclipse.jetty.servlet.ServletHolder;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.servlet.MultipartConfigElement;
|
||||||
|
import javax.servlet.ServletOutputStream;
|
||||||
|
import javax.servlet.annotation.MultipartConfig;
|
||||||
|
import javax.servlet.annotation.WebServlet;
|
||||||
|
import javax.servlet.http.*;
|
||||||
|
|
||||||
|
@WebServlet
|
||||||
|
@MultipartConfig
|
||||||
|
public class BaseServlet extends HttpServlet {
|
||||||
|
|
||||||
|
public static final int BUFFER_SIZE = 1 << 12;
|
||||||
|
public static final String CLONE_PATH = "/";
|
||||||
|
public static final String SMSHUB_PATH = "/send_api";
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private static final String TAG = "BaseServlet";
|
||||||
|
private static final SmsHubActionHandler.SmsHubMode smsHubMode = SmsHubActionHandler.SmsHubMode.server;
|
||||||
|
|
||||||
|
public BaseServlet(String path, Context context) {
|
||||||
|
this.path = path;
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String path;
|
||||||
|
@SuppressLint("StaticFieldLeak")
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
public static void addServlet(Server jettyServer, Context context) {
|
||||||
|
ServletContextHandler contextHandler = new ServletContextHandler();
|
||||||
|
addHolder(contextHandler, new BaseServlet(BaseServlet.CLONE_PATH, context));
|
||||||
|
addHolder(contextHandler, new BaseServlet(BaseServlet.SMSHUB_PATH, context));
|
||||||
|
// addholder(contextHandler, new BaseServlet("/", context));
|
||||||
|
jettyServer.setHandler(contextHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String read(Reader reader) throws IOException {
|
||||||
|
char[] buffer = new char[BUFFER_SIZE];
|
||||||
|
int size;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
while ((size = reader.read(buffer)) != -1) {
|
||||||
|
char[] chars = new char[size];
|
||||||
|
System.arraycopy(buffer, 0, chars, 0, size);
|
||||||
|
sb.append(chars);
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addHolder(ServletContextHandler servletContextHandler, BaseServlet baseServlet) {
|
||||||
|
ServletHolder servletHolder = new ServletHolder(baseServlet);
|
||||||
|
servletHolder.getRegistration().setMultipartConfig(new MultipartConfigElement(baseServlet.getContext().getCacheDir().getAbsolutePath() + File.pathSeparator + "jettyServer"));
|
||||||
|
servletContextHandler.addServlet(servletHolder, baseServlet.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Context getContext() {
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||||
|
if (CLONE_PATH.equals(path)) {
|
||||||
|
clone(req, resp);
|
||||||
|
} else if (SMSHUB_PATH.equals(path)) {
|
||||||
|
send_api(req, resp);
|
||||||
|
} else {
|
||||||
|
notFound(req, resp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notFound(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||||
|
PrintWriter writer = resp.getWriter();
|
||||||
|
try {
|
||||||
|
String text = "NOT FOUND";
|
||||||
|
resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||||
|
writer.println(text);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
IOUtils.close(writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void send_api(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||||
|
resp.setCharacterEncoding("utf-8");
|
||||||
|
PrintWriter writer = resp.getWriter();
|
||||||
|
BufferedReader reader = req.getReader();
|
||||||
|
try {
|
||||||
|
String read = read(reader);
|
||||||
|
Log.i(TAG, "请求内容:" + read);
|
||||||
|
List<SmsHubVo> smsHubVos = JSON.parseArray(read, SmsHubVo.class);
|
||||||
|
if (smsHubVos.size() == 1 && SmsHubVo.Action.heartbeat.code().equals(smsHubVos.get(0).getAction())) {
|
||||||
|
smsHubVos.clear();
|
||||||
|
SmsHubVo smsHubVo = SmsHubVo.heartbeatInstance();
|
||||||
|
smsHubVos.add(smsHubVo);
|
||||||
|
List<SmsHubVo> data = SmsHubActionHandler.getData(smsHubMode);
|
||||||
|
if (data != null && data.size() > 0) {
|
||||||
|
smsHubVo.setChildren(data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (SmsHubVo vo : smsHubVos) {
|
||||||
|
SmsHubActionHandler.handle(TAG, vo);
|
||||||
|
}
|
||||||
|
List<SmsHubVo> data = SmsHubActionHandler.getData(smsHubMode);
|
||||||
|
if (data != null && data.size() > 0) {
|
||||||
|
SmsHubVo smsHubVo = SmsHubVo.heartbeatInstance();
|
||||||
|
smsHubVo.setChildren(data);
|
||||||
|
smsHubVos.add(smsHubVo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resp.setContentType("application/json;charset=utf-8");
|
||||||
|
String text = JSON.toJSONString(smsHubVos);
|
||||||
|
writer.println(text);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
printErrMsg(resp, writer, e);
|
||||||
|
} finally {
|
||||||
|
IOUtils.close(reader);
|
||||||
|
IOUtils.close(writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printErrMsg(HttpServletResponse resp, PrintWriter writer, Exception e) {
|
||||||
|
String text = "服务器内部错误:" + e.getMessage();
|
||||||
|
Log.e(TAG, text);
|
||||||
|
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||||
|
writer.println(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clone(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||||
|
File file = context.getDatabasePath(CloneActivity.DATABASE_NAME);
|
||||||
|
resp.addHeader("Content-Disposition", "attachment;filename=" + CloneActivity.DATABASE_NAME);
|
||||||
|
ServletOutputStream outputStream = resp.getOutputStream();
|
||||||
|
InputStream inputStream = new FileInputStream(file);
|
||||||
|
try {
|
||||||
|
byte[] buffer = new byte[BUFFER_SIZE];
|
||||||
|
int size;
|
||||||
|
while ((size = inputStream.read(buffer)) != -1) {
|
||||||
|
outputStream.write(buffer, 0, size);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
String text = "服务器内部错误:" + e.getMessage();
|
||||||
|
Log.e(TAG, text);
|
||||||
|
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||||
|
} finally {
|
||||||
|
IOUtils.close(inputStream);
|
||||||
|
IOUtils.close(outputStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -10,13 +10,10 @@ import android.util.Log;
|
|||||||
import com.idormy.sms.forwarder.R;
|
import com.idormy.sms.forwarder.R;
|
||||||
import com.idormy.sms.forwarder.model.CallInfo;
|
import com.idormy.sms.forwarder.model.CallInfo;
|
||||||
import com.idormy.sms.forwarder.model.PhoneBookEntity;
|
import com.idormy.sms.forwarder.model.PhoneBookEntity;
|
||||||
|
import com.idormy.sms.forwarder.model.vo.SmsHubVo;
|
||||||
import com.idormy.sms.forwarder.model.vo.SmsVo;
|
import com.idormy.sms.forwarder.model.vo.SmsVo;
|
||||||
import com.idormy.sms.forwarder.sender.SendUtil;
|
import com.idormy.sms.forwarder.sender.SendUtil;
|
||||||
import com.idormy.sms.forwarder.utils.CommonUtil;
|
import com.idormy.sms.forwarder.utils.*;
|
||||||
import com.idormy.sms.forwarder.utils.ContactHelper;
|
|
||||||
import com.idormy.sms.forwarder.utils.PhoneUtils;
|
|
||||||
import com.idormy.sms.forwarder.utils.SettingUtil;
|
|
||||||
import com.idormy.sms.forwarder.utils.SimUtil;
|
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -113,5 +110,6 @@ public class PhoneStateReceiver extends BroadcastReceiver {
|
|||||||
SmsVo smsVo = new SmsVo(phoneNumber, name + context.getString(R.string.calling), new Date(), simInfo);
|
SmsVo smsVo = new SmsVo(phoneNumber, name + context.getString(R.string.calling), new Date(), simInfo);
|
||||||
Log.d(TAG, "send_msg" + smsVo.toString());
|
Log.d(TAG, "send_msg" + smsVo.toString());
|
||||||
SendUtil.send_msg(context, smsVo, simId, "call");
|
SendUtil.send_msg(context, smsVo, simId, "call");
|
||||||
|
SmsHubActionHandler.putData(new SmsHubVo(SmsHubVo.Type.phone, simId, name + context.getString(R.string.calling), phoneNumber));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,10 @@ import android.os.Bundle;
|
|||||||
import android.telephony.SmsMessage;
|
import android.telephony.SmsMessage;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.idormy.sms.forwarder.model.vo.SmsHubVo;
|
||||||
import com.idormy.sms.forwarder.model.vo.SmsVo;
|
import com.idormy.sms.forwarder.model.vo.SmsVo;
|
||||||
import com.idormy.sms.forwarder.sender.SendUtil;
|
import com.idormy.sms.forwarder.sender.SendUtil;
|
||||||
import com.idormy.sms.forwarder.utils.SettingUtil;
|
import com.idormy.sms.forwarder.utils.*;
|
||||||
import com.idormy.sms.forwarder.utils.SimUtil;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -80,12 +80,14 @@ public class SmsBroadcastReceiver extends BroadcastReceiver {
|
|||||||
mobileToContent.put(mobile, content);
|
mobileToContent.put(mobile, content);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
List<SmsHubVo> smsHubVos = new ArrayList<>();
|
||||||
for (String mobile : mobileToContent.keySet()) {
|
for (String mobile : mobileToContent.keySet()) {
|
||||||
smsVoList.add(new SmsVo(mobile, mobileToContent.get(mobile), date, simInfo));
|
smsVoList.add(new SmsVo(mobile, mobileToContent.get(mobile), date, simInfo));
|
||||||
|
smsHubVos.add(new SmsHubVo(SmsHubVo.Type.sms, simId, mobileToContent.get(mobile), mobile));
|
||||||
}
|
}
|
||||||
|
SmsHubActionHandler.putData(smsHubVos.toArray(new SmsHubVo[0]));
|
||||||
Log.d(TAG, "短信:" + smsVoList);
|
Log.d(TAG, "短信:" + smsVoList);
|
||||||
SendUtil.send_msg_list(context, smsVoList, simId, "sms");
|
SendUtil.send_msg_list(context, smsVoList, simId, "sms");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Throwable throwable) {
|
} catch (Throwable throwable) {
|
||||||
@ -96,4 +98,4 @@ public class SmsBroadcastReceiver extends BroadcastReceiver {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,116 @@
|
|||||||
|
package com.idormy.sms.forwarder.sender;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.idormy.sms.forwarder.R;
|
||||||
|
import com.idormy.sms.forwarder.model.vo.SmsHubVo;
|
||||||
|
import com.idormy.sms.forwarder.receiver.BaseServlet;
|
||||||
|
import com.idormy.sms.forwarder.utils.*;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
|
||||||
|
|
||||||
|
public class HttpServer {
|
||||||
|
private static Boolean hasInit = false;
|
||||||
|
private static Server jettyServer;
|
||||||
|
private static int port = 5000;
|
||||||
|
@SuppressLint("StaticFieldLeak")
|
||||||
|
private static Context context;
|
||||||
|
private static long ts = 0L;
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressLint("HandlerLeak")
|
||||||
|
public static void init(Context context) {
|
||||||
|
//noinspection SynchronizeOnNonFinalField
|
||||||
|
synchronized (hasInit) {
|
||||||
|
if (hasInit) return;
|
||||||
|
|
||||||
|
hasInit = true;
|
||||||
|
HttpServer.context = context;
|
||||||
|
SmsHubActionHandler.init(context);
|
||||||
|
jettyServer = new Server(port);
|
||||||
|
BaseServlet.addServlet(jettyServer, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the Jetty is running
|
||||||
|
* boolean - true when server is running/starting/stopping, false otherwise
|
||||||
|
*/
|
||||||
|
public synchronized static Boolean asRunning() {
|
||||||
|
if (jettyServer != null) {
|
||||||
|
return jettyServer.isRunning() && !jettyServer.isStopping();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized static boolean update() {
|
||||||
|
if (!asRunning() && NetUtil.NETWORK_WIFI != NetUtil.getNetWorkStatus()) {
|
||||||
|
Toast.makeText(context, R.string.no_wifi_network, Toast.LENGTH_SHORT).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
long l = System.currentTimeMillis();
|
||||||
|
if (l - ts < 3000 && asRunning()) {
|
||||||
|
Toast.makeText(context, "点击启动后请等待3秒", Toast.LENGTH_SHORT).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (asRunning().equals(SettingUtil.getSwitchEnableHttpServer())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (SettingUtil.getSwitchEnableHttpServer()) {
|
||||||
|
SmsHubVo.getDevInfoMap(true);
|
||||||
|
start();
|
||||||
|
ts = System.currentTimeMillis();
|
||||||
|
Toast.makeText(context, R.string.server_has_started, Toast.LENGTH_SHORT).show();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
stop();
|
||||||
|
Toast.makeText(context, R.string.server_has_stopped, Toast.LENGTH_SHORT).show();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if Jetty is stopping
|
||||||
|
* boolean - True when server is stopping
|
||||||
|
*/
|
||||||
|
private synchronized static Boolean asStopp() {
|
||||||
|
if (jettyServer != null) {
|
||||||
|
return !(jettyServer.isRunning() || jettyServer.isStopping());
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void start() {
|
||||||
|
stop();
|
||||||
|
Log.i("HttpServer", "start");
|
||||||
|
//new Thread(() -> {
|
||||||
|
try {
|
||||||
|
//Start Jetty
|
||||||
|
jettyServer.start();
|
||||||
|
//jettyServer.join();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
//}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void stop() {
|
||||||
|
if (Boolean.FALSE.equals(asStopp())) {
|
||||||
|
try {
|
||||||
|
if (jettyServer != null) {
|
||||||
|
jettyServer.stop();
|
||||||
|
// jettyServer = new Server(port);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
package com.idormy.sms.forwarder.sender;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.idormy.sms.forwarder.model.vo.SmsHubVo;
|
||||||
|
import com.idormy.sms.forwarder.utils.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主动发送短信轮询任务
|
||||||
|
* @author xxc
|
||||||
|
* 2022/1/10 9:53
|
||||||
|
*/
|
||||||
|
public class SmsHubApiTask extends TimerTask {
|
||||||
|
private static Boolean hasInit = false;
|
||||||
|
public static final long DELAY_SECONDS = 30;
|
||||||
|
private static final String TAG = "SmsHubApiTask";
|
||||||
|
private static Timer sendApiTimer;
|
||||||
|
@SuppressLint("StaticFieldLeak")
|
||||||
|
private static Context context;
|
||||||
|
private static final SmsHubActionHandler.SmsHubMode smsHubMode = SmsHubActionHandler.SmsHubMode.client;
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressLint("HandlerLeak")
|
||||||
|
public static void init(Context context) {
|
||||||
|
//noinspection SynchronizeOnNonFinalField
|
||||||
|
synchronized (hasInit) {
|
||||||
|
if (hasInit) return;
|
||||||
|
|
||||||
|
hasInit = true;
|
||||||
|
SmsHubApiTask.context = context;
|
||||||
|
SmsHubActionHandler.init(SmsHubApiTask.context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
SmsHubVo smsHubVo = SmsHubVo.heartbeatInstance();
|
||||||
|
List<SmsHubVo> data = SmsHubActionHandler.getData(smsHubMode);
|
||||||
|
if (data != null && data.size() > 0) {
|
||||||
|
smsHubVo.setChildren(data);
|
||||||
|
}
|
||||||
|
smsHubVo.setChildren(data);
|
||||||
|
String url = SettingUtil.getSmsHubApiUrl();
|
||||||
|
HttpUtil.asyncPostJson(TAG, url, smsHubVo, response -> {
|
||||||
|
//HttpUtil.Toast(TAG, "Response:" + response.code() + "," + responseStr);
|
||||||
|
if (response.code() == 200) {
|
||||||
|
String responseStr = Objects.requireNonNull(response.body()).string();
|
||||||
|
List<SmsHubVo> vos = JSON.parseArray(responseStr, SmsHubVo.class);
|
||||||
|
for (SmsHubVo vo : vos) {
|
||||||
|
SmsHubActionHandler.handle(TAG, vo);
|
||||||
|
}
|
||||||
|
SmsHubActionHandler.putData(smsHubMode, vos.toArray(new SmsHubVo[0]));
|
||||||
|
}
|
||||||
|
}, null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
HttpUtil.Toast(TAG, "SmsHubApiTask 执行出错,请检查问题后重新开启" + e.getMessage());
|
||||||
|
cancelTimer();
|
||||||
|
SettingUtil.switchEnableSmsHubApi(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void updateTimer() {
|
||||||
|
cancelTimer();
|
||||||
|
if (SettingUtil.getSwitchEnableSmsHubApi()) {
|
||||||
|
SmsHubVo.getDevInfoMap(true);
|
||||||
|
startTimer();
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "Cancel SmsHubApiTaskTimer");
|
||||||
|
HttpUtil.Toast(TAG, "Cancel SmsHubApiTaskTimer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void cancelTimer() {
|
||||||
|
if (sendApiTimer != null) {
|
||||||
|
sendApiTimer.cancel();
|
||||||
|
sendApiTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void startTimer() {
|
||||||
|
Log.d(TAG, "Start SmsHubApiTimer");
|
||||||
|
if (SettingUtil.getSwitchEnableSmsHubApi()) {
|
||||||
|
long seconds = SmsHubApiTask.DELAY_SECONDS;
|
||||||
|
Log.d(TAG, "SmsHubApiTimer started " + seconds);
|
||||||
|
sendApiTimer = new Timer("SmsHubApiTimer", true);
|
||||||
|
sendApiTimer.schedule(new SmsHubApiTask(), 3000, seconds * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,9 +10,11 @@ import android.os.BatteryManager;
|
|||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.idormy.sms.forwarder.model.vo.SmsHubVo;
|
||||||
import com.idormy.sms.forwarder.model.vo.SmsVo;
|
import com.idormy.sms.forwarder.model.vo.SmsVo;
|
||||||
import com.idormy.sms.forwarder.sender.SendUtil;
|
import com.idormy.sms.forwarder.sender.SendUtil;
|
||||||
import com.idormy.sms.forwarder.utils.SettingUtil;
|
import com.idormy.sms.forwarder.utils.SettingUtil;
|
||||||
|
import com.idormy.sms.forwarder.utils.SmsHubActionHandler;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@ -176,9 +178,10 @@ public class BatteryService extends Service {
|
|||||||
SmsVo smsVo = new SmsVo("88888888", msg, new Date(), "电池状态监听");
|
SmsVo smsVo = new SmsVo("88888888", msg, new Date(), "电池状态监听");
|
||||||
Log.d(TAG, "send_msg" + smsVo.toString());
|
Log.d(TAG, "send_msg" + smsVo.toString());
|
||||||
SendUtil.send_msg(context, smsVo, 1, "app");
|
SendUtil.send_msg(context, smsVo, 1, "app");
|
||||||
|
SmsHubActionHandler.putData(new SmsHubVo(SmsHubVo.Type.phone, null, msg, "电池状态监听"));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "getLog e:" + e.getMessage());
|
Log.e(TAG, "getLog e:" + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,10 @@ import android.util.Log;
|
|||||||
|
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
|
|
||||||
|
import com.idormy.sms.forwarder.model.vo.SmsHubVo;
|
||||||
import com.idormy.sms.forwarder.model.vo.SmsVo;
|
import com.idormy.sms.forwarder.model.vo.SmsVo;
|
||||||
import com.idormy.sms.forwarder.sender.SendUtil;
|
import com.idormy.sms.forwarder.sender.SendUtil;
|
||||||
import com.idormy.sms.forwarder.utils.CommonUtil;
|
import com.idormy.sms.forwarder.utils.*;
|
||||||
import com.idormy.sms.forwarder.utils.SettingUtil;
|
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -79,6 +79,7 @@ public class NotifyService extends NotificationListenerService {
|
|||||||
SmsVo smsVo = new SmsVo(packageName, text, new Date(), title);
|
SmsVo smsVo = new SmsVo(packageName, text, new Date(), title);
|
||||||
Log.d(TAG, "send_msg" + smsVo.toString());
|
Log.d(TAG, "send_msg" + smsVo.toString());
|
||||||
SendUtil.send_msg(this, smsVo, 1, "app");
|
SendUtil.send_msg(this, smsVo, 1, "app");
|
||||||
|
SmsHubActionHandler.putData(new SmsHubVo(SmsHubVo.Type.app, null, text, packageName));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "onNotificationPosted:", e);
|
Log.e(TAG, "onNotificationPosted:", e);
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,9 @@ public class Define {
|
|||||||
public static final String SP_MSG_KEY_STRING_RETRY_DELAY_TIME3 = "tsms_msg_key_string_retry_delay_time3";
|
public static final String SP_MSG_KEY_STRING_RETRY_DELAY_TIME3 = "tsms_msg_key_string_retry_delay_time3";
|
||||||
public static final String SP_MSG_KEY_STRING_RETRY_DELAY_TIME4 = "tsms_msg_key_string_retry_delay_time4";
|
public static final String SP_MSG_KEY_STRING_RETRY_DELAY_TIME4 = "tsms_msg_key_string_retry_delay_time4";
|
||||||
public static final String SP_MSG_KEY_STRING_RETRY_DELAY_TIME5 = "tsms_msg_key_string_retry_delay_time5";
|
public static final String SP_MSG_KEY_STRING_RETRY_DELAY_TIME5 = "tsms_msg_key_string_retry_delay_time5";
|
||||||
|
public static final String SP_MSG_KEY_STRING_ENABLE_SMSHUB_API = "tsms_msg_key_string_enable_smshub_api";
|
||||||
|
public static final String SP_MSG_KEY_STRING_SMSHUB_API_URL = "tsms_msg_key_string_smshub_api_url";
|
||||||
|
public static final String SP_MSG_KEY_STRING_ENABLE_HTTP_SERVER = "tsms_msg_key_string_enable_http_server";
|
||||||
|
|
||||||
public static final String SP_MSG = "forwarder_msg";
|
public static final String SP_MSG = "forwarder_msg";
|
||||||
public static final String SP_MSG_SET_KEY = "forwarder_msg_set_key";
|
public static final String SP_MSG_SET_KEY = "forwarder_msg_set_key";
|
||||||
|
167
app/src/main/java/com/idormy/sms/forwarder/utils/HttpUtil.java
Normal file
167
app/src/main/java/com/idormy/sms/forwarder/utils/HttpUtil.java
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
package com.idormy.sms.forwarder.utils;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.*;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.TypeReference;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import okhttp3.*;
|
||||||
|
|
||||||
|
public class HttpUtil {
|
||||||
|
private static final OkHttpClient client = new OkHttpClient();
|
||||||
|
private static final String TAG = "HttpUtil";
|
||||||
|
private static Boolean hasInit = false;
|
||||||
|
@SuppressLint("StaticFieldLeak")
|
||||||
|
private static Context context;
|
||||||
|
// @SuppressLint("StaticFieldLeak")
|
||||||
|
// private static Handler handError;
|
||||||
|
private static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json;charset=utf-8");
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressLint("HandlerLeak")
|
||||||
|
public static void init(Context context) {
|
||||||
|
//noinspection SynchronizeOnNonFinalField
|
||||||
|
synchronized (hasInit) {
|
||||||
|
if (hasInit) return;
|
||||||
|
|
||||||
|
hasInit = true;
|
||||||
|
HttpUtil.context = context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void asyncGet(String tag, String url, Object param, Lamda.Consumer<Response> onResponse, Lamda.Consumer<Exception> onFailure) {
|
||||||
|
StringBuilder resUrl = appendQueryStr(tag, url, param);
|
||||||
|
Request request = new Request.Builder().url(resUrl.toString()).get().build();
|
||||||
|
Lamda.Func<Call, String> func = call -> {
|
||||||
|
call.enqueue(new Callback0(tag, onResponse, onFailure));
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
callAndCatch(tag, request, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void asyncPostJson(String tag, String url, Object param, Lamda.Consumer<Response> onResponse, Lamda.Consumer<Exception> onFailure) {
|
||||||
|
String jsonString = JSON.toJSONString(param);
|
||||||
|
Request request = new Request.Builder().url(url).post(RequestBody.create(jsonString, MEDIA_TYPE_JSON)).build();
|
||||||
|
Lamda.Func<Call, String> func = call -> {
|
||||||
|
call.enqueue(new Callback0(tag, onResponse, onFailure));
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
callAndCatch(tag, request, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String postJson(String tag, String url, Object param) {
|
||||||
|
String jsonString = JSON.toJSONString(param);
|
||||||
|
Request request = new Request.Builder().url(url).post(RequestBody.create(jsonString, MEDIA_TYPE_JSON)).build();
|
||||||
|
Lamda.Func<Call, String> func = call -> {
|
||||||
|
Response response = call.execute();
|
||||||
|
if (response.code() == 200) {
|
||||||
|
return Objects.requireNonNull(response.body()).toString();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
return callAndCatch(tag, request, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String get(String tag, String url, Object param) {
|
||||||
|
StringBuilder resUrl = appendQueryStr(tag, url, param);
|
||||||
|
Request request = new Request.Builder().url(resUrl.toString()).get().build();
|
||||||
|
Lamda.Func<Call, String> func = call -> {
|
||||||
|
Response response = call.execute();
|
||||||
|
if (response.code() == 200) {
|
||||||
|
return Objects.requireNonNull(response.body()).toString();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
return callAndCatch(tag, request, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Toast(String Tag, String data) {
|
||||||
|
Log.i(Tag, data);
|
||||||
|
try {
|
||||||
|
Toast.makeText(HttpUtil.context, Tag + "-" + data, Toast.LENGTH_LONG).show();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static StringBuilder appendQueryStr(String tag, String url, Object param) {
|
||||||
|
StringBuilder resUrl = new StringBuilder(url);
|
||||||
|
if (!url.contains("?")) {
|
||||||
|
resUrl.append("?");
|
||||||
|
} else {
|
||||||
|
resUrl.append("&");
|
||||||
|
}
|
||||||
|
Map<String, String> paramMap = param instanceof Map ? (Map<String, String>) param
|
||||||
|
: JSON.parseObject(JSON.toJSONString(param), new TypeReference<Map<String, String>>() {
|
||||||
|
}.getType());
|
||||||
|
for (Map.Entry<String, String> entry : paramMap.entrySet()) {
|
||||||
|
if (entry.getValue() != null) {
|
||||||
|
resUrl.append(URLEncoder.encode(entry.getKey())).append("=").append(URLEncoder.encode(entry.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.i(tag, "url:" + resUrl);
|
||||||
|
return resUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String callAndCatch(String tag, Request request, Lamda.Func<Call, String> func) {
|
||||||
|
try {
|
||||||
|
Call call = client.newCall(request);
|
||||||
|
return func.execute(call);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Toast(tag, "请求失败:" + e.getMessage());
|
||||||
|
Log.e(tag, "请求失败:" + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Callback0 implements Callback {
|
||||||
|
public Callback0(String tag, Lamda.Consumer<Response> onResponse, Lamda.Consumer<Exception> onFailure) {
|
||||||
|
this.tag = tag;
|
||||||
|
this.onResponse = onResponse;
|
||||||
|
this.onFailure = onFailure;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Callback0(String tag, Lamda.Consumer<Response> onResponse) {
|
||||||
|
this.tag = tag;
|
||||||
|
this.onResponse = onResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String tag;
|
||||||
|
private final Lamda.Consumer<Response> onResponse;
|
||||||
|
private Lamda.Consumer<Exception> onFailure;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NonNull Call call, @NonNull final IOException e) {
|
||||||
|
Toast(tag, "onFailure:" + e.getMessage());
|
||||||
|
Log.d(tag, "onFailure:" + e.getMessage());
|
||||||
|
if (onFailure != null) {
|
||||||
|
onFailure.executeThrowRunTimeExcp(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
|
||||||
|
Log.d(tag, "onResponse:" + response.code() + ":" + Objects.requireNonNull(response.body()).toString());
|
||||||
|
if (onResponse != null)
|
||||||
|
onResponse.executeThrowRunTimeExcp(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTag() {
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
39
app/src/main/java/com/idormy/sms/forwarder/utils/Lamda.java
Normal file
39
app/src/main/java/com/idormy/sms/forwarder/utils/Lamda.java
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package com.idormy.sms.forwarder.utils;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class Lamda {
|
||||||
|
public interface Consumer<T> extends Func<T, T> {
|
||||||
|
void accept(T t) throws Exception;
|
||||||
|
|
||||||
|
default T execute(T t) throws Exception {
|
||||||
|
accept(t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Func<T, R> {
|
||||||
|
R execute(T t) throws Exception;
|
||||||
|
|
||||||
|
default R executeThrowRunTimeExcp(T t) {
|
||||||
|
try {
|
||||||
|
return execute(t);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default R executeIgnoreExcp(T t) {
|
||||||
|
try {
|
||||||
|
return execute(t);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
default <E> Func<T, E> andThen(Func<? super R, ? extends E> after) {
|
||||||
|
Objects.requireNonNull(after);
|
||||||
|
return (T t) -> after.execute(execute(t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -249,6 +249,36 @@ public class SettingUtil {
|
|||||||
sp_setting.edit().putString(key, value).apply();
|
sp_setting.edit().putString(key, value).apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void switchEnableSmsHubApi(Boolean enable) {
|
||||||
|
sp_setting.edit()
|
||||||
|
.putBoolean(Define.SP_MSG_KEY_STRING_ENABLE_SMSHUB_API, enable)
|
||||||
|
.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean getSwitchEnableSmsHubApi() {
|
||||||
|
return sp_setting.getBoolean(Define.SP_MSG_KEY_STRING_ENABLE_SMSHUB_API, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void switchEnableHttpServer(Boolean enable) {
|
||||||
|
sp_setting.edit()
|
||||||
|
.putBoolean(Define.SP_MSG_KEY_STRING_ENABLE_HTTP_SERVER, enable)
|
||||||
|
.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean getSwitchEnableHttpServer() {
|
||||||
|
return sp_setting.getBoolean(Define.SP_MSG_KEY_STRING_ENABLE_HTTP_SERVER, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void smsHubApiUrl(String url) {
|
||||||
|
sp_setting.edit()
|
||||||
|
.putString(Define.SP_MSG_KEY_STRING_SMSHUB_API_URL, url)
|
||||||
|
.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getSmsHubApiUrl() {
|
||||||
|
return sp_setting.getString(Define.SP_MSG_KEY_STRING_SMSHUB_API_URL, "http://xxx.com/send_api");
|
||||||
|
}
|
||||||
|
|
||||||
//获取当前版本名称
|
//获取当前版本名称
|
||||||
public static String getVersionName() {
|
public static String getVersionName() {
|
||||||
// 获取PackageManager的实例
|
// 获取PackageManager的实例
|
||||||
|
@ -0,0 +1,127 @@
|
|||||||
|
package com.idormy.sms.forwarder.utils;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.idormy.sms.forwarder.model.LogModel;
|
||||||
|
import com.idormy.sms.forwarder.model.vo.SmsHubVo;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public class SmsHubActionHandler {
|
||||||
|
public static final long RULE_ID = -999L;
|
||||||
|
private static Boolean hasInit = false;
|
||||||
|
|
||||||
|
private static ConcurrentHashMap<SmsHubMode, List<SmsHubVo>> cache;
|
||||||
|
|
||||||
|
public enum SmsHubMode {
|
||||||
|
server, client
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("StaticFieldLeak")
|
||||||
|
private static Context context;
|
||||||
|
|
||||||
|
@SuppressLint("HandlerLeak")
|
||||||
|
public static void init(Context context) {
|
||||||
|
//noinspection SynchronizeOnNonFinalField
|
||||||
|
synchronized (hasInit) {
|
||||||
|
if (hasInit) return;
|
||||||
|
|
||||||
|
hasInit = true;
|
||||||
|
SmsHubActionHandler.context = context;
|
||||||
|
cache = new ConcurrentHashMap<>();
|
||||||
|
for (SmsHubMode smsHubMode : SmsHubMode.values()) {
|
||||||
|
cache.put(smsHubMode, new ArrayList<>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized int size(SmsHubMode smsHubMode) {
|
||||||
|
return Objects.requireNonNull(cache.get(smsHubMode)).size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized List<SmsHubVo> getData(SmsHubMode smsHubMode) {
|
||||||
|
List<SmsHubVo> smsHubVoList = cache.get(smsHubMode);
|
||||||
|
if (smsHubVoList.size() > 0) {
|
||||||
|
cache.put(smsHubMode, new ArrayList<>());
|
||||||
|
return smsHubVoList;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized void putData(SmsHubMode smsHubMode, SmsHubVo... smsHubVos) {
|
||||||
|
if (isEnable(smsHubMode)) {
|
||||||
|
Objects.requireNonNull(cache.get(smsHubMode)).addAll(Arrays.asList(smsHubVos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized void putData(SmsHubVo... smsHubVos) {
|
||||||
|
for (SmsHubMode smsHubMode : SmsHubMode.values()) {
|
||||||
|
putData(smsHubMode, smsHubVos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isEnable(SmsHubMode smsHubMode) {
|
||||||
|
boolean enable = false;
|
||||||
|
if (smsHubMode == SmsHubMode.client) {
|
||||||
|
enable = SettingUtil.getSwitchEnableSmsHubApi();
|
||||||
|
} else if (smsHubMode == SmsHubMode.server) {
|
||||||
|
enable = SettingUtil.getSwitchEnableHttpServer();
|
||||||
|
}
|
||||||
|
return enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void handle(String tag, SmsHubVo vo) {
|
||||||
|
String action = vo.getAction();
|
||||||
|
if (SmsHubVo.Action.send.code().equals(action)) {
|
||||||
|
send(tag, vo);
|
||||||
|
} else {
|
||||||
|
String errMsg = "暂不支持的action:" + action;
|
||||||
|
vo.setErrMsg(errMsg);
|
||||||
|
vo.setAction(SmsHubVo.Action.failure.code());
|
||||||
|
}
|
||||||
|
vo.setTs(Long.toString(System.currentTimeMillis()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void send(String tag, SmsHubVo vo) {
|
||||||
|
boolean failure = true;
|
||||||
|
String msg = "";
|
||||||
|
Long logId = null;
|
||||||
|
try {
|
||||||
|
if (SmsHubVo.Action.send.code().equals(vo.getAction())) {
|
||||||
|
vo.setType(SmsHubVo.Type.sms.code());
|
||||||
|
logId = LogUtil.addLog(new LogModel(vo.getType(), vo.getTarget(), vo.getContent(), "SIM" + vo.getChannel(), RULE_ID));
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {
|
||||||
|
int simId = Integer.parseInt(vo.getChannel());
|
||||||
|
vo.setChannel("SIM" + simId);
|
||||||
|
msg = SmsUtil.sendSms(SimUtil.getSubscriptionIdBySimId(simId), vo.getTarget(), vo.getContent());
|
||||||
|
if (msg == null) {
|
||||||
|
failure = false;
|
||||||
|
HttpUtil.Toast(tag, "短信发送成功");
|
||||||
|
Log.i(tag, "短信发送成功");
|
||||||
|
vo.setAction(SmsHubVo.Action.suessces.code());
|
||||||
|
LogUtil.updateLog(logId, 2, SmsHubVo.Action.suessces.code());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
msg = "api<22";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
msg += e.getMessage();
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (failure) {
|
||||||
|
msg = "短信发送失败:" + msg;
|
||||||
|
HttpUtil.Toast(tag, msg);
|
||||||
|
Log.i(tag, msg);
|
||||||
|
vo.setAction(SmsHubVo.Action.failure.code());
|
||||||
|
vo.setErrMsg(msg);
|
||||||
|
if (logId != null) {
|
||||||
|
LogUtil.updateLog(logId, 0, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,6 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -250,6 +249,60 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:background="@android:color/white"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="15dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="4"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/send_sms_config_title"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:ignore="RelativeOverlap" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="end"
|
||||||
|
android:text="@string/send_sms_config_title2"
|
||||||
|
android:textSize="9sp"
|
||||||
|
tools:ignore="SmallSp" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editText_text_sms_hub_url"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:autofillHints=""
|
||||||
|
android:ems="16"
|
||||||
|
android:inputType="text"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text=""
|
||||||
|
tools:ignore="LabelFor" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
android:id="@+id/switch_enable_sms_hub"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="end"
|
||||||
|
android:textSize="18sp"
|
||||||
|
tools:ignore="UseSwitchCompatOrMaterialXml" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -713,4 +766,4 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
@ -207,7 +207,7 @@
|
|||||||
<!--CloneActivity-->
|
<!--CloneActivity-->
|
||||||
<string name="local_ip">Local IP:</string>
|
<string name="local_ip">Local IP:</string>
|
||||||
<string name="operating_instruction">Instructions: \n1. Please keep the SOURCE and DESTINATION phones in the same Wi-Fi network, and do not turn on isolation. \n2. Tap "Send" on SOURCE mobile phone, and get "server IP" \n3. After filling in "Server IP" on DESTINATION phone, tap "Receive". \n [NOTE:] sender(s), forwarding rule(s) and log(s) will be overwritten after cloning!</string> <!-- 原文是“新旧手机”,英文翻译中处理为“源”手机和“目标”手机,因为担心“新旧”的表述引起混淆(有没一种可能就是用户就是用从新手机的设备复制到旧手机上去呢?)。 -->
|
<string name="operating_instruction">Instructions: \n1. Please keep the SOURCE and DESTINATION phones in the same Wi-Fi network, and do not turn on isolation. \n2. Tap "Send" on SOURCE mobile phone, and get "server IP" \n3. After filling in "Server IP" on DESTINATION phone, tap "Receive". \n [NOTE:] sender(s), forwarding rule(s) and log(s) will be overwritten after cloning!</string> <!-- 原文是“新旧手机”,英文翻译中处理为“源”手机和“目标”手机,因为担心“新旧”的表述引起混淆(有没一种可能就是用户就是用从新手机的设备复制到旧手机上去呢?)。 -->
|
||||||
<string name="send">Send</string>
|
<string name="send">Start Server</string>
|
||||||
<string name="stop">Stop</string>
|
<string name="stop">Stop</string>
|
||||||
<string name="old_mobile_phone">I\'m the SCOURCE phone</string>
|
<string name="old_mobile_phone">I\'m the SCOURCE phone</string>
|
||||||
<string name="receive">Receive</string>
|
<string name="receive">Receive</string>
|
||||||
@ -263,4 +263,6 @@
|
|||||||
<string name="proxy_authenticator">Proxy Authenticator</string>
|
<string name="proxy_authenticator">Proxy Authenticator</string>
|
||||||
<string name="username">Username</string>
|
<string name="username">Username</string>
|
||||||
<string name="password">Password</string>
|
<string name="password">Password</string>
|
||||||
|
<string name="send_sms_config_title">SmsHub client Mode</string>
|
||||||
|
<string name="send_sms_config_title2">Execute the operation returned by the interface</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -206,7 +206,7 @@
|
|||||||
<string name="get">GET</string>
|
<string name="get">GET</string>
|
||||||
<string name="local_ip">本机IP:</string>
|
<string name="local_ip">本机IP:</string>
|
||||||
<string name="operating_instruction">操作说明:\n1.新旧手机连接同一个WiFi网络(禁用AP隔离)\n2.旧手机直接点【发送】按钮,获取到【服务端IP】\n3.新手机填写【服务端IP】后,点【接收】按钮\n【注意】新手机接收后,发送通道、转发规则将完全被覆盖,清空历史记录!</string>
|
<string name="operating_instruction">操作说明:\n1.新旧手机连接同一个WiFi网络(禁用AP隔离)\n2.旧手机直接点【发送】按钮,获取到【服务端IP】\n3.新手机填写【服务端IP】后,点【接收】按钮\n【注意】新手机接收后,发送通道、转发规则将完全被覆盖,清空历史记录!</string>
|
||||||
<string name="send">发送</string>
|
<string name="send">启动服务</string>
|
||||||
<string name="stop">停止</string>
|
<string name="stop">停止</string>
|
||||||
<string name="old_mobile_phone">我是旧手机</string>
|
<string name="old_mobile_phone">我是旧手机</string>
|
||||||
<string name="receive">接收</string>
|
<string name="receive">接收</string>
|
||||||
@ -262,4 +262,6 @@
|
|||||||
<string name="proxy_authenticator">代理身份验证</string>
|
<string name="proxy_authenticator">代理身份验证</string>
|
||||||
<string name="username">用户</string>
|
<string name="username">用户</string>
|
||||||
<string name="password">密码</string>
|
<string name="password">密码</string>
|
||||||
|
<string name="send_sms_config_title">SmsHub client 模式</string>
|
||||||
|
<string name="send_sms_config_title2">执行接口返回的操作</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
|
ext.jetty_version = '9.2.30.v20200428'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user