Signal-Android/app/src/main/java/org/thoughtcrime/securesms/mms/SlideFactory.java

175 wiersze
6.2 KiB
Java

package org.thoughtcrime.securesms.mms;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.OpenableColumns;
import android.text.TextUtils;
import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.blurhash.BlurHash;
import org.thoughtcrime.securesms.util.MediaUtil;
import java.io.IOException;
/**
* SlideFactory encapsulates logic related to constructing slides from a set of paramaeters as defined
* by {@link SlideFactory#getSlide}.
*/
public final class SlideFactory {
private static final String TAG = Log.tag(SlideFactory.class);
private SlideFactory() {
}
/**
* Generates a slide from the given parameters.
*
* @param context Application context
* @param contentType The contentType of the given Uri
* @param uri The Uri pointing to the resource to create a slide out of
* @param width (Optional) width, can be 0.
* @param height (Optional) height, can be 0.
*
* @return A Slide with all the information we can gather about it.
*/
@WorkerThread
public static @Nullable Slide getSlide(@NonNull Context context, @Nullable String contentType, @NonNull Uri uri, int width, int height) {
MediaType mediaType = MediaType.from(contentType);
try {
if (PartAuthority.isLocalUri(uri)) {
return getManuallyCalculatedSlideInfo(context, mediaType, uri, width, height);
} else {
Slide result = getContentResolverSlideInfo(context, mediaType, uri, width, height);
if (result == null) return getManuallyCalculatedSlideInfo(context, mediaType, uri, width, height);
else return result;
}
} catch (IOException e) {
Log.w(TAG, e);
return null;
}
}
private static @Nullable Slide getContentResolverSlideInfo(@NonNull Context context, @NonNull MediaType mediaType, @NonNull Uri uri, int width, int height) {
Cursor cursor = null;
long start = System.currentTimeMillis();
try {
cursor = context.getContentResolver().query(uri, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
String fileName = cursor.getString(cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME));
long fileSize = cursor.getLong(cursor.getColumnIndexOrThrow(OpenableColumns.SIZE));
String mimeType = context.getContentResolver().getType(uri);
if (width == 0 || height == 0) {
Pair<Integer, Integer> dimens = MediaUtil.getDimensions(context, mimeType, uri);
width = dimens.first;
height = dimens.second;
}
Log.d(TAG, "remote slide with size " + fileSize + " took " + (System.currentTimeMillis() - start) + "ms");
return mediaType.createSlide(context, uri, fileName, mimeType, null, fileSize, width, height);
}
} finally {
if (cursor != null) cursor.close();
}
return null;
}
private static @NonNull Slide getManuallyCalculatedSlideInfo(@NonNull Context context, @NonNull MediaType mediaType, @NonNull Uri uri, int width, int height) throws IOException {
long start = System.currentTimeMillis();
Long mediaSize = null;
String fileName = null;
String mimeType = null;
if (PartAuthority.isLocalUri(uri)) {
mediaSize = PartAuthority.getAttachmentSize(context, uri);
fileName = PartAuthority.getAttachmentFileName(context, uri);
mimeType = PartAuthority.getAttachmentContentType(context, uri);
}
if (mediaSize == null) {
mediaSize = MediaUtil.getMediaSize(context, uri);
}
if (mimeType == null) {
mimeType = MediaUtil.getMimeType(context, uri);
}
if (width == 0 || height == 0) {
Pair<Integer, Integer> dimens = MediaUtil.getDimensions(context, mimeType, uri);
width = dimens.first;
height = dimens.second;
}
Log.d(TAG, "local slide with size " + mediaSize + " took " + (System.currentTimeMillis() - start) + "ms");
return mediaType.createSlide(context, uri, fileName, mimeType, null, mediaSize, width, height);
}
public enum MediaType {
IMAGE(MediaUtil.IMAGE_JPEG),
GIF(MediaUtil.IMAGE_GIF),
AUDIO(MediaUtil.AUDIO_AAC),
VIDEO(MediaUtil.VIDEO_MP4),
DOCUMENT(MediaUtil.UNKNOWN),
VCARD(MediaUtil.VCARD);
private final String fallbackMimeType;
MediaType(String fallbackMimeType) {
this.fallbackMimeType = fallbackMimeType;
}
public @NonNull Slide createSlide(@NonNull Context context,
@NonNull Uri uri,
@Nullable String fileName,
@Nullable String mimeType,
@Nullable BlurHash blurHash,
long dataSize,
int width,
int height)
{
if (mimeType == null) {
mimeType = "application/octet-stream";
}
switch (this) {
case IMAGE: return new ImageSlide(context, uri, dataSize, width, height, blurHash);
case GIF: return new GifSlide(context, uri, dataSize, width, height);
case AUDIO: return new AudioSlide(context, uri, dataSize, false);
case VIDEO: return new VideoSlide(context, uri, dataSize);
case VCARD:
case DOCUMENT: return new DocumentSlide(context, uri, mimeType, dataSize, fileName);
default: throw new AssertionError("unrecognized enum");
}
}
public static @Nullable MediaType from(final @Nullable String mimeType) {
if (TextUtils.isEmpty(mimeType)) return null;
if (MediaUtil.isGif(mimeType)) return GIF;
if (MediaUtil.isImageType(mimeType)) return IMAGE;
if (MediaUtil.isAudioType(mimeType)) return AUDIO;
if (MediaUtil.isVideoType(mimeType)) return VIDEO;
if (MediaUtil.isVcard(mimeType)) return VCARD;
return DOCUMENT;
}
public String toFallbackMimeType() {
return fallbackMimeType;
}
}
}