From 493e836f5673c291aff575edc6fb56d8666169d3 Mon Sep 17 00:00:00 2001 From: lionel Date: Fri, 12 Mar 2021 10:32:47 +0100 Subject: [PATCH 1/5] Create ForegroundService --- app/src/main/AndroidManifest.xml | 17 +-- .../main/java/com/localtransfer/Progress.java | 102 ++++++++++-------- .../com/localtransfer/TransferService.java | 43 ++++++++ .../fragment/ProgressFragment.java | 2 +- 4 files changed, 109 insertions(+), 55 deletions(-) create mode 100644 app/src/main/java/com/localtransfer/TransferService.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ae3108f..bd2ee7c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -13,6 +13,10 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> + - - + android:label="@string/title_activity_settings"> - + - + + - + + - diff --git a/app/src/main/java/com/localtransfer/Progress.java b/app/src/main/java/com/localtransfer/Progress.java index 983ffe5..19dc597 100644 --- a/app/src/main/java/com/localtransfer/Progress.java +++ b/app/src/main/java/com/localtransfer/Progress.java @@ -1,5 +1,6 @@ package com.localtransfer; +import android.app.Notification; import android.app.PendingIntent; import android.content.Intent; import android.view.LayoutInflater; @@ -12,6 +13,7 @@ import android.widget.TextView; import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationManagerCompat; +import androidx.core.content.ContextCompat; import java.util.ArrayList; import java.util.ConcurrentModificationException; @@ -25,17 +27,24 @@ public class Progress { public static final int DOWNLOAD = 1001; - private static NotificationCompat.Builder bl = new NotificationCompat.Builder(Transfer.activity, null); + private static Notification.Builder bl = new Notification.Builder(Transfer.activity); private static NotificationManagerCompat notifiManager = NotificationManagerCompat.from(Transfer.activity); private static final LayoutInflater inflater = (LayoutInflater) Transfer.activity.getSystemService(Transfer.activity.LAYOUT_INFLATER_SERVICE); + private static Intent notificationIntent = new Intent(Transfer.activity, MainActivity.class); + private static PendingIntent pendingIntent = PendingIntent.getActivity(Transfer.activity,0, notificationIntent, 0); + private static List instances = new ArrayList<>(); private Integer id; private String name; + private long size; + private String HumanSize; public long loaded; + private String HumanLoaded; + public long percent; public static View root; @@ -47,7 +56,7 @@ public class Progress { private String info; public Button button; - private boolean run = false; + private boolean run; public Progress(String name, long size, int type) { @@ -57,6 +66,7 @@ public class Progress { this.name = name; this.size = size; + this.HumanSize = Transfer.humanReadableByteCountBin(size); id = View.generateViewId(); @@ -73,6 +83,10 @@ public class Progress { throw new IllegalStateException("Unexpected value: " + type); } + Intent serviceIntent = new Intent(Transfer.activity, TransferService.class); + serviceIntent.putExtra("id", id); + ContextCompat.startForegroundService(Transfer.activity, serviceIntent); + timer.schedule(new TimerTask() { @Override public void run() { @@ -91,15 +105,18 @@ public class Progress { run = false; + Intent serviceIntent = new Intent(Transfer.activity, TransferService.class); + Transfer.activity.stopService(serviceIntent); + if(! app_started) { bl.setSmallIcon(R.drawable.ic_upload_and_download_from_the_cloud) .setContentTitle(name) .setContentText(info) .setProgress(0, 0, false) - .setAutoCancel(true) - .setOngoing(false); + .setContentIntent(pendingIntent); notifiManager.notify(id, bl.build()); } + } public void delete() { @@ -127,55 +144,21 @@ public class Progress { return false; } - - public void showProgress(){ + private void showProgress(){ try { - String HumanLoaded = Transfer.humanReadableByteCountBin(loaded); - String HumanSize = Transfer.humanReadableByteCountBin(size); + HumanLoaded = Transfer.humanReadableByteCountBin(loaded); - if(app_started) { - notifiManager.cancel(id); - } - else { - - Intent intent = new Intent(Transfer.activity, MainActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - PendingIntent pendingIntent = PendingIntent.getActivity(Transfer.activity, 0, intent, 0); - - bl.setSmallIcon(R.drawable.ic_upload_and_download_from_the_cloud) - .setContentTitle(name) - .setContentText(String.format("%d%% %s/%s", percent, HumanLoaded, HumanSize)) - .setProgress(100, (int) percent, false) - .setContentIntent(pendingIntent) - .setAutoCancel(true) - .setOngoing(true); - notifiManager.notify(id, bl.build()); - } + bl.setSmallIcon(R.drawable.ic_upload_and_download_from_the_cloud) + .setContentTitle(name) + .setContentText(String.format("%d%% %s/%s", percent, HumanLoaded, HumanSize)) + .setProgress(100, (int) percent, false) + .setContentIntent(pendingIntent); + notifiManager.notify(id, bl.build()); if(app_started && fragment_on) { - LinearLayout groot = root.findViewById(R.id.groot); - - final View progress; - - if (groot.findViewById(id) != null) { - progress = groot.findViewById(id); - } else { - progress = inflater.inflate(R.layout.progress, null); - progress.setId(id); - Transfer.activity.runOnUiThread(() -> { - groot.addView(progress, 0); - }); - } - - Transfer.activity.runOnUiThread(() -> { - ((ProgressBar) progress.findViewById(R.id.progressBar)).setProgress((int) percent); - ((ImageView) progress.findViewById(R.id.transferType)).setImageResource(drawable); - ((TextView) progress.findViewById(R.id.progressText)).setText(percent + " %"); - ((TextView) progress.findViewById(R.id.fileName)).setText(name); - ((TextView) progress.findViewById(R.id.fileSize)).setText(String.format("%s/%s", HumanLoaded, HumanSize)); - }); + showProgressFragment(); } @@ -185,4 +168,29 @@ public class Progress { } + public void showProgressFragment(){ + + LinearLayout groot = root.findViewById(R.id.groot); + + final View progress; + + if (groot.findViewById(id) != null) { + progress = groot.findViewById(id); + } else { + progress = inflater.inflate(R.layout.progress, null); + progress.setId(id); + Transfer.activity.runOnUiThread(() -> { + groot.addView(progress, 0); + }); + } + + Transfer.activity.runOnUiThread(() -> { + ((ProgressBar) progress.findViewById(R.id.progressBar)).setProgress((int) percent); + ((ImageView) progress.findViewById(R.id.transferType)).setImageResource(drawable); + ((TextView) progress.findViewById(R.id.progressText)).setText(percent + " %"); + ((TextView) progress.findViewById(R.id.fileName)).setText(name); + ((TextView) progress.findViewById(R.id.fileSize)).setText(String.format("%s/%s", HumanLoaded, HumanSize)); + }); + + } } diff --git a/app/src/main/java/com/localtransfer/TransferService.java b/app/src/main/java/com/localtransfer/TransferService.java new file mode 100644 index 0000000..894e9a0 --- /dev/null +++ b/app/src/main/java/com/localtransfer/TransferService.java @@ -0,0 +1,43 @@ +package com.localtransfer; + +import android.app.Notification; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +import androidx.core.app.NotificationCompat; + +public class TransferService extends Service { + + @Override + public void onCreate() { + super.onCreate(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + int id = intent.getIntExtra("id", 0); + + Intent notificationIntent = new Intent(this, MainActivity.class); + PendingIntent pendingIntent = PendingIntent.getActivity(this, + 0, notificationIntent, 0); + + Notification notification = new NotificationCompat.Builder(this, "CHANNEL_ID") + .setContentIntent(pendingIntent) + .build(); + + startForeground(id, notification); + + //do heavy work on a background thread + //stopSelf(); + + return START_NOT_STICKY; + } + + @Override + public IBinder onBind(Intent intent) { + // TODO: Return the communication channel to the service. + throw new UnsupportedOperationException("Not yet implemented"); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/localtransfer/fragment/ProgressFragment.java b/app/src/main/java/com/localtransfer/fragment/ProgressFragment.java index 57396f0..afe7cc0 100644 --- a/app/src/main/java/com/localtransfer/fragment/ProgressFragment.java +++ b/app/src/main/java/com/localtransfer/fragment/ProgressFragment.java @@ -57,7 +57,7 @@ public class ProgressFragment extends Fragment { List instances = Progress.getInstances(); for (Object obj: instances) { Progress p = (Progress) obj; - p.showProgress(); + p.showProgressFragment(); } } From 168e01e09aff8e548bde87c9bc64b318bdb44245 Mon Sep 17 00:00:00 2001 From: lionel Date: Sun, 14 Mar 2021 19:40:41 +0100 Subject: [PATCH 2/5] Foreground Service Integration - Add Foreground Service - Reviewed Progress Method - Reviewed Transfer Object Integration - Fix Some Error --- app/build.gradle | 2 +- .../java/com/localtransfer/MainActivity.java | 13 +- .../main/java/com/localtransfer/Progress.java | 221 +++--- .../main/java/com/localtransfer/Transfer.java | 720 ++++++++++-------- .../com/localtransfer/TransferService.java | 3 +- .../fragment/DownloadFragment.java | 45 +- .../fragment/ProgressFragment.java | 6 +- 7 files changed, 515 insertions(+), 495 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index c010a38..8b01084 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,7 +9,7 @@ android { minSdkVersion 24 targetSdkVersion 30 versionCode 1 - versionName "1.0" + versionName "2.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/com/localtransfer/MainActivity.java b/app/src/main/java/com/localtransfer/MainActivity.java index 92f5c89..3f789c3 100644 --- a/app/src/main/java/com/localtransfer/MainActivity.java +++ b/app/src/main/java/com/localtransfer/MainActivity.java @@ -78,16 +78,14 @@ public class MainActivity extends AppCompatActivity { String action = intent.getAction(); String type = intent.getType(); - Transfer tr = new Transfer(); - if (Intent.ACTION_SEND.equals(action) && type != null) { viewPager.setCurrentItem(2); if ("text/plain".equals(type)) { String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); - tr.handleSendText(sharedText); + Transfer.handleSendText(sharedText); } else { Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM); - tr.handleSendFile(uri); + Transfer.handleSendFile(uri); } } else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) { viewPager.setCurrentItem(2); @@ -95,7 +93,7 @@ public class MainActivity extends AppCompatActivity { int nbItem = fileUris.size(); Toast.makeText(this, "You select " + nbItem + " files", Toast.LENGTH_SHORT).show(); if (fileUris != null) - for(Uri uri : fileUris) tr.handleSendFile(uri); + for(Uri uri : fileUris) Transfer.handleSendFile(uri); } } @@ -110,11 +108,10 @@ public class MainActivity extends AppCompatActivity { ViewPager viewPager = this.findViewById(R.id.view_pager); viewPager.setCurrentItem(2); - Transfer tr = new Transfer(); if (type != null) { String sharedText = data.getStringExtra(Intent.EXTRA_TEXT); - tr.handleSendText(sharedText); + Transfer.handleSendText(sharedText); } else { ArrayList fileUris = new ArrayList<>(); @@ -130,7 +127,7 @@ public class MainActivity extends AppCompatActivity { fileUris.add(uri); } for (Uri uri : fileUris) { - tr.handleSendFile(uri); + Transfer.handleSendFile(uri); } } } diff --git a/app/src/main/java/com/localtransfer/Progress.java b/app/src/main/java/com/localtransfer/Progress.java index 19dc597..3a50e4a 100644 --- a/app/src/main/java/com/localtransfer/Progress.java +++ b/app/src/main/java/com/localtransfer/Progress.java @@ -1,32 +1,29 @@ package com.localtransfer; +import android.animation.ObjectAnimator; import android.app.Notification; import android.app.PendingIntent; import android.content.Intent; +import android.graphics.Color; +import android.graphics.drawable.Drawable; import android.view.LayoutInflater; import android.view.View; -import android.widget.Button; +import android.view.animation.Animation; +import android.view.animation.LinearInterpolator; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; +import android.widget.Toast; -import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationManagerCompat; -import androidx.core.content.ContextCompat; -import java.util.ArrayList; +import com.google.android.material.snackbar.Snackbar; + import java.util.ConcurrentModificationException; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; public class Progress { - public static final int UPLOAD = 1000; - public static final int DOWNLOAD = 1001; - - private static Notification.Builder bl = new Notification.Builder(Transfer.activity); private static NotificationManagerCompat notifiManager = NotificationManagerCompat.from(Transfer.activity); private static final LayoutInflater inflater = (LayoutInflater) Transfer.activity.getSystemService(Transfer.activity.LAYOUT_INFLATER_SERVICE); @@ -34,163 +31,131 @@ public class Progress { private static Intent notificationIntent = new Intent(Transfer.activity, MainActivity.class); private static PendingIntent pendingIntent = PendingIntent.getActivity(Transfer.activity,0, notificationIntent, 0); - private static List instances = new ArrayList<>(); - - private Integer id; - private String name; - - private long size; - private String HumanSize; - - public long loaded; - private String HumanLoaded; - - public long percent; - public static View root; public static boolean fragment_on = false; public static boolean app_started = false; - private Timer timer = new Timer(); - private int drawable; - private String info; + private static long savedTimeMillis; - public Button button; - private boolean run; - - public Progress(String name, long size, int type) { - - instances.add(this); - - run = true; - - this.name = name; - this.size = size; - this.HumanSize = Transfer.humanReadableByteCountBin(size); - - id = View.generateViewId(); - - switch (type) { - case Progress.DOWNLOAD: - drawable = R.drawable.ic_download_24; - info = "Download complete"; - break; - case Progress.UPLOAD: - drawable = R.drawable.ic_upload_24; - info = "Upload complete"; - break; - default: - throw new IllegalStateException("Unexpected value: " + type); - } - - Intent serviceIntent = new Intent(Transfer.activity, TransferService.class); - serviceIntent.putExtra("id", id); - ContextCompat.startForegroundService(Transfer.activity, serviceIntent); - - timer.schedule(new TimerTask() { + public static void PreProgress(Transfer tr) { + Transfer.activity.runOnUiThread(new Runnable() { @Override public void run() { - showProgress(); + + final Drawable image = Transfer.activity.getDrawable(R.drawable.ic_spinner_rotate); + + if(tr.button != null) { + int h = image.getIntrinsicHeight(); + int w = image.getIntrinsicWidth(); + image.setBounds(0, 0, w, h); + tr.button.setCompoundDrawables(tr.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(); + } } - }, 0, 1000); + }); } - public static List getInstances() { - return instances; - } - - public void stopProgress() { - timer.cancel(); - showProgress(); - - run = false; - - Intent serviceIntent = new Intent(Transfer.activity, TransferService.class); - Transfer.activity.stopService(serviceIntent); - - if(! app_started) { - bl.setSmallIcon(R.drawable.ic_upload_and_download_from_the_cloud) - .setContentTitle(name) - .setContentText(info) - .setProgress(0, 0, false) - .setContentIntent(pendingIntent); - notifiManager.notify(id, bl.build()); + public static void ProgressUpdateDelay(Transfer tr) { + // Run only every second to reduce CPU usage + if (System.currentTimeMillis() > (savedTimeMillis + 1000)) { + savedTimeMillis = System.currentTimeMillis(); + ProgressUpdate(tr); } - } - public void delete() { - instances.remove(this); - } + private static void ProgressUpdate(Transfer tr){ + Transfer.activity.runOnUiThread(new Runnable() { + @Override + public void run() { - public static Progress getProgress(int id) { + if (Progress.app_started && tr.button != null) + tr.button.setText(String.format("Download in progress %d%%", tr.percent)); - for (Object obj: instances) { - Progress p = (Progress) obj; - if (p.id == id) return p; - } - return null; - } + try { - public static boolean setButton(String name, Button button) { + bl.setSmallIcon(R.drawable.ic_upload_and_download_from_the_cloud) + .setContentTitle(tr.fileName) + .setContentText(String.format("%d%% %s/%s", tr.percent, tr.loadedHuman, tr.fileSizeHuman)) + .setProgress(100, (int) tr.percent, false) + .setContentIntent(pendingIntent); + notifiManager.notify(Transfer.NOTIF_SERVICE, bl.build()); - for (Object obj: instances) { - Progress p = (Progress) obj; - if (name.equals(p.name) && p.run) { - p.button = button; - return true; + if (app_started && fragment_on) + showProgressFragment(tr); + + } catch (ConcurrentModificationException e) { + e.printStackTrace(); + } } - } - return false; + }); } - private void showProgress(){ + public static void PostProgress(Transfer tr) { + ProgressUpdate(tr); + Transfer.activity.runOnUiThread(new Runnable() { + @Override + public void run() { - try { + notifiManager.cancel(Transfer.NOTIF_SERVICE); - HumanLoaded = Transfer.humanReadableByteCountBin(loaded); + if (!app_started) { + bl.setSmallIcon(R.drawable.ic_upload_and_download_from_the_cloud) + .setContentTitle(tr.fileName) + .setContentText(tr.info) + .setProgress(0, 0, false) + .setContentIntent(pendingIntent); + notifiManager.notify(tr.id, bl.build()); + } - bl.setSmallIcon(R.drawable.ic_upload_and_download_from_the_cloud) - .setContentTitle(name) - .setContentText(String.format("%d%% %s/%s", percent, HumanLoaded, HumanSize)) - .setProgress(100, (int) percent, false) - .setContentIntent(pendingIntent); - notifiManager.notify(id, bl.build()); + if (tr.button != null) { + final LinearLayout layout = (LinearLayout) tr.button.getParent(); + layout.findViewById(R.id.file_view).setVisibility(LinearLayout.VISIBLE); + layout.findViewById(R.id.file_share).setVisibility(LinearLayout.VISIBLE); + tr.button.setVisibility(LinearLayout.GONE); + tr.button.setEnabled(true); - if(app_started && fragment_on) { - showProgressFragment(); + tr.button.setText(Transfer.activity.getString(R.string.file_download)); + tr.button.setCompoundDrawables(tr.button.getCompoundDrawables()[0], null, null, null); + } + + System.out.println(tr.message); + /*Snackbar.make(Transfer.activity.findViewById(R.id.view_pager), tr.message, Snackbar.LENGTH_LONG) + .setAction("Action", null).show();*/ + Toast.makeText(Transfer.activity, tr.message, Toast.LENGTH_SHORT).show(); } - - } catch (ConcurrentModificationException e) { - e.printStackTrace(); - } - + }); } - public void showProgressFragment(){ + public static void showProgressFragment(Transfer tr){ LinearLayout groot = root.findViewById(R.id.groot); final View progress; - if (groot.findViewById(id) != null) { - progress = groot.findViewById(id); + if (groot.findViewById(tr.id) != null) { + progress = groot.findViewById(tr.id); } else { progress = inflater.inflate(R.layout.progress, null); - progress.setId(id); + progress.setId(tr.id); Transfer.activity.runOnUiThread(() -> { groot.addView(progress, 0); }); } - Transfer.activity.runOnUiThread(() -> { - ((ProgressBar) progress.findViewById(R.id.progressBar)).setProgress((int) percent); - ((ImageView) progress.findViewById(R.id.transferType)).setImageResource(drawable); - ((TextView) progress.findViewById(R.id.progressText)).setText(percent + " %"); - ((TextView) progress.findViewById(R.id.fileName)).setText(name); - ((TextView) progress.findViewById(R.id.fileSize)).setText(String.format("%s/%s", HumanLoaded, HumanSize)); - }); + ((ProgressBar) progress.findViewById(R.id.progressBar)).setProgress((int) tr.percent); + ((ImageView) progress.findViewById(R.id.transferType)).setImageResource(tr.drawable); + ((TextView) progress.findViewById(R.id.progressText)).setText(tr.percent + " %"); + ((TextView) progress.findViewById(R.id.fileName)).setText(tr.fileName); + ((TextView) progress.findViewById(R.id.fileSize)).setText(String.format("%s/%s", tr.loadedHuman, tr.fileSizeHuman)); + if (tr.state == Transfer.STATE_SUCCESS) + ((TextView) progress.findViewById(R.id.fileName)).setTextColor(Color.GREEN); + else if (tr.state == Transfer.STATE_FAILED) + ((TextView) progress.findViewById(R.id.fileName)).setTextColor(Color.RED); } } diff --git a/app/src/main/java/com/localtransfer/Transfer.java b/app/src/main/java/com/localtransfer/Transfer.java index b4272a0..2c5d544 100644 --- a/app/src/main/java/com/localtransfer/Transfer.java +++ b/app/src/main/java/com/localtransfer/Transfer.java @@ -1,25 +1,19 @@ package com.localtransfer; -import android.animation.ObjectAnimator; import android.app.Activity; import android.content.Context; +import android.content.Intent; 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.ContextCompat; import androidx.core.content.FileProvider; import androidx.preference.PreferenceManager; @@ -32,7 +26,6 @@ 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; @@ -41,6 +34,7 @@ import java.nio.charset.StandardCharsets; import java.text.CharacterIterator; import java.text.SimpleDateFormat; import java.text.StringCharacterIterator; +import java.util.ArrayList; import java.util.ConcurrentModificationException; import java.util.Date; import java.util.List; @@ -59,6 +53,127 @@ public class Transfer { public static Activity activity; + public static final int STATE_STANDBY = 100; + public static final int STATE_RUNNING = 101; + public static final int STATE_SUCCESS = 102; + public static final int STATE_FAILED = 103; + + public static final int TYPE_DOWNLOAD = 200; + public static final int TYPE_UPLOAD = 201; + + public static final int NOTIF_SERVICE = 1000; + public static final int NOTIF_GROUP = 1001; + + public static boolean runningTransfer = false; + + private static List instances = new ArrayList<>(); + + public static List getInstances() { + return instances; + } + + public int state; + public String error; + + public int type; + + public Integer id; + public int drawable; + public String info; + public String message; + public String fileName; + + public long fileSize; + public String fileSizeHuman; + + public long loaded; + public String loadedHuman = "0"; + public long percent; + + public Transfer(int type) { + + id = View.generateViewId(); + + switch (type) { + case TYPE_DOWNLOAD: + drawable = R.drawable.ic_download_24; + info = "Download complete"; + break; + case TYPE_UPLOAD: + drawable = R.drawable.ic_upload_24; + info = "Upload complete"; + break; + default: + throw new IllegalStateException("Unexpected value: " + type); + } + + state = STATE_STANDBY; + this.type = type; + + } + + public void AddTransfer() { + instances.add(this); + + if(!runningTransfer) { + Intent serviceIntent = new Intent(activity, TransferService.class); + ContextCompat.startForegroundService(activity, serviceIntent); + runningTransfer = true; + new Thread(() -> StartTransfer(this)).start(); + } + } + + private static void StartTransfer(Transfer tr) { + try { + switch (tr.type) { + case Transfer.TYPE_DOWNLOAD: + tr.downloadFile(); + break; + case Transfer.TYPE_UPLOAD: + tr.uploadFile(); + break; + default: + throw new IllegalStateException("Unexpected value: " + tr.type); + } + } catch (IOException e) { + final String ExceptionName = e.getClass().getSimpleName(); + final String ExceptionMess = e.getMessage(); + + tr.state = Transfer.STATE_FAILED; + tr.error = ExceptionName + ": " + ExceptionMess; + Progress.PostProgress(tr); + + if(ExceptionName != null && ExceptionMess != null) { + Transfer.error(ExceptionMess); + } + + } + + try { + for (Object obj : Transfer.getInstances()) { + Transfer transfer = (Transfer) obj; + if (transfer.state == Transfer.STATE_STANDBY) + StartTransfer(transfer); + } + } catch (ConcurrentModificationException e) { + e.printStackTrace(); + try { + Thread.sleep(10); + } catch (InterruptedException InterrupEx) { + InterrupEx.printStackTrace(); + } + for (Object obj : Transfer.getInstances()) { + Transfer transfer = (Transfer) obj; + if (transfer.state == Transfer.STATE_STANDBY) + StartTransfer(transfer); + } + } + + Intent serviceIntent = new Intent(Transfer.activity, TransferService.class); + Transfer.activity.stopService(serviceIntent); + Transfer.runningTransfer = false; + } + public static void parameter(Context context) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); @@ -72,7 +187,267 @@ public class Transfer { protocol = "http"; } - private URL checkRedirection(URL url) throws IOException { + public Uri uri; + + public static void handleSendFile(Uri uri) { + if (uri != null) { + Transfer tr = new Transfer(Transfer.TYPE_UPLOAD); + tr.uri = uri; + + Cursor cursor = activity.getContentResolver().query(uri, null, null, null, null); + cursor.moveToFirst(); + + tr.fileName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); + tr.fileSize = cursor.getLong(cursor.getColumnIndex(OpenableColumns.SIZE)); + tr.fileSizeHuman = Transfer.humanReadableByteCountBin(tr.fileSize); + + tr.AddTransfer(); + } + } + + public static void handleSendText(String sharedText) { + if (sharedText != null) { + SimpleDateFormat sdfDate = new SimpleDateFormat("yyyyMMdd_HHmmss"); + Date now = new Date(); + String strDate = sdfDate.format(now); + Uri uri = null; + + 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 = FileProvider.getUriForFile(activity, activity.getPackageName(), outputFile); + + } catch (IOException e) { + e.printStackTrace(); + } + handleSendFile(uri); + } + } + + public String uploadFile() throws IOException { + URL url = null; + HttpURLConnection conn = null; + DataOutputStream request = null; + String boundary = "*****"; + int maxBufferSize = 1 * 1024 * 1024; + byte[] buffer = new byte[maxBufferSize]; + int bufferLength; + loaded = 0; + + String fileNameUTF8 = new String(fileName.getBytes(), StandardCharsets.ISO_8859_1); + + String type = activity.getContentResolver().getType(uri); + + url = new URL(protocol, host, port, root + "/upload.php"); + + url = checkRedirection(url); + + Progress.PreProgress(this); + + 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; + loadedHuman = Transfer.humanReadableByteCountBin(loaded); + percent = ((loaded * 100) / fileSize); + Progress.ProgressUpdateDelay(this); + } + + 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"; + state = Transfer.STATE_SUCCESS; + Progress.PostProgress(this); + } + else { + String s = conn.getResponseMessage(); + throw new HttpErrorException("HTTP Error code " + responseCode + " " + s); + } + + request.flush(); + + request.close(); + + conn.disconnect(); + } + + return message; + } + + + public File file; + public String href; + public Button button; + + public void downloadFile() throws IOException { + URL url = null; + HttpURLConnection conn = null; + int maxBufferSize = 1 * 1024 * 1024; + byte[] buffer = new byte[maxBufferSize]; + int bufferLength; + loaded = 0; + + Progress.PreProgress(this); + + 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; + loadedHuman = Transfer.humanReadableByteCountBin(loaded); + percent = ((loaded * 100) / fileSize); + Progress.ProgressUpdateDelay(this); + } + fileOutput.close(); + + conn.disconnect(); + + message = "File " + fileName + " successful download"; + state = Transfer.STATE_SUCCESS; + Progress.PostProgress(this); + + } + else { + String s = conn.getResponseMessage(); + throw new HttpErrorException("HTTP Error code " + responseCode + " " + s); + } + + conn.disconnect(); + } + + public static boolean setButton(String name, Button button) { + + for (Object obj: instances) { + Transfer tr = (Transfer) obj; + if (name.equals(tr.fileName) && tr.state == STATE_RUNNING) { + tr.button = button; + return true; + } + } + return false; + } + + public static 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("HTTP Error code " + responseCode + " " + s); + } + + conn.disconnect(); + + return fileList; + } + + public static 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("HTTP Error code " + responseCode + " " + s); + } + + conn.disconnect(); + + return message; + } + + private static URL checkRedirection(URL url) throws IOException { String location = null; HttpURLConnection conn = null; int responseCode; @@ -113,331 +488,18 @@ public class Transfer { 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 File file, 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;*/ - - 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) { + public static void error(final String message) { 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() { + if (activity != null) { + activity.runOnUiThread(new Runnable() { @Override public void run() { - timeout = 0; + Snackbar.make(activity.findViewById(R.id.view_pager), message, Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); } - }, 3000); + }); } } diff --git a/app/src/main/java/com/localtransfer/TransferService.java b/app/src/main/java/com/localtransfer/TransferService.java index 894e9a0..02cc73f 100644 --- a/app/src/main/java/com/localtransfer/TransferService.java +++ b/app/src/main/java/com/localtransfer/TransferService.java @@ -17,7 +17,6 @@ public class TransferService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { - int id = intent.getIntExtra("id", 0); Intent notificationIntent = new Intent(this, MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, @@ -27,7 +26,7 @@ public class TransferService extends Service { .setContentIntent(pendingIntent) .build(); - startForeground(id, notification); + startForeground(Transfer.NOTIF_SERVICE, notification); //do heavy work on a background thread //stopSelf(); diff --git a/app/src/main/java/com/localtransfer/fragment/DownloadFragment.java b/app/src/main/java/com/localtransfer/fragment/DownloadFragment.java index 54984ca..9f33455 100644 --- a/app/src/main/java/com/localtransfer/fragment/DownloadFragment.java +++ b/app/src/main/java/com/localtransfer/fragment/DownloadFragment.java @@ -27,7 +27,6 @@ import android.widget.TextView; import com.google.android.material.snackbar.Snackbar; import com.localtransfer.BuildConfig; -import com.localtransfer.Progress; import com.localtransfer.R; import com.localtransfer.Transfer; @@ -111,8 +110,7 @@ public class DownloadFragment extends Fragment { final String file = String.valueOf(fileDesc.getTag(R.id.ID_FILE_NAME)); new Thread(() -> { try { - Transfer tr = new Transfer(); - String message = tr.deleteFile(file); + String message = Transfer.deleteFile(file); System.out.println(message); Transfer.activity.runOnUiThread(() -> Snackbar.make(getActivity().findViewById(R.id.view_pager), message, Snackbar.LENGTH_LONG) @@ -123,7 +121,7 @@ public class DownloadFragment extends Fragment { String ExceptionMess = e.getMessage(); if(ExceptionName != null && ExceptionMess != null) { - Transfer.error(ExceptionName + ": " + ExceptionMess, null, null); + Transfer.error(ExceptionMess); } } @@ -143,18 +141,24 @@ public class DownloadFragment extends Fragment { final LinearLayout main_layout = root.findViewById(R.id.main_layout); final LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(getContext().LAYOUT_INFLATER_SERVICE); - Transfer tr = new Transfer(); - String data = ""; try { - data = tr.getFileList(); + data = Transfer.getFileList(); } catch (IOException e) { final String ExceptionName = e.getClass().getSimpleName(); final String ExceptionMess = e.getMessage(); if(ExceptionName != null && ExceptionMess != null) { - Transfer.error(ExceptionName + ": " + ExceptionMess, title, main_layout); + Transfer.error(ExceptionMess); + Transfer.activity.runOnUiThread(() -> { + if(main_layout != null) + main_layout.removeAllViews(); + if(title != null) { + main_layout.addView(title); + title.setText(ExceptionMess); + } + }); } } @@ -253,7 +257,7 @@ public class DownloadFragment extends Fragment { Bshare.setVisibility(LinearLayout.GONE); } - if (Progress.setButton(name, dl)) { + if (Transfer.setButton(name, dl)) { dl.setEnabled(false); final Drawable spinner = Transfer.activity.getDrawable(R.drawable.ic_spinner_rotate); int h = spinner.getIntrinsicHeight(); @@ -304,21 +308,14 @@ public class DownloadFragment extends Fragment { new File(save_location).mkdirs(); File file = new File(save_location, name); - Transfer tr = new Transfer(); - - new Thread(() -> { - try { - tr.downloadFile(file, name, fileSize, href, button); - } 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(); + Transfer tr = new Transfer(Transfer.TYPE_DOWNLOAD); + tr.file = file; + tr.fileName = name; + tr.fileSize = fileSize; + tr.fileSizeHuman = Transfer.humanReadableByteCountBin(fileSize); + tr.href = href; + tr.button = button; + tr.AddTransfer(); }; private View.OnClickListener ListenerShare = v -> { diff --git a/app/src/main/java/com/localtransfer/fragment/ProgressFragment.java b/app/src/main/java/com/localtransfer/fragment/ProgressFragment.java index afe7cc0..9c70e09 100644 --- a/app/src/main/java/com/localtransfer/fragment/ProgressFragment.java +++ b/app/src/main/java/com/localtransfer/fragment/ProgressFragment.java @@ -54,10 +54,10 @@ public class ProgressFragment extends Fragment { Progress.fragment_on = true; - List instances = Progress.getInstances(); + List instances = Transfer.getInstances(); for (Object obj: instances) { - Progress p = (Progress) obj; - p.showProgressFragment(); + Transfer tr = (Transfer) obj; + Progress.showProgressFragment(tr); } } From f6b652fb7ec5aaecaf705267eeb6f179dde53bcc Mon Sep 17 00:00:00 2001 From: lionel <> Date: Wed, 23 Feb 2022 16:27:01 +0100 Subject: [PATCH 3/5] Manual Merge master in foregroundService base master Several bug still present - No notification - No Upload - Need more test --- .idea/compiler.xml | 2 +- .idea/gradle.xml | 4 +- .idea/misc.xml | 14 +- app/build.gradle | 5 +- app/src/main/AndroidManifest.xml | 10 +- .../java/com/localtransfer/MainActivity.java | 56 +- .../main/java/com/localtransfer/Progress.java | 161 ----- .../java/com/localtransfer/ServerFile.java | 395 +++++++++++ .../main/java/com/localtransfer/Transfer.java | 612 +++++++----------- .../fragment/DownloadFragment.java | 392 ++++++----- .../fragment/ProgressFragment.java | 26 +- app/src/main/res/values/ids.xml | 6 +- app/src/main/res/values/strings.xml | 2 +- .../main/res/xml/network_security_config.xml | 6 + build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 16 files changed, 893 insertions(+), 802 deletions(-) delete mode 100644 app/src/main/java/com/localtransfer/Progress.java create mode 100644 app/src/main/java/com/localtransfer/ServerFile.java create mode 100644 app/src/main/res/xml/network_security_config.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 61a9130..fb7f4a8 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 23a89bb..526b4c2 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -4,10 +4,9 @@ diff --git a/.idea/misc.xml b/.idea/misc.xml index a8f62cd..f1a2d08 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,5 +1,14 @@ + + + - + diff --git a/app/build.gradle b/app/build.gradle index 8b01084..27c226f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,7 +2,6 @@ apply plugin: 'com.android.application' android { compileSdkVersion 30 - buildToolsVersion "30.0.2" defaultConfig { applicationId "com.localtransfer" @@ -21,8 +20,8 @@ android { } } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bd2ee7c..0414bfa 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,13 +3,17 @@ package="com.localtransfer"> - + + @@ -17,7 +21,7 @@ android:name=".TransferService" android:enabled="true" android:exported="true"> - + fileUris = new ArrayList<>(); @@ -127,7 +143,7 @@ public class MainActivity extends AppCompatActivity { fileUris.add(uri); } for (Uri uri : fileUris) { - Transfer.handleSendFile(uri); + tr.handleSendFile(uri); } } } @@ -137,14 +153,14 @@ public class MainActivity extends AppCompatActivity { public void onResume(){ super.onResume(); - Progress.app_started = true; + Transfer.app_started = true; } @Override public void onPause(){ super.onPause(); - Progress.app_started = false; + Transfer.app_started = false; } @Override diff --git a/app/src/main/java/com/localtransfer/Progress.java b/app/src/main/java/com/localtransfer/Progress.java deleted file mode 100644 index 3a50e4a..0000000 --- a/app/src/main/java/com/localtransfer/Progress.java +++ /dev/null @@ -1,161 +0,0 @@ -package com.localtransfer; - -import android.animation.ObjectAnimator; -import android.app.Notification; -import android.app.PendingIntent; -import android.content.Intent; -import android.graphics.Color; -import android.graphics.drawable.Drawable; -import android.view.LayoutInflater; -import android.view.View; -import android.view.animation.Animation; -import android.view.animation.LinearInterpolator; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.ProgressBar; -import android.widget.TextView; -import android.widget.Toast; - -import androidx.core.app.NotificationManagerCompat; - -import com.google.android.material.snackbar.Snackbar; - -import java.util.ConcurrentModificationException; - -public class Progress { - - private static Notification.Builder bl = new Notification.Builder(Transfer.activity); - private static NotificationManagerCompat notifiManager = NotificationManagerCompat.from(Transfer.activity); - private static final LayoutInflater inflater = (LayoutInflater) Transfer.activity.getSystemService(Transfer.activity.LAYOUT_INFLATER_SERVICE); - - private static Intent notificationIntent = new Intent(Transfer.activity, MainActivity.class); - private static PendingIntent pendingIntent = PendingIntent.getActivity(Transfer.activity,0, notificationIntent, 0); - - public static View root; - public static boolean fragment_on = false; - public static boolean app_started = false; - - private static long savedTimeMillis; - - public static void PreProgress(Transfer tr) { - Transfer.activity.runOnUiThread(new Runnable() { - @Override - public void run() { - - final Drawable image = Transfer.activity.getDrawable(R.drawable.ic_spinner_rotate); - - if(tr.button != null) { - int h = image.getIntrinsicHeight(); - int w = image.getIntrinsicWidth(); - image.setBounds(0, 0, w, h); - tr.button.setCompoundDrawables(tr.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(); - } - } - }); - } - - public static void ProgressUpdateDelay(Transfer tr) { - // Run only every second to reduce CPU usage - if (System.currentTimeMillis() > (savedTimeMillis + 1000)) { - savedTimeMillis = System.currentTimeMillis(); - ProgressUpdate(tr); - } - } - - private static void ProgressUpdate(Transfer tr){ - Transfer.activity.runOnUiThread(new Runnable() { - @Override - public void run() { - - if (Progress.app_started && tr.button != null) - tr.button.setText(String.format("Download in progress %d%%", tr.percent)); - - try { - - bl.setSmallIcon(R.drawable.ic_upload_and_download_from_the_cloud) - .setContentTitle(tr.fileName) - .setContentText(String.format("%d%% %s/%s", tr.percent, tr.loadedHuman, tr.fileSizeHuman)) - .setProgress(100, (int) tr.percent, false) - .setContentIntent(pendingIntent); - notifiManager.notify(Transfer.NOTIF_SERVICE, bl.build()); - - if (app_started && fragment_on) - showProgressFragment(tr); - - } catch (ConcurrentModificationException e) { - e.printStackTrace(); - } - } - }); - } - - public static void PostProgress(Transfer tr) { - ProgressUpdate(tr); - Transfer.activity.runOnUiThread(new Runnable() { - @Override - public void run() { - - notifiManager.cancel(Transfer.NOTIF_SERVICE); - - if (!app_started) { - bl.setSmallIcon(R.drawable.ic_upload_and_download_from_the_cloud) - .setContentTitle(tr.fileName) - .setContentText(tr.info) - .setProgress(0, 0, false) - .setContentIntent(pendingIntent); - notifiManager.notify(tr.id, bl.build()); - } - - if (tr.button != null) { - final LinearLayout layout = (LinearLayout) tr.button.getParent(); - layout.findViewById(R.id.file_view).setVisibility(LinearLayout.VISIBLE); - layout.findViewById(R.id.file_share).setVisibility(LinearLayout.VISIBLE); - tr.button.setVisibility(LinearLayout.GONE); - tr.button.setEnabled(true); - - tr.button.setText(Transfer.activity.getString(R.string.file_download)); - tr.button.setCompoundDrawables(tr.button.getCompoundDrawables()[0], null, null, null); - } - - System.out.println(tr.message); - /*Snackbar.make(Transfer.activity.findViewById(R.id.view_pager), tr.message, Snackbar.LENGTH_LONG) - .setAction("Action", null).show();*/ - Toast.makeText(Transfer.activity, tr.message, Toast.LENGTH_SHORT).show(); - - } - }); - } - - public static void showProgressFragment(Transfer tr){ - - LinearLayout groot = root.findViewById(R.id.groot); - - final View progress; - - if (groot.findViewById(tr.id) != null) { - progress = groot.findViewById(tr.id); - } else { - progress = inflater.inflate(R.layout.progress, null); - progress.setId(tr.id); - Transfer.activity.runOnUiThread(() -> { - groot.addView(progress, 0); - }); - } - - ((ProgressBar) progress.findViewById(R.id.progressBar)).setProgress((int) tr.percent); - ((ImageView) progress.findViewById(R.id.transferType)).setImageResource(tr.drawable); - ((TextView) progress.findViewById(R.id.progressText)).setText(tr.percent + " %"); - ((TextView) progress.findViewById(R.id.fileName)).setText(tr.fileName); - ((TextView) progress.findViewById(R.id.fileSize)).setText(String.format("%s/%s", tr.loadedHuman, tr.fileSizeHuman)); - - if (tr.state == Transfer.STATE_SUCCESS) - ((TextView) progress.findViewById(R.id.fileName)).setTextColor(Color.GREEN); - else if (tr.state == Transfer.STATE_FAILED) - ((TextView) progress.findViewById(R.id.fileName)).setTextColor(Color.RED); - } -} diff --git a/app/src/main/java/com/localtransfer/ServerFile.java b/app/src/main/java/com/localtransfer/ServerFile.java new file mode 100644 index 0000000..61dd828 --- /dev/null +++ b/app/src/main/java/com/localtransfer/ServerFile.java @@ -0,0 +1,395 @@ +package com.localtransfer; + +import android.animation.ObjectAnimator; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.provider.MediaStore; +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.ImageView; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.ConcurrentModificationException; +import java.util.List; + +public class ServerFile extends Transfer { + + private Integer id; + + public String name; + + public String href; + + public String mime; + + public String type; + + public long size; + + public String save_location; + + public Uri uri; + + public Button button; + + private static List instances = new ArrayList<>(); + + public ServerFile(Integer id) { + this.id = id; + instances.add(this); + drawable = R.drawable.ic_download_24; + info = "Download complete"; + state = STATE_NOT_REQUESTED; + } + + @Override + public void StartTransfer() { + super.StartTransfer(); + + if (uri == null && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { + ContentValues values = new ContentValues(); + values.put(MediaStore.MediaColumns.DISPLAY_NAME, name); + values.put(MediaStore.MediaColumns.MIME_TYPE, mime); + values.put(MediaStore.MediaColumns.RELATIVE_PATH, Transfer.local_storage); + uri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values); + } + try { + downloadFile(); + } catch (IOException e) { + final String ExceptionName = e.getClass().getSimpleName(); + final String ExceptionMess = e.getMessage(); + + state = Transfer.STATE_FAILED; + error = ExceptionName + ": " + ExceptionMess; + PostProgress(); + + if(ExceptionName != null && ExceptionMess != null) { + errorSnackbar(ExceptionMess); + } + + } + + try { + for (Object obj : getInstances()) { + Transfer transfer = (Transfer) obj; + if (transfer.state == Transfer.STATE_STANDBY) + StartTransfer(); + } + } catch (ConcurrentModificationException e) { + e.printStackTrace(); + try { + Thread.sleep(10); + } catch (InterruptedException InterrupEx) { + InterrupEx.printStackTrace(); + } + for (Object obj : getInstances()) { + Transfer transfer = (Transfer) obj; + if (transfer.state == Transfer.STATE_STANDBY) + StartTransfer(); + } + } + + /*Intent serviceIntent = new Intent(Transfer.activity, TransferService.class); + Transfer.activity.stopService(serviceIntent); + Transfer.runningTransfer = false;*/ + } + + public static List getInstances() { + return instances; + } + + public static ServerFile getFileById(int id) { + for (Object obj: instances) { + ServerFile p = (ServerFile) obj; + if (p.id == id) return p; + } + return null; + } + + public Integer getId() { + return id; + } + + public boolean exist(Context context) { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { + Cursor cursor = context.getContentResolver().query(MediaStore.Downloads.EXTERNAL_CONTENT_URI, null, null, null, null); + while (cursor.moveToNext()) { + String MediaStore_File_name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Downloads.DISPLAY_NAME)); + long MediaStore_File_size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Downloads.SIZE)); + if(MediaStore_File_name.equals(name) && MediaStore_File_size == size) { + int cursor_id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Downloads._ID)); + uri = ContentUris.withAppendedId(MediaStore.Downloads.EXTERNAL_CONTENT_URI, cursor_id); + return true; + } + } + } + else { + File file = new File(save_location, name); + new File(save_location).mkdirs(); + uri = Uri.fromFile(file); + if (file.exists() && file.length() == size) + return true; + } + return false; + } + + public boolean setButton(Button button) { + if (this.state == STATE_RUNNING) { + this.button = button; + return true; + } + return false; + } + + public InputStream getThumbnail() { + InputStream thumbnail = null; + URL url; + try { + String query = URLEncoder.encode(href, StandardCharsets.UTF_8.toString()); + String serverUrl = root + "/thumbnail.php?file=" + query; + url = new URL(protocol, host, port, serverUrl); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + conn.setConnectTimeout(2000); + + conn.connect(); + + thumbnail = conn.getInputStream(); + } catch (IOException e) { + e.printStackTrace(); + } + return thumbnail; + } + + public void downloadFile() throws IOException { + + URL url = null; + HttpURLConnection conn = null; + int maxBufferSize = 1 * 1024 * 1024; + byte[] buffer = new byte[maxBufferSize]; + int bufferLength; + loaded = 0; + + PreProgress(); + + 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) { + + OutputStream fileOutput = activity.getContentResolver().openOutputStream(uri); + InputStream in = conn.getInputStream(); + + while ((bufferLength = in.read(buffer)) > 0) { + fileOutput.write(buffer, 0, bufferLength); + loaded+= bufferLength; + percent = ((loaded * 100) / size); + ProgressUpdateDelay(); + } + fileOutput.close(); + + conn.disconnect(); + + message = "File " + name + " successful download"; + state = Transfer.STATE_SUCCESS; + PostProgress(); + + } + else { + String s = conn.getResponseMessage(); + throw new HttpErrorException("error code: " + responseCode + " " + s); + } + + conn.disconnect(); + } + + public String deleteFile() throws IOException { + + URL url = null; + HttpURLConnection conn = null; + + String message; + + String query = URLEncoder.encode(name, 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 " + name + " successful deleted"; + } + else { + String s = conn.getResponseMessage(); + throw new HttpErrorException("error code: " + responseCode + " " + s); + } + + conn.disconnect(); + + return message; + } + + public void PreProgress() { + activity.runOnUiThread(() -> { + + final Drawable image = Transfer.activity.getDrawable(R.drawable.ic_spinner_rotate); + sizeSI = Transfer.humanReadableByteCountBin(size); + + state = STATE_RUNNING; + + if(button != null) { + int h = image.getIntrinsicHeight(); + int w = image.getIntrinsicWidth(); + image.setBounds(0, 0, w, h); + 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(); + } + }); + } + + public void ProgressUpdateDelay() { + // Run only every second to reduce CPU usage + if (System.currentTimeMillis() > (savedTimeMillis + 1000)) { + savedTimeMillis = System.currentTimeMillis(); + ProgressUpdate(); + } + } + + private void ProgressUpdate(){ + + loadedSI = Transfer.humanReadableByteCountBin(loaded); + + activity.runOnUiThread(() -> { + + if (app_started && button != null) + button.setText(String.format("Download in progress %d%%", percent)); + + try { + + notifBuilder.setSmallIcon(R.drawable.ic_upload_and_download_from_the_cloud) + .setContentTitle(name) + .setContentText(String.format("%d%% %s/%s", percent, loadedSI, sizeSI)) + .setProgress(100, (int) percent, false) + .setContentIntent(pendingIntent); + notifiManager.notify(Transfer.NOTIF_SERVICE, notifBuilder.build()); + + if (app_started && fragment_on) + showProgressFragment(); + + } catch (ConcurrentModificationException e) { + e.printStackTrace(); + } + }); + } + + public void PostProgress() { + ProgressUpdate(); + activity.runOnUiThread(() -> { + + notifiManager.cancel(Transfer.NOTIF_SERVICE); + + if (!app_started) { + notifBuilder.setSmallIcon(R.drawable.ic_upload_and_download_from_the_cloud) + .setContentTitle(name) + .setContentText(info) + .setProgress(0, 0, false) + .setContentIntent(pendingIntent); + notifiManager.notify(id, notifBuilder.build()); + } + + if (button != null) { + final LinearLayout layout = (LinearLayout) button.getParent(); + layout.findViewById(R.id.file_view).setVisibility(LinearLayout.VISIBLE); + layout.findViewById(R.id.file_share).setVisibility(LinearLayout.VISIBLE); + button.setVisibility(LinearLayout.GONE); + button.setEnabled(true); + + button.setText(activity.getString(R.string.file_download)); + button.setCompoundDrawables(button.getCompoundDrawables()[0], null, null, null); + } + + System.out.println(message); + /*Snackbar.make(Transfer.activity.findViewById(R.id.view_pager), tr.message, Snackbar.LENGTH_LONG) + .setAction("Action", null).show();*/ + Toast.makeText(activity, message, Toast.LENGTH_SHORT).show(); + + }); + } + + public void showProgressFragment(){ + + if(Arrays.asList(STATE_RUNNING, STATE_SUCCESS, STATE_FAILED).contains(state)) { + + LinearLayout groot = fragment_progress.findViewById(R.id.groot); + + View progress = groot.findViewById(id); + + if (progress == null) { + progress = inflater.inflate(R.layout.progress, null); + progress.setId(id); + final View final_progress = progress; + activity.runOnUiThread(() -> { + groot.addView(final_progress, 0); + }); + } + + ((ProgressBar) progress.findViewById(R.id.progressBar)).setProgress((int) percent); + ((ImageView) progress.findViewById(R.id.transferType)).setImageResource(drawable); + ((TextView) progress.findViewById(R.id.progressText)).setText(percent + " %"); + ((TextView) progress.findViewById(R.id.fileName)).setText(name); + ((TextView) progress.findViewById(R.id.fileSize)).setText(String.format("%s/%s", loadedSI, sizeSI)); + + if (state == Transfer.STATE_SUCCESS) + ((TextView) progress.findViewById(R.id.fileName)).setTextColor(Color.GREEN); + else if (state == Transfer.STATE_FAILED) + ((TextView) progress.findViewById(R.id.fileName)).setTextColor(Color.RED); + + } + } +} diff --git a/app/src/main/java/com/localtransfer/Transfer.java b/app/src/main/java/com/localtransfer/Transfer.java index 2c5d544..f874331 100644 --- a/app/src/main/java/com/localtransfer/Transfer.java +++ b/app/src/main/java/com/localtransfer/Transfer.java @@ -1,19 +1,21 @@ package com.localtransfer; +import static java.lang.Integer.valueOf; + import android.app.Activity; +import android.app.Notification; +import android.app.PendingIntent; +import android.content.ContentResolver; import android.content.Context; -import android.content.Intent; import android.content.SharedPreferences; import android.database.Cursor; import android.net.Uri; import android.provider.OpenableColumns; import android.util.Log; +import android.view.LayoutInflater; import android.view.View; -import android.widget.Button; -import android.widget.LinearLayout; -import android.widget.TextView; -import androidx.core.content.ContextCompat; +import androidx.core.app.NotificationManagerCompat; import androidx.core.content.FileProvider; import androidx.preference.PreferenceManager; @@ -29,22 +31,27 @@ import java.io.OutputStreamWriter; 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.ArrayList; -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 { + protected static Notification.Builder notifBuilder; + protected static NotificationManagerCompat notifiManager; + protected static LayoutInflater inflater; + protected static ContentResolver resolver; + + protected static PendingIntent pendingIntent; + + public static View fragment_progress; + public static boolean fragment_on = false; + public static boolean app_started = false; + + protected static long savedTimeMillis; + public static String host; public static Integer port; public static String root; @@ -53,398 +60,63 @@ public class Transfer { public static Activity activity; - public static final int STATE_STANDBY = 100; - public static final int STATE_RUNNING = 101; - public static final int STATE_SUCCESS = 102; - public static final int STATE_FAILED = 103; - - public static final int TYPE_DOWNLOAD = 200; - public static final int TYPE_UPLOAD = 201; - - public static final int NOTIF_SERVICE = 1000; - public static final int NOTIF_GROUP = 1001; - - public static boolean runningTransfer = false; - - private static List instances = new ArrayList<>(); - - public static List getInstances() { - return instances; - } - public int state; - public String error; - public int type; - - public Integer id; public int drawable; public String info; public String message; - public String fileName; + public String error; - public long fileSize; - public String fileSizeHuman; + public String sizeSI; public long loaded; - public String loadedHuman = "0"; + public String loadedSI = "0"; public long percent; - public Transfer(int type) { + public static final int NOTIF_SERVICE = 1000; - id = View.generateViewId(); + public static final int STATE_NOT_REQUESTED = 100; + public static final int STATE_STANDBY = 110; + public static final int STATE_RUNNING = 120; + public static final int STATE_SUCCESS = 130; + public static final int STATE_FAILED = 140; - switch (type) { - case TYPE_DOWNLOAD: - drawable = R.drawable.ic_download_24; - info = "Download complete"; - break; - case TYPE_UPLOAD: - drawable = R.drawable.ic_upload_24; - info = "Upload complete"; - break; - default: - throw new IllegalStateException("Unexpected value: " + type); - } - - state = STATE_STANDBY; - this.type = type; - - } - - public void AddTransfer() { - instances.add(this); - - if(!runningTransfer) { - Intent serviceIntent = new Intent(activity, TransferService.class); - ContextCompat.startForegroundService(activity, serviceIntent); - runningTransfer = true; - new Thread(() -> StartTransfer(this)).start(); - } - } - - private static void StartTransfer(Transfer tr) { - try { - switch (tr.type) { - case Transfer.TYPE_DOWNLOAD: - tr.downloadFile(); - break; - case Transfer.TYPE_UPLOAD: - tr.uploadFile(); - break; - default: - throw new IllegalStateException("Unexpected value: " + tr.type); - } - } catch (IOException e) { - final String ExceptionName = e.getClass().getSimpleName(); - final String ExceptionMess = e.getMessage(); - - tr.state = Transfer.STATE_FAILED; - tr.error = ExceptionName + ": " + ExceptionMess; - Progress.PostProgress(tr); - - if(ExceptionName != null && ExceptionMess != null) { - Transfer.error(ExceptionMess); - } - - } - - try { - for (Object obj : Transfer.getInstances()) { - Transfer transfer = (Transfer) obj; - if (transfer.state == Transfer.STATE_STANDBY) - StartTransfer(transfer); - } - } catch (ConcurrentModificationException e) { - e.printStackTrace(); - try { - Thread.sleep(10); - } catch (InterruptedException InterrupEx) { - InterrupEx.printStackTrace(); - } - for (Object obj : Transfer.getInstances()) { - Transfer transfer = (Transfer) obj; - if (transfer.state == Transfer.STATE_STANDBY) - StartTransfer(transfer); - } - } - - Intent serviceIntent = new Intent(Transfer.activity, TransferService.class); - Transfer.activity.stopService(serviceIntent); - Transfer.runningTransfer = false; - } + public static boolean runningTransfer = false; 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"; + String portValue = prefs.getString("port", null); + if(portValue.equals("")){ + if(protocol.equals("http")) + port = 80; + else if(protocol.equals("https")) + port = 443; + } + else + port = valueOf(portValue); } - public Uri uri; + public void AddTransfer() { - public static void handleSendFile(Uri uri) { - if (uri != null) { - Transfer tr = new Transfer(Transfer.TYPE_UPLOAD); - tr.uri = uri; - - Cursor cursor = activity.getContentResolver().query(uri, null, null, null, null); - cursor.moveToFirst(); - - tr.fileName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); - tr.fileSize = cursor.getLong(cursor.getColumnIndex(OpenableColumns.SIZE)); - tr.fileSizeHuman = Transfer.humanReadableByteCountBin(tr.fileSize); - - tr.AddTransfer(); + if(!runningTransfer) { + /*Intent serviceIntent = new Intent(activity, TransferService.class); + ContextCompat.startForegroundService(activity, serviceIntent);*/ + runningTransfer = true; + state = STATE_STANDBY; + new Thread(() -> StartTransfer()).start(); } } - public static void handleSendText(String sharedText) { - if (sharedText != null) { - SimpleDateFormat sdfDate = new SimpleDateFormat("yyyyMMdd_HHmmss"); - Date now = new Date(); - String strDate = sdfDate.format(now); - Uri uri = null; - - 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 = FileProvider.getUriForFile(activity, activity.getPackageName(), outputFile); - - } catch (IOException e) { - e.printStackTrace(); - } - handleSendFile(uri); - } - } - - public String uploadFile() throws IOException { - URL url = null; - HttpURLConnection conn = null; - DataOutputStream request = null; - String boundary = "*****"; - int maxBufferSize = 1 * 1024 * 1024; - byte[] buffer = new byte[maxBufferSize]; - int bufferLength; - loaded = 0; - - String fileNameUTF8 = new String(fileName.getBytes(), StandardCharsets.ISO_8859_1); - - String type = activity.getContentResolver().getType(uri); - - url = new URL(protocol, host, port, root + "/upload.php"); - - url = checkRedirection(url); - - Progress.PreProgress(this); - - 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; - loadedHuman = Transfer.humanReadableByteCountBin(loaded); - percent = ((loaded * 100) / fileSize); - Progress.ProgressUpdateDelay(this); - } - - 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"; - state = Transfer.STATE_SUCCESS; - Progress.PostProgress(this); - } - else { - String s = conn.getResponseMessage(); - throw new HttpErrorException("HTTP Error code " + responseCode + " " + s); - } - - request.flush(); - - request.close(); - - conn.disconnect(); - } - - return message; - } - - - public File file; - public String href; - public Button button; - - public void downloadFile() throws IOException { - URL url = null; - HttpURLConnection conn = null; - int maxBufferSize = 1 * 1024 * 1024; - byte[] buffer = new byte[maxBufferSize]; - int bufferLength; - loaded = 0; - - Progress.PreProgress(this); - - 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; - loadedHuman = Transfer.humanReadableByteCountBin(loaded); - percent = ((loaded * 100) / fileSize); - Progress.ProgressUpdateDelay(this); - } - fileOutput.close(); - - conn.disconnect(); - - message = "File " + fileName + " successful download"; - state = Transfer.STATE_SUCCESS; - Progress.PostProgress(this); - - } - else { - String s = conn.getResponseMessage(); - throw new HttpErrorException("HTTP Error code " + responseCode + " " + s); - } - - conn.disconnect(); - } - - public static boolean setButton(String name, Button button) { - - for (Object obj: instances) { - Transfer tr = (Transfer) obj; - if (name.equals(tr.fileName) && tr.state == STATE_RUNNING) { - tr.button = button; - return true; - } - } - return false; - } - - public static 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("HTTP Error code " + responseCode + " " + s); - } - - conn.disconnect(); - - return fileList; - } - - public static 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("HTTP Error code " + responseCode + " " + s); - } - - conn.disconnect(); - - return message; + public void StartTransfer() { + int x = 35 + 65; } private static URL checkRedirection(URL url) throws IOException { @@ -488,18 +160,190 @@ public class Transfer { return url; } - public static void error(final String message) { + public static void handleSendFile(Uri uri) { + if (uri != null) { + new Thread(() -> { + try { + Transfer.uploadFile(uri); + } catch (IOException e) { + final String ExceptionName = e.getClass().getSimpleName(); + final String ExceptionMess = e.getMessage(); + + if(ExceptionName != null && ExceptionMess != null) { + Transfer.errorSnackbar(ExceptionMess); + } + + } + }).start(); + } + } + + public static void handleSendText(String sharedText) { + if (sharedText != null) { + SimpleDateFormat sdfDate = new SimpleDateFormat("text_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); + + Transfer.uploadFile(uri); + } catch (IOException e) { + e.printStackTrace(); + } + }).start(); + } + } + + public static String uploadFile(Uri uri) throws IOException { + String message = null; + URL url = null; + HttpURLConnection conn = null; + DataOutputStream request = null; + String boundary = "*****"; + final 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 type = activity.getContentResolver().getType(uri); + + String fileName = null; + int col_name = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); + if (col_name != -1) + fileName = cursor.getString(col_name); + if(fileName == null) + fileName = type.split("/")[0] + "_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) + "." + type.split("/")[1]; + String fileNameUTF8 = new String(fileName.getBytes(), StandardCharsets.ISO_8859_1); + + long fileSize = -1; + int col_size = cursor.getColumnIndex(OpenableColumns.SIZE); + if (col_size != -1) + fileSize = cursor.getLong(col_size); + + url = new URL(protocol, host, port, root + "/upload.php"); + + url = checkRedirection(url); + + 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); + + if (fileSize < 1) + fileSize = in.available(); + + //Progress p = new Progress(fileName, fileSize, Progress.UPLOAD); + + 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 static 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; + } + + private static int timeout; + + public static void errorSnackbar(final String message) { System.out.println(message); if (activity != null) { - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - Snackbar.make(activity.findViewById(R.id.view_pager), message, Snackbar.LENGTH_LONG) - .setAction("Action", null).show(); - } - }); + activity.runOnUiThread(() -> Snackbar.make(activity.findViewById(R.id.view_pager), message, Snackbar.LENGTH_LONG) + .setAction("Action", null).show()); } } diff --git a/app/src/main/java/com/localtransfer/fragment/DownloadFragment.java b/app/src/main/java/com/localtransfer/fragment/DownloadFragment.java index 9f33455..95a7af5 100644 --- a/app/src/main/java/com/localtransfer/fragment/DownloadFragment.java +++ b/app/src/main/java/com/localtransfer/fragment/DownloadFragment.java @@ -3,14 +3,10 @@ package com.localtransfer.fragment; import android.animation.ObjectAnimator; import android.content.ActivityNotFoundException; import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.drawable.Drawable; -import android.net.Uri; import android.os.Bundle; - -import androidx.core.content.FileProvider; -import androidx.fragment.app.Fragment; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; - import android.os.Environment; import android.view.ContextMenu; import android.view.Gravity; @@ -25,9 +21,12 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import androidx.fragment.app.Fragment; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + import com.google.android.material.snackbar.Snackbar; -import com.localtransfer.BuildConfig; import com.localtransfer.R; +import com.localtransfer.ServerFile; import com.localtransfer.Transfer; import org.json.JSONArray; @@ -35,8 +34,6 @@ import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -52,6 +49,7 @@ public class DownloadFragment extends Fragment { } private View root; + private LayoutInflater inflater; public static DownloadFragment newInstance() { DownloadFragment fragment = new DownloadFragment(); @@ -68,17 +66,20 @@ public class DownloadFragment extends Fragment { Bundle savedInstanceState) { root = inflater.inflate(R.layout.fragment_download, container, false); + this.inflater = inflater; + new Timer().schedule(new TimerTask() { @Override public void run() { - showFileList(); + listFile(); } }, 100); SwipeRefreshLayout refresh = root.findViewById(R.id.refresh); + refresh.setOnRefreshListener(() -> { - new Thread(() -> showFileList()).start(); + listFile(); refresh.setRefreshing(false); }); @@ -107,21 +108,21 @@ public class DownloadFragment extends Fragment { public boolean onContextItemSelected(MenuItem item) { if (item.getTitle() == "Delete") { LinearLayout fileDesc = (LinearLayout) root.findViewById(item.getItemId()); - final String file = String.valueOf(fileDesc.getTag(R.id.ID_FILE_NAME)); + ServerFile file = ServerFile.getFileById((Integer) fileDesc.getTag(R.id.ID_DOWNLOAD)); new Thread(() -> { try { - String message = Transfer.deleteFile(file); + String message = file.deleteFile(); System.out.println(message); - Transfer.activity.runOnUiThread(() -> + getActivity().runOnUiThread(() -> Snackbar.make(getActivity().findViewById(R.id.view_pager), message, Snackbar.LENGTH_LONG) .setAction("Action", null).show()); - showFileList(); + listFile(); } catch (IOException e) { String ExceptionName = e.getClass().getSimpleName(); String ExceptionMess = e.getMessage(); if(ExceptionName != null && ExceptionMess != null) { - Transfer.error(ExceptionMess); + Transfer.errorSnackbar(ExceptionMess); } } @@ -133,166 +134,166 @@ public class DownloadFragment extends Fragment { return true; } - public void showFileList() { + public void listFile() { + new Thread(() -> { + final TextView title = new TextView(Transfer.activity); + final LinearLayout main_layout = root.findViewById(R.id.main_layout); + try { + String data = Transfer.getFileList(); - final TextView title = new TextView(Transfer.activity); - title.setTextSize(18); - title.setGravity(Gravity.CENTER); - final LinearLayout main_layout = root.findViewById(R.id.main_layout); - final LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(getContext().LAYOUT_INFLATER_SERVICE); + if (data.equals("[]")) { + title.setTextSize(18); + title.setGravity(Gravity.CENTER); + main_layout.removeAllViews(); + main_layout.addView(title); + title.setHeight(1000); + title.setText("No file to download"); + } + else { - String data = ""; - - try { - data = Transfer.getFileList(); - } catch (IOException e) { - final String ExceptionName = e.getClass().getSimpleName(); - final String ExceptionMess = e.getMessage(); - - if(ExceptionName != null && ExceptionMess != null) { - Transfer.error(ExceptionMess); - Transfer.activity.runOnUiThread(() -> { - if(main_layout != null) + getActivity().runOnUiThread(() -> { main_layout.removeAllViews(); - if(title != null) { - main_layout.addView(title); - title.setText(ExceptionMess); - } - }); - } - - } - if (data.equals("[]")) { - Transfer.activity.runOnUiThread(() -> { - main_layout.removeAllViews(); - main_layout.addView(title); - title.setHeight(1000); - title.setText("No file to download"); - }); - return; - } - - try { - - JSONArray array; - array = new JSONArray(data); - - Transfer.activity.runOnUiThread(() -> { - main_layout.removeAllViews(); - final View line = inflater.inflate(R.layout.horizontal_line, null); - main_layout.addView(line); - }); - for (int i = 0; i < array.length(); i++) { - JSONObject row = array.getJSONObject(i); - final String name = row.getString("name"); - final String href = row.getString("href"); - final long size = row.getLong("size"); - final String mime = row.getString("mime"); - final String type = row.getString("type"); - - Transfer.activity.runOnUiThread(() -> { - title.setText("Choose file to download"); - View file_info = inflater.inflate(R.layout.file_info, null); - main_layout.addView(file_info); - ImageView image = file_info.findViewById(R.id.file_image); - TextView viewName = file_info.findViewById(R.id.file_name); - TextView viewType = file_info.findViewById(R.id.file_type); - TextView viewSize = file_info.findViewById(R.id.file_size); - LinearLayout fileDesc = file_info.findViewById(R.id.file_desc); - LinearLayout file_buttons = file_info.findViewById(R.id.file_buttons); - - fileDesc.setId(View.generateViewId()); - file_buttons.setId(View.generateViewId()); - file_buttons.setTag(R.id.ID_FILE_BUTTONS, "FOR VISIBILITY"); - - registerForContextMenu(fileDesc); - fileDesc.setTag(R.id.ID_FILE_NAME, name); - - viewName.setText(name); - viewType.setText(mime); - viewSize.setText(Transfer.humanReadableByteCountBin(size)); - - switch (type) { - case "file-image": - image.setImageResource(R.drawable.ic_icon_image); - break; - case "file-audio": - image.setImageResource(R.drawable.ic_icon_music); - break; - case "file-video": - image.setImageResource(R.drawable.ic_icon_video); - break; - default: - image.setImageResource(R.drawable.ic_icon_file); - } - - fileDesc.setOnClickListener(view -> { - String save_location; - - if (mime.equals("text/plain")) - save_location = getContext().getCacheDir().toString(); - else - save_location = Environment.getExternalStorageDirectory() + "/" + Transfer.local_storage; - - File file = new File(save_location, name); - - file_buttons.setId(View.generateViewId()); - - Button Bview = file_buttons.findViewById(R.id.file_view); - Button Bshare = file_buttons.findViewById(R.id.file_share); - Button dl = file_buttons.findViewById(R.id.file_download); - - dl.setOnClickListener(ListenerDL); - Bview.setOnClickListener(ListenerView); - Bshare.setOnClickListener(ListenerShare); - - if (file.exists() && file.length() == size) { - Bview.setVisibility(LinearLayout.VISIBLE); - Bshare.setVisibility(LinearLayout.VISIBLE); - dl.setVisibility(LinearLayout.GONE); - } - else { - dl.setVisibility(LinearLayout.VISIBLE); - Bview.setVisibility(LinearLayout.GONE); - Bshare.setVisibility(LinearLayout.GONE); - } - - if (Transfer.setButton(name, dl)) { - dl.setEnabled(false); - final Drawable spinner = Transfer.activity.getDrawable(R.drawable.ic_spinner_rotate); - int h = spinner.getIntrinsicHeight(); - int w = spinner.getIntrinsicWidth(); - spinner.setBounds(0, 0, w, h); - dl.setCompoundDrawables(dl.getCompoundDrawables()[0], null, spinner, null); - ObjectAnimator anim = ObjectAnimator.ofInt(spinner, "level", 0, 10000); - anim.setDuration(1000); - anim.setRepeatCount(Animation.INFINITE); - anim.setInterpolator(new LinearInterpolator()); - anim.start(); - } - - file_buttons.setTag(R.id.ID_FILE_NAME, name); - file_buttons.setTag(R.id.ID_FILE_SIZE, size); - file_buttons.setTag(R.id.ID_FILE_HREF, href); - file_buttons.setTag(R.id.ID_FILE_MIME, mime); - file_buttons.setTag(R.id.ID_SAVE_LOCATION, save_location); - int state = file_buttons.getVisibility(); - if(state == LinearLayout.GONE) { - for(View child : getAllChildren(main_layout)) { - if(child.getTag(R.id.ID_FILE_BUTTONS) != null) - child.setVisibility(LinearLayout.GONE); - } - file_buttons.setVisibility(LinearLayout.VISIBLE); - } - else if(state == LinearLayout.VISIBLE) - file_buttons.setVisibility(LinearLayout.GONE); + final View line = inflater.inflate(R.layout.horizontal_line, null); + main_layout.addView(line); }); - }); + try { + JSONArray array = new JSONArray(data); + for (int i = 0; i < array.length(); i++) { + Integer id = View.generateViewId(); + ServerFile trFile = new ServerFile(id); + + JSONObject row = array.getJSONObject(i); + trFile.name = row.getString("name"); + trFile.size = row.getLong("size"); + trFile.href = row.getString("href"); + trFile.mime = row.getString("mime"); + trFile.type = row.getString("type"); + + getActivity().runOnUiThread(() -> showFileList(trFile)); + + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } catch (IOException e) { + final String ExceptionName = e.getClass().getSimpleName(); + final String ExceptionMess = e.getMessage(); + + if(ExceptionName != null && ExceptionMess != null) { + Transfer.errorSnackbar(ExceptionMess); + } + } - } catch (JSONException e) { - e.printStackTrace(); + }).start(); + } + + private void setThumbnail(ServerFile file, ImageView image) { + new Thread(() -> { + InputStream thumbnail = file.getThumbnail(); + Bitmap bitmap = BitmapFactory.decodeStream(thumbnail); + getActivity().runOnUiThread(() -> { + image.setImageBitmap(bitmap); + }); + }).start(); + } + + private void showFileList(ServerFile trFile) { + + final LinearLayout main_layout = root.findViewById(R.id.main_layout); + + View file_info = inflater.inflate(R.layout.file_info, null); + main_layout.addView(file_info); + ImageView image = file_info.findViewById(R.id.file_image); + TextView viewName = file_info.findViewById(R.id.file_name); + TextView viewType = file_info.findViewById(R.id.file_type); + TextView viewSize = file_info.findViewById(R.id.file_size); + LinearLayout fileDesc = file_info.findViewById(R.id.file_desc); + LinearLayout file_buttons = file_info.findViewById(R.id.file_buttons); + + fileDesc.setId(View.generateViewId()); + + registerForContextMenu(fileDesc); + + file_buttons.setId(trFile.getId()); + file_buttons.setTag(R.id.ID_DOWNLOAD, trFile.getId()); + fileDesc.setTag(R.id.ID_DOWNLOAD, trFile.getId()); + file_buttons.setTag(R.id.ID_FILE_BUTTONS, "FOR VISIBILITY"); + + trFile.button = file_buttons.findViewById(R.id.file_download); + + if (trFile.mime.equals("text/plain")) + trFile.save_location = getContext().getCacheDir().toString(); + else + trFile.save_location = Environment.getExternalStorageDirectory() + "/" + Transfer.local_storage; + + viewName.setText(trFile.name); + viewType.setText(trFile.mime); + viewSize.setText(Transfer.humanReadableByteCountBin(trFile.size)); + + switch (trFile.type) { + case "file-image": + image.setImageResource(R.drawable.ic_icon_image); + setThumbnail(trFile, image); + break; + case "file-video": + image.setImageResource(R.drawable.ic_icon_video); + setThumbnail(trFile, image); + break; + case "file-audio": + image.setImageResource(R.drawable.ic_icon_music); + break; + default: + image.setImageResource(R.drawable.ic_icon_file); } + + fileDesc.setOnClickListener(view -> { + + Button Bview = file_buttons.findViewById(R.id.file_view); + Button Bshare = file_buttons.findViewById(R.id.file_share); + Button Bdownload = file_buttons.findViewById(R.id.file_download); + + Bdownload.setOnClickListener(ListenerDL); + Bview.setOnClickListener(ListenerView); + Bshare.setOnClickListener(ListenerShare); + + if (trFile.exist(getContext())) { + Bview.setVisibility(LinearLayout.VISIBLE); + Bshare.setVisibility(LinearLayout.VISIBLE); + Bdownload.setVisibility(LinearLayout.GONE); + } + else { + Bdownload.setVisibility(LinearLayout.VISIBLE); + Bview.setVisibility(LinearLayout.GONE); + Bshare.setVisibility(LinearLayout.GONE); + } + + if (trFile.setButton(Bdownload)) { + Bdownload.setEnabled(false); + final Drawable spinner = Transfer.activity.getDrawable(R.drawable.ic_spinner_rotate); + int h = spinner.getIntrinsicHeight(); + int w = spinner.getIntrinsicWidth(); + spinner.setBounds(0, 0, w, h); + Bdownload.setCompoundDrawables(Bdownload.getCompoundDrawables()[0], null, spinner, null); + ObjectAnimator anim = ObjectAnimator.ofInt(spinner, "level", 0, 10000); + anim.setDuration(1000); + anim.setRepeatCount(Animation.INFINITE); + anim.setInterpolator(new LinearInterpolator()); + anim.start(); + } + + int state = file_buttons.getVisibility(); + if(state == LinearLayout.GONE) { + for(View child : getAllChildren(main_layout)) { + if(child.getTag(R.id.ID_FILE_BUTTONS) != null) + child.setVisibility(LinearLayout.GONE); + } + file_buttons.setVisibility(LinearLayout.VISIBLE); + } + else if(state == LinearLayout.VISIBLE) + file_buttons.setVisibility(LinearLayout.GONE); + }); } private View.OnClickListener ListenerDL = v -> { @@ -300,37 +301,33 @@ public class DownloadFragment extends Fragment { final LinearLayout layout = (LinearLayout) v.getParent(); final Button button = layout.findViewById(R.id.file_download); - final String name = (String) layout.getTag(R.id.ID_FILE_NAME); - final String save_location = String.valueOf(layout.getTag(R.id.ID_SAVE_LOCATION)); - final long fileSize = (long) layout.getTag(R.id.ID_FILE_SIZE); - final String href = (String) layout.getTag(R.id.ID_FILE_HREF); + final Integer id = (Integer) layout.getTag(R.id.ID_DOWNLOAD); - new File(save_location).mkdirs(); - File file = new File(save_location, name); + final Drawable image = getActivity().getDrawable(R.drawable.ic_spinner_rotate); + int h = image.getIntrinsicHeight(); + int w = image.getIntrinsicWidth(); + image.setBounds(0, 0, w, h); + 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(); - Transfer tr = new Transfer(Transfer.TYPE_DOWNLOAD); - tr.file = file; - tr.fileName = name; - tr.fileSize = fileSize; - tr.fileSizeHuman = Transfer.humanReadableByteCountBin(fileSize); - tr.href = href; - tr.button = button; - tr.AddTransfer(); + ServerFile file = ServerFile.getFileById(id); + file.AddTransfer(); }; private View.OnClickListener ListenerShare = v -> { LinearLayout layout = (LinearLayout) v.getParent(); - final String name = (String) layout.getTag(R.id.ID_FILE_NAME); - final String type = (String) layout.getTag(R.id.ID_FILE_MIME); + final Integer id = (Integer) layout.getTag(R.id.ID_DOWNLOAD); - final String save_location = String.valueOf(layout.getTag(R.id.ID_SAVE_LOCATION)); - File file = new File(save_location, name); - Uri uri = FileProvider.getUriForFile(getContext(), BuildConfig.APPLICATION_ID, file); + ServerFile dl = ServerFile.getFileById(id); - if(type.equals("text/plain")) { + if(dl.type.equals("text/plain")) { String text = null; try { - InputStream is = new FileInputStream(file); + InputStream is = getActivity().getContentResolver().openInputStream(dl.uri); BufferedReader buf = new BufferedReader(new InputStreamReader(is)); String line; @@ -348,7 +345,7 @@ public class DownloadFragment extends Fragment { try { Intent intent = new Intent(Intent.ACTION_SEND); - intent.setType(type); + intent.setType(dl.type); intent.putExtra(Intent.EXTRA_TEXT, text); startActivity(Intent.createChooser(intent, getString(R.string.share_title))); } catch (ActivityNotFoundException e) { @@ -358,8 +355,8 @@ public class DownloadFragment extends Fragment { else { try { Intent intent = new Intent(Intent.ACTION_SEND); - intent.putExtra(Intent.EXTRA_STREAM, uri); - intent.setType(type); + intent.putExtra(Intent.EXTRA_STREAM, dl.uri); + intent.setType(dl.mime); intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); startActivity(Intent.createChooser(intent, getString(R.string.share_title))); } catch (ActivityNotFoundException e) { @@ -372,16 +369,13 @@ public class DownloadFragment extends Fragment { private View.OnClickListener ListenerView = v -> { LinearLayout layout = (LinearLayout) v.getParent(); - final String name = (String) layout.getTag(R.id.ID_FILE_NAME); - final String type = (String) layout.getTag(R.id.ID_FILE_MIME); + final Integer id = (Integer) layout.getTag(R.id.ID_DOWNLOAD); - final String save_location = String.valueOf(layout.getTag(R.id.ID_SAVE_LOCATION)); - File file = new File(save_location, name); - Uri uri = FileProvider.getUriForFile(getContext(), BuildConfig.APPLICATION_ID, file); + ServerFile dl = ServerFile.getFileById(id); try { Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(uri, type); + intent.setDataAndType(dl.uri, dl.mime); intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); startActivity(intent); } catch (ActivityNotFoundException e) { diff --git a/app/src/main/java/com/localtransfer/fragment/ProgressFragment.java b/app/src/main/java/com/localtransfer/fragment/ProgressFragment.java index 9c70e09..c5b0214 100644 --- a/app/src/main/java/com/localtransfer/fragment/ProgressFragment.java +++ b/app/src/main/java/com/localtransfer/fragment/ProgressFragment.java @@ -2,26 +2,17 @@ package com.localtransfer.fragment; import android.os.Bundle; -import androidx.core.app.NotificationCompat; -import androidx.core.app.NotificationManagerCompat; import androidx.fragment.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.ProgressBar; -import android.widget.TextView; -import com.localtransfer.Progress; import com.localtransfer.R; +import com.localtransfer.ServerFile; import com.localtransfer.Transfer; -import java.util.ConcurrentModificationException; import java.util.List; -import java.util.Timer; -import java.util.TimerTask; public class ProgressFragment extends Fragment { @@ -43,21 +34,20 @@ public class ProgressFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment - Progress.root = inflater.inflate(R.layout.fragment_progress, container, false); + Transfer.fragment_progress = inflater.inflate(R.layout.fragment_progress, container, false); - return Progress.root; + return Transfer.fragment_progress; } @Override public void onResume(){ super.onResume(); - Progress.fragment_on = true; + Transfer.fragment_on = true; - List instances = Transfer.getInstances(); - for (Object obj: instances) { - Transfer tr = (Transfer) obj; - Progress.showProgressFragment(tr); + List instances = ServerFile.getInstances(); + for (ServerFile file: instances) { + file.showProgressFragment(); } } @@ -65,6 +55,6 @@ public class ProgressFragment extends Fragment { public void onPause(){ super.onPause(); - Progress.fragment_on = false; + Transfer.fragment_on = false; } } \ No newline at end of file diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml index 4be3d1e..feaf92e 100644 --- a/app/src/main/res/values/ids.xml +++ b/app/src/main/res/values/ids.xml @@ -1,9 +1,5 @@ - - - - - + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6c2f8dc..e7fe80f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -25,7 +25,7 @@ Use secure https www.netdldata.net Port - 80 + Root /transfer diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml new file mode 100644 index 0000000..583fb1d --- /dev/null +++ b/app/src/main/res/xml/network_security_config.xml @@ -0,0 +1,6 @@ + + + + netdldata.net + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index 5e3e27e..781e205 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:4.1.2' + classpath 'com.android.tools.build:gradle:7.1.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b1f9077..3cf3705 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip From d87296a534fe828f8cd3ad71e52d5375f76e1ada Mon Sep 17 00:00:00 2001 From: lionel <> Date: Thu, 24 Feb 2022 16:05:05 +0100 Subject: [PATCH 4/5] Upload fix, Progress fix - transfer one by one --- .idea/runConfigurations.xml | 12 - .../{ServerFile.java => DownloadFile.java} | 190 ++-------- .../java/com/localtransfer/MainActivity.java | 13 +- .../main/java/com/localtransfer/Transfer.java | 327 +++++++++--------- .../java/com/localtransfer/UploadFile.java | 197 +++++++++++ .../fragment/DownloadFragment.java | 48 +-- .../fragment/ProgressFragment.java | 5 +- 7 files changed, 411 insertions(+), 381 deletions(-) delete mode 100644 .idea/runConfigurations.xml rename app/src/main/java/com/localtransfer/{ServerFile.java => DownloadFile.java} (59%) create mode 100644 app/src/main/java/com/localtransfer/UploadFile.java diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml deleted file mode 100644 index 7f68460..0000000 --- a/.idea/runConfigurations.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/java/com/localtransfer/ServerFile.java b/app/src/main/java/com/localtransfer/DownloadFile.java similarity index 59% rename from app/src/main/java/com/localtransfer/ServerFile.java rename to app/src/main/java/com/localtransfer/DownloadFile.java index 61dd828..80c35fd 100644 --- a/app/src/main/java/com/localtransfer/ServerFile.java +++ b/app/src/main/java/com/localtransfer/DownloadFile.java @@ -5,20 +5,14 @@ import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; -import android.graphics.Color; import android.graphics.drawable.Drawable; import android.net.Uri; import android.provider.MediaStore; 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.ImageView; import android.widget.LinearLayout; -import android.widget.ProgressBar; -import android.widget.TextView; -import android.widget.Toast; import java.io.File; import java.io.IOException; @@ -28,16 +22,9 @@ import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.ConcurrentModificationException; -import java.util.List; +import java.sql.Timestamp; -public class ServerFile extends Transfer { - - private Integer id; - - public String name; +public class DownloadFile extends Transfer { public String href; @@ -45,27 +32,29 @@ public class ServerFile extends Transfer { public String type; - public long size; - public String save_location; public Uri uri; - public Button button; + private Button button; - private static List instances = new ArrayList<>(); - - public ServerFile(Integer id) { + public DownloadFile(Integer id) { this.id = id; instances.add(this); - drawable = R.drawable.ic_download_24; info = "Download complete"; state = STATE_NOT_REQUESTED; + drawable = R.drawable.ic_download_24; } @Override - public void StartTransfer() { - super.StartTransfer(); + public void startTransfer() { + super.startTransfer(); + + startedTime = new Timestamp(System.currentTimeMillis()); + + state = STATE_RUNNING; + + buttonProgressStart(); if (uri == null && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { ContentValues values = new ContentValues(); @@ -76,59 +65,21 @@ public class ServerFile extends Transfer { } try { downloadFile(); - } catch (IOException e) { + } catch (IOException | NullPointerException e) { final String ExceptionName = e.getClass().getSimpleName(); final String ExceptionMess = e.getMessage(); + e.printStackTrace(); state = Transfer.STATE_FAILED; error = ExceptionName + ": " + ExceptionMess; - PostProgress(); + progressEnd(); + buttonProgressEnd(); if(ExceptionName != null && ExceptionMess != null) { - errorSnackbar(ExceptionMess); + errorSnackbar(ExceptionName + ": " + ExceptionMess); } } - - try { - for (Object obj : getInstances()) { - Transfer transfer = (Transfer) obj; - if (transfer.state == Transfer.STATE_STANDBY) - StartTransfer(); - } - } catch (ConcurrentModificationException e) { - e.printStackTrace(); - try { - Thread.sleep(10); - } catch (InterruptedException InterrupEx) { - InterrupEx.printStackTrace(); - } - for (Object obj : getInstances()) { - Transfer transfer = (Transfer) obj; - if (transfer.state == Transfer.STATE_STANDBY) - StartTransfer(); - } - } - - /*Intent serviceIntent = new Intent(Transfer.activity, TransferService.class); - Transfer.activity.stopService(serviceIntent); - Transfer.runningTransfer = false;*/ - } - - public static List getInstances() { - return instances; - } - - public static ServerFile getFileById(int id) { - for (Object obj: instances) { - ServerFile p = (ServerFile) obj; - if (p.id == id) return p; - } - return null; - } - - public Integer getId() { - return id; } public boolean exist(Context context) { @@ -154,12 +105,11 @@ public class ServerFile extends Transfer { return false; } - public boolean setButton(Button button) { - if (this.state == STATE_RUNNING) { - this.button = button; - return true; + public void setButton(Button button) { + this.button = button; + if (this.state == STATE_STANDBY) { + buttonProgressStart(); } - return false; } public InputStream getThumbnail() { @@ -191,8 +141,6 @@ public class ServerFile extends Transfer { int bufferLength; loaded = 0; - PreProgress(); - String[] parts = href.split("/"); String path = ""; for(int i=0; i< parts.length - 1; i++) { @@ -220,7 +168,8 @@ public class ServerFile extends Transfer { fileOutput.write(buffer, 0, bufferLength); loaded+= bufferLength; percent = ((loaded * 100) / size); - ProgressUpdateDelay(); + progressUpdateDelay(); + buttonProgressUpdate(); } fileOutput.close(); @@ -228,7 +177,8 @@ public class ServerFile extends Transfer { message = "File " + name + " successful download"; state = Transfer.STATE_SUCCESS; - PostProgress(); + progressEnd(); + buttonProgressEnd(); } else { @@ -271,13 +221,9 @@ public class ServerFile extends Transfer { return message; } - public void PreProgress() { + public void buttonProgressStart() { activity.runOnUiThread(() -> { - final Drawable image = Transfer.activity.getDrawable(R.drawable.ic_spinner_rotate); - sizeSI = Transfer.humanReadableByteCountBin(size); - - state = STATE_RUNNING; if(button != null) { int h = image.getIntrinsicHeight(); @@ -293,56 +239,15 @@ public class ServerFile extends Transfer { }); } - public void ProgressUpdateDelay() { - // Run only every second to reduce CPU usage - if (System.currentTimeMillis() > (savedTimeMillis + 1000)) { - savedTimeMillis = System.currentTimeMillis(); - ProgressUpdate(); - } - } - - private void ProgressUpdate(){ - - loadedSI = Transfer.humanReadableByteCountBin(loaded); - + private void buttonProgressUpdate(){ activity.runOnUiThread(() -> { - if (app_started && button != null) button.setText(String.format("Download in progress %d%%", percent)); - - try { - - notifBuilder.setSmallIcon(R.drawable.ic_upload_and_download_from_the_cloud) - .setContentTitle(name) - .setContentText(String.format("%d%% %s/%s", percent, loadedSI, sizeSI)) - .setProgress(100, (int) percent, false) - .setContentIntent(pendingIntent); - notifiManager.notify(Transfer.NOTIF_SERVICE, notifBuilder.build()); - - if (app_started && fragment_on) - showProgressFragment(); - - } catch (ConcurrentModificationException e) { - e.printStackTrace(); - } }); } - public void PostProgress() { - ProgressUpdate(); + public void buttonProgressEnd() { activity.runOnUiThread(() -> { - - notifiManager.cancel(Transfer.NOTIF_SERVICE); - - if (!app_started) { - notifBuilder.setSmallIcon(R.drawable.ic_upload_and_download_from_the_cloud) - .setContentTitle(name) - .setContentText(info) - .setProgress(0, 0, false) - .setContentIntent(pendingIntent); - notifiManager.notify(id, notifBuilder.build()); - } - if (button != null) { final LinearLayout layout = (LinearLayout) button.getParent(); layout.findViewById(R.id.file_view).setVisibility(LinearLayout.VISIBLE); @@ -353,43 +258,6 @@ public class ServerFile extends Transfer { button.setText(activity.getString(R.string.file_download)); button.setCompoundDrawables(button.getCompoundDrawables()[0], null, null, null); } - - System.out.println(message); - /*Snackbar.make(Transfer.activity.findViewById(R.id.view_pager), tr.message, Snackbar.LENGTH_LONG) - .setAction("Action", null).show();*/ - Toast.makeText(activity, message, Toast.LENGTH_SHORT).show(); - }); } - - public void showProgressFragment(){ - - if(Arrays.asList(STATE_RUNNING, STATE_SUCCESS, STATE_FAILED).contains(state)) { - - LinearLayout groot = fragment_progress.findViewById(R.id.groot); - - View progress = groot.findViewById(id); - - if (progress == null) { - progress = inflater.inflate(R.layout.progress, null); - progress.setId(id); - final View final_progress = progress; - activity.runOnUiThread(() -> { - groot.addView(final_progress, 0); - }); - } - - ((ProgressBar) progress.findViewById(R.id.progressBar)).setProgress((int) percent); - ((ImageView) progress.findViewById(R.id.transferType)).setImageResource(drawable); - ((TextView) progress.findViewById(R.id.progressText)).setText(percent + " %"); - ((TextView) progress.findViewById(R.id.fileName)).setText(name); - ((TextView) progress.findViewById(R.id.fileSize)).setText(String.format("%s/%s", loadedSI, sizeSI)); - - if (state == Transfer.STATE_SUCCESS) - ((TextView) progress.findViewById(R.id.fileName)).setTextColor(Color.GREEN); - else if (state == Transfer.STATE_FAILED) - ((TextView) progress.findViewById(R.id.fileName)).setTextColor(Color.RED); - - } - } } diff --git a/app/src/main/java/com/localtransfer/MainActivity.java b/app/src/main/java/com/localtransfer/MainActivity.java index 1649992..21969e6 100644 --- a/app/src/main/java/com/localtransfer/MainActivity.java +++ b/app/src/main/java/com/localtransfer/MainActivity.java @@ -91,16 +91,14 @@ public class MainActivity extends AppCompatActivity { String action = intent.getAction(); String type = intent.getType(); - Transfer tr = new Transfer(); - if (Intent.ACTION_SEND.equals(action) && type != null) { viewPager.setCurrentItem(2); if ("text/plain".equals(type)) { String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); - tr.handleSendText(sharedText); + UploadFile.handleSendText(sharedText); } else { Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM); - tr.handleSendFile(uri); + UploadFile.handleSendFile(uri); } } else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) { viewPager.setCurrentItem(2); @@ -108,7 +106,7 @@ public class MainActivity extends AppCompatActivity { int nbItem = fileUris.size(); Toast.makeText(this, "You select " + nbItem + " files", Toast.LENGTH_SHORT).show(); if (fileUris != null) - for(Uri uri : fileUris) tr.handleSendFile(uri); + for(Uri uri : fileUris) UploadFile.handleSendFile(uri); } } @@ -123,11 +121,10 @@ public class MainActivity extends AppCompatActivity { ViewPager viewPager = this.findViewById(R.id.view_pager); viewPager.setCurrentItem(2); - Transfer tr = new Transfer(); if (type != null) { String sharedText = data.getStringExtra(Intent.EXTRA_TEXT); - tr.handleSendText(sharedText); + UploadFile.handleSendText(sharedText); } else { ArrayList fileUris = new ArrayList<>(); @@ -143,7 +140,7 @@ public class MainActivity extends AppCompatActivity { fileUris.add(uri); } for (Uri uri : fileUris) { - tr.handleSendFile(uri); + UploadFile.handleSendFile(uri); } } } diff --git a/app/src/main/java/com/localtransfer/Transfer.java b/app/src/main/java/com/localtransfer/Transfer.java index f874331..07a53bb 100644 --- a/app/src/main/java/com/localtransfer/Transfer.java +++ b/app/src/main/java/com/localtransfer/Transfer.java @@ -8,34 +8,34 @@ import android.app.PendingIntent; import android.content.ContentResolver; import android.content.Context; import android.content.SharedPreferences; -import android.database.Cursor; -import android.net.Uri; -import android.provider.OpenableColumns; +import android.graphics.Color; import android.util.Log; import android.view.LayoutInflater; import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; 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.net.HttpURLConnection; import java.net.ProtocolException; import java.net.URL; -import java.nio.charset.StandardCharsets; +import java.sql.Timestamp; import java.text.CharacterIterator; -import java.text.SimpleDateFormat; import java.text.StringCharacterIterator; -import java.util.Date; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.ConcurrentModificationException; +import java.util.List; public class Transfer { @@ -81,7 +81,46 @@ public class Transfer { public static final int STATE_SUCCESS = 130; public static final int STATE_FAILED = 140; - public static boolean runningTransfer = false; + public static Thread thread = new Thread(); + + Integer id; + + public String name; + + public long size; + + Timestamp addedTime; + Timestamp startedTime; + + static List instances = new ArrayList<>(); + + public static List getInstances() { + List in = new ArrayList<>(); + for (Transfer file: instances) { + //if(Arrays.asList(STATE_STANDBY, STATE_RUNNING, STATE_SUCCESS, STATE_FAILED).contains(file.state)) { + if(file.state == STATE_STANDBY || + file.state == STATE_RUNNING || + file.state == STATE_SUCCESS || + file.state == STATE_FAILED) { + in.add(file); + } + } + //in.sort(Comparator.comparing(Transfer::getAddedTime).reversed()); + in.sort(Comparator.comparing(e -> e.addedTime)); + return in; + } + + public static Transfer getFileById(int id) { + for (Object obj: instances) { + Transfer p = (Transfer) obj; + if (p.id == id) return p; + } + return null; + } + + public Integer getId() { + return id; + } public static void parameter(Context context) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); @@ -106,20 +145,125 @@ public class Transfer { public void AddTransfer() { - if(!runningTransfer) { + state = STATE_STANDBY; + + addedTime = new Timestamp(System.currentTimeMillis()); + + Thread.State state = thread.getState(); + + if(state == Thread.State.NEW || state == Thread.State.TERMINATED) { + thread = new Thread(startTransfers); + thread.start(); + /*Intent serviceIntent = new Intent(activity, TransferService.class); ContextCompat.startForegroundService(activity, serviceIntent);*/ - runningTransfer = true; - state = STATE_STANDBY; - new Thread(() -> StartTransfer()).start(); } } - public void StartTransfer() { - int x = 35 + 65; + public void startTransfer() { + } - private static URL checkRedirection(URL url) throws IOException { + public static Runnable startTransfers = () -> { + try { + for (Transfer transfer : getInstances()) { + if (transfer.state == Transfer.STATE_STANDBY) { + transfer.startTransfer(); + thread.run(); // restart thread for another potential standby transfer + break; // ignore remainder instance + } + } + } catch (ConcurrentModificationException e) { + e.printStackTrace(); + } + + /*Intent serviceIntent = new Intent(Transfer.activity, TransferService.class); + Transfer.activity.stopService(serviceIntent);*/ + }; + + public void progressUpdateDelay() { + // Run only every second to reduce CPU usage + if (System.currentTimeMillis() > (savedTimeMillis + 1000)) { + savedTimeMillis = System.currentTimeMillis(); + progressUpdate(); + } + } + + private void progressUpdate(){ + + loadedSI = Transfer.humanReadableByteCountBin(loaded); + + activity.runOnUiThread(() -> { + + try { + + notifBuilder.setSmallIcon(R.drawable.ic_upload_and_download_from_the_cloud) + .setContentTitle(name) + .setContentText(String.format("%d%% %s/%s", percent, loadedSI, sizeSI)) + .setProgress(100, (int) percent, false) + .setContentIntent(pendingIntent); + notifiManager.notify(Transfer.NOTIF_SERVICE, notifBuilder.build()); + + if (app_started && fragment_on) + showProgressFragment(); + + } catch (ConcurrentModificationException e) { + e.printStackTrace(); + } + }); + } + + public void progressEnd() { + progressUpdate(); + activity.runOnUiThread(() -> { + + notifiManager.cancel(Transfer.NOTIF_SERVICE); + + if (!app_started) { + notifBuilder.setSmallIcon(R.drawable.ic_upload_and_download_from_the_cloud) + .setContentTitle(name) + .setContentText(info) + .setProgress(0, 0, false) + .setContentIntent(pendingIntent); + notifiManager.notify(id, notifBuilder.build()); + } + + System.out.println(message); + /*Snackbar.make(Transfer.activity.findViewById(R.id.view_pager), tr.message, Snackbar.LENGTH_LONG) + .setAction("Action", null).show();*/ + Toast.makeText(activity, message, Toast.LENGTH_SHORT).show(); + + }); + } + + public void showProgressFragment(){ + + LinearLayout groot = fragment_progress.findViewById(R.id.groot); + + View progress = groot.findViewById(id); + + if (progress == null) { + progress = inflater.inflate(R.layout.progress, null); + progress.setId(id); + final View final_progress = progress; + activity.runOnUiThread(() -> { + groot.addView(final_progress, 0); + }); + } + + ((ProgressBar) progress.findViewById(R.id.progressBar)).setProgress((int) percent); + ((ImageView) progress.findViewById(R.id.transferType)).setImageResource(drawable); + ((TextView) progress.findViewById(R.id.progressText)).setText(percent + " %"); + ((TextView) progress.findViewById(R.id.fileName)).setText(name); + ((TextView) progress.findViewById(R.id.fileSize)).setText(String.format("%s/%s", loadedSI, sizeSI)); + + if (state == Transfer.STATE_SUCCESS) + ((TextView) progress.findViewById(R.id.fileName)).setTextColor(Color.GREEN); + else if (state == Transfer.STATE_FAILED) + ((TextView) progress.findViewById(R.id.fileName)).setTextColor(Color.RED); + } + + static URL checkRedirection(URL url) throws IOException { String location = null; HttpURLConnection conn = null; int responseCode; @@ -160,149 +304,6 @@ public class Transfer { return url; } - public static void handleSendFile(Uri uri) { - if (uri != null) { - new Thread(() -> { - try { - Transfer.uploadFile(uri); - } catch (IOException e) { - final String ExceptionName = e.getClass().getSimpleName(); - final String ExceptionMess = e.getMessage(); - - if(ExceptionName != null && ExceptionMess != null) { - Transfer.errorSnackbar(ExceptionMess); - } - - } - }).start(); - } - } - - public static void handleSendText(String sharedText) { - if (sharedText != null) { - SimpleDateFormat sdfDate = new SimpleDateFormat("text_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); - - Transfer.uploadFile(uri); - } catch (IOException e) { - e.printStackTrace(); - } - }).start(); - } - } - - public static String uploadFile(Uri uri) throws IOException { - String message = null; - URL url = null; - HttpURLConnection conn = null; - DataOutputStream request = null; - String boundary = "*****"; - final 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 type = activity.getContentResolver().getType(uri); - - String fileName = null; - int col_name = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); - if (col_name != -1) - fileName = cursor.getString(col_name); - if(fileName == null) - fileName = type.split("/")[0] + "_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) + "." + type.split("/")[1]; - String fileNameUTF8 = new String(fileName.getBytes(), StandardCharsets.ISO_8859_1); - - long fileSize = -1; - int col_size = cursor.getColumnIndex(OpenableColumns.SIZE); - if (col_size != -1) - fileSize = cursor.getLong(col_size); - - url = new URL(protocol, host, port, root + "/upload.php"); - - url = checkRedirection(url); - - 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); - - if (fileSize < 1) - fileSize = in.available(); - - //Progress p = new Progress(fileName, fileSize, Progress.UPLOAD); - - 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 static String getFileList() throws IOException { URL url = null; HttpURLConnection conn = null; diff --git a/app/src/main/java/com/localtransfer/UploadFile.java b/app/src/main/java/com/localtransfer/UploadFile.java new file mode 100644 index 0000000..7636552 --- /dev/null +++ b/app/src/main/java/com/localtransfer/UploadFile.java @@ -0,0 +1,197 @@ +package com.localtransfer; + +import android.database.Cursor; +import android.net.Uri; +import android.provider.OpenableColumns; +import android.util.Log; +import android.view.View; + +import androidx.core.content.FileProvider; + +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.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.sql.Timestamp; +import java.text.SimpleDateFormat; +import java.util.ConcurrentModificationException; +import java.util.Date; + +public class UploadFile extends Transfer { + + public Uri uri; + + public UploadFile() { + this.id = View.generateViewId(); + instances.add(this); + info = "Upload complete"; + state = STATE_NOT_REQUESTED; + drawable = R.drawable.ic_upload_24; + } + + public static void handleSendFile(Uri uri) { + if (uri != null) { + UploadFile file = new UploadFile(); + file.uri = uri; + + Cursor cursor = activity.getContentResolver().query(uri, null, null, null, null); + cursor.moveToFirst(); + + file.name = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); + file.size = cursor.getLong(cursor.getColumnIndex(OpenableColumns.SIZE)); + file.sizeSI = Transfer.humanReadableByteCountBin(file.size); + + file.AddTransfer(); + } + } + + public static void handleSendText(String sharedText) { + if (sharedText != null) { + SimpleDateFormat sdfDate = new SimpleDateFormat("yyyyMMdd_HHmmss"); + Date now = new Date(); + String strDate = sdfDate.format(now); + Uri uri = null; + + 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 = FileProvider.getUriForFile(activity, activity.getPackageName(), outputFile); + + } catch (IOException e) { + e.printStackTrace(); + } + handleSendFile(uri); + } + } + + @Override + public void startTransfer() { + super.startTransfer(); + + startedTime = new Timestamp(System.currentTimeMillis()); + + state = STATE_RUNNING; + + try { + uploadFile(); + } catch (IOException e) { + final String ExceptionName = e.getClass().getSimpleName(); + final String ExceptionMess = e.getMessage(); + + state = Transfer.STATE_FAILED; + error = ExceptionName + ": " + ExceptionMess; + progressEnd(); + + if(ExceptionName != null && ExceptionMess != null) { + errorSnackbar(ExceptionMess); + } + + } + } + + private String uploadFile() throws IOException { + String message = null; + URL url = null; + HttpURLConnection conn = null; + DataOutputStream request = null; + String boundary = "*****"; + final int maxBufferSize = 1 * 1024 * 1024; + byte[] buffer = new byte[maxBufferSize]; + int bufferLength; + loaded = 0; + + Cursor cursor = activity.getContentResolver().query(uri, null, null, null, null); + cursor.moveToFirst(); + + String type = activity.getContentResolver().getType(uri); + + String fileName = null; + int col_name = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); + if (col_name != -1) + fileName = cursor.getString(col_name); + if(fileName == null) + fileName = type.split("/")[0] + "_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) + "." + type.split("/")[1]; + String fileNameUTF8 = new String(fileName.getBytes(), StandardCharsets.ISO_8859_1); + + url = new URL(protocol, host, port, root + "/upload.php"); + + url = checkRedirection(url); + + 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); + + size = in.available(); + + while ((bufferLength = in.read(buffer)) > 0) { + request.write(buffer, 0, bufferLength); + loaded+= bufferLength; + percent = ((loaded * 100) / size); + progressUpdateDelay(); + } + + 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"; + state = Transfer.STATE_SUCCESS; + progressEnd(); + } + 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; + } +} diff --git a/app/src/main/java/com/localtransfer/fragment/DownloadFragment.java b/app/src/main/java/com/localtransfer/fragment/DownloadFragment.java index 95a7af5..01bfda3 100644 --- a/app/src/main/java/com/localtransfer/fragment/DownloadFragment.java +++ b/app/src/main/java/com/localtransfer/fragment/DownloadFragment.java @@ -26,7 +26,7 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.google.android.material.snackbar.Snackbar; import com.localtransfer.R; -import com.localtransfer.ServerFile; +import com.localtransfer.DownloadFile; import com.localtransfer.Transfer; import org.json.JSONArray; @@ -108,7 +108,7 @@ public class DownloadFragment extends Fragment { public boolean onContextItemSelected(MenuItem item) { if (item.getTitle() == "Delete") { LinearLayout fileDesc = (LinearLayout) root.findViewById(item.getItemId()); - ServerFile file = ServerFile.getFileById((Integer) fileDesc.getTag(R.id.ID_DOWNLOAD)); + DownloadFile file = (DownloadFile) DownloadFile.getFileById((Integer) fileDesc.getTag(R.id.ID_DOWNLOAD)); new Thread(() -> { try { String message = file.deleteFile(); @@ -161,7 +161,7 @@ public class DownloadFragment extends Fragment { JSONArray array = new JSONArray(data); for (int i = 0; i < array.length(); i++) { Integer id = View.generateViewId(); - ServerFile trFile = new ServerFile(id); + DownloadFile trFile = new DownloadFile(id); JSONObject row = array.getJSONObject(i); trFile.name = row.getString("name"); @@ -189,7 +189,7 @@ public class DownloadFragment extends Fragment { }).start(); } - private void setThumbnail(ServerFile file, ImageView image) { + private void setThumbnail(DownloadFile file, ImageView image) { new Thread(() -> { InputStream thumbnail = file.getThumbnail(); Bitmap bitmap = BitmapFactory.decodeStream(thumbnail); @@ -199,7 +199,7 @@ public class DownloadFragment extends Fragment { }).start(); } - private void showFileList(ServerFile trFile) { + private void showFileList(DownloadFile trFile) { final LinearLayout main_layout = root.findViewById(R.id.main_layout); @@ -221,7 +221,8 @@ public class DownloadFragment extends Fragment { fileDesc.setTag(R.id.ID_DOWNLOAD, trFile.getId()); file_buttons.setTag(R.id.ID_FILE_BUTTONS, "FOR VISIBILITY"); - trFile.button = file_buttons.findViewById(R.id.file_download); + + trFile.setButton(file_buttons.findViewById(R.id.file_download)); if (trFile.mime.equals("text/plain")) trFile.save_location = getContext().getCacheDir().toString(); @@ -269,19 +270,7 @@ public class DownloadFragment extends Fragment { Bshare.setVisibility(LinearLayout.GONE); } - if (trFile.setButton(Bdownload)) { - Bdownload.setEnabled(false); - final Drawable spinner = Transfer.activity.getDrawable(R.drawable.ic_spinner_rotate); - int h = spinner.getIntrinsicHeight(); - int w = spinner.getIntrinsicWidth(); - spinner.setBounds(0, 0, w, h); - Bdownload.setCompoundDrawables(Bdownload.getCompoundDrawables()[0], null, spinner, null); - ObjectAnimator anim = ObjectAnimator.ofInt(spinner, "level", 0, 10000); - anim.setDuration(1000); - anim.setRepeatCount(Animation.INFINITE); - anim.setInterpolator(new LinearInterpolator()); - anim.start(); - } + trFile.setButton(Bdownload); int state = file_buttons.getVisibility(); if(state == LinearLayout.GONE) { @@ -299,22 +288,13 @@ public class DownloadFragment extends Fragment { private View.OnClickListener ListenerDL = v -> { v.setEnabled(false); final LinearLayout layout = (LinearLayout) v.getParent(); - final Button button = layout.findViewById(R.id.file_download); + final Button button = (Button) v; + button.setText(String.format("Download pending")); final Integer id = (Integer) layout.getTag(R.id.ID_DOWNLOAD); - final Drawable image = getActivity().getDrawable(R.drawable.ic_spinner_rotate); - int h = image.getIntrinsicHeight(); - int w = image.getIntrinsicWidth(); - image.setBounds(0, 0, w, h); - 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(); - - ServerFile file = ServerFile.getFileById(id); + DownloadFile file = (DownloadFile) DownloadFile.getFileById(id); + file.sizeSI = Transfer.humanReadableByteCountBin(file.size); file.AddTransfer(); }; @@ -322,7 +302,7 @@ public class DownloadFragment extends Fragment { LinearLayout layout = (LinearLayout) v.getParent(); final Integer id = (Integer) layout.getTag(R.id.ID_DOWNLOAD); - ServerFile dl = ServerFile.getFileById(id); + DownloadFile dl = (DownloadFile) DownloadFile.getFileById(id); if(dl.type.equals("text/plain")) { String text = null; @@ -371,7 +351,7 @@ public class DownloadFragment extends Fragment { LinearLayout layout = (LinearLayout) v.getParent(); final Integer id = (Integer) layout.getTag(R.id.ID_DOWNLOAD); - ServerFile dl = ServerFile.getFileById(id); + DownloadFile dl = (DownloadFile) DownloadFile.getFileById(id); try { Intent intent = new Intent(Intent.ACTION_VIEW); diff --git a/app/src/main/java/com/localtransfer/fragment/ProgressFragment.java b/app/src/main/java/com/localtransfer/fragment/ProgressFragment.java index c5b0214..d776dd8 100644 --- a/app/src/main/java/com/localtransfer/fragment/ProgressFragment.java +++ b/app/src/main/java/com/localtransfer/fragment/ProgressFragment.java @@ -9,7 +9,6 @@ import android.view.View; import android.view.ViewGroup; import com.localtransfer.R; -import com.localtransfer.ServerFile; import com.localtransfer.Transfer; import java.util.List; @@ -45,8 +44,8 @@ public class ProgressFragment extends Fragment { Transfer.fragment_on = true; - List instances = ServerFile.getInstances(); - for (ServerFile file: instances) { + List instances = Transfer.getInstances(); + for (Transfer file: instances) { file.showProgressFragment(); } } From 778415cf0b6a28dc0ba4e8729b70810042058857 Mon Sep 17 00:00:00 2001 From: lionel <> Date: Fri, 25 Feb 2022 17:11:23 +0100 Subject: [PATCH 5/5] Shared Storage optional setting --- .idea/misc.xml | 2 + .../java/com/localtransfer/DownloadFile.java | 66 +++++++++++++------ .../java/com/localtransfer/MainActivity.java | 5 +- .../com/localtransfer/SettingsActivity.java | 23 ++++++- .../main/java/com/localtransfer/Transfer.java | 8 +-- .../java/com/localtransfer/UploadFile.java | 1 - .../fragment/DownloadFragment.java | 13 ++-- app/src/main/res/values/strings.xml | 5 +- app/src/main/res/xml/root_preferences.xml | 14 ++-- 9 files changed, 92 insertions(+), 45 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index f1a2d08..f4f18d3 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -5,7 +5,9 @@ + + diff --git a/app/src/main/java/com/localtransfer/DownloadFile.java b/app/src/main/java/com/localtransfer/DownloadFile.java index 80c35fd..42fe433 100644 --- a/app/src/main/java/com/localtransfer/DownloadFile.java +++ b/app/src/main/java/com/localtransfer/DownloadFile.java @@ -7,6 +7,7 @@ import android.content.Context; import android.database.Cursor; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.Environment; import android.provider.MediaStore; import android.util.Log; import android.view.animation.Animation; @@ -14,6 +15,8 @@ import android.view.animation.LinearInterpolator; import android.widget.Button; import android.widget.LinearLayout; +import androidx.core.content.FileProvider; + import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -32,8 +35,6 @@ public class DownloadFile extends Transfer { public String type; - public String save_location; - public Uri uri; private Button button; @@ -60,7 +61,7 @@ public class DownloadFile extends Transfer { ContentValues values = new ContentValues(); values.put(MediaStore.MediaColumns.DISPLAY_NAME, name); values.put(MediaStore.MediaColumns.MIME_TYPE, mime); - values.put(MediaStore.MediaColumns.RELATIVE_PATH, Transfer.local_storage); + values.put(MediaStore.MediaColumns.RELATIVE_PATH, Transfer.shared_storage); uri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values); } try { @@ -71,7 +72,6 @@ public class DownloadFile extends Transfer { e.printStackTrace(); state = Transfer.STATE_FAILED; - error = ExceptionName + ": " + ExceptionMess; progressEnd(); buttonProgressEnd(); @@ -83,25 +83,51 @@ public class DownloadFile extends Transfer { } public boolean exist(Context context) { - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { - Cursor cursor = context.getContentResolver().query(MediaStore.Downloads.EXTERNAL_CONTENT_URI, null, null, null, null); - while (cursor.moveToNext()) { - String MediaStore_File_name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Downloads.DISPLAY_NAME)); - long MediaStore_File_size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Downloads.SIZE)); - if(MediaStore_File_name.equals(name) && MediaStore_File_size == size) { - int cursor_id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Downloads._ID)); - uri = ContentUris.withAppendedId(MediaStore.Downloads.EXTERNAL_CONTENT_URI, cursor_id); - return true; - } - } - } - else { - File file = new File(save_location, name); - new File(save_location).mkdirs(); - uri = Uri.fromFile(file); + if (!Transfer.use_shared_storage){ + File file = new File(activity.getFilesDir(), name); + + uri = FileProvider.getUriForFile(activity, activity.getPackageName(), file); + if (file.exists() && file.length() == size) return true; } + else { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { + Cursor cursor = context.getContentResolver().query(MediaStore.Downloads.EXTERNAL_CONTENT_URI, null, null, null, null); + while (cursor.moveToNext()) { + String MediaStore_File_name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Downloads.DISPLAY_NAME)); + long MediaStore_File_size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Downloads.SIZE)); + if(MediaStore_File_name.equals(name) && MediaStore_File_size == size) { + int cursor_id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Downloads._ID)); + uri = ContentUris.withAppendedId(MediaStore.Downloads.EXTERNAL_CONTENT_URI, cursor_id); + return true; + } + } + } + else { + String save_location = null; + if (mime.equals("text/plain")) + save_location = context.getCacheDir().toString(); + else + save_location = Environment.getExternalStorageDirectory() + "/" + Transfer.shared_storage; + new File(save_location).mkdirs(); + File file = new File(save_location, name); + try { + file.createNewFile(); + } catch (IOException e) { + final String ExceptionName = e.getClass().getSimpleName(); + final String ExceptionMess = e.getMessage(); + e.printStackTrace(); + + if(ExceptionName != null && ExceptionMess != null) { + errorSnackbar(ExceptionName + ": " + ExceptionMess); + } + } + uri = Uri.fromFile(file); + if (file.exists() && file.length() == size) + return true; + } + } return false; } diff --git a/app/src/main/java/com/localtransfer/MainActivity.java b/app/src/main/java/com/localtransfer/MainActivity.java index 21969e6..15497f5 100644 --- a/app/src/main/java/com/localtransfer/MainActivity.java +++ b/app/src/main/java/com/localtransfer/MainActivity.java @@ -81,7 +81,8 @@ public class MainActivity extends AppCompatActivity { .putString("host", getString(R.string.server_host_def)) .putString("port", getString(R.string.server_port_def)) .putString("root", getString(R.string.server_root_def)) - .putString("local_storage", getString(R.string.local_storage_def)) + .putString("shared_storage", getString(R.string.shared_storage_def)) + .putBoolean("use_shared_storage", false) .apply(); Transfer.parameter(this); @@ -195,7 +196,7 @@ public class MainActivity extends AppCompatActivity { startActivity(settings); break; case R.id.action_folder: - String save_location = Environment.getExternalStorageDirectory() + "/" + Transfer.local_storage; + String save_location = Environment.getExternalStorageDirectory() + "/" + Transfer.shared_storage; Uri selectedUri = Uri.parse(save_location.toString()); boolean intentSuccess = false; try { diff --git a/app/src/main/java/com/localtransfer/SettingsActivity.java b/app/src/main/java/com/localtransfer/SettingsActivity.java index 43d97d6..44afe9c 100644 --- a/app/src/main/java/com/localtransfer/SettingsActivity.java +++ b/app/src/main/java/com/localtransfer/SettingsActivity.java @@ -13,6 +13,7 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceManager; +import androidx.preference.SwitchPreference; import lib.folderpicker.FolderPicker; @@ -42,8 +43,24 @@ public class SettingsActivity extends AppCompatActivity { setPreferencesFromResource(R.xml.root_preferences, rootKey); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); - directory = findPreference("local_storage"); - directory.setSummary(prefs.getString("local_storage", null)); + + directory = findPreference("shared_storage"); + directory.setSummary(prefs.getString("shared_storage", null)); + + SwitchPreference shared; + shared = findPreference("use_shared_storage"); + if(shared.isChecked()) + directory.setVisible(true); + else + directory.setVisible(false); + + shared.setOnPreferenceClickListener(preference -> { + if(shared.isChecked()) + directory.setVisible(true); + else + directory.setVisible(false); + return false; + }); directory.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { @@ -65,7 +82,7 @@ public class SettingsActivity extends AppCompatActivity { String save_location = currentPath.replace(Environment.getExternalStorageDirectory() + "/", ""); Log.d("Path", save_location); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); - prefs.edit().putString("local_storage", save_location).apply(); + prefs.edit().putString("shared_storage", save_location).apply(); directory.setSummary(save_location); } } diff --git a/app/src/main/java/com/localtransfer/Transfer.java b/app/src/main/java/com/localtransfer/Transfer.java index 07a53bb..060c363 100644 --- a/app/src/main/java/com/localtransfer/Transfer.java +++ b/app/src/main/java/com/localtransfer/Transfer.java @@ -32,7 +32,6 @@ import java.sql.Timestamp; import java.text.CharacterIterator; import java.text.StringCharacterIterator; import java.util.ArrayList; -import java.util.Arrays; import java.util.Comparator; import java.util.ConcurrentModificationException; import java.util.List; @@ -56,7 +55,8 @@ public class Transfer { public static Integer port; public static String root; public static String protocol; - public static String local_storage; + public static String shared_storage; + public static boolean use_shared_storage; public static Activity activity; @@ -65,7 +65,6 @@ public class Transfer { public int drawable; public String info; public String message; - public String error; public String sizeSI; @@ -127,7 +126,8 @@ public class Transfer { host = prefs.getString("host", null); root = prefs.getString("root", null); - local_storage = prefs.getString("local_storage", null); + shared_storage = prefs.getString("shared_storage", null); + use_shared_storage = prefs.getBoolean("use_shared_storage", false); if(prefs.getBoolean("protocol", false)) protocol = "https"; else diff --git a/app/src/main/java/com/localtransfer/UploadFile.java b/app/src/main/java/com/localtransfer/UploadFile.java index 7636552..84fc0f4 100644 --- a/app/src/main/java/com/localtransfer/UploadFile.java +++ b/app/src/main/java/com/localtransfer/UploadFile.java @@ -93,7 +93,6 @@ public class UploadFile extends Transfer { final String ExceptionMess = e.getMessage(); state = Transfer.STATE_FAILED; - error = ExceptionName + ": " + ExceptionMess; progressEnd(); if(ExceptionName != null && ExceptionMess != null) { diff --git a/app/src/main/java/com/localtransfer/fragment/DownloadFragment.java b/app/src/main/java/com/localtransfer/fragment/DownloadFragment.java index 01bfda3..fe41d76 100644 --- a/app/src/main/java/com/localtransfer/fragment/DownloadFragment.java +++ b/app/src/main/java/com/localtransfer/fragment/DownloadFragment.java @@ -20,6 +20,7 @@ import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import android.widget.Toast; import androidx.fragment.app.Fragment; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; @@ -224,11 +225,6 @@ public class DownloadFragment extends Fragment { trFile.setButton(file_buttons.findViewById(R.id.file_download)); - if (trFile.mime.equals("text/plain")) - trFile.save_location = getContext().getCacheDir().toString(); - else - trFile.save_location = Environment.getExternalStorageDirectory() + "/" + Transfer.local_storage; - viewName.setText(trFile.name); viewType.setText(trFile.mime); viewSize.setText(Transfer.humanReadableByteCountBin(trFile.size)); @@ -330,6 +326,7 @@ public class DownloadFragment extends Fragment { startActivity(Intent.createChooser(intent, getString(R.string.share_title))); } catch (ActivityNotFoundException e) { e.printStackTrace(); + Toast.makeText(getActivity(), "Can't share " + dl.mime, Toast.LENGTH_SHORT).show(); } } else { @@ -341,10 +338,9 @@ public class DownloadFragment extends Fragment { startActivity(Intent.createChooser(intent, getString(R.string.share_title))); } catch (ActivityNotFoundException e) { e.printStackTrace(); + Toast.makeText(getActivity(), "Can't share " + dl.mime, Toast.LENGTH_SHORT).show(); } } - - }; private View.OnClickListener ListenerView = v -> { @@ -360,9 +356,8 @@ public class DownloadFragment extends Fragment { startActivity(intent); } catch (ActivityNotFoundException e) { e.printStackTrace(); + Toast.makeText(getActivity(), "No " + dl.mime + " viewer", Toast.LENGTH_SHORT).show(); } - - }; private List getAllChildren(View v) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e7fe80f..474e6fa 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -30,8 +30,9 @@ /transfer - Local Storage - Download/TransferLocal + Use shared storage + Shared Storage + Download/TransferLocal Share diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml index 0d06de5..d398c07 100644 --- a/app/src/main/res/xml/root_preferences.xml +++ b/app/src/main/res/xml/root_preferences.xml @@ -31,11 +31,17 @@ + + + app:key="shared_storage" + app:title="@string/shared_storage" + app:defaultValue="@string/shared_storage_def" + app:useSimpleSummaryProvider="true" + app:isPreferenceVisible="false"/>