@ -1,8 +1,12 @@
package com.idormy.sms.forwarder ;
import android.annotation.SuppressLint ;
import android.app.ProgressDialog ;
import android.content.Context ;
import android.os.Bundle ;
import android.os.Handler ;
import android.os.Message ;
import android.text.TextUtils ;
import android.util.Log ;
import android.widget.Button ;
import android.widget.TextView ;
@ -11,26 +15,32 @@ import android.widget.Toast;
import androidx.annotation.NonNull ;
import androidx.appcompat.app.AppCompatActivity ;
import com.alibaba.fastjson.JSON ;
import com.idormy.sms.forwarder.model.vo.CloneInfoVo ;
import com.idormy.sms.forwarder.receiver.BaseServlet ;
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.BackupDbTask ;
import com.idormy.sms.forwarder.utils.Define ;
import com.idormy.sms.forwarder.utils.DownloadUtil ;
import com.idormy.sms.forwarder.utils.HttpUtil ;
import com.idormy.sms.forwarder.utils.NetUtil ;
import com.idormy.sms.forwarder.utils.SettingUtil ;
import com.idormy.sms.forwarder.view.IPEditText ;
import java.io.File ;
import java.io.FileInputStream ;
import java.io.FileNotFoundException ;
import java.io.FileOutputStream ;
import java.io.IOException ;
import java. io.InputStream ;
import java. io.OutputStream ;
import java.util.HashMap ;
import java.util.Map ;
import java.util.Objects ;
import java.util.concurrent.TimeUnit ;
import okhttp3.Call ;
import okhttp3.Callback ;
import okhttp3.MediaType ;
import okhttp3.OkHttpClient ;
import okhttp3.Request ;
import okhttp3.RequestBody ;
import okhttp3.Response ;
public class CloneActivity extends AppCompatActivity {
@ -38,6 +48,28 @@ public class CloneActivity extends AppCompatActivity {
private Context context ;
private String serverIp ;
public static final String DATABASE_NAME = "sms_forwarder.db" ;
private IPEditText textServerIp ;
private TextView sendTxt ;
private TextView receiveTxt ;
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 ) {
Toast . makeText ( CloneActivity . this , msg . getData ( ) . getString ( "DATA" ) , Toast . LENGTH_LONG ) . show ( ) ;
} 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 ) ;
}
}
} ;
@Override
public void onCreate ( Bundle savedInstanceState ) {
@ -49,24 +81,27 @@ public class CloneActivity extends AppCompatActivity {
setContentView ( R . layout . activity_clone ) ;
Log . d ( TAG , "onCreate: " + RebootBroadcastReceiver . class . getName ( ) ) ;
HttpUtil . init ( this ) ;
HttpServer . init ( this ) ;
}
@SuppressWarnings ( { "rawtypes" , "unchecked" , "deprecation" } )
@SuppressLint ( "SetTextI18n" )
@Override
protected void onStart ( ) {
super . onStart ( ) ;
Log . d ( TAG , "onStart" ) ;
IPEditText textServerIp = findViewById ( R . id . textServerIp ) ;
TextView sendTxt = findViewById ( R . id . sendTxt ) ;
TextView receiveTxt = findViewById ( R . id . receiveTxt ) ;
sendBtn = findViewById ( R . id . sendBtn ) ;
sendTxt = findViewById ( R . id . sendTxt ) ;
TextView ipText = findViewById ( R . id . ipText ) ;
textServerIp = findViewById ( R . id . textServerIp ) ;
receiveTxt = findViewById ( R . id . receiveTxt ) ;
Button receiveBtn = findViewById ( R . id . receiveBtn ) ;
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 ) ;
@ -77,9 +112,15 @@ public class CloneActivity extends AppCompatActivity {
}
sendBtn . setOnClickListener ( v - > {
if ( ! HttpServer . asRunning ( ) & & NetUtil . NETWORK_WIFI ! = NetUtil . getNetWorkStatus ( ) ) {
Toast .makeText ( CloneActivity . this , R . string . no_wifi_network , Toast . LENGTH_SHORT ). show ( ) ;
Toast (handError , TAG , getString ( R . string . no_wifi_network )) ;
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 ( ) ) ;
if ( ! HttpServer . update ( ) ) {
SettingUtil . switchEnableHttpServer ( ! SettingUtil . getSwitchEnableHttpServer ( ) ) ;
@ -96,128 +137,106 @@ public class CloneActivity extends AppCompatActivity {
}
} ) ;
Button receiveBtn = findViewById ( R . id . receiveBtn ) ;
receiveBtn . setOnClickListener ( v - > {
if ( HttpServer . asRunning ( ) ) {
receiveTxt . setText ( R . string . sender_cannot_receive ) ;
Toast .makeText ( CloneActivity . this , R . string . sender_cannot_receive , Toast . LENGTH_SHORT ). show ( ) ;
Toast (handError , TAG , getString ( R . string . sender_cannot_receive )) ;
return ;
}
if ( NetUtil . NETWORK_WIFI ! = NetUtil . getNetWorkStatus ( ) ) {
receiveTxt . setText ( R . string . no_wifi_network ) ;
Toast .makeText ( CloneActivity . this , R . string . no_wifi_network , Toast . LENGTH_SHORT ). show ( ) ;
Toast (handError , TAG , getString ( R . string . no_wifi_network )) ;
return ;
}
serverIp = textServerIp . getIP ( ) ;
if ( serverIp = = null | | serverIp . isEmpty ( ) ) {
receiveTxt . setText ( R . string . invalid_server_ip ) ;
Toast .makeText ( CloneActivity . this , R . string . invalid_server_ip , Toast . LENGTH_SHORT ). show ( ) ;
Toast (handError , TAG , getString ( R . string . invalid_server_ip )) ;
return ;
}
//下载连接
final String url = "http://" + serverIp + ":5000/" ;
Log . d ( TAG , url ) ;
//保存路径
final String savePath = context . getCacheDir ( ) . getPath ( ) + File . separator + DATABASE_NAME ;
Log . d ( TAG , savePath ) ;
final long startTime = System . currentTimeMillis ( ) ;
Log . i ( TAG , "startTime=" + startTime ) ;
OkHttpClient okHttpClient = new OkHttpClient ( ) ;
Request request = new Request . Builder ( ) . url ( url ) . addHeader ( "Connection" , "close" ) . build ( ) ;
okHttpClient . newCall ( request ) . enqueue ( new Callback ( ) {
OkHttpClient . Builder builder = new OkHttpClient . Builder ( ) ;
//设置读取超时时间
OkHttpClient client = builder
. readTimeout ( Define . REQUEST_TIMEOUT_SECONDS , TimeUnit . SECONDS )
. writeTimeout ( Define . REQUEST_TIMEOUT_SECONDS , TimeUnit . SECONDS )
. connectTimeout ( Define . REQUEST_TIMEOUT_SECONDS , TimeUnit . SECONDS )
. build ( ) ;
Map msgMap = new HashMap ( ) ;
msgMap . put ( "versionCode" , SettingUtil . getVersionCode ( ) ) ;
msgMap . put ( "versionName" , SettingUtil . getVersionName ( ) ) ;
String requestMsg = JSON . toJSONString ( msgMap ) ;
Log . i ( TAG , "requestMsg:" + requestMsg ) ;
RequestBody requestBody = RequestBody . create ( MediaType . parse ( "application/json;charset=utf-8" ) , requestMsg ) ;
//请求链接: post 获取版本信息, get 下载备份文件
final String requestUrl = "http://" + serverIp + ":" + Define . HTTP_SERVER_PORT + BaseServlet . CLONE_PATH + "?" + System . currentTimeMillis ( ) ;
Log . i ( TAG , "requestUrl:" + requestUrl ) ;
//获取版本信息
final Request request = new Request . Builder ( )
. url ( requestUrl )
. addHeader ( "Content-Type" , "application/json; charset=utf-8" )
. post ( requestBody )
. build ( ) ;
client . newCall ( request ) . enqueue ( new Callback ( ) {
@Override
public void onFailure ( @NonNull Call call , @NonNull IOException e ) {
e . printStackTrace ( ) ;
//Toast.makeText(CloneActivity.this, R.string.download_failed + e.getMessage(), Toast.LENGTH_SHORT).show();
public void onFailure ( @NonNull Call call , @NonNull final IOException e ) {
Toast ( handError , TAG , "从发送端获取一键克隆信息失败" ) ;
}
@Override
public void onResponse ( @NonNull Call call , @NonNull Response response ) {
InputStream is = null ;
byte [ ] buf = new byte [ 2048 ] ;
int len ;
FileOutputStream fos = null ;
public void onResponse ( @NonNull Call call , @NonNull Response response ) throws IOException {
final String responseStr = Objects . requireNonNull ( response . body ( ) ) . string ( ) ;
Log . d ( TAG , "Response: " + response . code ( ) + ", " + responseStr ) ;
try {
is = Objects . requireNonNull ( response . body ( ) ) . byteStream ( ) ;
long total = Objects . requireNonNull ( response . body ( ) ) . contentLength ( ) ;
File file = new File ( savePath , url . substring ( url . lastIndexOf ( "/" ) + 1 ) ) ;
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 ) ;
Log . e ( TAG , "download progress : " + progress ) ;
}
fos . flush ( ) ;
Log . e ( TAG , "download success" ) ;
Log . e ( TAG , "totalTime=" + ( System . currentTimeMillis ( ) - startTime ) ) ;
//Toast.makeText(CloneActivity.this, R.string.download_success, Toast.LENGTH_SHORT).show();
} catch ( Exception e ) {
e . printStackTrace ( ) ;
//Toast.makeText(CloneActivity.this, R.string.download_failed + e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
try {
if ( is ! = null ) is . close ( ) ;
} catch ( IOException ignored ) {
}
try {
if ( fos ! = null ) fos . close ( ) ;
} catch ( IOException ignored ) {
}
if ( TextUtils . isEmpty ( responseStr ) ) {
Toast ( handError , TAG , "从发送端获取一键克隆信息失败" ) ;
return ;
}
}
} ) ;
//TODO:替换sqlite
File dbFile = new File ( savePath ) ;
FileInputStream fis ;
try {
fis = new FileInputStream ( dbFile ) ;
} catch ( FileNotFoundException e ) {
e . printStackTrace ( ) ;
return ;
}
try {
CloneInfoVo cloneInfoVo = JSON . parseObject ( responseStr , CloneInfoVo . class ) ;
if ( SettingUtil . getVersionCode ( ) ! = cloneInfoVo . getVersionCode ( ) ) {
Toast ( handError , TAG , "发送端与接收端的APP版本不一致, 无法一键克隆! " ) ;
return ;
}
String outFileName = context . getDatabasePath ( DATABASE_NAME ) . getAbsolutePath ( ) ;
Log . d ( TAG , outFileName ) ;
//应用配置
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 ( ) ) ;
// Open the empty db as the output stream
OutputStream output ;
try {
output = new FileOutputStream ( outFileName ) ;
} catch ( FileNotFoundException e ) {
e . printStackTrace ( ) ;
return ;
}
//下载备份文件
Message msg = new Message ( ) ;
msg . what = DOWNLOAD ;
Bundle bundle = new Bundle ( ) ;
bundle . putString ( "URL" , requestUrl ) ;
msg . setData ( bundle ) ;
handError . sendMessage ( msg ) ;
// Transfer bytes from the input file to the output file
byte [ ] buffer = new byte [ 1024 ] ;
int length ;
while ( true ) {
try {
if ( ! ( ( length = fis . read ( buffer ) ) > 0 ) ) break ;
output . write ( buffer , 0 , length ) ;
} catch ( IOException e ) {
e . printStackTrace ( ) ;
} catch ( Exception e ) {
Toast ( handError , TAG , "一键克隆失败:" + e . getMessage ( ) ) ;
}
}
}
// Close the streams
try {
output . flush ( ) ;
output . close ( ) ;
fis . close ( ) ;
} catch ( IOException e ) {
e . printStackTrace ( ) ;
}
LogUtil . delLog ( null , null ) ;
} ) ;
receiveTxt . setText ( R . string . download_success ) ;
} ) ;
}
@ -231,4 +250,63 @@ public class CloneActivity extends AppCompatActivity {
TextView ipText = findViewById ( R . id . ipText ) ;
ipText . setText ( getString ( R . string . local_ip ) + serverIp ) ;
}
/ * *
* 文 件 下 载
*
* @param url 下 载 链 接
* /
public void downloadFile ( String url , final String destFileDir , final String destFileName ) {
ProgressDialog progressDialog = new ProgressDialog ( context ) ;
progressDialog . setProgressStyle ( ProgressDialog . STYLE_HORIZONTAL ) ;
progressDialog . setTitle ( "正在下载" ) ;
progressDialog . setMessage ( "请稍后..." ) ;
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 , "下载完成,正准备还原数据..." ) ;
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 ) ;
Toast ( handError , TAG , "一键克隆操作成功!请进入通用设置检查各项开关是否已开启!" ) ;
}
@Override
public void onDownloading ( int progress ) {
progressDialog . setProgress ( progress ) ;
}
@SuppressLint ( "SetTextI18n" )
@Override
public void onDownloadFailed ( Exception e ) {
//下载异常进行相关提示操作
Log . e ( TAG , "下载失败:" + e . getMessage ( ) ) ;
Toast ( handError , TAG , "下载失败:" + 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 ) ;
}
}
}