• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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