Commit 72908966 authored by YONG-LIN SU's avatar YONG-LIN SU

新增FTP上傳功能

parent 9d543f85
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<runningDeviceTargetSelectedWithDropDown>
<Target>
<type value="RUNNING_DEVICE_TARGET" />
<deviceKey>
<Key>
<type value="SERIAL_NUMBER" />
<value value="577125220043" />
</Key>
</deviceKey>
</Target>
</runningDeviceTargetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2022-08-19T03:06:22.756618100Z" />
</component>
</project>
\ No newline at end of file
package ecom.android.newparkapp;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.StringTokenizer;
public class FtpConn {
private static Socket socket = null;
private static BufferedReader reader = null;
private static BufferedWriter writer = null;
InputStream is = null;
OutputStream os = null;
public FtpConn() {
}
public synchronized static Boolean connect(String host, int port, String user, String pass) throws IOException {
if (socket != null) {
return false;
}
socket = new Socket(host, port);
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String response = readLine();//220 Service ready for new user.
if (response.startsWith("220-"))
response = readLine();
if (response.startsWith("220-"))
response = readLine();
if (!response.startsWith("220")) {
disconnect();
return false;
}
sendLine("USER " + user);
response = readLine();//331 User name okay, need password.
if (!response.startsWith("331 ")) {
disconnect();
return false;
}
sendLine("PASS " + pass);
response = readLine();//230 User logged in, proceed. Logged out if appropriate.
if (!response.startsWith("230")) {
throw new IOException("SimpleFTP was unable to log in with the supplied password: " + response);
}
return true;
}
public synchronized static void disconnect() throws IOException {
try {
sendLine("QUIT");
} finally {
socket = null;
}
}
public synchronized static boolean stor(File file) throws IOException {
if (file.isDirectory()) {
}
String filename = file.getName();
return stor(new FileInputStream(file), filename);
}
public synchronized static boolean stor(InputStream inputStream, String filename) throws IOException {
bin();
BufferedInputStream input = new BufferedInputStream(inputStream);
sendLine("PASV");
String response = readLine();//Entering Passive Mode (h1,h2,h3,h4,p1,p2).
if (!response.startsWith("227")) {
}
String ip = null;
int port = -1;
int opening = response.indexOf('(');
int closing = response.indexOf(')', opening + 1);
if (closing > 0) {
String dataLink = response.substring(opening + 1, closing);
StringTokenizer tokenizer = new StringTokenizer(dataLink, ",");
try {
ip = tokenizer.nextToken() + "." + tokenizer.nextToken() + "."
+ tokenizer.nextToken() + "." + tokenizer.nextToken();
port = Integer.parseInt(tokenizer.nextToken()) * 256
+ Integer.parseInt(tokenizer.nextToken());
} catch (Exception e) {
e.printStackTrace();
}
}
sendLine("STOR " + filename);
Socket dataSocket = new Socket(ip, port);
response = readLine();
if (!response.startsWith("125")) {
}
BufferedOutputStream output = new BufferedOutputStream(dataSocket.getOutputStream());
byte[] buffer = new byte[4096];
int bytesRead = 0;
while ((bytesRead = input.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
output.flush();
output.close();
input.close();
response = readLine();
return response.startsWith("226");
}
/**
* Binary 二進制格式
* */
public synchronized static boolean bin() throws IOException {
sendLine("TYPE I");
String response = readLine();
return (response.startsWith("200"));
}
public synchronized boolean ascii() throws IOException {
sendLine("TYPE A");
String response = readLine();
return (response.startsWith("200"));
}
private static void sendLine(String line) throws IOException {
if (socket == null) {
throw new IOException("SimpleFTP is not connected.");
}
try {
writer.write(line + "\r\n");
writer.flush();
} catch (IOException e) {
disconnect();
throw e;
}
}
private static String readLine() throws IOException {
return reader.readLine();
}
}
\ No newline at end of file
...@@ -34,6 +34,7 @@ import ecom.android.newparkapp.R; ...@@ -34,6 +34,7 @@ import ecom.android.newparkapp.R;
import ecom.android.newparkapp.databinding.ActivityMainBinding; import ecom.android.newparkapp.databinding.ActivityMainBinding;
import ecom.android.newparkapp.entity.Shift; import ecom.android.newparkapp.entity.Shift;
import ecom.android.newparkapp.entity.User; import ecom.android.newparkapp.entity.User;
import ecom.android.newparkapp.viewModel.FTPUploadViewModel;
import ecom.android.newparkapp.viewModel.T01SettingViewModel; import ecom.android.newparkapp.viewModel.T01SettingViewModel;
public class MainActivity extends AppCompatActivity { public class MainActivity extends AppCompatActivity {
...@@ -41,6 +42,7 @@ public class MainActivity extends AppCompatActivity { ...@@ -41,6 +42,7 @@ public class MainActivity extends AppCompatActivity {
private ActivityMainBinding dataBinding; private ActivityMainBinding dataBinding;
private ViewModelProvider viewModelProvider; private ViewModelProvider viewModelProvider;
private T01SettingViewModel t01SettingViewModel; private T01SettingViewModel t01SettingViewModel;
private FTPUploadViewModel ftpUploadViewModel;
private ActivityResultLauncher<String[]> requestPermissionLauncher; private ActivityResultLauncher<String[]> requestPermissionLauncher;
private ActivityResultLauncher requestAllFilesAccessPermissionLauncher; // Android 11 以上需申請較高權限 private ActivityResultLauncher requestAllFilesAccessPermissionLauncher; // Android 11 以上需申請較高權限
...@@ -56,6 +58,8 @@ public class MainActivity extends AppCompatActivity { ...@@ -56,6 +58,8 @@ public class MainActivity extends AppCompatActivity {
dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main); dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
viewModelProvider = new ViewModelProvider(this); viewModelProvider = new ViewModelProvider(this);
t01SettingViewModel = viewModelProvider.get(T01SettingViewModel.class); t01SettingViewModel = viewModelProvider.get(T01SettingViewModel.class);
ftpUploadViewModel = viewModelProvider.get(FTPUploadViewModel.class);
ftpUploadViewModel.setT01SettingViewModel(t01SettingViewModel);
initLayout(); initLayout();
...@@ -70,10 +74,20 @@ public class MainActivity extends AppCompatActivity { ...@@ -70,10 +74,20 @@ public class MainActivity extends AppCompatActivity {
// 有權限再綁定按鈕功能 // 有權限再綁定按鈕功能
hasPermissions.observe(this, has -> { hasPermissions.observe(this, has -> {
if (has){ if (has){
// 註冊事件綁定 // 檢查存放目錄是否存在
eventBinding(); boolean isSuccess = t01SettingViewModel.checkAndMkdirs();
// 複製assert下的模型 if (!isSuccess){
copyModelFromAssetsToData(this); Toast.makeText(this, "新增檔案目錄失敗,請重啟程式", Toast.LENGTH_LONG).show();
}else {
// 註冊事件綁定
eventBinding();
// 複製assert下的模型
copyModelFromAssetsToData(this);
// 啟動 FTP 背景上傳
ftpUploadViewModel.startFTPUploadService();
// 監聽事件綁定
observeBinding();
}
} }
}); });
} }
...@@ -173,6 +187,9 @@ public class MainActivity extends AppCompatActivity { ...@@ -173,6 +187,9 @@ public class MainActivity extends AppCompatActivity {
dataBinding.tvCurrentUsr.setText("請先設定當前使用者"); dataBinding.tvCurrentUsr.setText("請先設定當前使用者");
} }
// TODO: 2022/8/19 更新 FTP Upload Service
}); });
} }
...@@ -185,6 +202,11 @@ public class MainActivity extends AppCompatActivity { ...@@ -185,6 +202,11 @@ public class MainActivity extends AppCompatActivity {
dataBinding.btnGoSetting.setOnClickListener(view -> {btnGoSettingOnClicked();}); dataBinding.btnGoSetting.setOnClickListener(view -> {btnGoSettingOnClicked();});
} }
private void observeBinding(){
ftpUploadViewModel.getMessage().observe(this, s -> {
Toast.makeText(this, s, Toast.LENGTH_SHORT).show();
});
}
private void btnStartOnClicked(Shift shift){ private void btnStartOnClicked(Shift shift){
if (t01SettingViewModel.getCurrentUser() == null || t01SettingViewModel.getCurrentUser().id == 999){ if (t01SettingViewModel.getCurrentUser() == null || t01SettingViewModel.getCurrentUser().id == 999){
...@@ -207,4 +229,6 @@ public class MainActivity extends AppCompatActivity { ...@@ -207,4 +229,6 @@ public class MainActivity extends AppCompatActivity {
intent.setClass(this, T01SettingActivity.class); intent.setClass(this, T01SettingActivity.class);
settingActivityResultLauncher.launch(intent); settingActivityResultLauncher.launch(intent);
} }
} }
\ No newline at end of file
...@@ -172,8 +172,11 @@ public class T01SettingActivity extends AppCompatActivity { ...@@ -172,8 +172,11 @@ public class T01SettingActivity extends AppCompatActivity {
@Override @Override
public void afterTextChanged(Editable editable) { public void afterTextChanged(Editable editable) {
try { try {
int FtpPort = Integer.parseInt(dataBinding.setFtpPortEditText.getText().toString()); String ftpPortSting = dataBinding.setFtpPortEditText.getText().toString();
t01SettingViewModel.set_pref_FtpPort(FtpPort); if (!ftpPortSting.trim().isEmpty()){
int FtpPort = Integer.parseInt(ftpPortSting);
t01SettingViewModel.set_pref_FtpPort(FtpPort);
}
}catch (NullPointerException nullPointerException){ }catch (NullPointerException nullPointerException){
return; return;
} }
......
...@@ -133,6 +133,14 @@ public class T02StartActivity extends AppCompatActivity { ...@@ -133,6 +133,14 @@ public class T02StartActivity extends AppCompatActivity {
} }
@Override
protected void onDestroy() {
if (blueToothViewModel != null){
blueToothViewModel.disconnect();
}
super.onDestroy();
}
private void eventBinding() { private void eventBinding() {
dataBinding.btnVehicleType.setOnClickListener(v -> btnVehicleTypeOnClicked()); dataBinding.btnVehicleType.setOnClickListener(v -> btnVehicleTypeOnClicked());
......
...@@ -199,9 +199,14 @@ public class BlueToothPortViewModel extends AndroidViewModel { ...@@ -199,9 +199,14 @@ public class BlueToothPortViewModel extends AndroidViewModel {
e.printStackTrace(); e.printStackTrace();
} }
} }
if (bluetoothRequestThread != null || bluetoothRequestThread.isAlive()){ if (bluetoothRequestThread != null && bluetoothRequestThread.isAlive()){
bluetoothRequestThread.interrupt(); bluetoothRequestThread.interrupt();
} }
if ( getPrinterPowerPercentFullTimer != null){
getPrinterPowerPercentFullTimer.cancel();
getPrinterPowerPercentFullTimer = null;
}
} }
/** /**
......
package ecom.android.newparkapp.viewModel;
import android.app.Application;
import android.os.Environment;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import java.util.Objects;
import java.util.Timer;
import java.util.TimerTask;
import ecom.android.newparkapp.Common;
import ecom.android.newparkapp.FilesFilter;
import ecom.android.newparkapp.FtpConn;
import ecom.android.newparkapp.R;
public class FTPUploadViewModel extends AndroidViewModel {
private T01SettingViewModel t01SettingViewModel;
private Timer timer = new Timer();
private ftpUploadTimerTask ftpUploadTimerTask = new ftpUploadTimerTask();
private Calendar calendar;
private MutableLiveData<String> messageLiveData = new MutableLiveData<>();
public FTPUploadViewModel(@NonNull Application application) {
super(application);
calendar = Calendar.getInstance();
}
public LiveData<String> getMessage(){
return messageLiveData;
}
private void UploadFiles(String szPath, String szExt) throws IOException {
File fileTemp = new File(szPath);
if (!fileTemp.isDirectory()) {
return;
}
if (!FtpConn.connect(t01SettingViewModel.getFTPAddress(), t01SettingViewModel.getFTPPort(), t01SettingViewModel.getFTPUser(), t01SettingViewModel.getFTPPassword())) {
messageLiveData.postValue("FTP 伺服器連線失敗");
return;
}
messageLiveData.postValue("FTP 伺服器連線成功");
String szYYMMDD = Common.getDate(calendar, false);
// 轉換成 2位 使用者編號
String szUserId = String.format("%02d",t01SettingViewModel.getCurrentUser().id);
if (Objects.requireNonNull(fileTemp.listFiles(new FilesFilter(szUserId, szYYMMDD, szExt, false))).length > 0) {
for (File file : Objects.requireNonNull(fileTemp.listFiles(new FilesFilter(szUserId, szYYMMDD, szExt, false)))) {
String szPathTemp = szPath + "/" + file.getName();
File fTemp = new File(szPathTemp);
if (fTemp.exists() && FtpConn.stor(fTemp) && szExt.equals(".txt")) {
if (!fTemp.delete()){
messageLiveData.postValue("目錄 " + fTemp.getName() + " 刪除失敗!");
};
}
}
}
FtpConn.disconnect();
}
private class ftpUploadTimerTask extends TimerTask {
@Override
public void run() {
try {
String szPath = Environment.getExternalStorageDirectory() + getApplication().getString(R.string.sysDataUpload_path);//sdcardpath + getString(R.string.sysData_path)
UploadFiles(szPath, ".txt");
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void setT01SettingViewModel(T01SettingViewModel t01SettingViewModel) {
this.t01SettingViewModel = t01SettingViewModel;
}
public void startFTPUploadService(){
timer.schedule(ftpUploadTimerTask, 0, t01SettingViewModel.getFTPUploadInterval());
}
public void stopFTPUploadService(){
if (timer != null){
timer.cancel();
}
}
}
...@@ -5,6 +5,8 @@ import static android.content.Context.MODE_PRIVATE; ...@@ -5,6 +5,8 @@ import static android.content.Context.MODE_PRIVATE;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Environment;
import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
...@@ -15,6 +17,9 @@ import androidx.lifecycle.MutableLiveData; ...@@ -15,6 +17,9 @@ import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer; import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
...@@ -173,4 +178,49 @@ public class T01SettingViewModel extends AndroidViewModel { ...@@ -173,4 +178,49 @@ public class T01SettingViewModel extends AndroidViewModel {
} }
public boolean getAutoNext(){return PREF.getValue().pref_autoNext;} public boolean getAutoNext(){return PREF.getValue().pref_autoNext;}
/**
* 檢查程式使用的目錄是否都存在
*/
public boolean checkAndMkdirs() {
SimpleDateFormat dFormat = new SimpleDateFormat("yyyyMMdd", Locale.TAIWAN);
String[] Filename = new String[4];
Filename[0] = Environment.getExternalStorageDirectory() + getApplication().getString(R.string.sysDataPhoto_path) + dFormat.format(new Date());
Filename[1] = Environment.getExternalStorageDirectory() + getApplication().getString(R.string.sysDataUpload_path);
Filename[2] = Environment.getExternalStorageDirectory() + getApplication().getString(R.string.sysData_path) + dFormat.format(new Date());
Filename[3] = Environment.getExternalStorageDirectory() + getApplication().getString(R.string.sysDataDB_path);
boolean ret = true;
for (String s : Filename) {
File mFile = new File(s);
if (!mFile.exists()) {
if (!mFile.mkdirs()) {
ret = false;
}
}
}
String path = Environment.getExternalStorageDirectory() + getApplication().getString(R.string.sysData_path);
return ret;
}
public String getFTPUser() {
return PREF.getValue() != null ? PREF.getValue().pref_FtpUser: null;
}
public String getFTPPassword() {
return PREF.getValue() != null ? PREF.getValue().pref_FtpPsw: null;
}
public int getFTPPort(){
return PREF.getValue() != null ? PREF.getValue().pref_FtpPort: -1;
}
public String getFTPAddress(){
return PREF.getValue() != null ? PREF.getValue().pref_FtpAddr: null;
}
public int getFTPUploadInterval(){
return PREF.getValue() != null ? PREF.getValue().pref_UploadT * 60 * 1000: 0;
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment