/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.photopicker.cts.util; import android.app.UiAutomation; import android.content.Context; import android.net.Uri; import android.os.Bundle; import android.os.FileUtils; import android.os.UserHandle; import android.photopicker.cts.R; import android.provider.MediaStore; import android.provider.cts.media.MediaProviderTestUtils; import android.provider.cts.media.MediaStoreUtils; import android.util.Pair; import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import com.android.compatibility.common.util.ShellUtils; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; /** * Photo Picker Utility methods for media files creation and deletion. */ public class PhotoPickerFilesUtils { public static final String DISPLAY_NAME_PREFIX = "ctsPhotoPicker"; public static List createImagesAndGetUris(int count, int userId) throws Exception { return createImagesAndGetUris(count, userId, /* isFavorite */ false); } public static List createImagesAndGetUris(int count, int userId, boolean isFavorite) throws Exception { List> createdImagesData = createImagesAndGetUriAndPath(count, userId, isFavorite); List uriList = new ArrayList<>(); for (Pair createdImageData: createdImagesData) { uriList.add(createdImageData.first); } return uriList; } /** * Create multiple images according to the given parameters and returns the uris and filenames * of the images created. * * @param count number of images to create * @param userId user id to create images in * * @return list of data (uri and filename pair) about the images created */ public static List> createImagesAndGetUriAndPath(int count, int userId, boolean isFavorite) throws Exception { List> createdImagesData = new ArrayList<>(); for (int i = 0; i < count; i++) { Pair createdImageData = createImage(userId, isFavorite); createdImagesData.add(createdImageData); clearMediaOwner(createdImageData.first, userId); } // Wait for Picker db sync to complete MediaStore.waitForIdle(InstrumentationRegistry.getContext().getContentResolver()); return createdImagesData; } private static Pair createImage(int userId, boolean isFavorite) throws Exception { return getPermissionAndStageMedia(R.raw.lg_g4_iso_800_jpg, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/jpeg", userId, isFavorite); } public static List createMj2VideosAndGetUris(int count, int userId) throws Exception { List uriList = new ArrayList<>(); for (int i = 0; i < count; i++) { final Uri uri = createMj2Video(userId); uriList.add(uri); clearMediaOwner(uri, userId); } // Wait for Picker db sync to complete MediaStore.waitForIdle(InstrumentationRegistry.getContext().getContentResolver()); return uriList; } public static List createVideosAndGetUris(int count, int userId) throws Exception { List uriList = new ArrayList<>(); for (int i = 0; i < count; i++) { final Uri uri = createVideo(userId); uriList.add(uri); clearMediaOwner(uri, userId); } // Wait for Picker db sync to complete MediaStore.waitForIdle(InstrumentationRegistry.getContext().getContentResolver()); return uriList; } /** * Return media id from a given Uri * @param Uri uri to parse * @return String media id */ public static String getMediaId(Uri uri) throws Exception { return uri.getLastPathSegment(); } public static void deleteMedia(Uri uri, Context context) throws Exception { try { MediaProviderTestUtils.setOwner(uri, context.getPackageName()); context.getContentResolver().delete(uri, Bundle.EMPTY); } catch (Exception ignored) { } } private static void clearMediaOwner(Uri uri, int userId) throws Exception { final String cmd = String.format( "content update --uri %s --user %d --bind owner_package_name:n:", uri, userId); ShellUtils.runShellCommand(cmd); } private static Uri createMj2Video(int userId) throws Exception { return getPermissionAndStageMedia(R.raw.test_video_mj2, MediaStore.Video.Media.EXTERNAL_CONTENT_URI, "video/mp4", userId, /* isFavorite */ false).first; } private static Uri createVideo(int userId) throws Exception { return getPermissionAndStageMedia(R.raw.test_video, MediaStore.Video.Media.EXTERNAL_CONTENT_URI, "video/mp4", userId, /* isFavorite */ false).first; } private static Pair getPermissionAndStageMedia(int resId, Uri collectionUri, String mimeType, int userId, boolean isFavorite) throws Exception { UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); uiAutomation.adoptShellPermissionIdentity( android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL); try { final Context context = InstrumentationRegistry.getTargetContext(); final Context userContext = userId == context.getUserId() ? context : context.createPackageContextAsUser("android", /* flags= */ 0, UserHandle.of(userId)); return stageMedia(resId, collectionUri, mimeType, userContext, isFavorite); } finally { uiAutomation.dropShellPermissionIdentity(); } } private static Pair stageMedia(int resId, Uri collectionUri, String mimeType, Context context, boolean isFavorite) throws IOException { final String displayName = DISPLAY_NAME_PREFIX + System.nanoTime(); final MediaStoreUtils.PendingParams params = new MediaStoreUtils.PendingParams( collectionUri, displayName, mimeType); params.setIsFavorite(isFavorite); final Uri pendingUri = MediaStoreUtils.createPending(context, params); try (MediaStoreUtils.PendingSession session = MediaStoreUtils.openPending(context, pendingUri)) { try (InputStream source = context.getResources().openRawResource(resId); OutputStream target = session.openOutputStream()) { FileUtils.copy(source, target); } return new Pair(session.publish(), displayName); } } @NonNull public static Uri createSvgImage(int userId) throws Exception { return getPermissionAndStageMedia(R.raw.lg_g4_iso_800_svg, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/svg+xml", userId, /* isFavorite */ false).first; } @NonNull public static Uri createImageWithUnknownMimeType(int userId) throws Exception { return getPermissionAndStageMedia(R.raw.lg_g4_iso_800_unknown_mime_type, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/jpeg", userId, /* isFavorite */ false).first; } @NonNull public static Uri createMpegVideo(int userId) throws Exception { return getPermissionAndStageMedia(R.raw.test_video_mpeg, MediaStore.Video.Media.EXTERNAL_CONTENT_URI, "video/mpeg", userId, /* isFavorite */ false).first; } @NonNull public static Uri createVideoWithUnknownMimeType(int userId) throws Exception { return getPermissionAndStageMedia(R.raw.test_video_unknown_mime_type, MediaStore.Video.Media.EXTERNAL_CONTENT_URI, "video/mp4", userId, /* isFavorite */ false).first; } }