From 6a387e4cb8865653453b4e8267b3cebc86d06dd3 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Sat, 1 May 2021 02:11:31 +0200 Subject: [PATCH 1/4] add support for PDF (by intent) Signed-off-by: Marcel Hibbe --- .../MagicPreviewMessageViewHolder.java | 77 ++++++++++++++----- app/src/main/res/xml/file_provider_paths.xml | 2 +- 2 files changed, 59 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java b/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java index f03e74cf5..67983fc57 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java @@ -26,14 +26,17 @@ import android.annotation.SuppressLint; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.net.Uri; +import android.os.Build; import android.os.Handler; import android.util.Log; import android.view.Gravity; import android.view.View; import android.widget.PopupMenu; +import android.widget.Toast; import com.google.common.util.concurrent.ListenableFuture; import com.nextcloud.talk.R; @@ -54,13 +57,16 @@ import com.nextcloud.talk.utils.bundle.BundleKeys; import com.stfalcon.chatkit.messages.MessageHolders; import java.io.File; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import javax.inject.Inject; +import androidx.core.app.ShareCompat; import androidx.core.content.ContextCompat; +import androidx.core.content.FileProvider; import androidx.emoji.widget.EmojiTextView; import androidx.work.Data; import androidx.work.OneTimeWorkRequest; @@ -195,25 +201,6 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM } } - public boolean isSupportedMimetype(String mimetype){ - switch (mimetype) { - case "image/png": - case "image/jpeg": - case "image/gif": - case "audio/mpeg": - case "audio/wav": - case "audio/ogg": - case "video/mp4": - case "video/quicktime": - case "video/ogg": - case "text/markdown": - case "text/plain": - return true; - default: - return false; - } - } - private void openOrDownloadFile(ChatMessage message) { String filename = message.getSelectedIndividualHashMap().get("name"); String mimetype = message.getSelectedIndividualHashMap().get("mimetype"); @@ -243,6 +230,26 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM } } + public boolean isSupportedMimetype(String mimetype){ + switch (mimetype) { + case "image/png": + case "image/jpeg": + case "image/gif": + case "audio/mpeg": + case "audio/wav": + case "audio/ogg": + case "video/mp4": + case "video/quicktime": + case "video/ogg": + case "text/markdown": + case "text/plain": + case "application/pdf": + return true; + default: + return false; + } + } + private void openFile(String filename, String mimetype) { switch (mimetype) { case "audio/mpeg": @@ -262,11 +269,43 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM case "text/plain": openTextView(filename, mimetype); break; + case "application/pdf": + openPdf(filename); + break; default: Log.w(TAG, "no method defined for mimetype: " + mimetype); } } + private void openPdf(String fileName) { + String path = context.getCacheDir().getAbsolutePath() + "/" + fileName; + File file = new File(path); + Intent intent = null; + if (Build.VERSION.SDK_INT < 24) { + intent = new Intent(Intent.ACTION_VIEW); + intent.setDataAndType(Uri.fromFile(file), "application/pdf"); + intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + } else { + intent = new Intent(); + intent.setAction(Intent.ACTION_VIEW); + Uri pdfURI = FileProvider.getUriForFile(context, context.getPackageName(), file); + intent.setDataAndType(pdfURI, "application/pdf"); + intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } + + try { + if (intent.resolveActivity(context.getPackageManager()) != null) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } else { + Toast.makeText(context, "No Application found to open the pdf", Toast.LENGTH_SHORT).show(); + } + } catch (Exception e) { + Log.e(TAG, "Error while opening pdf file", e); + } + } + private void openImageView(String filename, String mimetype) { Intent fullScreenImageIntent = new Intent(context, FullScreenImageActivity.class); fullScreenImageIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); diff --git a/app/src/main/res/xml/file_provider_paths.xml b/app/src/main/res/xml/file_provider_paths.xml index f8f81c61f..70b5bfb0d 100644 --- a/app/src/main/res/xml/file_provider_paths.xml +++ b/app/src/main/res/xml/file_provider_paths.xml @@ -23,6 +23,6 @@ name="files" path="/" /> From b97e6702531432d92d39d829a3c4d99582e0c9ca Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Mon, 3 May 2021 12:32:33 +0200 Subject: [PATCH 2/4] add support for all files that can be handled by an external app Signed-off-by: Marcel Hibbe --- .../MagicPreviewMessageViewHolder.java | 87 +++++++++---------- 1 file changed, 41 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java b/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java index 67983fc57..8f41fd2ec 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java @@ -26,7 +26,6 @@ import android.annotation.SuppressLint; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.net.Uri; @@ -57,14 +56,12 @@ import com.nextcloud.talk.utils.bundle.BundleKeys; import com.stfalcon.chatkit.messages.MessageHolders; import java.io.File; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import javax.inject.Inject; -import androidx.core.app.ShareCompat; import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; import androidx.emoji.widget.EmojiTextView; @@ -149,7 +146,7 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM image.setOnClickListener(v -> { String mimetype = message.getSelectedIndividualHashMap().get("mimetype"); - if (isSupportedMimetype(mimetype)) { + if (isSupportedForInternalViewer(mimetype) || canBeHandledByExternalApp(mimetype, fileName)) { openOrDownloadFile(message); } else { openFileInFilesApp(message, accountString); @@ -208,29 +205,11 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM if (file.exists()) { openFile(filename, mimetype); } else { - String size = message.getSelectedIndividualHashMap().get("size"); - - if (size == null) { - size = "-1"; - } - Integer fileSize = Integer.valueOf(size); - - String fileId = message.getSelectedIndividualHashMap().get("id"); - String path = message.getSelectedIndividualHashMap().get("path"); - downloadFileToCache( - message.activeUser.getBaseUrl(), - message.activeUser.getUserId(), - message.activeUser.getAttachmentFolder(), - filename, - path, - mimetype, - fileSize, - fileId - ); + downloadFileToCache(message); } } - public boolean isSupportedMimetype(String mimetype){ + public boolean isSupportedForInternalViewer(String mimetype){ switch (mimetype) { case "image/png": case "image/jpeg": @@ -243,7 +222,6 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM case "video/ogg": case "text/markdown": case "text/plain": - case "application/pdf": return true; default: return false; @@ -269,27 +247,24 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM case "text/plain": openTextView(filename, mimetype); break; - case "application/pdf": - openPdf(filename); - break; default: - Log.w(TAG, "no method defined for mimetype: " + mimetype); + openFileByExternalApp(filename, mimetype); } } - private void openPdf(String fileName) { + private void openFileByExternalApp(String fileName, String mimetype) { String path = context.getCacheDir().getAbsolutePath() + "/" + fileName; File file = new File(path); - Intent intent = null; + Intent intent; if (Build.VERSION.SDK_INT < 24) { intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(Uri.fromFile(file), "application/pdf"); + intent.setDataAndType(Uri.fromFile(file), mimetype); intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); } else { intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); Uri pdfURI = FileProvider.getUriForFile(context, context.getPackageName(), file); - intent.setDataAndType(pdfURI, "application/pdf"); + intent.setDataAndType(pdfURI, mimetype); intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } @@ -299,13 +274,22 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); } else { - Toast.makeText(context, "No Application found to open the pdf", Toast.LENGTH_SHORT).show(); + Log.e(TAG, "No Application found to open the file. This should have been handled beforehand!"); } } catch (Exception e) { - Log.e(TAG, "Error while opening pdf file", e); + Log.e(TAG, "Error while opening file", e); } } + private boolean canBeHandledByExternalApp(String mimetype, String fileName){ + String path = context.getCacheDir().getAbsolutePath() + "/" + fileName; + File file = new File(path); + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setDataAndType(Uri.fromFile(file), mimetype); + + return intent.resolveActivity(context.getPackageManager()) != null; + } + private void openImageView(String filename, String mimetype) { Intent fullScreenImageIntent = new Intent(context, FullScreenImageActivity.class); fullScreenImageIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); @@ -332,7 +316,7 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM } private void onMessageViewLongClick(ChatMessage message, String accountString) { - if (isSupportedMimetype(message.getSelectedIndividualHashMap().get("mimetype"))) { + if (isSupportedForInternalViewer(message.getSelectedIndividualHashMap().get("mimetype"))) { return; } @@ -348,14 +332,24 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM } @SuppressLint("LongLogTag") - private void downloadFileToCache(String baseUrl, - String userId, - String attachmentFolder, - String fileName, - String path, - String mimetype, - Integer size, - String fileId) { + private void downloadFileToCache(ChatMessage message) { + + String baseUrl = message.activeUser.getBaseUrl(); + String userId = message.activeUser.getUserId(); + String attachmentFolder = message.activeUser.getAttachmentFolder(); + + String fileName = message.getSelectedIndividualHashMap().get("name"); + String mimetype = message.getSelectedIndividualHashMap().get("mimetype"); + + String size = message.getSelectedIndividualHashMap().get("size"); + + if (size == null) { + size = "-1"; + } + Integer fileSize = Integer.valueOf(size); + + String fileId = message.getSelectedIndividualHashMap().get("id"); + String path = message.getSelectedIndividualHashMap().get("path"); // check if download worker is already running ListenableFuture> workers = WorkManager.getInstance(context).getWorkInfosByTag(fileId); @@ -381,7 +375,7 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM .putString(DownloadFileToCacheWorker.KEY_ATTACHMENT_FOLDER, attachmentFolder) .putString(DownloadFileToCacheWorker.KEY_FILE_NAME, fileName) .putString(DownloadFileToCacheWorker.KEY_FILE_PATH, path) - .putInt(DownloadFileToCacheWorker.KEY_FILE_SIZE, size) + .putInt(DownloadFileToCacheWorker.KEY_FILE_SIZE, fileSize) .build(); downloadWorker = new OneTimeWorkRequest.Builder(DownloadFileToCacheWorker.class) @@ -411,7 +405,8 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM if (image.isShown()) { openFile(fileName, mimetype); } else { - Log.d(TAG, "image " + fileName + " was downloaded but it's not opened (view is not shown)"); + Log.d(TAG, "file " + fileName + " was downloaded but it's not opened because view is not shown on" + + " screen"); } messageText.setText(fileName); progressBar.setVisibility(View.GONE); From 5914f01524db4cd337ba22e4480366028875ada0 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Mon, 3 May 2021 14:06:31 +0200 Subject: [PATCH 3/4] add info about permissions on api level 30 for resolveActivity Signed-off-by: Marcel Hibbe --- .../talk/adapters/messages/MagicPreviewMessageViewHolder.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java b/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java index 8f41fd2ec..1787cb5e9 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java @@ -281,12 +281,14 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM } } - private boolean canBeHandledByExternalApp(String mimetype, String fileName){ + private boolean canBeHandledByExternalApp(String mimetype, String fileName) { String path = context.getCacheDir().getAbsolutePath() + "/" + fileName; File file = new File(path); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(file), mimetype); + // TODO resolveActivity might need more permissions starting with android 11 (api 30) + // https://developer.android.com/about/versions/11/privacy/package-visibility return intent.resolveActivity(context.getPackageManager()) != null; } From 4f0c01adfdaca0121f26d70efd6f92f28d7a5ccc Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Mon, 3 May 2021 15:47:01 +0200 Subject: [PATCH 4/4] add changelog entry Signed-off-by: Marcel Hibbe --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b38632a8..9659f94b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Types of changes can be: Added/Changed/Deprecated/Removed/Fixed/Security ## [UNRELEASED] ### Added - open files inside app (jpg, .png, .gif, .mp3, .mp4, .mov, .wav, .txt, .md) + - other data types are opened with external apps if they are able to handle it - edit profile information and privacy settings ### Changed