diff --git a/.idea/misc.xml b/.idea/misc.xml index 9efabab..f4f18d3 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,8 +3,11 @@ @@ -52,7 +55,7 @@ - + diff --git a/app/build.gradle b/app/build.gradle index a95302c..27c226f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,7 +8,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/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bfa73f6..0414bfa 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,20 +3,25 @@ package="com.localtransfer"> - + - - + android:theme="@style/AppTheme"> + + - - + android:label="@string/title_activity_settings"> - + - + + - + + - diff --git a/app/src/main/java/com/localtransfer/DownloadFile.java b/app/src/main/java/com/localtransfer/DownloadFile.java new file mode 100644 index 0000000..42fe433 --- /dev/null +++ b/app/src/main/java/com/localtransfer/DownloadFile.java @@ -0,0 +1,289 @@ +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.drawable.Drawable; +import android.net.Uri; +import android.os.Environment; +import android.provider.MediaStore; +import android.util.Log; +import android.view.animation.Animation; +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; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.sql.Timestamp; + +public class DownloadFile extends Transfer { + + public String href; + + public String mime; + + public String type; + + public Uri uri; + + private Button button; + + public DownloadFile(Integer id) { + this.id = id; + instances.add(this); + info = "Download complete"; + state = STATE_NOT_REQUESTED; + drawable = R.drawable.ic_download_24; + } + + @Override + 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(); + values.put(MediaStore.MediaColumns.DISPLAY_NAME, name); + values.put(MediaStore.MediaColumns.MIME_TYPE, mime); + values.put(MediaStore.MediaColumns.RELATIVE_PATH, Transfer.shared_storage); + uri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values); + } + try { + downloadFile(); + } catch (IOException | NullPointerException e) { + final String ExceptionName = e.getClass().getSimpleName(); + final String ExceptionMess = e.getMessage(); + e.printStackTrace(); + + state = Transfer.STATE_FAILED; + progressEnd(); + buttonProgressEnd(); + + if(ExceptionName != null && ExceptionMess != null) { + errorSnackbar(ExceptionName + ": " + ExceptionMess); + } + + } + } + + public boolean exist(Context context) { + 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; + } + + public void setButton(Button button) { + this.button = button; + if (this.state == STATE_STANDBY) { + buttonProgressStart(); + } + } + + 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; + + 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(); + buttonProgressUpdate(); + } + fileOutput.close(); + + conn.disconnect(); + + message = "File " + name + " successful download"; + state = Transfer.STATE_SUCCESS; + progressEnd(); + buttonProgressEnd(); + + } + 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 buttonProgressStart() { + activity.runOnUiThread(() -> { + final Drawable image = Transfer.activity.getDrawable(R.drawable.ic_spinner_rotate); + + 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(); + } + }); + } + + private void buttonProgressUpdate(){ + activity.runOnUiThread(() -> { + if (app_started && button != null) + button.setText(String.format("Download in progress %d%%", percent)); + }); + } + + public void buttonProgressEnd() { + activity.runOnUiThread(() -> { + 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); + } + }); + } +} diff --git a/app/src/main/java/com/localtransfer/MainActivity.java b/app/src/main/java/com/localtransfer/MainActivity.java index 097fee6..15497f5 100644 --- a/app/src/main/java/com/localtransfer/MainActivity.java +++ b/app/src/main/java/com/localtransfer/MainActivity.java @@ -2,31 +2,33 @@ package com.localtransfer; import android.Manifest; import android.app.Activity; +import android.app.Notification; +import android.app.PendingIntent; import android.content.ActivityNotFoundException; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; - -import com.google.android.material.floatingactionbutton.FloatingActionButton; -import com.google.android.material.snackbar.Snackbar; -import com.google.android.material.tabs.TabLayout; - -import androidx.appcompat.widget.Toolbar; -import androidx.core.app.ActivityCompat; -import androidx.core.content.ContextCompat; -import androidx.preference.PreferenceManager; -import androidx.viewpager.widget.ViewPager; -import androidx.appcompat.app.AppCompatActivity; - import android.os.Environment; import android.util.Log; +import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Toast; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.core.app.ActivityCompat; +import androidx.core.app.NotificationManagerCompat; +import androidx.core.content.ContextCompat; +import androidx.preference.PreferenceManager; +import androidx.viewpager.widget.ViewPager; + +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.google.android.material.tabs.TabLayout; + import java.io.File; import java.util.ArrayList; @@ -63,6 +65,15 @@ public class MainActivity extends AppCompatActivity { checkAndRequestPermissions(); } + + Transfer.notifBuilder = new Notification.Builder(this); + Transfer.notifiManager = NotificationManagerCompat.from(this); + Transfer.inflater = (LayoutInflater) this.getSystemService(this.LAYOUT_INFLATER_SERVICE); + Transfer.resolver = this.getContentResolver(); + + Intent notificationIntent = new Intent(this, MainActivity.class); + Transfer.pendingIntent = PendingIntent.getActivity(this,0, notificationIntent, 0); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); if(prefs.getString("host", null) == null) @@ -70,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); @@ -80,16 +92,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); @@ -97,7 +107,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); } } @@ -112,11 +122,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<>(); @@ -132,7 +141,7 @@ public class MainActivity extends AppCompatActivity { fileUris.add(uri); } for (Uri uri : fileUris) { - tr.handleSendFile(uri); + UploadFile.handleSendFile(uri); } } } @@ -142,14 +151,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 @@ -187,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/Progress.java b/app/src/main/java/com/localtransfer/Progress.java deleted file mode 100644 index 983ffe5..0000000 --- a/app/src/main/java/com/localtransfer/Progress.java +++ /dev/null @@ -1,188 +0,0 @@ -package com.localtransfer; - -import android.app.PendingIntent; -import android.content.Intent; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.ProgressBar; -import android.widget.TextView; - -import androidx.core.app.NotificationCompat; -import androidx.core.app.NotificationManagerCompat; - -import java.util.ArrayList; -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 NotificationCompat.Builder bl = new NotificationCompat.Builder(Transfer.activity, null); - private static NotificationManagerCompat notifiManager = NotificationManagerCompat.from(Transfer.activity); - private static final LayoutInflater inflater = (LayoutInflater) Transfer.activity.getSystemService(Transfer.activity.LAYOUT_INFLATER_SERVICE); - - private static List instances = new ArrayList<>(); - - private Integer id; - private String name; - private long size; - - public long loaded; - 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; - - public Button button; - private boolean run = false; - - public Progress(String name, long size, int type) { - - instances.add(this); - - run = true; - - this.name = name; - this.size = 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); - } - - timer.schedule(new TimerTask() { - @Override - public void run() { - showProgress(); - } - }, 0, 1000); - } - - public static List getInstances() { - return instances; - } - - public void stopProgress() { - timer.cancel(); - showProgress(); - - run = false; - - 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); - notifiManager.notify(id, bl.build()); - } - } - - public void delete() { - instances.remove(this); - } - - public static Progress getProgress(int id) { - - for (Object obj: instances) { - Progress p = (Progress) obj; - if (p.id == id) return p; - } - return null; - } - - public static boolean setButton(String name, Button button) { - - for (Object obj: instances) { - Progress p = (Progress) obj; - if (name.equals(p.name) && p.run) { - p.button = button; - return true; - } - } - return false; - } - - - public void showProgress(){ - - try { - - String HumanLoaded = Transfer.humanReadableByteCountBin(loaded); - String HumanSize = Transfer.humanReadableByteCountBin(size); - - 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()); - } - - 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)); - }); - - } - - } catch (ConcurrentModificationException e) { - e.printStackTrace(); - } - - } - -} diff --git a/app/src/main/java/com/localtransfer/ServerFile.java b/app/src/main/java/com/localtransfer/ServerFile.java deleted file mode 100644 index c37a809..0000000 --- a/app/src/main/java/com/localtransfer/ServerFile.java +++ /dev/null @@ -1,217 +0,0 @@ -package com.localtransfer; - -import android.content.ContentUris; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.provider.MediaStore; -import android.util.Log; -import android.widget.Button; -import android.widget.LinearLayout; - -import com.google.android.material.snackbar.Snackbar; - -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.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; - - public Progress progress; - - private static List instances = new ArrayList<>(); - - public ServerFile(Integer id) { - this.id = id; - instances.add(this); - } - - 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 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; - long loaded = 0; - - 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+= (long) bufferLength; - progress.loaded = loaded; - progress.percent = ((loaded * 100) / size); - if(Progress.app_started && progress.button != null) - activity.runOnUiThread(() -> progress.button.setText(String.format("Download in progress %d%%", progress.percent))); - } - fileOutput.close(); - - conn.disconnect(); - - progress.stopProgress(); - - if(progress.button != null) { - activity.runOnUiThread(() -> { - final LinearLayout layout = (LinearLayout) progress.button.getParent(); - layout.findViewById(R.id.file_view).setVisibility(LinearLayout.VISIBLE); - layout.findViewById(R.id.file_share).setVisibility(LinearLayout.VISIBLE); - progress.button.setVisibility(LinearLayout.GONE); - progress.button.setEnabled(true); - - progress.button.setText(activity.getString(R.string.file_download)); - progress.button.setCompoundDrawables(progress.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() 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; - } -} diff --git a/app/src/main/java/com/localtransfer/SettingsActivity.java b/app/src/main/java/com/localtransfer/SettingsActivity.java index f39f28c..44afe9c 100644 --- a/app/src/main/java/com/localtransfer/SettingsActivity.java +++ b/app/src/main/java/com/localtransfer/SettingsActivity.java @@ -1,14 +1,10 @@ package com.localtransfer; import android.app.Activity; -import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.database.Cursor; -import android.net.Uri; import android.os.Bundle; import android.os.Environment; -import android.provider.MediaStore; import android.util.Log; import android.view.MenuItem; @@ -17,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; @@ -46,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) { @@ -69,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 cd39481..060c363 100644 --- a/app/src/main/java/com/localtransfer/Transfer.java +++ b/app/src/main/java/com/localtransfer/Transfer.java @@ -1,64 +1,133 @@ package com.localtransfer; -import android.animation.ObjectAnimator; +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.SharedPreferences; -import android.database.Cursor; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.provider.OpenableColumns; +import android.graphics.Color; import android.util.Log; -import android.view.Gravity; -import android.view.animation.Animation; -import android.view.animation.LinearInterpolator; -import android.widget.Button; +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.content.FileProvider; +import androidx.core.app.NotificationManagerCompat; 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.OutputStream; -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.sql.Timestamp; import java.text.CharacterIterator; -import java.text.SimpleDateFormat; import java.text.StringCharacterIterator; -import java.util.Date; -import java.util.Timer; -import java.util.TimerTask; - -import static java.lang.Integer.valueOf; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.ConcurrentModificationException; +import java.util.List; 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; public static String protocol; - public static String local_storage; + public static String shared_storage; + public static boolean use_shared_storage; public static Activity activity; + public int state; + + public int drawable; + public String info; + public String message; + + public String sizeSI; + + public long loaded; + public String loadedSI = "0"; + public long percent; + + public static final int NOTIF_SERVICE = 1000; + + 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; + + 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); 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 @@ -74,7 +143,127 @@ public class Transfer { port = valueOf(portValue); } - private static URL checkRedirection(URL url) throws IOException { + public void AddTransfer() { + + 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);*/ + } + } + + public void startTransfer() { + + } + + 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; @@ -115,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.error(ExceptionName + ": " + ExceptionMess, null, null); - } - - } - }).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; @@ -292,33 +338,13 @@ public class Transfer { private static int timeout; - public static void error(final String message, final TextView title, final LinearLayout layout) { + public static void errorSnackbar(final String message) { System.out.println(message); - if (timeout == 0) { - if (activity != null) { - activity.runOnUiThread(() -> { - if(layout != null) - layout.removeAllViews(); - if(title != null) { - title.setTextSize(18); - title.setGravity(Gravity.CENTER); - title.setHeight(1000); - layout.addView(title); - title.setText(message); - } - Snackbar.make(activity.findViewById(R.id.view_pager), message, Snackbar.LENGTH_LONG) - .setAction("Action", null).show(); - }); - } - timeout = 1; - new Timer().schedule(new TimerTask() { - @Override - public void run() { - timeout = 0; - } - }, 3000); + if (activity != null) { + 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/TransferService.java b/app/src/main/java/com/localtransfer/TransferService.java new file mode 100644 index 0000000..02cc73f --- /dev/null +++ b/app/src/main/java/com/localtransfer/TransferService.java @@ -0,0 +1,42 @@ +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) { + + 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(Transfer.NOTIF_SERVICE, 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/UploadFile.java b/app/src/main/java/com/localtransfer/UploadFile.java new file mode 100644 index 0000000..84fc0f4 --- /dev/null +++ b/app/src/main/java/com/localtransfer/UploadFile.java @@ -0,0 +1,196 @@ +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; + 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 e95db89..fe41d76 100644 --- a/app/src/main/java/com/localtransfer/fragment/DownloadFragment.java +++ b/app/src/main/java/com/localtransfer/fragment/DownloadFragment.java @@ -2,14 +2,12 @@ package com.localtransfer.fragment; import android.animation.ObjectAnimator; import android.content.ActivityNotFoundException; -import android.content.ContentValues; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Environment; -import android.provider.MediaStore; import android.view.ContextMenu; import android.view.Gravity; import android.view.LayoutInflater; @@ -22,15 +20,15 @@ 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; import com.google.android.material.snackbar.Snackbar; -import com.localtransfer.Progress; import com.localtransfer.R; +import com.localtransfer.DownloadFile; import com.localtransfer.Transfer; -import com.localtransfer.ServerFile; import org.json.JSONArray; import org.json.JSONException; @@ -111,7 +109,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(); @@ -125,7 +123,7 @@ public class DownloadFragment extends Fragment { String ExceptionMess = e.getMessage(); if(ExceptionName != null && ExceptionMess != null) { - Transfer.error(ExceptionName + ": " + ExceptionMess, null, null); + Transfer.errorSnackbar(ExceptionMess); } } @@ -164,7 +162,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"); @@ -185,14 +183,14 @@ public class DownloadFragment extends Fragment { final String ExceptionMess = e.getMessage(); if(ExceptionName != null && ExceptionMess != null) { - Transfer.error(ExceptionName + ": " + ExceptionMess, title, main_layout); + Transfer.errorSnackbar(ExceptionMess); } } }).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); @@ -202,7 +200,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); @@ -224,12 +222,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); - if (trFile.mime.equals("text/plain")) - trFile.save_location = getContext().getCacheDir().toString(); - else - trFile.save_location = Environment.getExternalStorageDirectory() + "/" + Transfer.local_storage; + trFile.setButton(file_buttons.findViewById(R.id.file_download)); viewName.setText(trFile.name); viewType.setText(trFile.mime); @@ -272,19 +266,7 @@ public class DownloadFragment extends Fragment { Bshare.setVisibility(LinearLayout.GONE); } - if (Progress.setButton(trFile.name, 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) { @@ -302,54 +284,21 @@ 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); - - file.progress = new Progress(file.name, file.size, Progress.DOWNLOAD); - file.progress.button = file.button; - - if (file.uri == null && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { - ContentValues values = new ContentValues(); - values.put(MediaStore.MediaColumns.DISPLAY_NAME, file.name); - values.put(MediaStore.MediaColumns.MIME_TYPE, file.mime); - values.put(MediaStore.MediaColumns.RELATIVE_PATH, Transfer.local_storage); - file.uri = getContext().getContentResolver().insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values); - } - - new Thread(() -> { - try { - file.downloadFile(); - } 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(); + DownloadFile file = (DownloadFile) DownloadFile.getFileById(id); + file.sizeSI = Transfer.humanReadableByteCountBin(file.size); + file.AddTransfer(); }; private View.OnClickListener ListenerShare = v -> { 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; @@ -377,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 { @@ -388,17 +338,16 @@ 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 -> { 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); @@ -407,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/java/com/localtransfer/fragment/ProgressFragment.java b/app/src/main/java/com/localtransfer/fragment/ProgressFragment.java index 57396f0..d776dd8 100644 --- a/app/src/main/java/com/localtransfer/fragment/ProgressFragment.java +++ b/app/src/main/java/com/localtransfer/fragment/ProgressFragment.java @@ -2,26 +2,16 @@ 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.Transfer; -import java.util.ConcurrentModificationException; import java.util.List; -import java.util.Timer; -import java.util.TimerTask; public class ProgressFragment extends Fragment { @@ -43,21 +33,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 = Progress.getInstances(); - for (Object obj: instances) { - Progress p = (Progress) obj; - p.showProgress(); + List instances = Transfer.getInstances(); + for (Transfer file: instances) { + file.showProgressFragment(); } } @@ -65,6 +54,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/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"/>