Media repository no longer uses deprecated API.

This commit is contained in:
Anton Chekulaev 2020-09-09 17:12:06 +10:00
parent 263a540151
commit 45b41219e1
12 changed files with 44 additions and 63 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 325 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 681 B

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M10,4H4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8c0,-1.1 -0.9,-2 -2,-2h-8l-2,-2z"/>
</vector>

View File

@ -33,7 +33,8 @@
android:layout_width="20dp" android:layout_width="20dp"
android:layout_height="20dp" android:layout_height="20dp"
android:layout_marginEnd="6dp" android:layout_marginEnd="6dp"
android:src="@drawable/ic_folder_white_48dp"/> android:tint="@android:color/white"
android:src="@drawable/ic_baseline_folder_24"/>
<TextView <TextView
android:id="@+id/mediapicker_folder_item_title" android:id="@+id/mediapicker_folder_item_title"

View File

@ -12,14 +12,12 @@ public class MediaFolder {
private final String title; private final String title;
private final int itemCount; private final int itemCount;
private final String bucketId; private final String bucketId;
private final FolderType folderType;
MediaFolder(@NonNull Uri thumbnailUri, @NonNull String title, int itemCount, @NonNull String bucketId, @NonNull FolderType folderType) { MediaFolder(@NonNull Uri thumbnailUri, @NonNull String title, int itemCount, @NonNull String bucketId) {
this.thumbnailUri = thumbnailUri; this.thumbnailUri = thumbnailUri;
this.title = title; this.title = title;
this.itemCount = itemCount; this.itemCount = itemCount;
this.bucketId = bucketId; this.bucketId = bucketId;
this.folderType = folderType;
} }
Uri getThumbnailUri() { Uri getThumbnailUri() {
@ -38,10 +36,6 @@ public class MediaFolder {
return bucketId; return bucketId;
} }
FolderType getFolderType() {
return folderType;
}
enum FolderType { enum FolderType {
NORMAL, CAMERA NORMAL, CAMERA
} }

View File

@ -75,7 +75,6 @@ class MediaPickerFolderAdapter extends RecyclerView.Adapter<MediaPickerFolderAda
void bind(@NonNull MediaFolder folder, @NonNull GlideRequests glideRequests, @NonNull EventListener eventListener) { void bind(@NonNull MediaFolder folder, @NonNull GlideRequests glideRequests, @NonNull EventListener eventListener) {
title.setText(folder.getTitle()); title.setText(folder.getTitle());
count.setText(String.valueOf(folder.getItemCount())); count.setText(String.valueOf(folder.getItemCount()));
icon.setImageResource(folder.getFolderType() == MediaFolder.FolderType.CAMERA ? R.drawable.ic_camera_alt_white_24dp : R.drawable.ic_folder_white_48dp);
glideRequests.load(folder.getThumbnailUri()) glideRequests.load(folder.getThumbnailUri())
.diskCacheStrategy(DiskCacheStrategy.NONE) .diskCacheStrategy(DiskCacheStrategy.NONE)

View File

@ -5,7 +5,6 @@ import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Environment;
import android.provider.MediaStore.Images; import android.provider.MediaStore.Images;
import android.provider.MediaStore.Video; import android.provider.MediaStore.Video;
import android.provider.OpenableColumns; import android.provider.OpenableColumns;
@ -33,11 +32,6 @@ import java.util.Map;
/** /**
* Handles the retrieval of media present on the user's device. * Handles the retrieval of media present on the user's device.
* @deprecated Usage of this class is unsafe on Android API 30 and up,
* the public external directory is no longer exposed to the apps.
* <p><b>
* The functionality of this class should be refactored to use
* <a href="https://developer.android.com/reference/android/provider/MediaStore">MediaStore</a>.
*/ */
class MediaRepository { class MediaRepository {
@ -82,30 +76,17 @@ class MediaRepository {
} }
} }
String cameraBucketId = imageFolders.getCameraBucketId() != null ? imageFolders.getCameraBucketId() : videoFolders.getCameraBucketId(); List<MediaFolder> mediaFolders = Stream.of(folders.values()).map(folder -> new MediaFolder(folder.getThumbnail(),
FolderData cameraFolder = cameraBucketId != null ? folders.remove(cameraBucketId) : null;
List<MediaFolder> mediaFolders = Stream.of(folders.values()).map(folder -> new MediaFolder(folder.getThumbnail(),
folder.getTitle(), folder.getTitle(),
folder.getCount(), folder.getCount(),
folder.getBucketId(), folder.getBucketId()))
MediaFolder.FolderType.NORMAL))
.sorted((o1, o2) -> o1.getTitle().toLowerCase().compareTo(o2.getTitle().toLowerCase())) .sorted((o1, o2) -> o1.getTitle().toLowerCase().compareTo(o2.getTitle().toLowerCase()))
.toList(); .toList();
Uri allMediaThumbnail = imageFolders.getThumbnailTimestamp() > videoFolders.getThumbnailTimestamp() ? imageFolders.getThumbnail() : videoFolders.getThumbnail(); Uri allMediaThumbnail = imageFolders.getThumbnailTimestamp() > videoFolders.getThumbnailTimestamp() ? imageFolders.getThumbnail() : videoFolders.getThumbnail();
if (allMediaThumbnail != null) { if (allMediaThumbnail != null) {
int allMediaCount = Stream.of(mediaFolders).reduce(0, (count, folder) -> count + folder.getItemCount()); int allMediaCount = Stream.of(mediaFolders).reduce(0, (count, folder) -> count + folder.getItemCount());
mediaFolders.add(0, new MediaFolder(allMediaThumbnail, context.getString(R.string.MediaRepository_all_media), allMediaCount, Media.ALL_MEDIA_BUCKET_ID));
if (cameraFolder != null) {
allMediaCount += cameraFolder.getCount();
}
mediaFolders.add(0, new MediaFolder(allMediaThumbnail, context.getString(R.string.MediaRepository_all_media), allMediaCount, Media.ALL_MEDIA_BUCKET_ID, MediaFolder.FolderType.NORMAL));
}
if (cameraFolder != null) {
mediaFolders.add(0, new MediaFolder(cameraFolder.getThumbnail(), cameraFolder.getTitle(), cameraFolder.getCount(), cameraFolder.getBucketId(), MediaFolder.FolderType.CAMERA));
} }
return mediaFolders; return mediaFolders;
@ -113,8 +94,6 @@ class MediaRepository {
@WorkerThread @WorkerThread
private @NonNull FolderResult getFolders(@NonNull Context context, @NonNull Uri contentUri) { private @NonNull FolderResult getFolders(@NonNull Context context, @NonNull Uri contentUri) {
String cameraPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath() + File.separator + "Camera";
String cameraBucketId = null;
Uri globalThumbnail = null; Uri globalThumbnail = null;
long thumbnailTimestamp = 0; long thumbnailTimestamp = 0;
Map<String, FolderData> folders = new HashMap<>(); Map<String, FolderData> folders = new HashMap<>();
@ -135,10 +114,6 @@ class MediaRepository {
folder.incrementCount(); folder.incrementCount();
folders.put(bucketId, folder); folders.put(bucketId, folder);
if (cameraBucketId == null && path.startsWith(cameraPath)) {
cameraBucketId = bucketId;
}
if (timestamp > thumbnailTimestamp) { if (timestamp > thumbnailTimestamp) {
globalThumbnail = thumbnail; globalThumbnail = thumbnail;
thumbnailTimestamp = timestamp; thumbnailTimestamp = timestamp;
@ -146,7 +121,7 @@ class MediaRepository {
} }
} }
return new FolderResult(cameraBucketId, globalThumbnail, thumbnailTimestamp, folders); return new FolderResult(globalThumbnail, thumbnailTimestamp, folders);
} }
@WorkerThread @WorkerThread
@ -284,26 +259,19 @@ class MediaRepository {
} }
private static class FolderResult { private static class FolderResult {
private final String cameraBucketId;
private final Uri thumbnail; private final Uri thumbnail;
private final long thumbnailTimestamp; private final long thumbnailTimestamp;
private final Map<String, FolderData> folderData; private final Map<String, FolderData> folderData;
private FolderResult(@Nullable String cameraBucketId, private FolderResult(@Nullable Uri thumbnail,
@Nullable Uri thumbnail,
long thumbnailTimestamp, long thumbnailTimestamp,
@NonNull Map<String, FolderData> folderData) @NonNull Map<String, FolderData> folderData)
{ {
this.cameraBucketId = cameraBucketId;
this.thumbnail = thumbnail; this.thumbnail = thumbnail;
this.thumbnailTimestamp = thumbnailTimestamp; this.thumbnailTimestamp = thumbnailTimestamp;
this.folderData = folderData; this.folderData = folderData;
} }
@Nullable String getCameraBucketId() {
return cameraBucketId;
}
@Nullable Uri getThumbnail() { @Nullable Uri getThumbnail() {
return thumbnail; return thumbnail;
} }

View File

@ -1,6 +1,8 @@
package org.thoughtcrime.securesms.mediasend; package org.thoughtcrime.securesms.mediasend;
import android.Manifest; import android.Manifest;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders; import androidx.lifecycle.ViewModelProviders;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -133,7 +135,7 @@ public class MediaSendActivity extends PassphraseRequiredActionBarActivity imple
countButtonText = findViewById(R.id.mediasend_count_button_text); countButtonText = findViewById(R.id.mediasend_count_button_text);
cameraButton = findViewById(R.id.mediasend_camera_button); cameraButton = findViewById(R.id.mediasend_camera_button);
viewModel = ViewModelProviders.of(this, new MediaSendViewModel.Factory(getApplication(), new MediaRepository())).get(MediaSendViewModel.class); viewModel = new ViewModelProvider(this, new MediaSendViewModel.Factory(getApplication(), new MediaRepository())).get(MediaSendViewModel.class);
recipient = Recipient.from(this, Address.fromSerialized(getIntent().getStringExtra(KEY_ADDRESS)), true); recipient = Recipient.from(this, Address.fromSerialized(getIntent().getStringExtra(KEY_ADDRESS)), true);
transport = getIntent().getParcelableExtra(KEY_TRANSPORT); transport = getIntent().getParcelableExtra(KEY_TRANSPORT);

View File

@ -371,28 +371,34 @@ public class AttachmentManager {
} }
public static void selectDocument(Activity activity, int requestCode) { public static void selectDocument(Activity activity, int requestCode) {
Permissions.with(activity) // Permissions.with(activity)
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE) // .request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
.withPermanentDenialDialog(activity.getString(R.string.AttachmentManager_signal_requires_the_external_storage_permission_in_order_to_attach_photos_videos_or_audio)) // .withPermanentDenialDialog(activity.getString(R.string.AttachmentManager_signal_requires_the_external_storage_permission_in_order_to_attach_photos_videos_or_audio))
.onAllGranted(() -> selectMediaType(activity, "*/*", null, requestCode)) // .onAllGranted(() -> selectMediaType(activity, "*/*", null, requestCode))
.execute(); // .execute();
selectMediaType(activity, "*/*", null, requestCode);
} }
public static void selectGallery(Activity activity, int requestCode, @NonNull Recipient recipient, @NonNull String body, @NonNull TransportOption transport) { public static void selectGallery(Activity activity, int requestCode, @NonNull Recipient recipient, @NonNull String body, @NonNull TransportOption transport) {
Permissions.with(activity) // Permissions.with(activity)
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE) // .request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
.withPermanentDenialDialog(activity.getString(R.string.AttachmentManager_signal_requires_the_external_storage_permission_in_order_to_attach_photos_videos_or_audio)) // .withPermanentDenialDialog(activity.getString(R.string.AttachmentManager_signal_requires_the_external_storage_permission_in_order_to_attach_photos_videos_or_audio))
.onAllGranted(() -> selectMediaType(activity, "image/*", new String[] {"image/*", "video/*"}, requestCode)) //// .onAllGranted(() -> selectMediaType(activity, "image/*", new String[] {"image/*", "video/*"}, requestCode))
.onAllGranted(() -> activity.startActivityForResult(MediaSendActivity.buildGalleryIntent(activity, recipient, body, transport), requestCode)) // .onAllGranted(() -> activity.startActivityForResult(MediaSendActivity.buildGalleryIntent(activity, recipient, body, transport), requestCode))
.execute(); // .execute();
activity.startActivityForResult(MediaSendActivity.buildGalleryIntent(activity, recipient, body, transport), requestCode);
} }
public static void selectAudio(Activity activity, int requestCode) { public static void selectAudio(Activity activity, int requestCode) {
Permissions.with(activity) // Permissions.with(activity)
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE) //// .request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
.withPermanentDenialDialog(activity.getString(R.string.AttachmentManager_signal_requires_the_external_storage_permission_in_order_to_attach_photos_videos_or_audio)) //// .withPermanentDenialDialog(activity.getString(R.string.AttachmentManager_signal_requires_the_external_storage_permission_in_order_to_attach_photos_videos_or_audio))
.onAllGranted(() -> selectMediaType(activity, "audio/*", null, requestCode)) //// .onAllGranted(() -> selectMediaType(activity, "audio/*", null, requestCode))
.execute(); //// .execute();
selectMediaType(activity, "audio/*", null, requestCode);
} }
public static void selectContactInfo(Activity activity, int requestCode) { public static void selectContactInfo(Activity activity, int requestCode) {
@ -463,6 +469,7 @@ public class AttachmentManager {
} }
private static void selectMediaType(Activity activity, @NonNull String type, @Nullable String[] extraMimeType, int requestCode) { private static void selectMediaType(Activity activity, @NonNull String type, @Nullable String[] extraMimeType, int requestCode) {
//TODO Constrain media file size to match the Loki protocol limit.
final Intent intent = new Intent(); final Intent intent = new Intent();
intent.setType(type); intent.setType(type);