1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.providers.media.photopicker.data.model; 18 19 import static android.provider.CloudMediaProviderContract.MediaColumns; 20 import static android.provider.MediaStore.Files.FileColumns._SPECIAL_FORMAT_ANIMATED_WEBP; 21 import static android.provider.MediaStore.Files.FileColumns._SPECIAL_FORMAT_GIF; 22 import static android.provider.MediaStore.Files.FileColumns._SPECIAL_FORMAT_MOTION_PHOTO; 23 24 import static com.android.providers.media.photopicker.util.CursorUtils.getCursorInt; 25 import static com.android.providers.media.photopicker.util.CursorUtils.getCursorLong; 26 import static com.android.providers.media.photopicker.util.CursorUtils.getCursorString; 27 28 import static java.util.Objects.requireNonNull; 29 30 import android.content.Context; 31 import android.database.Cursor; 32 import android.net.Uri; 33 import android.text.format.DateUtils; 34 35 import androidx.annotation.NonNull; 36 import androidx.annotation.VisibleForTesting; 37 38 import com.android.providers.media.R; 39 import com.android.providers.media.photopicker.data.ItemsProvider; 40 import com.android.providers.media.photopicker.util.DateTimeUtils; 41 import com.android.providers.media.util.MimeUtils; 42 43 /** 44 * Base class for representing a single media item (a picture, a video, etc.) in the PhotoPicker. 45 */ 46 public class Item { 47 private String mId; 48 private long mDateTaken; 49 private long mGenerationModified; 50 private long mDuration; 51 private String mMimeType; 52 private Uri mUri; 53 private boolean mIsImage; 54 private boolean mIsVideo; 55 private int mSpecialFormat; 56 Item(@onNull Cursor cursor, @NonNull UserId userId)57 public Item(@NonNull Cursor cursor, @NonNull UserId userId) { 58 updateFromCursor(cursor, userId); 59 } 60 61 @VisibleForTesting Item(String id, String mimeType, long dateTaken, long generationModified, long duration, Uri uri, int specialFormat)62 public Item(String id, String mimeType, long dateTaken, long generationModified, long duration, 63 Uri uri, int specialFormat) { 64 mId = id; 65 mMimeType = mimeType; 66 mDateTaken = dateTaken; 67 mGenerationModified = generationModified; 68 mDuration = duration; 69 mUri = uri; 70 mSpecialFormat = specialFormat; 71 parseMimeType(); 72 } 73 getId()74 public String getId() { 75 return mId; 76 } 77 isImage()78 public boolean isImage() { 79 return mIsImage; 80 } 81 isVideo()82 public boolean isVideo() { 83 return mIsVideo; 84 } 85 isGifOrAnimatedWebp()86 public boolean isGifOrAnimatedWebp() { 87 return isGif() || isAnimatedWebp(); 88 } 89 isGif()90 public boolean isGif() { 91 return mSpecialFormat == _SPECIAL_FORMAT_GIF; 92 } 93 isAnimatedWebp()94 public boolean isAnimatedWebp() { 95 return mSpecialFormat == _SPECIAL_FORMAT_ANIMATED_WEBP; 96 } 97 isMotionPhoto()98 public boolean isMotionPhoto() { 99 return mSpecialFormat == _SPECIAL_FORMAT_MOTION_PHOTO; 100 } 101 getContentUri()102 public Uri getContentUri() { 103 return mUri; 104 } 105 getDuration()106 public long getDuration() { 107 return mDuration; 108 } 109 getMimeType()110 public String getMimeType() { 111 return mMimeType; 112 } 113 getDateTaken()114 public long getDateTaken() { 115 return mDateTaken; 116 } 117 getGenerationModified()118 public long getGenerationModified() { 119 return mGenerationModified; 120 } 121 122 @VisibleForTesting getSpecialFormat()123 public int getSpecialFormat() { 124 return mSpecialFormat; 125 } 126 fromCursor(@onNull Cursor cursor, UserId userId)127 public static Item fromCursor(@NonNull Cursor cursor, UserId userId) { 128 return new Item(requireNonNull(cursor), userId); 129 } 130 131 /** 132 * Update the item based on the cursor 133 * 134 * @param cursor the cursor to update the data 135 * @param userId the user id to create an {@link Item} for 136 */ updateFromCursor(@onNull Cursor cursor, @NonNull UserId userId)137 public void updateFromCursor(@NonNull Cursor cursor, @NonNull UserId userId) { 138 final String authority = getCursorString(cursor, MediaColumns.AUTHORITY); 139 mId = getCursorString(cursor, MediaColumns.ID); 140 mMimeType = getCursorString(cursor, MediaColumns.MIME_TYPE); 141 mDateTaken = getCursorLong(cursor, MediaColumns.DATE_TAKEN_MILLIS); 142 mGenerationModified = getCursorLong(cursor, MediaColumns.SYNC_GENERATION); 143 mDuration = getCursorLong(cursor, MediaColumns.DURATION_MILLIS); 144 mSpecialFormat = getCursorInt(cursor, MediaColumns.STANDARD_MIME_TYPE_EXTENSION); 145 mUri = ItemsProvider.getItemsUri(mId, authority, userId); 146 147 parseMimeType(); 148 } 149 getContentDescription(@onNull Context context)150 public String getContentDescription(@NonNull Context context) { 151 if (isVideo()) { 152 return context.getString(R.string.picker_video_item_content_desc, 153 DateTimeUtils.getDateTimeStringForContentDesc(getDateTaken()), 154 getDurationText()); 155 } 156 157 final String itemType; 158 if (isGif() || isAnimatedWebp()) { 159 itemType = context.getString(R.string.picker_gif); 160 } else if (isMotionPhoto()) { 161 itemType = context.getString(R.string.picker_motion_photo); 162 } else { 163 itemType = context.getString(R.string.picker_photo); 164 } 165 166 return context.getString(R.string.picker_item_content_desc, itemType, 167 DateTimeUtils.getDateTimeStringForContentDesc(getDateTaken())); 168 } 169 getDurationText()170 public String getDurationText() { 171 if (mDuration == -1) { 172 return ""; 173 } 174 return DateUtils.formatElapsedTime(mDuration / 1000); 175 } 176 parseMimeType()177 private void parseMimeType() { 178 if (MimeUtils.isImageMimeType(mMimeType)) { 179 mIsImage = true; 180 } else if (MimeUtils.isVideoMimeType(mMimeType)) { 181 mIsVideo = true; 182 } 183 } 184 185 /** 186 * Compares this item with given {@code anotherItem} by comparing 187 * {@link Item#getDateTaken()} value. When {@link Item#getDateTaken()} is 188 * same, Items are compared based on {@link Item#getId}. 189 */ compareTo(Item anotherItem)190 public int compareTo(Item anotherItem) { 191 if (mDateTaken > anotherItem.getDateTaken()) { 192 return 1; 193 } else if (mDateTaken < anotherItem.getDateTaken()) { 194 return -1; 195 } else { 196 return mId.compareTo(anotherItem.getId()); 197 } 198 } 199 } 200