Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/stefan-niedermann/nextcloud-deck.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordesperateCoder <echotodevnull@gmail.com>2020-02-02 01:02:30 +0300
committerdesperateCoder <echotodevnull@gmail.com>2020-02-02 01:02:30 +0300
commit8191eff363b0edd9a3e7798783e26a1c2e896b82 (patch)
tree0df44dfaf14d8c87ddab3dd5e8fe0ce3adb240c2
parent08530e19c307ecfd3cb401b10a4ed21e2e15c50f (diff)
attachments upload: something does something
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/SyncManager.java12
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/ServerAdapter.java5
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AttachmentDataProvider.java4
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardAttachmentsFragment.java11
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/util/FileUtils.java373
5 files changed, 386 insertions, 19 deletions
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/SyncManager.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/SyncManager.java
index 2a8ddab03..1c678687f 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/SyncManager.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/SyncManager.java
@@ -13,6 +13,7 @@ import androidx.lifecycle.MutableLiveData;
import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException;
import com.nextcloud.android.sso.exceptions.NoCurrentAccountSelectedException;
+import java.io.File;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
@@ -964,18 +965,13 @@ public class SyncManager {
}
}
- public LiveData<Attachment> addAttachmentToCard(long accountId, long localCardId, @NonNull Uri uri) {
- try {
- DeckLog.log(getPath(dataBaseAdapter.getContext(), uri));
- } catch (URISyntaxException e) {
- e.printStackTrace();
- }
+ public LiveData<Attachment> addAttachmentToCard(long accountId, long localCardId, @NonNull String mimeType, @NonNull File file) {
MutableLiveData<Attachment> liveData = new MutableLiveData<>();
doAsync(() -> {
Attachment attachment = new Attachment();
attachment.setCardId(localCardId);
- attachment.setMimetype(Attachment.getMimetypeForUri(dataBaseAdapter.getContext(), uri));
- attachment.setLocalPath(uri.getPath());
+ attachment.setMimetype(mimeType);
+ attachment.setLocalPath(file.getAbsolutePath());
attachment.setCreatedAt(new Date());
dataBaseAdapter.createAttachment(accountId, attachment);
if (serverAdapter.hasInternetConnection()) {
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/ServerAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/ServerAdapter.java
index 7ddf8fa9a..5ab72e99b 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/ServerAdapter.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/ServerAdapter.java
@@ -46,7 +46,6 @@ import it.niedermann.nextcloud.deck.model.full.FullStack;
import it.niedermann.nextcloud.deck.model.ocs.Capabilities;
import it.niedermann.nextcloud.deck.model.propagation.CardUpdate;
import it.niedermann.nextcloud.deck.model.propagation.Reorder;
-import it.niedermann.nextcloud.deck.persistence.util.RealPathUtils;
import it.niedermann.nextcloud.deck.util.DateUtil;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
@@ -279,10 +278,8 @@ public class ServerAdapter {
}
// ## ATTACHMENTS
- public void uploadAttachment(Long remoteBoardId, long remoteStackId, long remoteCardId, String contentType, Uri attachmentUri, IResponseCallback<Attachment> responseCallback) {
+ public void uploadAttachment(Long remoteBoardId, long remoteStackId, long remoteCardId, String contentType, File attachment, IResponseCallback<Attachment> responseCallback) {
ensureInternetConnection();
-// File attachment = new File(getUriRealPath( applicationContext, attachmentUri));
- File attachment = RealPathUtils.getRealPath(applicationContext, attachmentUri);
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", attachment.getName(), RequestBody.create(MediaType.parse(contentType), attachment));
MultipartBody.Part typePart = MultipartBody.Part.createFormData("type", attachment.getName(), RequestBody.create(MediaType.parse("text/plain"), "deck_file"));
RequestHelper.request(sourceActivity, provider, () -> provider.getDeckAPI().uploadAttachment(remoteBoardId, remoteStackId, remoteCardId, typePart, filePart), responseCallback);
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AttachmentDataProvider.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AttachmentDataProvider.java
index 4a9688b3c..6869d7fe5 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AttachmentDataProvider.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AttachmentDataProvider.java
@@ -64,9 +64,7 @@ public class AttachmentDataProvider extends AbstractSyncDataProvider<Attachment>
@Override
public void createOnServer(ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, long accountId, IResponseCallback<Attachment> responder, Attachment entity) {
- Uri uri = Uri.fromFile(new File(entity.getLocalPath()));
- String type = Attachment.getMimetypeForUri(dataBaseAdapter.getContext(), uri);
- serverAdapter.uploadAttachment(board.getId(), stack.getId(), card.getId(), type, uri, responder);
+ serverAdapter.uploadAttachment(board.getId(), stack.getId(), card.getId(), entity.getType(), new File(entity.getLocalPath()), responder);
}
@Override
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardAttachmentsFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardAttachmentsFragment.java
index a7410e587..10d56fe31 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardAttachmentsFragment.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/CardAttachmentsFragment.java
@@ -15,12 +15,12 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
-import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
+import java.io.File;
import java.util.Objects;
import butterknife.BindView;
@@ -31,6 +31,7 @@ import it.niedermann.nextcloud.deck.model.Account;
import it.niedermann.nextcloud.deck.model.Attachment;
import it.niedermann.nextcloud.deck.persistence.sync.SyncManager;
import it.niedermann.nextcloud.deck.ui.helper.emptycontentview.EmptyContentView;
+import it.niedermann.nextcloud.deck.util.FileUtils;
import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper.observeOnce;
import static it.niedermann.nextcloud.deck.ui.card.CardAdapter.BUNDLE_KEY_ACCOUNT_ID;
@@ -91,7 +92,7 @@ public class CardAttachmentsFragment extends Fragment implements AttachmentAdapt
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT && canEdit) {
fab.setOnClickListener(v -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
+ requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
REQUEST_PERMISSION);
} else {
startFilePickerIntent();
@@ -120,7 +121,7 @@ public class CardAttachmentsFragment extends Fragment implements AttachmentAdapt
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private void startFilePickerIntent() {
// Snackbar.make(coordinatorLayout, "Adding attachments is not yet implemented", Snackbar.LENGTH_LONG).show();
- Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
startActivityForResult(intent, REQUEST_CODE_ADD_ATTACHMENT);
@@ -134,7 +135,9 @@ public class CardAttachmentsFragment extends Fragment implements AttachmentAdapt
if (data != null) {
uri = data.getData();
Log.i(TAG, "Uri: " + uri.toString());
- syncManager.addAttachmentToCard(accountId, cardId, uri);
+ String path = FileUtils.getPath(getContext(), uri);
+ File uploadFile = new File(path);
+ syncManager.addAttachmentToCard(accountId, cardId, Attachment.getMimetypeForUri(getContext(), uri), uploadFile);
}
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/util/FileUtils.java b/app/src/main/java/it/niedermann/nextcloud/deck/util/FileUtils.java
new file mode 100644
index 000000000..6dd015692
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/util/FileUtils.java
@@ -0,0 +1,373 @@
+package it.niedermann.nextcloud.deck.util;
+
+import android.annotation.SuppressLint;
+import android.content.ContentUris;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.provider.DocumentsContract;
+import android.provider.MediaStore;
+import android.provider.OpenableColumns;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+
+public class FileUtils {
+
+ /**
+ * Get a file path from a Uri. This will get the the path for Storage Access
+ * Framework Documents, as well as the _data field for the MediaStore and
+ * other file-based ContentProviders.<br>
+ * <br>
+ * Callers should check whether the path is local before assuming it
+ * represents a local file.
+ *
+ * @param context The context.
+ * @param uri The Uri to query.
+ */
+ @SuppressLint("NewApi")
+ public static String getPath(final Context context, final Uri uri) {
+ // check here to KITKAT or new version
+ final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
+ String selection = null;
+ String[] selectionArgs = null;
+ // DocumentProvider
+ if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
+ // ExternalStorageProvider
+ if (isExternalStorageDocument(uri)) {
+ final String docId = DocumentsContract.getDocumentId(uri);
+ final String[] split = docId.split(":");
+ final String type = split[0];
+
+ String fullPath = getPathFromExtSD(split);
+ if (fullPath != "") {
+ return fullPath;
+ } else {
+ return null;
+ }
+ }
+
+ // DownloadsProvider
+ else if (isDownloadsDocument(uri)) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ final String id;
+ Cursor cursor = null;
+ try {
+ cursor = context.getContentResolver().query(uri, new String[]{MediaStore.MediaColumns.DISPLAY_NAME}, null, null, null);
+ if (cursor != null && cursor.moveToFirst()) {
+ String fileName = cursor.getString(0);
+ String path = Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName;
+ if (!TextUtils.isEmpty(path)) {
+ return path;
+ }
+ }
+ } finally {
+ if (cursor != null)
+ cursor.close();
+ }
+ id = DocumentsContract.getDocumentId(uri);
+ if (!TextUtils.isEmpty(id)) {
+ if (id.startsWith("raw:")) {
+ return id.replaceFirst("raw:", "");
+ }
+ String[] contentUriPrefixesToTry = new String[]{
+ "content://downloads/public_downloads",
+ "content://downloads/my_downloads"
+ };
+ for (String contentUriPrefix : contentUriPrefixesToTry) {
+ try {
+ final Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));
+
+ /* final Uri contentUri = ContentUris.withAppendedId(
+ Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));*/
+
+ return getDataColumn(context, contentUri, null, null);
+ } catch (NumberFormatException e) {
+ //In Android 8 and Android P the id is not a number
+ return uri.getPath().replaceFirst("^/document/raw:", "").replaceFirst("^raw:", "");
+ }
+ }
+
+
+ }
+
+ } else {
+ final String id = DocumentsContract.getDocumentId(uri);
+ final boolean isOreo = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
+ if (id.startsWith("raw:")) {
+ return id.replaceFirst("raw:", "");
+ }
+ Uri contentUri = null;
+ try {
+ contentUri = ContentUris.withAppendedId(
+ Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
+
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ }
+ if (contentUri != null) {
+ return getDataColumn(context, contentUri, null, null);
+ }
+ }
+
+
+ }
+ // MediaProvider
+ else if (isMediaDocument(uri)) {
+ final String docId = DocumentsContract.getDocumentId(uri);
+ final String[] split = docId.split(":");
+ final String type = split[0];
+
+ Uri contentUri = null;
+
+ if ("image".equals(type)) {
+ contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+ } else if ("video".equals(type)) {
+ contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
+ } else if ("audio".equals(type)) {
+ contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
+ }
+ selection = "_id=?";
+ selectionArgs = new String[]{split[1]};
+
+
+ return getDataColumn(context, contentUri, selection,
+ selectionArgs);
+ } else if (isGoogleDriveUri(uri)) {
+ return getDriveFilePath(uri, context);
+ }
+ }
+
+
+ // MediaStore (and general)
+ else if ("content".equalsIgnoreCase(uri.getScheme())) {
+
+ if (isGooglePhotosUri(uri)) {
+ return uri.getLastPathSegment();
+ }
+
+ if (isGoogleDriveUri(uri)) {
+ return getDriveFilePath(uri, context);
+ }
+ if( Build.VERSION.SDK_INT == Build.VERSION_CODES.N)
+ {
+ // return getFilePathFromURI(context,uri);
+ return getMediaFilePathForN(uri, context);
+ // return getRealPathFromURI(context,uri);
+ }else
+ {
+
+ return getDataColumn(context, uri, null, null);
+ }
+
+
+ }
+ // File
+ else if ("file".equalsIgnoreCase(uri.getScheme())) {
+ return uri.getPath();
+ }
+
+ return null;
+ }
+
+ /**
+ * Check if a file exists on device
+ *
+ * @param filePath The absolute file path
+ */
+ private static boolean fileExists(String filePath) {
+ File file = new File(filePath);
+
+ return file.exists();
+ }
+
+
+ /**
+ * Get full file path from external storage
+ *
+ * @param pathData The storage type and the relative path
+ */
+ private static String getPathFromExtSD(String[] pathData) {
+ final String type = pathData[0];
+ final String relativePath = "/" + pathData[1];
+ String fullPath = "";
+
+ // on my Sony devices (4.4.4 & 5.1.1), `type` is a dynamic string
+ // something like "71F8-2C0A", some kind of unique id per storage
+ // don't know any API that can get the root path of that storage based on its id.
+ //
+ // so no "primary" type, but let the check here for other devices
+ if ("primary".equalsIgnoreCase(type)) {
+ fullPath = Environment.getExternalStorageDirectory() + relativePath;
+ if (fileExists(fullPath)) {
+ return fullPath;
+ }
+ }
+
+ // Environment.isExternalStorageRemovable() is `true` for external and internal storage
+ // so we cannot relay on it.
+ //
+ // instead, for each possible path, check if file exists
+ // we'll start with secondary storage as this could be our (physically) removable sd card
+ fullPath = System.getenv("SECONDARY_STORAGE") + relativePath;
+ if (fileExists(fullPath)) {
+ return fullPath;
+ }
+
+ fullPath = System.getenv("EXTERNAL_STORAGE") + relativePath;
+ if (fileExists(fullPath)) {
+ return fullPath;
+ }
+
+ return fullPath;
+ }
+
+ private static String getDriveFilePath(Uri uri, Context context) {
+ Uri returnUri = uri;
+ Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
+ /*
+ * Get the column indexes of the data in the Cursor,
+ * * move to the first row in the Cursor, get the data,
+ * * and display it.
+ * */
+ int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
+ int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
+ returnCursor.moveToFirst();
+ String name = (returnCursor.getString(nameIndex));
+ String size = (Long.toString(returnCursor.getLong(sizeIndex)));
+ File file = new File(context.getCacheDir(), name);
+ try {
+ InputStream inputStream = context.getContentResolver().openInputStream(uri);
+ FileOutputStream outputStream = new FileOutputStream(file);
+ int read = 0;
+ int maxBufferSize = 1 * 1024 * 1024;
+ int bytesAvailable = inputStream.available();
+
+ //int bufferSize = 1024;
+ int bufferSize = Math.min(bytesAvailable, maxBufferSize);
+
+ final byte[] buffers = new byte[bufferSize];
+ while ((read = inputStream.read(buffers)) != -1) {
+ outputStream.write(buffers, 0, read);
+ }
+ Log.e("File Size", "Size " + file.length());
+ inputStream.close();
+ outputStream.close();
+ Log.e("File Path", "Path " + file.getPath());
+ Log.e("File Size", "Size " + file.length());
+ } catch (Exception e) {
+ Log.e("Exception", e.getMessage());
+ }
+ return file.getPath();
+ }
+
+ private static String getMediaFilePathForN(Uri uri, Context context) {
+ Uri returnUri = uri;
+ Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
+ /*
+ * Get the column indexes of the data in the Cursor,
+ * * move to the first row in the Cursor, get the data,
+ * * and display it.
+ * */
+ int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
+ int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
+ returnCursor.moveToFirst();
+ String name = (returnCursor.getString(nameIndex));
+ String size = (Long.toString(returnCursor.getLong(sizeIndex)));
+ File file = new File(context.getFilesDir(), name);
+ try {
+ InputStream inputStream = context.getContentResolver().openInputStream(uri);
+ FileOutputStream outputStream = new FileOutputStream(file);
+ int read = 0;
+ int maxBufferSize = 1 * 1024 * 1024;
+ int bytesAvailable = inputStream.available();
+
+ //int bufferSize = 1024;
+ int bufferSize = Math.min(bytesAvailable, maxBufferSize);
+
+ final byte[] buffers = new byte[bufferSize];
+ while ((read = inputStream.read(buffers)) != -1) {
+ outputStream.write(buffers, 0, read);
+ }
+ Log.e("File Size", "Size " + file.length());
+ inputStream.close();
+ outputStream.close();
+ Log.e("File Path", "Path " + file.getPath());
+ Log.e("File Size", "Size " + file.length());
+ } catch (Exception e) {
+ Log.e("Exception", e.getMessage());
+ }
+ return file.getPath();
+ }
+
+
+ private static String getDataColumn(Context context, Uri uri,
+ String selection, String[] selectionArgs) {
+ Cursor cursor = null;
+ final String column = "_data";
+ final String[] projection = {column};
+
+ try {
+ cursor = context.getContentResolver().query(uri, projection,
+ selection, selectionArgs, null);
+
+ if (cursor != null && cursor.moveToFirst()) {
+ final int index = cursor.getColumnIndexOrThrow(column);
+ return cursor.getString(index);
+ }
+ } finally {
+ if (cursor != null)
+ cursor.close();
+ }
+
+ return null;
+ }
+
+ /**
+ * @param uri - The Uri to check.
+ * @return - Whether the Uri authority is ExternalStorageProvider.
+ */
+ private static boolean isExternalStorageDocument(Uri uri) {
+ return "com.android.externalstorage.documents".equals(uri.getAuthority());
+ }
+
+ /**
+ * @param uri - The Uri to check.
+ * @return - Whether the Uri authority is DownloadsProvider.
+ */
+ private static boolean isDownloadsDocument(Uri uri) {
+ return "com.android.providers.downloads.documents".equals(uri.getAuthority());
+ }
+
+ /**
+ * @param uri - The Uri to check.
+ * @return - Whether the Uri authority is MediaProvider.
+ */
+ private static boolean isMediaDocument(Uri uri) {
+ return "com.android.providers.media.documents".equals(uri.getAuthority());
+ }
+
+ /**
+ * @param uri - The Uri to check.
+ * @return - Whether the Uri authority is Google Photos.
+ */
+ private static boolean isGooglePhotosUri(Uri uri) {
+ return "com.google.android.apps.photos.content".equals(uri.getAuthority());
+ }
+
+
+ /**
+ * @param uri The Uri to check.
+ * @return Whether the Uri authority is Google Drive.
+ */
+ private static boolean isGoogleDriveUri(Uri uri) {
+ return "com.google.android.apps.docs.storage".equals(uri.getAuthority()) || "com.google.android.apps.docs.storage.legacy".equals(uri.getAuthority());
+ }
+
+
+} \ No newline at end of file