@@ -11,6 +11,7 @@ import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
+import android.graphics.pdf.PdfRenderer;
import android.media.MediaMetadataRetriever;
import android.media.MediaScannerConnection;
import android.net.Uri;
@@ -25,6 +26,7 @@ import android.system.Os;
import android.system.StructStat;
import android.util.Base64;
import android.util.Base64OutputStream;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.util.LruCache;
@@ -59,6 +61,7 @@ import eu.siacs.conversations.services.AttachFileToConversationRunnable;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.RecordingActivity;
import eu.siacs.conversations.ui.util.Attachment;
+import eu.siacs.conversations.utils.Compatibility;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.ExifHelper;
import eu.siacs.conversations.utils.FileUtils;
@@ -509,7 +512,6 @@ public class FileBackend {
}
-
public DownloadableFile getFileForPath(String path) {
return getFileForPath(path, MimeUtils.guessMimeTypeFromExtension(MimeUtils.extractRelevantExtension(path)));
}
@@ -818,7 +820,9 @@ public class FileBackend {
}
DownloadableFile file = getFile(message);
final String mime = file.getMimeType();
- if (mime.startsWith("video/")) {
+ if ("application/pdf".equals(mime) && Compatibility.runsTwentyOne()) {
+ thumbnail = getPdfDocumentPreview(file, size);
+ } else if (mime.startsWith("video/")) {
thumbnail = getVideoPreview(file, size);
} else {
Bitmap fullsize = getFullsizeImagePreview(file, size);
@@ -897,8 +901,8 @@ public class FileBackend {
}
}
- private Bitmap getVideoPreview(File file, int size) {
- MediaMetadataRetriever metadataRetriever = new MediaMetadataRetriever();
+ private Bitmap getVideoPreview(final File file, final int size) {
+ final MediaMetadataRetriever metadataRetriever = new MediaMetadataRetriever();
Bitmap frame;
try {
metadataRetriever.setDataSource(file.getAbsolutePath());
@@ -913,6 +917,24 @@ public class FileBackend {
return frame;
}
+ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ private Bitmap getPdfDocumentPreview(final File file, final int size) {
+ try {
+ final ParcelFileDescriptor fileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
+ final PdfRenderer pdfRenderer = new PdfRenderer(fileDescriptor);
+ final PdfRenderer.Page page = pdfRenderer.openPage(0);
+ Dimensions dimensions = scalePdfDimensions(new Dimensions(page.getHeight(), page.getWidth()));
+ final Bitmap rendered = Bitmap.createBitmap(dimensions.width, dimensions.height, Bitmap.Config.ARGB_8888);
+ page.render(rendered, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
+ return rendered;
+ } catch (IOException e) {
+ Log.d(Config.LOGTAG, "unable to render PDF document preview", e);
+ final Bitmap placeholder = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+ placeholder.eraseColor(0xff000000);
+ return placeholder;
+ }
+ }
+
public Uri getTakePhotoUri() {
File file;
if (Config.ONLY_INTERNAL_STORAGE) {
@@ -1210,14 +1232,22 @@ public class FileBackend {
final boolean image = message.getType() == Message.TYPE_IMAGE || (mime != null && mime.startsWith("image/"));
final boolean video = mime != null && mime.startsWith("video/");
final boolean audio = mime != null && mime.startsWith("audio/");
+ final boolean pdf = "application/pdf".equals(mime);
final StringBuilder body = new StringBuilder();
if (url != null) {
body.append(url.toString());
}
body.append('|').append(file.getSize());
- if (image || video) {
+ if (image || video || (pdf && Compatibility.runsTwentyOne())) {
try {
- Dimensions dimensions = image ? getImageDimensions(file) : getVideoDimensions(file);
+ final Dimensions dimensions;
+ if (video) {
+ dimensions = getVideoDimensions(file);
+ } else if (pdf && Compatibility.runsTwentyOne()) {
+ dimensions = getPdfDocumentDimensions(file);
+ } else {
+ dimensions = getImageDimensions(file);
+ }
if (dimensions.valid()) {
body.append('|').append(dimensions.width).append('|').append(dimensions.height);
}
@@ -1264,6 +1294,45 @@ public class FileBackend {
return getVideoDimensions(metadataRetriever);
}
+ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ private Dimensions getPdfDocumentDimensions(final File file) {
+ final ParcelFileDescriptor fileDescriptor;
+ try {
+ fileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
+ if (fileDescriptor == null) {
+ return new Dimensions(0, 0);
+ }
+ } catch (FileNotFoundException e) {
+ return new Dimensions(0, 0);
+ }
+ try {
+ final PdfRenderer pdfRenderer = new PdfRenderer(fileDescriptor);
+ final PdfRenderer.Page page = pdfRenderer.openPage(0);
+ final int height = page.getHeight();
+ final int width = page.getWidth();
+ page.close();
+ pdfRenderer.close();
+ return scalePdfDimensions(new Dimensions(height, width));
+ } catch (IOException e) {
+ Log.d(Config.LOGTAG, "unable to get dimensions for pdf document", e);
+ return new Dimensions(0, 0);
+ }
+ }
+
+ private Dimensions scalePdfDimensions(Dimensions in) {
+ final DisplayMetrics displayMetrics = mXmppConnectionService.getResources().getDisplayMetrics();
+ final int target = (int) (displayMetrics.density * 288);
+ final int w, h;
+ if (in.width <= in.height) {
+ w = Math.max((int) (in.width / ((double) in.height / target)), 1);
+ h = target;
+ } else {
+ w = target;
+ h = Math.max((int) (in.height / ((double) in.width / target)), 1);
+ }
+ return new Dimensions(h, w);
+ }
+
public Bitmap getAvatar(String avatar, int size) {
if (avatar == null) {
return null;
@@ -1275,10 +1344,6 @@ public class FileBackend {
return bm;
}
- public boolean isFileAvailable(Message message) {
- return getFile(message).exists();
- }
-
private static class Dimensions {
public final int width;
public final int height;
@@ -540,15 +540,15 @@ public class MessageAdapter extends ArrayAdapter<Message> implements CopyTextVie
this.audioPlayer.init(audioPlayer, message);
}
- private void displayImageMessage(ViewHolder viewHolder, final Message message, final boolean darkBackground) {
+ private void displayMediaPreviewMessage(ViewHolder viewHolder, final Message message, final boolean darkBackground) {
toggleWhisperInfo(viewHolder, message, darkBackground);
viewHolder.download_button.setVisibility(View.GONE);
viewHolder.audioPlayer.setVisibility(View.GONE);
viewHolder.image.setVisibility(View.VISIBLE);
- FileParams params = message.getFileParams();
- double target = metrics.density * 288;
- int scaledW;
- int scaledH;
+ final FileParams params = message.getFileParams();
+ final double target = metrics.density * 288;
+ final int scaledW;
+ final int scaledH;
if (Math.max(params.height, params.width) * metrics.density <= target) {
scaledW = (int) (params.width * metrics.density);
scaledH = (int) (params.height * metrics.density);
@@ -747,7 +747,7 @@ public class MessageAdapter extends ArrayAdapter<Message> implements CopyTextVie
}
} else if (message.isFileOrImage() && message.getEncryption() != Message.ENCRYPTION_PGP && message.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) {
if (message.getFileParams().width > 0 && message.getFileParams().height > 0) {
- displayImageMessage(viewHolder, message, darkBackground);
+ displayMediaPreviewMessage(viewHolder, message, darkBackground);
} else if (message.getFileParams().runtime > 0) {
displayAudioMessage(viewHolder, message, darkBackground);
} else {
@@ -38,14 +38,18 @@ public class Compatibility {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.M || ContextCompat.checkSelfPermission(context, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
}
- public static boolean runsTwentySix() {
- return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
+ public static boolean runsTwentyOne() {
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
}
- public static boolean runsTwentyFour() {
+ private static boolean runsTwentyFour() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
}
+ public static boolean runsTwentySix() {
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
+ }
+
public static boolean twentyEight() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
}