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 android.content.Context; 29 import android.database.Cursor; 30 import android.net.Uri; 31 import android.os.Bundle; 32 import android.provider.CloudMediaProviderContract; 33 import android.provider.MediaStore; 34 import android.text.format.DateUtils; 35 36 import androidx.annotation.NonNull; 37 import androidx.annotation.VisibleForTesting; 38 39 import com.android.providers.media.R; 40 import com.android.providers.media.photopicker.data.ItemsProvider; 41 import com.android.providers.media.photopicker.util.DateTimeUtils; 42 import com.android.providers.media.util.MimeUtils; 43 44 /** 45 * Base class representing one single entity/item in the PhotoPicker. 46 */ 47 public class Item { 48 private String mId; 49 private long mDateTaken; 50 private long mGenerationModified; 51 private long mDuration; 52 private String mMimeType; 53 private Uri mUri; 54 private boolean mIsImage; 55 private boolean mIsVideo; 56 private int mSpecialFormat; 57 private boolean mIsDate; 58 Item()59 private Item() {} 60 Item(@onNull Cursor cursor, @NonNull UserId userId)61 public Item(@NonNull Cursor cursor, @NonNull UserId userId) { 62 updateFromCursor(cursor, userId); 63 } 64 65 @VisibleForTesting Item(String id, String mimeType, long dateTaken, long generationModified, long duration, Uri uri, int specialFormat)66 public Item(String id, String mimeType, long dateTaken, long generationModified, long duration, 67 Uri uri, int specialFormat) { 68 mId = id; 69 mMimeType = mimeType; 70 mDateTaken = dateTaken; 71 mGenerationModified = generationModified; 72 mDuration = duration; 73 mUri = uri; 74 mSpecialFormat = specialFormat; 75 parseMimeType(); 76 } 77 getId()78 public String getId() { 79 return mId; 80 } 81 isImage()82 public boolean isImage() { 83 return mIsImage; 84 } 85 isVideo()86 public boolean isVideo() { 87 return mIsVideo; 88 } 89 isGifOrAnimatedWebp()90 public boolean isGifOrAnimatedWebp() { 91 return isGif() || isAnimatedWebp(); 92 } 93 isGif()94 public boolean isGif() { 95 return mSpecialFormat == _SPECIAL_FORMAT_GIF; 96 } 97 isAnimatedWebp()98 public boolean isAnimatedWebp() { 99 return mSpecialFormat == _SPECIAL_FORMAT_ANIMATED_WEBP; 100 } 101 isMotionPhoto()102 public boolean isMotionPhoto() { 103 return mSpecialFormat == _SPECIAL_FORMAT_MOTION_PHOTO; 104 } 105 isDate()106 public boolean isDate() { 107 return mIsDate; 108 } 109 getContentUri()110 public Uri getContentUri() { 111 return mUri; 112 } 113 getDuration()114 public long getDuration() { 115 return mDuration; 116 } 117 getMimeType()118 public String getMimeType() { 119 return mMimeType; 120 } 121 getDateTaken()122 public long getDateTaken() { 123 return mDateTaken; 124 } 125 getGenerationModified()126 public long getGenerationModified() { 127 return mGenerationModified; 128 } 129 130 @VisibleForTesting getSpecialFormat()131 public int getSpecialFormat() { 132 return mSpecialFormat; 133 } 134 fromCursor(Cursor cursor, UserId userId)135 public static Item fromCursor(Cursor cursor, UserId userId) { 136 assert(cursor != null); 137 final Item item = new Item(cursor, userId); 138 return item; 139 } 140 141 /** 142 * Return the date item. If dateTaken is 0, it is a recent item. 143 * @param dateTaken the time of date taken. The unit is in milliseconds 144 * since January 1, 1970 00:00:00.0 UTC. 145 * @return the item with date type 146 */ createDateItem(long dateTaken)147 public static Item createDateItem(long dateTaken) { 148 final Item item = new Item(); 149 item.mIsDate = true; 150 item.mDateTaken = dateTaken; 151 return item; 152 } 153 154 /** 155 * Update the item based on the cursor 156 * 157 * @param cursor the cursor to update the data 158 * @param userId the user id to create an {@link Item} for 159 */ updateFromCursor(@onNull Cursor cursor, @NonNull UserId userId)160 public void updateFromCursor(@NonNull Cursor cursor, @NonNull UserId userId) { 161 final String authority = getCursorString(cursor, MediaColumns.AUTHORITY); 162 mId = getCursorString(cursor, MediaColumns.ID); 163 mMimeType = getCursorString(cursor, MediaColumns.MIME_TYPE); 164 mDateTaken = getCursorLong(cursor, MediaColumns.DATE_TAKEN_MILLIS); 165 mGenerationModified = getCursorLong(cursor, MediaColumns.SYNC_GENERATION); 166 mDuration = getCursorLong(cursor, MediaColumns.DURATION_MILLIS); 167 mSpecialFormat = getCursorInt(cursor, MediaColumns.STANDARD_MIME_TYPE_EXTENSION); 168 mUri = ItemsProvider.getItemsUri(mId, authority, userId); 169 170 parseMimeType(); 171 } 172 getContentDescription(@onNull Context context)173 public String getContentDescription(@NonNull Context context) { 174 if (isVideo()) { 175 return context.getString(R.string.picker_video_item_content_desc, 176 DateTimeUtils.getDateTimeStringForContentDesc(getDateTaken()), 177 getDurationText()); 178 } 179 180 final String itemType; 181 if (isGif() || isAnimatedWebp()) { 182 itemType = context.getString(R.string.picker_gif); 183 } else if (isMotionPhoto()) { 184 itemType = context.getString(R.string.picker_motion_photo); 185 } else { 186 itemType = context.getString(R.string.picker_photo); 187 } 188 189 return context.getString(R.string.picker_item_content_desc, itemType, 190 DateTimeUtils.getDateTimeStringForContentDesc(getDateTaken())); 191 } 192 getDurationText()193 public String getDurationText() { 194 if (mDuration == -1) { 195 return ""; 196 } 197 return DateUtils.formatElapsedTime(mDuration / 1000); 198 } 199 parseMimeType()200 private void parseMimeType() { 201 if (MimeUtils.isImageMimeType(mMimeType)) { 202 mIsImage = true; 203 } else if (MimeUtils.isVideoMimeType(mMimeType)) { 204 mIsVideo = true; 205 } 206 } 207 208 /** 209 * Compares this item with given {@code anotherItem} by comparing 210 * {@link Item#getDateTaken()} value. When {@link Item#getDateTaken()} is 211 * same, Items are compared based on {@link Item#getId}. 212 */ compareTo(Item anotherItem)213 public int compareTo(Item anotherItem) { 214 if (mDateTaken > anotherItem.getDateTaken()) { 215 return 1; 216 } else if (mDateTaken < anotherItem.getDateTaken()) { 217 return -1; 218 } else { 219 return mId.compareTo(anotherItem.getId()); 220 } 221 } 222 } 223