package com.localtransfer; import android.animation.ObjectAnimator; import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.database.Cursor; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import android.provider.OpenableColumns; import android.util.Log; import android.view.View; import android.view.animation.Animation; import android.view.animation.LinearInterpolator; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationManagerCompat; import androidx.core.content.FileProvider; import androidx.preference.PreferenceManager; import com.google.android.material.snackbar.Snackbar; import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Serializable; import java.net.HttpURLConnection; import java.net.ProtocolException; import java.net.URL; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.text.CharacterIterator; import java.text.SimpleDateFormat; import java.text.StringCharacterIterator; import java.util.ConcurrentModificationException; import java.util.Date; import java.util.List; import java.util.Timer; import java.util.TimerTask; import static java.lang.Integer.valueOf; public class Transfer { public static String host; public static Integer port; public static String root; public static String protocol; public static String local_storage; public static Activity activity; public static void parameter(Context context) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); host = prefs.getString("host", null); port = valueOf(prefs.getString("port", null)); root = prefs.getString("root", null); local_storage = prefs.getString("local_storage", null); if(prefs.getBoolean("protocol", false)) protocol = "https"; else protocol = "http"; } private URL checkRedirection(URL url) throws IOException { String location = null; HttpURLConnection conn = null; int responseCode; int nbRedirect = 0; do { conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setInstanceFollowRedirects(false); conn.setConnectTimeout(2000); conn.connect(); responseCode = conn.getResponseCode(); Log.d("Réponse Code", String.valueOf(responseCode)); if(responseCode != HttpURLConnection.HTTP_MOVED_PERM && responseCode != HttpURLConnection.HTTP_MOVED_TEMP) { break; } location = conn.getHeaderField("Location"); Log.d("Location", location); url = new URL(location); conn.disconnect(); nbRedirect++; if(nbRedirect > 10) { throw new ProtocolException("Too many follow-up requests: " + nbRedirect); } } while (responseCode == HttpURLConnection.HTTP_MOVED_PERM || responseCode == HttpURLConnection.HTTP_MOVED_TEMP); return url; } public void handleSendFile(Uri uri) { if (uri != null) { new Thread(() -> { try { uploadFile(uri); } catch (IOException e) { final String ExceptionName = e.getClass().getSimpleName(); final String ExceptionMess = e.getMessage(); if(ExceptionName != null && ExceptionMess != null) { Transfer.error(ExceptionName + ": " + ExceptionMess, null, null); } } }).start(); } } public void handleSendText(String sharedText) { if (sharedText != null) { SimpleDateFormat sdfDate = new SimpleDateFormat("yyyyMMdd_HHmmss"); Date now = new Date(); String strDate = sdfDate.format(now); new Thread(() -> { try { File outputFile = new File(activity.getCacheDir(), strDate + ".txt"); FileOutputStream fileOut = new FileOutputStream(outputFile); OutputStreamWriter OutWriter = new OutputStreamWriter(fileOut); OutWriter.append(sharedText); OutWriter.close(); fileOut.flush(); fileOut.close(); Uri uri = FileProvider.getUriForFile(activity, activity.getPackageName(), outputFile); uploadFile(uri); } catch (IOException e) { e.printStackTrace(); } }).start(); } } public String uploadFile(Uri uri) throws IOException { String message = null; URL url = null; HttpURLConnection conn = null; DataOutputStream request = null; String boundary = "*****"; int maxBufferSize = 1 * 1024 * 1024; byte[] buffer = new byte[maxBufferSize]; int bufferLength; long loaded = 0; Cursor cursor = activity.getContentResolver().query(uri, null, null, null, null); cursor.moveToFirst(); String fileName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); String fileNameUTF8 = new String(fileName.getBytes(), StandardCharsets.ISO_8859_1); long fileSize = cursor.getLong(cursor.getColumnIndex(OpenableColumns.SIZE)); String type = activity.getContentResolver().getType(uri); url = new URL(protocol, host, port, root + "/upload.php"); url = checkRedirection(url); Progress p = new Progress(fileName, fileSize, Progress.UPLOAD); if(url != null) { Log.d("URL", url.toString()); conn = (HttpURLConnection) url.openConnection(); conn.setDoInput(true); // Allow Inputs conn.setDoOutput(true); // Allow Outputs conn.setUseCaches(false); // Don't use a Cached Copy conn.setChunkedStreamingMode(maxBufferSize); conn.setRequestMethod("POST"); conn.setRequestProperty("Connection", "keep-alive"); conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); conn.connect(); request = new DataOutputStream(conn.getOutputStream()); request.writeBytes("--" + boundary + "\r\n"); request.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\"" + fileNameUTF8 + "\"\r\n"); request.writeBytes("Content-Type: " + type + "\r\n\r\n"); InputStream in = activity.getContentResolver().openInputStream(uri); while ((bufferLength = in.read(buffer)) > 0) { request.write(buffer, 0, bufferLength); loaded+= (long) bufferLength; p.loaded = loaded; p.percent = ((loaded * 100) / fileSize); } request.writeBytes("\r\n"); request.writeBytes("--" + boundary + "--\r\n"); in.close(); int responseCode = conn.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { message = "File " + fileName + " successful upload"; p.stopProgress(); } else { String s = conn.getResponseMessage(); throw new HttpErrorException("error code: " + responseCode + " " + s); } request.flush(); request.close(); conn.disconnect(); System.out.println(message); if (activity != null) { String finalMessage = message; activity.runOnUiThread(() -> Snackbar.make(activity.findViewById(R.id.view_pager), finalMessage, Snackbar.LENGTH_LONG) .setAction("Action", null).show()); } } return message; } public String getFileList() throws IOException { URL url = null; HttpURLConnection conn = null; String fileList = ""; int buf; url = new URL(protocol, host, port, root + "/list.php"); conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(2000); conn.connect(); int responseCode = conn.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { InputStreamReader isw = new InputStreamReader(conn.getInputStream()); while ((buf = isw.read()) > 0) { fileList = fileList + (char) buf; } } else { String s = conn.getResponseMessage(); throw new HttpErrorException("error code: " + responseCode + " " + s); } conn.disconnect(); return fileList; } public void downloadFile(final Uri uri, String name, long fileSize, String href, Button button) throws IOException { /*final LinearLayout layout = activity.findViewById(id); final Button button; if(layout != null) button = layout.findViewById(R.id.file_download); else button = null;*/ final File file = new File(uri.getPath()); URL url = null; HttpURLConnection conn = null; int maxBufferSize = 1 * 1024 * 1024; byte[] buffer = new byte[maxBufferSize]; int bufferLength; long loaded = 0; final Drawable image = activity.getDrawable(R.drawable.ic_spinner_rotate); Progress p = new Progress(name, fileSize, Progress.DOWNLOAD); if(button != null) p.button = button; if(p.button != null) { activity.runOnUiThread(() -> { int h = image.getIntrinsicHeight(); int w = image.getIntrinsicWidth(); image.setBounds(0, 0, w, h); p.button.setCompoundDrawables(button.getCompoundDrawables()[0], null, image, null); ObjectAnimator anim = ObjectAnimator.ofInt(image, "level", 0, 10000); anim.setDuration(1000); anim.setRepeatCount(Animation.INFINITE); anim.setInterpolator(new LinearInterpolator()); anim.start(); }); } String[] parts = href.split("/"); String path = ""; for(int i=0; i< parts.length - 1; i++) { path = path + parts[i] + "/"; } String query = URLEncoder.encode(parts[parts.length - 1], StandardCharsets.UTF_8.toString()); url = new URL(protocol, host, port, path + query.replace("+", "%20")); conn = (HttpURLConnection) url.openConnection(); conn.setDoOutput(true); conn.setRequestMethod("GET"); conn.setConnectTimeout(2000); Log.d("URL", url.toString()); conn.connect(); int responseCode = conn.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { FileOutputStream fileOutput = new FileOutputStream(file); InputStream in = conn.getInputStream(); while ((bufferLength = in.read(buffer)) > 0) { fileOutput.write(buffer, 0, bufferLength); loaded+= (long) bufferLength; p.loaded = loaded; p.percent = ((loaded * 100) / fileSize); if(Progress.app_started && p.button != null) activity.runOnUiThread(() -> p.button.setText(String.format("Download in progress %d%%", p.percent))); } fileOutput.close(); conn.disconnect(); p.stopProgress(); if(p.button != null) { activity.runOnUiThread(() -> { final LinearLayout layout = (LinearLayout) p.button.getParent(); layout.findViewById(R.id.file_view).setVisibility(LinearLayout.VISIBLE); layout.findViewById(R.id.file_share).setVisibility(LinearLayout.VISIBLE); p.button.setVisibility(LinearLayout.GONE); p.button.setEnabled(true); p.button.setText(activity.getString(R.string.file_download)); p.button.setCompoundDrawables(p.button.getCompoundDrawables()[0], null, null, null); }); } activity.runOnUiThread(() -> { String message = "File " + name + " successful download"; System.out.println(message); Snackbar.make(activity.findViewById(R.id.view_pager), message, Snackbar.LENGTH_LONG) .setAction("Action", null).show(); }); } else { String s = conn.getResponseMessage(); throw new HttpErrorException("error code: " + responseCode + " " + s); } conn.disconnect(); } public String deleteFile(String file) throws IOException { URL url = null; HttpURLConnection conn = null; String message; String query = URLEncoder.encode(file, StandardCharsets.UTF_8.toString()); String serverUrl = root + "/delete.php?file=" + query; url = new URL(protocol, host, port, serverUrl); conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(2000); conn.connect(); int responseCode = conn.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { message = "File " + file + " successful deleted"; } else { String s = conn.getResponseMessage(); throw new HttpErrorException("error code: " + responseCode + " " + s); } conn.disconnect(); return message; } private static int timeout; public static void error(final String message, final TextView title, final LinearLayout layout) { System.out.println(message); if (timeout == 0) { if (activity != null) { activity.runOnUiThread(new Runnable() { @Override public void run() { if(layout != null) layout.removeAllViews(); if(title != null) { layout.addView(title); title.setText(message); } Snackbar.make(activity.findViewById(R.id.view_pager), message, Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }); } timeout = 1; new Timer().schedule(new TimerTask() { @Override public void run() { timeout = 0; } }, 3000); } } public static String humanReadableByteCountBin(long bytes) { long absB = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes); if (absB < 1024) { return bytes + " B"; } long value = absB; CharacterIterator ci = new StringCharacterIterator("KMGTPE"); for (int i = 40; i >= 0 && absB > 0xfffccccccccccccL >> i; i -= 10) { value >>= 10; ci.next(); } value *= Long.signum(bytes); return String.format("%.1f %ciB", value / 1024.0, ci.current()); } }