mirror of
https://github.com/pppscn/SmsForwarder
synced 2025-08-04 01:47:40 +08:00
新增:一键克隆增加离线模式(导出备份json文件到Download目录,其他机器读取文件导入)
优化:一键克隆机制优化(替换db文件→操作现有db)
This commit is contained in:
parent
60dde070b5
commit
31017609f9
@ -1,28 +1,32 @@
|
|||||||
package com.idormy.sms.forwarder;
|
package com.idormy.sms.forwarder;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Environment;
|
||||||
import android.os.Message;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.RadioGroup;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.hjq.permissions.OnPermissionCallback;
|
||||||
|
import com.hjq.permissions.Permission;
|
||||||
|
import com.hjq.permissions.XXPermissions;
|
||||||
import com.hjq.toast.ToastUtils;
|
import com.hjq.toast.ToastUtils;
|
||||||
import com.idormy.sms.forwarder.model.vo.CloneInfoVo;
|
import com.idormy.sms.forwarder.model.vo.CloneInfoVo;
|
||||||
import com.idormy.sms.forwarder.receiver.BaseServlet;
|
import com.idormy.sms.forwarder.receiver.BaseServlet;
|
||||||
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.sender.HttpServer;
|
||||||
import com.idormy.sms.forwarder.utils.BackupDbTask;
|
import com.idormy.sms.forwarder.utils.CloneUtils;
|
||||||
import com.idormy.sms.forwarder.utils.Define;
|
import com.idormy.sms.forwarder.utils.Define;
|
||||||
import com.idormy.sms.forwarder.utils.DownloadUtil;
|
import com.idormy.sms.forwarder.utils.FileUtils;
|
||||||
import com.idormy.sms.forwarder.utils.HttpUtil;
|
import com.idormy.sms.forwarder.utils.HttpUtil;
|
||||||
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.utils.SettingUtil;
|
||||||
@ -31,6 +35,7 @@ import com.idormy.sms.forwarder.view.IPEditText;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -47,37 +52,19 @@ public class CloneActivity extends AppCompatActivity {
|
|||||||
private final String TAG = "CloneActivity";
|
private final String TAG = "CloneActivity";
|
||||||
private Context context;
|
private Context context;
|
||||||
private String serverIp;
|
private String serverIp;
|
||||||
public static final String DATABASE_NAME = "sms_forwarder.db";
|
private String backupPath;
|
||||||
|
private final String backupFile = "SmsForwarder.json";
|
||||||
private IPEditText textServerIp;
|
private IPEditText textServerIp;
|
||||||
private TextView sendTxt;
|
private TextView sendTxt;
|
||||||
private TextView receiveTxt;
|
private TextView receiveTxt;
|
||||||
|
private TextView backupPathTxt;
|
||||||
private Button sendBtn;
|
private Button sendBtn;
|
||||||
public static final int TOAST = 0x9731994;
|
|
||||||
public static final int DOWNLOAD = 0x9731995;
|
|
||||||
|
|
||||||
//消息处理者,创建一个Handler的子类对象,目的是重写Handler的处理消息的方法(handleMessage())
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@SuppressLint("HandlerLeak")
|
|
||||||
private final Handler handError = new Handler() {
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message msg) {
|
|
||||||
if (msg.what == TOAST) {
|
|
||||||
ToastUtils.delayedShow(msg.getData().getString("DATA"), 3000);
|
|
||||||
} else if (msg.what == DOWNLOAD) {
|
|
||||||
String savePath = context.getCacheDir().getPath() + File.separator + BackupDbTask.BACKUP_FILE;
|
|
||||||
Log.d(TAG, savePath);
|
|
||||||
downloadFile(msg.getData().getString("URL"), context.getCacheDir().getPath(), BackupDbTask.BACKUP_FILE, msg.getData().getString("INFO"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
Log.d(TAG, "onCreate");
|
Log.d(TAG, "onCreate");
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
context = CloneActivity.this;
|
|
||||||
|
|
||||||
setContentView(R.layout.activity_clone);
|
setContentView(R.layout.activity_clone);
|
||||||
Log.d(TAG, "onCreate: " + RebootBroadcastReceiver.class.getName());
|
Log.d(TAG, "onCreate: " + RebootBroadcastReceiver.class.getName());
|
||||||
|
|
||||||
@ -92,6 +79,41 @@ public class CloneActivity extends AppCompatActivity {
|
|||||||
super.onStart();
|
super.onStart();
|
||||||
Log.d(TAG, "onStart");
|
Log.d(TAG, "onStart");
|
||||||
|
|
||||||
|
backupPathTxt = findViewById(R.id.backupPathTxt);
|
||||||
|
// 申请储存权限
|
||||||
|
XXPermissions.with(this).permission(Permission.Group.STORAGE).request(new OnPermissionCallback() {
|
||||||
|
@Override
|
||||||
|
public void onGranted(List<String> permissions, boolean all) {
|
||||||
|
backupPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
|
||||||
|
backupPathTxt.setText(backupPath + File.separator + backupFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDenied(List<String> permissions, boolean never) {
|
||||||
|
if (never) {
|
||||||
|
ToastUtils.show(R.string.toast_denied_never);
|
||||||
|
// 如果是被永久拒绝就跳转到应用权限系统设置页面
|
||||||
|
XXPermissions.startPermissionActivity(CloneActivity.this, permissions);
|
||||||
|
} else {
|
||||||
|
ToastUtils.show(R.string.toast_denied);
|
||||||
|
}
|
||||||
|
backupPathTxt.setText("未授权储存权限,该功能无法使用!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
LinearLayout layoutNetwork = findViewById(R.id.layoutNetwork);
|
||||||
|
LinearLayout layoutOffline = findViewById(R.id.layoutOffline);
|
||||||
|
final RadioGroup radioGroupTypeCheck = findViewById(R.id.radioGroupTypeCheck);
|
||||||
|
radioGroupTypeCheck.setOnCheckedChangeListener((group, checkedId) -> {
|
||||||
|
if (checkedId == R.id.btnTypeOffline) {
|
||||||
|
layoutNetwork.setVisibility(View.GONE);
|
||||||
|
layoutOffline.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
layoutNetwork.setVisibility(View.VISIBLE);
|
||||||
|
layoutOffline.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
sendBtn = findViewById(R.id.sendBtn);
|
sendBtn = findViewById(R.id.sendBtn);
|
||||||
sendTxt = findViewById(R.id.sendTxt);
|
sendTxt = findViewById(R.id.sendTxt);
|
||||||
TextView ipText = findViewById(R.id.ipText);
|
TextView ipText = findViewById(R.id.ipText);
|
||||||
@ -110,18 +132,14 @@ public class CloneActivity extends AppCompatActivity {
|
|||||||
sendBtn.setText(R.string.send);
|
sendBtn.setText(R.string.send);
|
||||||
sendTxt.setText(R.string.server_has_stopped);
|
sendTxt.setText(R.string.server_has_stopped);
|
||||||
}
|
}
|
||||||
//noinspection CommentedOutCode
|
|
||||||
|
//发送
|
||||||
sendBtn.setOnClickListener(v -> {
|
sendBtn.setOnClickListener(v -> {
|
||||||
if (!HttpServer.asRunning() && NetUtil.NETWORK_WIFI != NetUtil.getNetWorkStatus()) {
|
if (!HttpServer.asRunning() && NetUtil.NETWORK_WIFI != NetUtil.getNetWorkStatus()) {
|
||||||
Toast(handError, TAG, getString(R.string.no_wifi_network));
|
ToastUtils.show(getString(R.string.no_wifi_network));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//备份文件
|
|
||||||
//BackupDbTask task = new BackupDbTask(this);
|
|
||||||
//String backup_version = task.doInBackground(BackupDbTask.COMMAND_BACKUP);
|
|
||||||
//Log.d(TAG, "backup_version = " + backup_version);
|
|
||||||
|
|
||||||
SettingUtil.switchEnableHttpServer(!SettingUtil.getSwitchEnableHttpServer());
|
SettingUtil.switchEnableHttpServer(!SettingUtil.getSwitchEnableHttpServer());
|
||||||
if (!HttpServer.update()) {
|
if (!HttpServer.update()) {
|
||||||
SettingUtil.switchEnableHttpServer(!SettingUtil.getSwitchEnableHttpServer());
|
SettingUtil.switchEnableHttpServer(!SettingUtil.getSwitchEnableHttpServer());
|
||||||
@ -138,23 +156,24 @@ public class CloneActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//接收
|
||||||
receiveBtn.setOnClickListener(v -> {
|
receiveBtn.setOnClickListener(v -> {
|
||||||
if (HttpServer.asRunning()) {
|
if (HttpServer.asRunning()) {
|
||||||
receiveTxt.setText(R.string.sender_cannot_receive);
|
receiveTxt.setText(R.string.sender_cannot_receive);
|
||||||
Toast(handError, TAG, getString(R.string.sender_cannot_receive));
|
ToastUtils.show(getString(R.string.sender_cannot_receive));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NetUtil.NETWORK_WIFI != NetUtil.getNetWorkStatus()) {
|
if (NetUtil.NETWORK_WIFI != NetUtil.getNetWorkStatus()) {
|
||||||
receiveTxt.setText(R.string.no_wifi_network);
|
receiveTxt.setText(R.string.no_wifi_network);
|
||||||
Toast(handError, TAG, getString(R.string.no_wifi_network));
|
ToastUtils.show(getString(R.string.no_wifi_network));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
serverIp = textServerIp.getIP();
|
serverIp = textServerIp.getIP();
|
||||||
if (serverIp == null || serverIp.isEmpty()) {
|
if (serverIp == null || serverIp.isEmpty()) {
|
||||||
receiveTxt.setText(R.string.invalid_server_ip);
|
receiveTxt.setText(R.string.invalid_server_ip);
|
||||||
Toast(handError, TAG, getString(R.string.invalid_server_ip));
|
ToastUtils.show(getString(R.string.invalid_server_ip));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +206,7 @@ public class CloneActivity extends AppCompatActivity {
|
|||||||
client.newCall(request).enqueue(new Callback() {
|
client.newCall(request).enqueue(new Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(@NonNull Call call, @NonNull final IOException e) {
|
public void onFailure(@NonNull Call call, @NonNull final IOException e) {
|
||||||
Toast(handError, TAG, getString(R.string.tips_get_info_failed));
|
ToastUtils.show(getString(R.string.tips_get_info_failed));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -196,7 +215,7 @@ public class CloneActivity extends AppCompatActivity {
|
|||||||
Log.d(TAG, "Response:" + response.code() + "," + responseStr);
|
Log.d(TAG, "Response:" + response.code() + "," + responseStr);
|
||||||
|
|
||||||
if (TextUtils.isEmpty(responseStr)) {
|
if (TextUtils.isEmpty(responseStr)) {
|
||||||
Toast(handError, TAG, getString(R.string.tips_get_info_failed));
|
ToastUtils.show(getString(R.string.tips_get_info_failed));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,27 +224,68 @@ public class CloneActivity extends AppCompatActivity {
|
|||||||
Log.d(TAG, cloneInfoVo.toString());
|
Log.d(TAG, cloneInfoVo.toString());
|
||||||
|
|
||||||
if (!SettingUtil.getVersionName().equals(cloneInfoVo.getVersionName())) {
|
if (!SettingUtil.getVersionName().equals(cloneInfoVo.getVersionName())) {
|
||||||
Toast(handError, TAG, getString(R.string.tips_versions_inconsistent));
|
ToastUtils.show(getString(R.string.tips_versions_inconsistent));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//下载备份文件
|
if (CloneUtils.restoreSettings(cloneInfoVo)) {
|
||||||
Message msg = new Message();
|
ToastUtils.show(getString(R.string.tips_clone_done));
|
||||||
msg.what = DOWNLOAD;
|
} else {
|
||||||
Bundle bundle = new Bundle();
|
ToastUtils.show(getString(R.string.tips_clone_failed));
|
||||||
bundle.putString("URL", requestUrl);
|
}
|
||||||
bundle.putString("INFO", responseStr);
|
|
||||||
msg.setData(bundle);
|
|
||||||
handError.sendMessage(msg);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Toast(handError, TAG, getString(R.string.tips_clone_failed) + e.getMessage());
|
ToastUtils.show(getString(R.string.tips_clone_failed) + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Button exportBtn = findViewById(R.id.exportBtn);
|
||||||
|
TextView exportTxt = findViewById(R.id.exportTxt);
|
||||||
|
Button importBtn = findViewById(R.id.importBtn);
|
||||||
|
TextView importTxt = findViewById(R.id.importTxt);
|
||||||
|
|
||||||
|
//导出
|
||||||
|
exportBtn.setOnClickListener(v -> {
|
||||||
|
if (FileUtils.writeFileR(CloneUtils.exportSettings(), backupPath, backupFile, true)) {
|
||||||
|
ToastUtils.show("导出配置成功!");
|
||||||
|
} else {
|
||||||
|
exportTxt.setText("导出失败,请检查写入权限!");
|
||||||
|
ToastUtils.show("导出失败,请检查写入权限!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//导入
|
||||||
|
importBtn.setOnClickListener(v -> {
|
||||||
|
try {
|
||||||
|
String responseStr = FileUtils.readFileI(backupPath, backupFile);
|
||||||
|
if (TextUtils.isEmpty(responseStr)) {
|
||||||
|
ToastUtils.show(getString(R.string.tips_get_info_failed));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CloneInfoVo cloneInfoVo = JSON.parseObject(responseStr, CloneInfoVo.class);
|
||||||
|
Log.d(TAG, Objects.requireNonNull(cloneInfoVo).toString());
|
||||||
|
|
||||||
|
if (!SettingUtil.getVersionName().equals(cloneInfoVo.getVersionName())) {
|
||||||
|
ToastUtils.show(getString(R.string.tips_versions_inconsistent));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CloneUtils.restoreSettings(cloneInfoVo)) {
|
||||||
|
ToastUtils.show(getString(R.string.tips_clone_done));
|
||||||
|
} else {
|
||||||
|
ToastUtils.show(getString(R.string.tips_clone_failed));
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
importTxt.setText("还原失败:" + e.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
@ -238,82 +298,4 @@ public class CloneActivity extends AppCompatActivity {
|
|||||||
ipText.setText(getString(R.string.local_ip) + serverIp);
|
ipText.setText(getString(R.string.local_ip) + serverIp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件下载
|
|
||||||
*
|
|
||||||
* @param url 下载链接
|
|
||||||
*/
|
|
||||||
public void downloadFile(String url, final String destFileDir, final String destFileName, final String cloneInfo) {
|
|
||||||
ProgressDialog progressDialog = new ProgressDialog(context);
|
|
||||||
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
|
||||||
progressDialog.setTitle(getString(R.string.tips_downloading));
|
|
||||||
progressDialog.setMessage(getString(R.string.tips_please_wait));
|
|
||||||
progressDialog.setProgress(0);
|
|
||||||
progressDialog.setMax(100);
|
|
||||||
progressDialog.show();
|
|
||||||
progressDialog.setCancelable(false);
|
|
||||||
DownloadUtil.get().download(url, destFileDir, destFileName, new DownloadUtil.OnDownloadListener() {
|
|
||||||
@Override
|
|
||||||
public void onDownloadSuccess(File file) {
|
|
||||||
if (progressDialog.isShowing()) {
|
|
||||||
Toast(handError, TAG, getString(R.string.tips_download_done));
|
|
||||||
progressDialog.dismiss();
|
|
||||||
}
|
|
||||||
//下载完成进行相关逻辑操作
|
|
||||||
Log.d(TAG, file.getPath());
|
|
||||||
|
|
||||||
//还原数据库
|
|
||||||
BackupDbTask task = new BackupDbTask(context);
|
|
||||||
String backup_version = task.doInBackground(BackupDbTask.COMMAND_RESTORE);
|
|
||||||
Log.d(TAG, "backup_version = " + backup_version);
|
|
||||||
|
|
||||||
//应用配置
|
|
||||||
CloneInfoVo cloneInfoVo = JSON.parseObject(cloneInfo, CloneInfoVo.class);
|
|
||||||
System.out.println(cloneInfoVo.toString());
|
|
||||||
SettingUtil.init(context);
|
|
||||||
SettingUtil.switchEnableSms(cloneInfoVo.isEnableSms());
|
|
||||||
SettingUtil.switchEnablePhone(cloneInfoVo.isEnablePhone());
|
|
||||||
SettingUtil.switchCallType1(cloneInfoVo.isCallType1());
|
|
||||||
SettingUtil.switchCallType2(cloneInfoVo.isCallType2());
|
|
||||||
SettingUtil.switchCallType3(cloneInfoVo.isCallType3());
|
|
||||||
SettingUtil.switchEnableAppNotify(cloneInfoVo.isEnableAppNotify());
|
|
||||||
SettingUtil.switchCancelAppNotify(cloneInfoVo.isCancelAppNotify());
|
|
||||||
SettingUtil.smsHubApiUrl(cloneInfoVo.getSmsHubApiUrl());
|
|
||||||
SettingUtil.setBatteryLevelAlarmMin(cloneInfoVo.getBatteryLevelAlarmMin());
|
|
||||||
SettingUtil.setBatteryLevelAlarmMax(cloneInfoVo.getBatteryLevelAlarmMax());
|
|
||||||
SettingUtil.switchBatteryLevelAlarmOnce(cloneInfoVo.isBatteryLevelAlarmOnce());
|
|
||||||
SettingUtil.setRetryTimes(cloneInfoVo.getRetryTimes());
|
|
||||||
SettingUtil.setDelayTime(cloneInfoVo.getDelayTime());
|
|
||||||
SettingUtil.switchSmsTemplate(cloneInfoVo.isEnableSmsTemplate());
|
|
||||||
SettingUtil.setSmsTemplate(cloneInfoVo.getSmsTemplate());
|
|
||||||
|
|
||||||
Toast(handError, TAG, getString(R.string.tips_clone_done));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDownloading(int progress) {
|
|
||||||
progressDialog.setProgress(progress);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
|
||||||
@Override
|
|
||||||
public void onDownloadFailed(Exception e) {
|
|
||||||
//下载异常进行相关提示操作
|
|
||||||
Log.e(TAG, getString(R.string.tips_download_failed) + e.getMessage());
|
|
||||||
Toast(handError, TAG, getString(R.string.tips_download_failed) + e.getMessage());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Toast(Handler handError, String Tag, String data) {
|
|
||||||
Log.i(Tag, data);
|
|
||||||
if (handError != null) {
|
|
||||||
Message msg = new Message();
|
|
||||||
msg.what = TOAST;
|
|
||||||
Bundle bundle = new Bundle();
|
|
||||||
bundle.putString("DATA", data);
|
|
||||||
msg.setData(bundle);
|
|
||||||
handError.sendMessage(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,11 @@ package com.idormy.sms.forwarder.model.vo;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.idormy.sms.forwarder.model.RuleModel;
|
||||||
|
import com.idormy.sms.forwarder.model.SenderModel;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@ -28,7 +32,8 @@ public class CloneInfoVo implements Serializable {
|
|||||||
private int delayTime;
|
private int delayTime;
|
||||||
private boolean enableSmsTemplate;
|
private boolean enableSmsTemplate;
|
||||||
private String smsTemplate;
|
private String smsTemplate;
|
||||||
private String backupVersion;
|
private List<SenderModel> senderList;
|
||||||
|
private List<RuleModel> ruleList;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
@ -51,7 +56,8 @@ public class CloneInfoVo implements Serializable {
|
|||||||
", delayTime=" + delayTime +
|
", delayTime=" + delayTime +
|
||||||
", enableSmsTemplate=" + enableSmsTemplate +
|
", enableSmsTemplate=" + enableSmsTemplate +
|
||||||
", smsTemplate=" + smsTemplate +
|
", smsTemplate=" + smsTemplate +
|
||||||
", backupVersion=" + backupVersion +
|
", senderList=" + senderList.toString() +
|
||||||
|
", ruleList=" + ruleList.toString() +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import com.alibaba.fastjson.TypeReference;
|
|||||||
import com.alibaba.fastjson.util.IOUtils;
|
import com.alibaba.fastjson.util.IOUtils;
|
||||||
import com.idormy.sms.forwarder.model.vo.ResVo;
|
import com.idormy.sms.forwarder.model.vo.ResVo;
|
||||||
import com.idormy.sms.forwarder.model.vo.SmsHubVo;
|
import com.idormy.sms.forwarder.model.vo.SmsHubVo;
|
||||||
import com.idormy.sms.forwarder.utils.BackupDbTask;
|
import com.idormy.sms.forwarder.utils.CloneUtils;
|
||||||
import com.idormy.sms.forwarder.utils.SettingUtil;
|
import com.idormy.sms.forwarder.utils.SettingUtil;
|
||||||
import com.idormy.sms.forwarder.utils.SmsHubActionHandler;
|
import com.idormy.sms.forwarder.utils.SmsHubActionHandler;
|
||||||
|
|
||||||
@ -20,14 +20,11 @@ import org.eclipse.jetty.util.StringUtil;
|
|||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.util.HashMap;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.servlet.MultipartConfigElement;
|
import javax.servlet.MultipartConfigElement;
|
||||||
import javax.servlet.ServletOutputStream;
|
import javax.servlet.ServletOutputStream;
|
||||||
@ -118,7 +115,7 @@ public class BaseServlet extends HttpServlet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//发送短信api
|
||||||
private void send_api(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
private void send_api(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||||
resp.setCharacterEncoding("utf-8");
|
resp.setCharacterEncoding("utf-8");
|
||||||
PrintWriter writer = resp.getWriter();
|
PrintWriter writer = resp.getWriter();
|
||||||
@ -170,40 +167,15 @@ public class BaseServlet extends HttpServlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//一键克隆——查询接口
|
//一键克隆——查询接口
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
|
||||||
private void clone_api(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
private void clone_api(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||||
resp.setCharacterEncoding("utf-8");
|
resp.setCharacterEncoding("utf-8");
|
||||||
PrintWriter writer = resp.getWriter();
|
PrintWriter writer = resp.getWriter();
|
||||||
BufferedReader reader = req.getReader();
|
BufferedReader reader = req.getReader();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//备份文件
|
|
||||||
BackupDbTask task = new BackupDbTask(context);
|
|
||||||
String backup_version = task.doInBackground(BackupDbTask.COMMAND_BACKUP);
|
|
||||||
Log.d(TAG, "backup_version = " + backup_version);
|
|
||||||
|
|
||||||
Map msgMap = new HashMap();
|
|
||||||
msgMap.put("versionCode", SettingUtil.getVersionCode());
|
|
||||||
msgMap.put("versionName", SettingUtil.getVersionName());
|
|
||||||
msgMap.put("enableSms", SettingUtil.getSwitchEnableSms());
|
|
||||||
msgMap.put("enablePhone", SettingUtil.getSwitchEnablePhone());
|
|
||||||
msgMap.put("callType1", SettingUtil.getSwitchCallType1());
|
|
||||||
msgMap.put("callType2", SettingUtil.getSwitchCallType2());
|
|
||||||
msgMap.put("callType3", SettingUtil.getSwitchCallType3());
|
|
||||||
msgMap.put("enableAppNotify", SettingUtil.getSwitchEnableAppNotify());
|
|
||||||
msgMap.put("cancelAppNotify", SettingUtil.getSwitchCancelAppNotify());
|
|
||||||
msgMap.put("smsHubApiUrl", SettingUtil.getSmsHubApiUrl());
|
|
||||||
msgMap.put("batteryLevelAlarmMin", SettingUtil.getBatteryLevelAlarmMin());
|
|
||||||
msgMap.put("batteryLevelAlarmMax", SettingUtil.getBatteryLevelAlarmMax());
|
|
||||||
msgMap.put("batteryLevelAlarmOnce", SettingUtil.getBatteryLevelAlarmOnce());
|
|
||||||
msgMap.put("retryTimes", SettingUtil.getRetryTimes());
|
|
||||||
msgMap.put("delayTime", SettingUtil.getDelayTime());
|
|
||||||
msgMap.put("enableSmsTemplate", SettingUtil.getSwitchSmsTemplate());
|
|
||||||
msgMap.put("smsTemplate", SettingUtil.getSmsTemplate());
|
|
||||||
msgMap.put("backupVersion", backup_version);
|
|
||||||
|
|
||||||
resp.setContentType("application/json;charset=utf-8");
|
resp.setContentType("application/json;charset=utf-8");
|
||||||
String text = JSON.toJSONString(msgMap);
|
String json = CloneUtils.exportSettings();
|
||||||
writer.println(text);
|
writer.println(json);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
printErrMsg(resp, writer, e);
|
printErrMsg(resp, writer, e);
|
||||||
@ -215,23 +187,17 @@ public class BaseServlet extends HttpServlet {
|
|||||||
|
|
||||||
//一键克隆——下载接口
|
//一键克隆——下载接口
|
||||||
private void clone(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
private void clone(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||||
File file = new File(context.getCacheDir().getPath() + File.separator + BackupDbTask.BACKUP_FILE);
|
resp.addHeader("Content-Disposition", "attachment;filename=" + "SmsForwarder.json");
|
||||||
resp.addHeader("Content-Disposition", "attachment;filename=" + BackupDbTask.BACKUP_FILE);
|
|
||||||
ServletOutputStream outputStream = resp.getOutputStream();
|
ServletOutputStream outputStream = resp.getOutputStream();
|
||||||
InputStream inputStream = new FileInputStream(file);
|
|
||||||
try {
|
try {
|
||||||
byte[] buffer = new byte[BUFFER_SIZE];
|
String json = CloneUtils.exportSettings();
|
||||||
int size;
|
outputStream.write(json.getBytes(StandardCharsets.UTF_8));
|
||||||
while ((size = inputStream.read(buffer)) != -1) {
|
|
||||||
outputStream.write(buffer, 0, size);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
String text = "Internal server error: " + e.getMessage();
|
String text = "Internal server error: " + e.getMessage();
|
||||||
Log.e(TAG, text);
|
Log.e(TAG, text);
|
||||||
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||||
} finally {
|
} finally {
|
||||||
IOUtils.close(inputStream);
|
|
||||||
IOUtils.close(outputStream);
|
IOUtils.close(outputStream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ public class SenderBarkMsg extends SenderBaseMsg {
|
|||||||
|
|
||||||
static final String TAG = "SenderBarkMsg";
|
static final String TAG = "SenderBarkMsg";
|
||||||
|
|
||||||
|
@SuppressWarnings("RedundantThrows")
|
||||||
public static void sendMsg(final long logId, final Handler handError, final RetryIntercepter retryInterceptor, BarkSettingVo barkSettingVo, String title, String content, String groupName) throws Exception {
|
public static void sendMsg(final long logId, final Handler handError, final RetryIntercepter retryInterceptor, BarkSettingVo barkSettingVo, String title, String content, String groupName) throws Exception {
|
||||||
Log.i(TAG, "sendMsg barkServer:" + barkSettingVo.toString() + " title:" + title + " content:" + content);
|
Log.i(TAG, "sendMsg barkServer:" + barkSettingVo.toString() + " title:" + title + " content:" + content);
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ import okhttp3.Request;
|
|||||||
import okhttp3.RequestBody;
|
import okhttp3.RequestBody;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
@SuppressWarnings("RedundantThrows")
|
||||||
public class SenderGotifyMsg extends SenderBaseMsg {
|
public class SenderGotifyMsg extends SenderBaseMsg {
|
||||||
|
|
||||||
static final String TAG = "SenderGotifyMsg";
|
static final String TAG = "SenderGotifyMsg";
|
||||||
|
@ -24,7 +24,7 @@ import okhttp3.Request;
|
|||||||
import okhttp3.RequestBody;
|
import okhttp3.RequestBody;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
|
||||||
@SuppressWarnings({"rawtypes", "unchecked", "deprecation"})
|
@SuppressWarnings({"rawtypes", "unchecked", "deprecation", "RedundantThrows"})
|
||||||
public class SenderPushPlusMsg extends SenderBaseMsg {
|
public class SenderPushPlusMsg extends SenderBaseMsg {
|
||||||
|
|
||||||
static final String TAG = "SenderPushPlusMsg";
|
static final String TAG = "SenderPushPlusMsg";
|
||||||
|
@ -26,7 +26,7 @@ import okhttp3.Request;
|
|||||||
import okhttp3.RequestBody;
|
import okhttp3.RequestBody;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
|
||||||
@SuppressWarnings({"rawtypes", "unchecked", "deprecation"})
|
@SuppressWarnings({"rawtypes", "unchecked", "deprecation", "RedundantThrows"})
|
||||||
public class SenderQyWxAppMsg extends SenderBaseMsg {
|
public class SenderQyWxAppMsg extends SenderBaseMsg {
|
||||||
|
|
||||||
static final String TAG = "SenderQyWxAppMsg";
|
static final String TAG = "SenderQyWxAppMsg";
|
||||||
|
@ -23,7 +23,7 @@ import okhttp3.Request;
|
|||||||
import okhttp3.RequestBody;
|
import okhttp3.RequestBody;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
|
||||||
@SuppressWarnings({"rawtypes", "unchecked", "deprecation"})
|
@SuppressWarnings({"rawtypes", "unchecked", "deprecation", "RedundantThrows"})
|
||||||
public class SenderQyWxGroupRobotMsg extends SenderBaseMsg {
|
public class SenderQyWxGroupRobotMsg extends SenderBaseMsg {
|
||||||
|
|
||||||
static final String TAG = "SenderQyWxGroupRobotMsg";
|
static final String TAG = "SenderQyWxGroupRobotMsg";
|
||||||
|
@ -20,6 +20,7 @@ import okhttp3.Request;
|
|||||||
import okhttp3.RequestBody;
|
import okhttp3.RequestBody;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
@SuppressWarnings("RedundantThrows")
|
||||||
public class SenderServerChanMsg extends SenderBaseMsg {
|
public class SenderServerChanMsg extends SenderBaseMsg {
|
||||||
|
|
||||||
static final String TAG = "SenderServerChanMsg";
|
static final String TAG = "SenderServerChanMsg";
|
||||||
|
@ -8,6 +8,7 @@ import com.idormy.sms.forwarder.utils.LogUtil;
|
|||||||
import com.idormy.sms.forwarder.utils.SimUtil;
|
import com.idormy.sms.forwarder.utils.SimUtil;
|
||||||
import com.idormy.sms.forwarder.utils.SmsUtil;
|
import com.idormy.sms.forwarder.utils.SmsUtil;
|
||||||
|
|
||||||
|
@SuppressWarnings("RedundantThrows")
|
||||||
public class SenderSmsMsg extends SenderBaseMsg {
|
public class SenderSmsMsg extends SenderBaseMsg {
|
||||||
|
|
||||||
static final String TAG = "SenderSmsMsg";
|
static final String TAG = "SenderSmsMsg";
|
||||||
|
@ -46,10 +46,14 @@ public class SenderUtil {
|
|||||||
values.put(SenderTable.SenderEntry.COLUMN_NAME_STATUS, senderModel.getStatus());
|
values.put(SenderTable.SenderEntry.COLUMN_NAME_STATUS, senderModel.getStatus());
|
||||||
values.put(SenderTable.SenderEntry.COLUMN_NAME_JSON_SETTING, senderModel.getJsonSetting());
|
values.put(SenderTable.SenderEntry.COLUMN_NAME_JSON_SETTING, senderModel.getJsonSetting());
|
||||||
|
|
||||||
|
if (null != senderModel.getId()) {
|
||||||
|
values.put(BaseColumns._ID, senderModel.getId());
|
||||||
|
return db.replace(SenderTable.SenderEntry.TABLE_NAME, null, values);
|
||||||
|
} else {
|
||||||
// Insert the new row, returning the primary key value of the new row
|
// Insert the new row, returning the primary key value of the new row
|
||||||
|
|
||||||
return db.insert(SenderTable.SenderEntry.TABLE_NAME, null, values);
|
return db.insert(SenderTable.SenderEntry.TABLE_NAME, null, values);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static long updateSender(SenderModel senderModel) {
|
public static long updateSender(SenderModel senderModel) {
|
||||||
if (senderModel == null) return 0;
|
if (senderModel == null) return 0;
|
||||||
|
@ -1,117 +0,0 @@
|
|||||||
package com.idormy.sms.forwarder.utils;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Environment;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
import java.nio.channels.FileChannel;
|
|
||||||
|
|
||||||
@SuppressWarnings({"ResultOfMethodCallIgnored", "CommentedOutCode"})
|
|
||||||
public class BackupDbTask {
|
|
||||||
private static final String TAG = "BackupDbTask";
|
|
||||||
public static final String COMMAND_BACKUP = "backupDatabase";
|
|
||||||
public static final String COMMAND_RESTORE = "restoreDatabase";
|
|
||||||
public final static String BACKUP_FOLDER = "SmsForwarder";
|
|
||||||
public final static String BACKUP_FILE = "SmsForwarder.zip";
|
|
||||||
public String backup_version;
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
|
||||||
private static Context mContext;
|
|
||||||
|
|
||||||
public BackupDbTask(Context context) {
|
|
||||||
mContext = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static File getExternalStoragePublicDir() {
|
|
||||||
// /sdcard/SmsForwarder/
|
|
||||||
String path = Environment.getExternalStorageDirectory() + File.separator + BACKUP_FOLDER + File.separator;
|
|
||||||
File dir = new File(path);
|
|
||||||
if (!dir.exists()) dir.mkdirs();
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String doInBackground(String command) {
|
|
||||||
File dbFile = mContext.getDatabasePath(DbHelper.DATABASE_NAME);// 默认路径是 /data/data/(包名)/databases/*
|
|
||||||
File dbFile_shm = mContext.getDatabasePath(DbHelper.DATABASE_NAME + "-journal");// 默认路径是 /data/data/(包名)/databases/*
|
|
||||||
//File dbFile_wal = mContext.getDatabasePath("event_database-wal");// 默认路径是 /data/data/(包名)/databases/*
|
|
||||||
|
|
||||||
String bakFolder = mContext.getCacheDir().getPath() + File.separator + BACKUP_FOLDER;
|
|
||||||
String zipFile = mContext.getCacheDir().getPath() + File.separator + BACKUP_FILE;
|
|
||||||
Log.d(TAG, "备份目录名:" + bakFolder + ",备份文件名:" + zipFile);
|
|
||||||
|
|
||||||
File exportDir = new File(mContext.getCacheDir().getPath(), BACKUP_FOLDER);//直接丢在 cache 目录,可以在在关于目录下清除缓存
|
|
||||||
if (!exportDir.exists()) exportDir.mkdirs();
|
|
||||||
|
|
||||||
File backup = new File(bakFolder, dbFile.getName());//备份文件与原数据库文件名一致
|
|
||||||
File backup_shm = new File(bakFolder, dbFile_shm.getName());//备份文件与原数据库文件名一致
|
|
||||||
//File backup_wal = new File(bakFolder, dbFile_wal.getName());//备份文件与原数据库文件名一致
|
|
||||||
if (command.equals(COMMAND_BACKUP)) {
|
|
||||||
try {
|
|
||||||
//备份文件
|
|
||||||
backup.createNewFile();
|
|
||||||
backup_shm.createNewFile();
|
|
||||||
//backup_wal.createNewFile();
|
|
||||||
fileCopy(dbFile, backup);//数据库文件拷贝至备份文件
|
|
||||||
fileCopy(dbFile_shm, backup_shm);//数据库文件拷贝至备份文件
|
|
||||||
//fileCopy(dbFile_wal, backup_wal);//数据库文件拷贝至备份文件
|
|
||||||
//backup.setLastModified(MyTimeUtils.getTimeLong());
|
|
||||||
|
|
||||||
backup_version = TimeUtil.getTimeString("yyyy.MM.dd_HH:mm:ss");
|
|
||||||
Log.d(TAG, "backup ok! 备份目录:" + backup.getName() + "\t" + backup_version);
|
|
||||||
|
|
||||||
//打包文件
|
|
||||||
ZipUtils.ZipFolder(bakFolder, zipFile);
|
|
||||||
Log.d(TAG, "备份Zip包:" + zipFile);
|
|
||||||
|
|
||||||
return backup_version;
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
Log.d(TAG, "backup fail! 备份文件名:" + backup.getName());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} else if (command.equals(COMMAND_RESTORE)) {
|
|
||||||
try {
|
|
||||||
//解压文件
|
|
||||||
ZipUtils.UnZipFolder(zipFile, bakFolder);
|
|
||||||
Log.d(TAG, "解压Zip包:" + zipFile);
|
|
||||||
|
|
||||||
//还原文件
|
|
||||||
fileCopy(backup, dbFile);//备份文件拷贝至数据库文件
|
|
||||||
fileCopy(backup_shm, dbFile_shm);//备份文件拷贝至数据库文件
|
|
||||||
//fileCopy(backup_wal, dbFile_wal);//备份文件拷贝至数据库文件
|
|
||||||
backup_version = TimeUtil.getTimeString(backup.lastModified(), "yyyy.MM.dd_HH:mm:ss");
|
|
||||||
Log.d(TAG, "restore success! 数据库文件名:" + dbFile.getName() + "\t" + backup_version);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(1000);
|
|
||||||
} catch (final InterruptedException e) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
throw new InterruptedIOException(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
LogUtil.delLog(null, null);
|
|
||||||
|
|
||||||
return backup_version;
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
Log.d(TAG, "restore fail! 数据库文件名:" + dbFile.getName());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void fileCopy(File dbFile, File backup) {
|
|
||||||
try (FileChannel inChannel = new FileInputStream(dbFile).getChannel(); FileChannel outChannel = new FileOutputStream(backup).getChannel()) {
|
|
||||||
inChannel.transferTo(0, inChannel.size(), outChannel);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,88 @@
|
|||||||
|
package com.idormy.sms.forwarder.utils;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.idormy.sms.forwarder.model.RuleModel;
|
||||||
|
import com.idormy.sms.forwarder.model.SenderModel;
|
||||||
|
import com.idormy.sms.forwarder.model.vo.CloneInfoVo;
|
||||||
|
import com.idormy.sms.forwarder.sender.SenderUtil;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一键克隆工具类
|
||||||
|
*/
|
||||||
|
public class CloneUtils {
|
||||||
|
|
||||||
|
//导出设置
|
||||||
|
public static String exportSettings() {
|
||||||
|
CloneInfoVo cloneInfo = new CloneInfoVo();
|
||||||
|
try {
|
||||||
|
cloneInfo.setVersionCode(SettingUtil.getVersionCode());
|
||||||
|
cloneInfo.setVersionName(SettingUtil.getVersionName());
|
||||||
|
cloneInfo.setEnableSms(SettingUtil.getSwitchEnableSms());
|
||||||
|
cloneInfo.setEnablePhone(SettingUtil.getSwitchEnablePhone());
|
||||||
|
cloneInfo.setCallType1(SettingUtil.getSwitchCallType1());
|
||||||
|
cloneInfo.setCallType2(SettingUtil.getSwitchCallType2());
|
||||||
|
cloneInfo.setCallType3(SettingUtil.getSwitchCallType3());
|
||||||
|
cloneInfo.setEnableAppNotify(SettingUtil.getSwitchEnableAppNotify());
|
||||||
|
cloneInfo.setCancelAppNotify(SettingUtil.getSwitchCancelAppNotify());
|
||||||
|
cloneInfo.setSmsHubApiUrl(SettingUtil.getSmsHubApiUrl());
|
||||||
|
cloneInfo.setBatteryLevelAlarmMin(SettingUtil.getBatteryLevelAlarmMin());
|
||||||
|
cloneInfo.setBatteryLevelAlarmMax(SettingUtil.getBatteryLevelAlarmMax());
|
||||||
|
cloneInfo.setBatteryLevelAlarmOnce(SettingUtil.getBatteryLevelAlarmOnce());
|
||||||
|
cloneInfo.setRetryTimes(SettingUtil.getRetryTimes());
|
||||||
|
cloneInfo.setDelayTime(SettingUtil.getDelayTime());
|
||||||
|
cloneInfo.setEnableSmsTemplate(SettingUtil.getSwitchSmsTemplate());
|
||||||
|
cloneInfo.setSmsTemplate(SettingUtil.getSmsTemplate());
|
||||||
|
cloneInfo.setSenderList(SenderUtil.getSender(null, null));
|
||||||
|
cloneInfo.setRuleList(RuleUtil.getRule(null, null));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.toJSONString(cloneInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
//还原设置
|
||||||
|
public static boolean restoreSettings(CloneInfoVo cloneInfoVo) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
//应用配置
|
||||||
|
//SettingUtil.init(context);
|
||||||
|
SettingUtil.switchEnableSms(cloneInfoVo.isEnableSms());
|
||||||
|
SettingUtil.switchEnablePhone(cloneInfoVo.isEnablePhone());
|
||||||
|
SettingUtil.switchCallType1(cloneInfoVo.isCallType1());
|
||||||
|
SettingUtil.switchCallType2(cloneInfoVo.isCallType2());
|
||||||
|
SettingUtil.switchCallType3(cloneInfoVo.isCallType3());
|
||||||
|
SettingUtil.switchEnableAppNotify(cloneInfoVo.isEnableAppNotify());
|
||||||
|
SettingUtil.switchCancelAppNotify(cloneInfoVo.isCancelAppNotify());
|
||||||
|
SettingUtil.smsHubApiUrl(cloneInfoVo.getSmsHubApiUrl());
|
||||||
|
SettingUtil.setBatteryLevelAlarmMin(cloneInfoVo.getBatteryLevelAlarmMin());
|
||||||
|
SettingUtil.setBatteryLevelAlarmMax(cloneInfoVo.getBatteryLevelAlarmMax());
|
||||||
|
SettingUtil.switchBatteryLevelAlarmOnce(cloneInfoVo.isBatteryLevelAlarmOnce());
|
||||||
|
SettingUtil.setRetryTimes(cloneInfoVo.getRetryTimes());
|
||||||
|
SettingUtil.setDelayTime(cloneInfoVo.getDelayTime());
|
||||||
|
SettingUtil.switchSmsTemplate(cloneInfoVo.isEnableSmsTemplate());
|
||||||
|
SettingUtil.setSmsTemplate(cloneInfoVo.getSmsTemplate());
|
||||||
|
|
||||||
|
SenderUtil.delSender(null);
|
||||||
|
List<SenderModel> senderList = cloneInfoVo.getSenderList();
|
||||||
|
for (SenderModel senderModel : senderList) {
|
||||||
|
SenderUtil.addSender(senderModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
RuleUtil.delRule(null);
|
||||||
|
List<RuleModel> ruleList = cloneInfoVo.getRuleList();
|
||||||
|
for (RuleModel ruleModel : ruleList) {
|
||||||
|
RuleUtil.addRule(ruleModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
LogUtil.delLog(null, null);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,108 +0,0 @@
|
|||||||
package com.idormy.sms.forwarder.utils;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import okhttp3.Call;
|
|
||||||
import okhttp3.Callback;
|
|
||||||
import okhttp3.OkHttpClient;
|
|
||||||
import okhttp3.Request;
|
|
||||||
import okhttp3.Response;
|
|
||||||
|
|
||||||
public class DownloadUtil {
|
|
||||||
private static DownloadUtil downloadUtil;
|
|
||||||
private final OkHttpClient okHttpClient;
|
|
||||||
|
|
||||||
public static DownloadUtil get() {
|
|
||||||
if (downloadUtil == null) {
|
|
||||||
downloadUtil = new DownloadUtil();
|
|
||||||
}
|
|
||||||
return downloadUtil;
|
|
||||||
}
|
|
||||||
|
|
||||||
private DownloadUtil() {
|
|
||||||
okHttpClient = new OkHttpClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param url 下载连接
|
|
||||||
* @param destFileDir 下载的文件储存目录
|
|
||||||
* @param destFileName 下载文件名称
|
|
||||||
* @param listener 下载监听
|
|
||||||
*/
|
|
||||||
public void download(final String url, final String destFileDir, final String destFileName, final OnDownloadListener listener) {
|
|
||||||
|
|
||||||
Request request = new Request.Builder().url(url).addHeader("Connection", "close").build();
|
|
||||||
okHttpClient.newCall(request).enqueue(new Callback() {
|
|
||||||
@Override
|
|
||||||
public void onFailure(@NonNull Call call, @NonNull IOException e) {
|
|
||||||
// 下载失败监听回调
|
|
||||||
listener.onDownloadFailed(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
|
||||||
@Override
|
|
||||||
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
|
|
||||||
InputStream is = null;
|
|
||||||
byte[] buf = new byte[2048];
|
|
||||||
int len;
|
|
||||||
FileOutputStream fos = null;
|
|
||||||
|
|
||||||
// 储存下载文件的目录
|
|
||||||
File dir = new File(destFileDir);
|
|
||||||
if (!dir.exists()) dir.mkdirs();
|
|
||||||
|
|
||||||
File file = new File(dir, destFileName);
|
|
||||||
if (file.exists()) file.delete();
|
|
||||||
|
|
||||||
try {
|
|
||||||
is = Objects.requireNonNull(response.body()).byteStream();
|
|
||||||
long total = Objects.requireNonNull(response.body()).contentLength();
|
|
||||||
fos = new FileOutputStream(file);
|
|
||||||
long sum = 0;
|
|
||||||
while ((len = is.read(buf)) != -1) {
|
|
||||||
fos.write(buf, 0, len);
|
|
||||||
sum += len;
|
|
||||||
int progress = (int) (sum * 1.0f / total * 100);
|
|
||||||
// 下载中更新进度条
|
|
||||||
listener.onDownloading(progress);
|
|
||||||
}
|
|
||||||
fos.flush();
|
|
||||||
// 下载完成
|
|
||||||
listener.onDownloadSuccess(file);
|
|
||||||
} catch (Exception e) {
|
|
||||||
listener.onDownloadFailed(e);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (is != null) is.close();
|
|
||||||
if (fos != null) fos.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnDownloadListener {
|
|
||||||
/**
|
|
||||||
* @param file 下载成功后的文件
|
|
||||||
*/
|
|
||||||
void onDownloadSuccess(File file);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param progress 下载进度
|
|
||||||
*/
|
|
||||||
void onDownloading(int progress);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param e 下载异常信息
|
|
||||||
*/
|
|
||||||
void onDownloadFailed(Exception e);
|
|
||||||
}
|
|
||||||
}
|
|
253
app/src/main/java/com/idormy/sms/forwarder/utils/FileUtils.java
Normal file
253
app/src/main/java/com/idormy/sms/forwarder/utils/FileUtils.java
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
package com.idormy.sms.forwarder.utils;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 文件读写工具类
|
||||||
|
* external storage
|
||||||
|
外部存储 Environment.getExternalStorageDirectory() SD根目录:/mnt/sdcard/ (6.0后写入需要用户授权)
|
||||||
|
context.getExternalFilesDir(dir) 路径为:/mnt/sdcard/Android/data/< package name >/files/…
|
||||||
|
context.getExternalCacheDir() 路径为:/mnt/sdcard//Android/data/< package name >/cach/…
|
||||||
|
*
|
||||||
|
internal storage
|
||||||
|
内部存储
|
||||||
|
context.getFilesDir() 路径是:/data/data/< package name >/files/…
|
||||||
|
context.getCacheDir() 路径是:/data/data/< package name >/cach/…
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"UnusedReturnValue", "ResultOfMethodCallIgnored"})
|
||||||
|
public class FileUtils {
|
||||||
|
private static final String TAG = FileUtils.class.getSimpleName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return .外部储存sd卡 根路径
|
||||||
|
*/
|
||||||
|
public static String getRootPath() {
|
||||||
|
// /storage/emulated/0
|
||||||
|
return Environment.getExternalStorageDirectory().getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param context .
|
||||||
|
* @return . 外部储存sd卡 :/mnt/sdcard/Android/data/< package name >/files/…
|
||||||
|
*/
|
||||||
|
public static String getAppRootPth(Context context) {
|
||||||
|
// /storage/emulated/0/Android/data/pack_name/files
|
||||||
|
return context.getExternalFilesDir("").getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return .内部存储
|
||||||
|
*/
|
||||||
|
public static String getInternalPath() {
|
||||||
|
// /data
|
||||||
|
return Environment.getDataDirectory().getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param context .
|
||||||
|
* @return .内部储存:/data/data/< package name >/files/
|
||||||
|
*/
|
||||||
|
public static String getInternalAppPath(Context context) {
|
||||||
|
return context.getFilesDir().getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param path 路径
|
||||||
|
* @param fileName 文件名称
|
||||||
|
* @return .
|
||||||
|
*/
|
||||||
|
public static boolean createFile(String path, String fileName) {
|
||||||
|
File file = new File(path + File.separator + fileName);
|
||||||
|
|
||||||
|
//先创建文件夹 保证文件创建成功
|
||||||
|
createDirs(path);
|
||||||
|
|
||||||
|
if (!file.exists()) {
|
||||||
|
try {
|
||||||
|
file.createNewFile();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
//
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param folder 创建多级文件夹
|
||||||
|
* @return .
|
||||||
|
*/
|
||||||
|
public static boolean createDirs(String folder) {
|
||||||
|
File file = new File(folder);
|
||||||
|
|
||||||
|
if (!file.exists()) {
|
||||||
|
boolean mkdirs = file.mkdirs();
|
||||||
|
Log.i(TAG, "createDirs: 不存在文件夹 开始创建" + mkdirs + "--" + folder);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
Log.i(TAG, "createDirs: 文件夹已存在");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* =======================================文件读写=============================================
|
||||||
|
*
|
||||||
|
* @param content 写入字符串
|
||||||
|
* @param path . 目录
|
||||||
|
* @param fileName .文件名
|
||||||
|
* @param isRewrite 是否覆盖
|
||||||
|
*/
|
||||||
|
//1.RandomAccessFile 读写
|
||||||
|
public static boolean writeFileR(String content, String path, String fileName, boolean isRewrite) {
|
||||||
|
//路径非斜杆结尾
|
||||||
|
if (!path.endsWith("/")) path += File.separator;
|
||||||
|
|
||||||
|
File file = new File(path + fileName);
|
||||||
|
|
||||||
|
//文件目录不存在,先创建
|
||||||
|
if (!file.exists()) createFile(path, fileName);
|
||||||
|
|
||||||
|
RandomAccessFile randomAccessFile;
|
||||||
|
try {
|
||||||
|
randomAccessFile = new RandomAccessFile(file, "rw");
|
||||||
|
if (isRewrite) {
|
||||||
|
randomAccessFile.setLength(content.length());
|
||||||
|
randomAccessFile.seek(0);
|
||||||
|
} else {
|
||||||
|
randomAccessFile.seek(randomAccessFile.length());
|
||||||
|
}
|
||||||
|
randomAccessFile.write(content.getBytes());
|
||||||
|
randomAccessFile.close();
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean writeFileR(String content, String path, String fileName) {
|
||||||
|
return writeFileR(content, path, fileName, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读文件
|
||||||
|
*
|
||||||
|
* @param path .
|
||||||
|
* @param fileName .
|
||||||
|
* @return .
|
||||||
|
*/
|
||||||
|
public static String readFileR(String path, String fileName) {
|
||||||
|
//路径非斜杆结尾
|
||||||
|
if (!path.endsWith("/")) path += File.separator;
|
||||||
|
|
||||||
|
File file = new File(path + fileName);
|
||||||
|
if (!file.exists()) {
|
||||||
|
Log.i(TAG, "readFileR: return null");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder buffer = new StringBuilder();
|
||||||
|
try {
|
||||||
|
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
|
||||||
|
randomAccessFile.seek(0);
|
||||||
|
byte[] buf = new byte[(int) randomAccessFile.length()];
|
||||||
|
if (randomAccessFile.read(buf) != -1) {
|
||||||
|
buffer.append(new String(buf));
|
||||||
|
Log.i(TAG, "readFileR: length" + randomAccessFile.length());
|
||||||
|
//buffer.append(new String(buf, StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
randomAccessFile.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.i(TAG, "readFileR: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读文件
|
||||||
|
*
|
||||||
|
* @param path .文件路径
|
||||||
|
* @param name .名称
|
||||||
|
* @return .
|
||||||
|
*/
|
||||||
|
public static String readFileI(String path, String name) {
|
||||||
|
//路径非斜杆结尾
|
||||||
|
if (!path.endsWith("/")) path += File.separator;
|
||||||
|
|
||||||
|
//默认编码格式 StandardCharsets.UTF_8;
|
||||||
|
File file = new File(path, name);
|
||||||
|
if (!file.exists()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
try {
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8));
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
builder.append(line);
|
||||||
|
builder.append("\n");
|
||||||
|
}
|
||||||
|
reader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入文件
|
||||||
|
*
|
||||||
|
* @param content 内容.
|
||||||
|
* @param path 目录.
|
||||||
|
* @param fileName 文件名 .
|
||||||
|
*/
|
||||||
|
public static void writeFileO(String content, String path, String fileName) {
|
||||||
|
writeFileO(content, path, fileName, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param content .
|
||||||
|
* @param path .
|
||||||
|
* @param fileName .
|
||||||
|
* @param isReWrite .是否追加
|
||||||
|
*/
|
||||||
|
public static void writeFileO(String content, String path, String fileName, boolean isReWrite) {
|
||||||
|
//路径非斜杆结尾
|
||||||
|
if (!path.endsWith("/")) path += File.separator;
|
||||||
|
|
||||||
|
File file = new File(path + fileName);
|
||||||
|
|
||||||
|
//文件目录不存在,先创建
|
||||||
|
if (!file.exists()) createFile(path, fileName);
|
||||||
|
|
||||||
|
try {
|
||||||
|
FileOutputStream ops = new FileOutputStream(file, isReWrite);
|
||||||
|
OutputStreamWriter opsw = new OutputStreamWriter(ops, StandardCharsets.UTF_8);
|
||||||
|
// byte[] bytes = content.getBytes();
|
||||||
|
opsw.write(content);
|
||||||
|
opsw.close();
|
||||||
|
ops.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -147,6 +147,7 @@ public class HttpUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("RedundantThrows")
|
||||||
public static class Callback0 implements Callback {
|
public static class Callback0 implements Callback {
|
||||||
public Callback0(String tag, Lamda.Consumer<Response> onResponse, Lamda.Consumer<Exception> onFailure) {
|
public Callback0(String tag, Lamda.Consumer<Response> onResponse, Lamda.Consumer<Exception> onFailure) {
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
|
@ -48,10 +48,14 @@ public class RuleUtil {
|
|||||||
values.put(RuleTable.RuleEntry.COLUMN_REGEX_REPLACE, ruleModel.getRegexReplace());
|
values.put(RuleTable.RuleEntry.COLUMN_REGEX_REPLACE, ruleModel.getRegexReplace());
|
||||||
values.put(RuleTable.RuleEntry.COLUMN_NAME_STATUS, ruleModel.getStatus());
|
values.put(RuleTable.RuleEntry.COLUMN_NAME_STATUS, ruleModel.getStatus());
|
||||||
|
|
||||||
|
if (null != ruleModel.getId()) {
|
||||||
|
values.put(BaseColumns._ID, ruleModel.getId());
|
||||||
|
return db.replace(RuleTable.RuleEntry.TABLE_NAME, null, values);
|
||||||
|
} else {
|
||||||
// Insert the new row, returning the primary key value of the new row
|
// Insert the new row, returning the primary key value of the new row
|
||||||
|
|
||||||
return db.insert(RuleTable.RuleEntry.TABLE_NAME, null, values);
|
return db.insert(RuleTable.RuleEntry.TABLE_NAME, null, values);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static long updateRule(RuleModel ruleModel) {
|
public static long updateRule(RuleModel ruleModel) {
|
||||||
if (ruleModel == null) return 0;
|
if (ruleModel == null) return 0;
|
||||||
@ -91,6 +95,10 @@ public class RuleUtil {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<RuleModel> getRule(Long id, String key) {
|
||||||
|
return getRule(id, key, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
public static List<RuleModel> getRule(Long id, String key, String type) {
|
public static List<RuleModel> getRule(Long id, String key, String type) {
|
||||||
return getRule(id, key, type, null);
|
return getRule(id, key, type, null);
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,71 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingLeft="16dp"
|
<LinearLayout
|
||||||
android:paddingTop="16dp"
|
android:layout_width="match_parent"
|
||||||
android:paddingRight="16dp"
|
android:layout_height="wrap_content"
|
||||||
android:paddingBottom="16dp"
|
android:orientation="vertical">
|
||||||
android:weightSum="1">
|
|
||||||
|
<RadioGroup
|
||||||
|
android:id="@+id/radioGroupTypeCheck"
|
||||||
|
style="@style/rg_style"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_marginTop="5dip"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/btnTypeNetwork"
|
||||||
|
style="@style/select_style"
|
||||||
|
android:checked="true"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:minHeight="0dp"
|
||||||
|
android:paddingStart="10dp"
|
||||||
|
android:paddingTop="5dp"
|
||||||
|
android:paddingEnd="10dp"
|
||||||
|
android:paddingBottom="5dp"
|
||||||
|
android:tag="network"
|
||||||
|
android:text="@string/network_model" />
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/btnTypeOffline"
|
||||||
|
style="@style/select_style"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:minHeight="0dp"
|
||||||
|
android:paddingStart="10dp"
|
||||||
|
android:paddingTop="5dp"
|
||||||
|
android:paddingEnd="10dp"
|
||||||
|
android:paddingBottom="5dp"
|
||||||
|
android:tag="offline"
|
||||||
|
android:text="@string/offline_mode" />
|
||||||
|
|
||||||
|
</RadioGroup>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/radioGroupLine"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginEnd="25dp"
|
||||||
|
android:background="#aadcdcdc" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layoutNetwork"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
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"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
android:layout_weight="0.3"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical"
|
||||||
|
android:paddingTop="15dp">
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/sendBtn"
|
android:id="@+id/sendBtn"
|
||||||
@ -40,7 +89,6 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="0.1"
|
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:padding="15dp">
|
android:padding="15dp">
|
||||||
@ -58,11 +106,9 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="0.3"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
@ -88,9 +134,11 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="0.2"
|
|
||||||
android:gravity="start"
|
android:gravity="start"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="10dp"
|
||||||
|
android:paddingEnd="10dp"
|
||||||
|
android:paddingBottom="10dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/ipText"
|
android:id="@+id/ipText"
|
||||||
@ -109,4 +157,109 @@
|
|||||||
tools:ignore="SmallSp" />
|
tools:ignore="SmallSp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layoutOffline"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingTop="15dp">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/exportBtn"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:background="@drawable/send_btn"
|
||||||
|
android:text="@string/export"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="30sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/exportTxt"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10sp"
|
||||||
|
android:text="@string/old_mobile_phone" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="15dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/tips_backup_path"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/backupPathTxt"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text=""
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/importBtn"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:background="@drawable/receive_btn"
|
||||||
|
android:text="@string/imports"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="30sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/importTxt"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10sp"
|
||||||
|
android:text="@string/new_mobile_phone" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="start"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="10dp"
|
||||||
|
android:paddingEnd="10dp"
|
||||||
|
android:paddingBottom="10dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="@string/operating_instruction_offline"
|
||||||
|
android:textSize="10sp"
|
||||||
|
tools:ignore="SmallSp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
@ -227,8 +227,11 @@
|
|||||||
<!--CloneActivity-->
|
<!--CloneActivity-->
|
||||||
<string name="local_ip">Local IP:</string>
|
<string name="local_ip">Local IP:</string>
|
||||||
<string name="operating_instruction">Instructions: \n[Note] The APP version of the sender and receiver must be the same!\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: \n[Note] The APP version of the sender and receiver must be the same!\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_offline">[NOTE:] sender(s), forwarding rule(s) and log(s) will be overwritten after cloning!</string> <!-- 原文是“新旧手机”,英文翻译中处理为“源”手机和“目标”手机,因为担心“新旧”的表述引起混淆(有没一种可能就是用户就是用从新手机的设备复制到旧手机上去呢?)。 -->
|
||||||
<string name="send">Start</string>
|
<string name="send">Start</string>
|
||||||
<string name="stop">Stop</string>
|
<string name="stop">Stop</string>
|
||||||
|
<string name="export">Export</string>
|
||||||
|
<string name="imports">Import</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>
|
||||||
<string name="new_mobile_phone">I\'m the DESTINATION phone</string>
|
<string name="new_mobile_phone">I\'m the DESTINATION phone</string>
|
||||||
@ -393,10 +396,6 @@
|
|||||||
<string name="tips_compatible_solution">Compatible solution</string>
|
<string name="tips_compatible_solution">Compatible solution</string>
|
||||||
<string name="tips_wait_3_seconds">Please wait 3 seconds after clicking start</string>
|
<string name="tips_wait_3_seconds">Please wait 3 seconds after clicking start</string>
|
||||||
<string name="tips_clone_done">One-click clone operation is complete! \nPlease check whether the general settings and switches are turned on!</string>
|
<string name="tips_clone_done">One-click clone operation is complete! \nPlease check whether the general settings and switches are turned on!</string>
|
||||||
<string name="tips_download_done">Download complete, preparing to restore data…</string>
|
|
||||||
<string name="tips_download_failed">Download failed:</string>
|
|
||||||
<string name="tips_downloading">Downloading</string>
|
|
||||||
<string name="tips_please_wait">Please wait…</string>
|
|
||||||
<string name="tips_clone_failed">One-click clone failed:</string>
|
<string name="tips_clone_failed">One-click clone failed:</string>
|
||||||
<string name="tips_versions_inconsistent">The APP versions of the sender and the receiver are inconsistent, and cannot be cloned with one click!</string>
|
<string name="tips_versions_inconsistent">The APP versions of the sender and the receiver are inconsistent, and cannot be cloned with one click!</string>
|
||||||
<string name="tips_get_info_failed">Failed to get one-click clone information from sender</string>
|
<string name="tips_get_info_failed">Failed to get one-click clone information from sender</string>
|
||||||
@ -452,4 +451,7 @@
|
|||||||
<string name="tips_other_mail_type">For other email addresses, please fill in the complete email address and manually fill in the SMTP server information</string>
|
<string name="tips_other_mail_type">For other email addresses, please fill in the complete email address and manually fill in the SMTP server information</string>
|
||||||
<string name="optional">Optional</string>
|
<string name="optional">Optional</string>
|
||||||
<string name="TelegramChatIdTips">Follow the steps in the wiki to obtain it</string>
|
<string name="TelegramChatIdTips">Follow the steps in the wiki to obtain it</string>
|
||||||
|
<string name="network_model">网络模式</string>
|
||||||
|
<string name="offline_mode">离线模式</string>
|
||||||
|
<string name="tips_backup_path">Backup Path:</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -225,9 +225,12 @@
|
|||||||
<string name="post">POST</string>
|
<string name="post">POST</string>
|
||||||
<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\n注意事项:\n1.发送方与接收方的APP版本必须一致,才能克隆!\n2.新手机接收后,发送通道、转发规则将完全被覆盖,清空历史记录!\n3.主动请求、保活措施、个性设置不在克隆范围</string>
|
<string name="operating_instruction">严正声明:\n该功能仅限个人新旧手机切换使用,用于非法用途后果自负!\n\n操作说明:\n1.新旧手机连接同一个WiFi网络(禁用AP隔离)\n2.旧手机直接点【发送】按钮,获取到【服务端IP】\n3.新手机填写【服务端IP】后,点【接收】按钮\n\n注意事项:\n1.发送方与接收方的APP版本必须一致,才能克隆!\n2.新手机接收后,发送通道、转发规则将完全被覆盖,清空历史记录!\n3.主动请求、保活措施、个性设置不在克隆范围</string>
|
||||||
|
<string name="operating_instruction_offline">严正声明:\n该功能仅限个人新旧手机切换使用,用于非法用途后果自负!\n\n注意事项:\n1.发送方与接收方的APP版本必须一致,才能克隆!\n2.新手机接收后,发送通道、转发规则将完全被覆盖,清空历史记录!\n3.主动请求、保活措施、个性设置不在克隆范围</string>
|
||||||
<string name="send">启动</string>
|
<string name="send">启动</string>
|
||||||
<string name="stop">停止</string>
|
<string name="stop">停止</string>
|
||||||
|
<string name="export">导出</string>
|
||||||
|
<string name="imports">导入</string>
|
||||||
<string name="old_mobile_phone">我是旧手机</string>
|
<string name="old_mobile_phone">我是旧手机</string>
|
||||||
<string name="receive">接收</string>
|
<string name="receive">接收</string>
|
||||||
<string name="new_mobile_phone">我是新手机</string>
|
<string name="new_mobile_phone">我是新手机</string>
|
||||||
@ -392,13 +395,9 @@
|
|||||||
<string name="tips_compatible_solution">兼容方案</string>
|
<string name="tips_compatible_solution">兼容方案</string>
|
||||||
<string name="tips_wait_3_seconds">点击启动后请等待3秒</string>
|
<string name="tips_wait_3_seconds">点击启动后请等待3秒</string>
|
||||||
<string name="tips_clone_done">一键克隆操作完成!\n请检查·通用设置·各项开关是否已开启!</string>
|
<string name="tips_clone_done">一键克隆操作完成!\n请检查·通用设置·各项开关是否已开启!</string>
|
||||||
<string name="tips_download_done">下载完成,正准备还原数据…</string>
|
|
||||||
<string name="tips_download_failed">下载失败:</string>
|
|
||||||
<string name="tips_downloading">正在下载</string>
|
|
||||||
<string name="tips_please_wait">请稍后…</string>
|
|
||||||
<string name="tips_clone_failed">一键克隆失败:</string>
|
<string name="tips_clone_failed">一键克隆失败:</string>
|
||||||
<string name="tips_versions_inconsistent">发送端与接收端的APP版本不一致,无法一键克隆!</string>
|
<string name="tips_versions_inconsistent">APP版本不一致,无法一键克隆!</string>
|
||||||
<string name="tips_get_info_failed">从发送端获取一键克隆信息失败</string>
|
<string name="tips_get_info_failed">获取一键克隆信息失败</string>
|
||||||
<string name="linkman">联 系 人:</string>
|
<string name="linkman">联 系 人:</string>
|
||||||
<string name="via_number">来源号码:</string>
|
<string name="via_number">来源号码:</string>
|
||||||
<string name="bark_sound">消息声音</string>
|
<string name="bark_sound">消息声音</string>
|
||||||
@ -451,4 +450,7 @@
|
|||||||
<string name="tips_other_mail_type">其他邮箱,请填写完整的邮箱地址并手动填写SMTP服务器信息</string>
|
<string name="tips_other_mail_type">其他邮箱,请填写完整的邮箱地址并手动填写SMTP服务器信息</string>
|
||||||
<string name="optional">可选</string>
|
<string name="optional">可选</string>
|
||||||
<string name="TelegramChatIdTips">请按照wiki中的步骤获取</string>
|
<string name="TelegramChatIdTips">请按照wiki中的步骤获取</string>
|
||||||
|
<string name="network_model">网络模式</string>
|
||||||
|
<string name="offline_mode">离线模式</string>
|
||||||
|
<string name="tips_backup_path">备份文件存放路径:</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
#Fri Jul 16 10:33:23 CST 2021
|
#Fri Jul 16 10:33:23 CST 2021
|
||||||
versionName=2.4.3
|
versionName=2.4.4
|
||||||
versionCode=36
|
versionCode=37
|
||||||
|
Loading…
x
Reference in New Issue
Block a user