• 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 import static android.provider.MediaStore.Files.FileColumns._SPECIAL_FORMAT_NONE;
24 
25 import static com.google.common.truth.Truth.assertThat;
26 
27 import android.content.Context;
28 import android.database.Cursor;
29 import android.database.MatrixCursor;
30 import android.net.Uri;
31 import android.os.UserHandle;
32 import android.provider.MediaStore;
33 
34 import androidx.test.InstrumentationRegistry;
35 import androidx.test.runner.AndroidJUnit4;
36 
37 import com.android.providers.media.photopicker.PickerSyncController;
38 
39 import org.junit.Test;
40 import org.junit.runner.RunWith;
41 
42 import java.time.LocalDate;
43 import java.time.ZoneId;
44 
45 @RunWith(AndroidJUnit4.class)
46 public class ItemTest {
47 
48     @Test
testConstructor()49     public void testConstructor() {
50         final String id = "1";
51         final long dateTaken = 12345678L;
52         final long generationModified = 1L;
53         final String mimeType = "image/png";
54         final long duration = 1000;
55         final Cursor cursor = generateCursorForItem(id, mimeType, dateTaken, generationModified,
56                 duration, _SPECIAL_FORMAT_NONE);
57         cursor.moveToFirst();
58 
59         final Item item = new Item(cursor, UserId.CURRENT_USER);
60 
61         assertThat(item.getId()).isEqualTo(id);
62         assertThat(item.getDateTaken()).isEqualTo(dateTaken);
63         assertThat(item.getGenerationModified()).isEqualTo(generationModified);
64         assertThat(item.getMimeType()).isEqualTo(mimeType);
65         assertThat(item.getDuration()).isEqualTo(duration);
66         assertThat(item.getContentUri()).isEqualTo(
67                 Uri.parse("content://com.android.providers.media.photopicker/media/1"));
68 
69         assertThat(item.isDate()).isFalse();
70         assertThat(item.isImage()).isTrue();
71         assertThat(item.isVideo()).isFalse();
72         assertThat(item.isGifOrAnimatedWebp()).isFalse();
73         assertThat(item.isMotionPhoto()).isFalse();
74     }
75 
76     @Test
testConstructor_differentUser()77     public void testConstructor_differentUser() {
78         final String id = "1";
79         final long dateTaken = 12345678L;
80         final long generationModified = 1L;
81         final String mimeType = "image/png";
82         final long duration = 1000;
83         final Cursor cursor = generateCursorForItem(id, mimeType, dateTaken, generationModified,
84                 duration, _SPECIAL_FORMAT_NONE);
85         cursor.moveToFirst();
86         final UserId userId = UserId.of(UserHandle.of(10));
87 
88         final Item item = new Item(cursor, userId);
89 
90         assertThat(item.getId()).isEqualTo(id);
91         assertThat(item.getDateTaken()).isEqualTo(dateTaken);
92         assertThat(item.getGenerationModified()).isEqualTo(generationModified);
93         assertThat(item.getMimeType()).isEqualTo(mimeType);
94         assertThat(item.getDuration()).isEqualTo(duration);
95         assertThat(item.getContentUri()).isEqualTo(
96                 Uri.parse("content://10@com.android.providers.media.photopicker/media/1"));
97 
98         assertThat(item.isImage()).isTrue();
99 
100         assertThat(item.isDate()).isFalse();
101         assertThat(item.isVideo()).isFalse();
102         assertThat(item.isGifOrAnimatedWebp()).isFalse();
103         assertThat(item.isMotionPhoto()).isFalse();
104     }
105 
106     @Test
testIsImage()107     public void testIsImage() {
108         final String id = "1";
109         final long dateTaken = 12345678L;
110         final long generationModified = 1L;
111         final String mimeType = "image/png";
112         final long duration = 1000;
113         final Item item = generateItem(id, mimeType, dateTaken, generationModified, duration);
114 
115         assertThat(item.isImage()).isTrue();
116 
117         assertThat(item.isDate()).isFalse();
118         assertThat(item.isVideo()).isFalse();
119         assertThat(item.isGifOrAnimatedWebp()).isFalse();
120         assertThat(item.isMotionPhoto()).isFalse();
121     }
122 
123     @Test
testIsVideo()124     public void testIsVideo() {
125         final String id = "1";
126         final long dateTaken = 12345678L;
127         final long generationModified = 1L;
128         final String mimeType = "video/mpeg";
129         final long duration = 1000;
130         final Item item = generateItem(id, mimeType, dateTaken, generationModified, duration);
131 
132         assertThat(item.isVideo()).isTrue();
133 
134         assertThat(item.isDate()).isFalse();
135         assertThat(item.isImage()).isFalse();
136         assertThat(item.isGifOrAnimatedWebp()).isFalse();
137         assertThat(item.isMotionPhoto()).isFalse();
138     }
139 
140     @Test
testIsMotionPhoto()141     public void testIsMotionPhoto() {
142         final String id = "1";
143         final long dateTaken = 12345678L;
144         final long generationModified = 1L;
145         final String mimeType = "image/jpeg";
146         final long duration = 1000;
147         final Item item = generateSpecialFormatItem(id, mimeType, dateTaken, generationModified,
148                 duration, _SPECIAL_FORMAT_MOTION_PHOTO);
149 
150         assertThat(item.isMotionPhoto()).isTrue();
151         assertThat(item.isImage()).isTrue();
152 
153         assertThat(item.isGifOrAnimatedWebp()).isFalse();
154         assertThat(item.isDate()).isFalse();
155         assertThat(item.isVideo()).isFalse();
156     }
157 
158     @Test
testIsGifOrAnimatedWebp()159     public void testIsGifOrAnimatedWebp() {
160         final String id = "1";
161         final long dateTaken = 12345678L;
162         final long generationModified = 1L;
163         final String mimeType = "image/jpeg";
164         final long duration = 1000;
165         final Item gifItem = generateSpecialFormatItem(id, mimeType, dateTaken, generationModified,
166                 duration, _SPECIAL_FORMAT_GIF);
167 
168         assertThat(gifItem.isGifOrAnimatedWebp()).isTrue();
169         assertThat(gifItem.isGif()).isTrue();
170         assertThat(gifItem.isImage()).isTrue();
171 
172         assertThat(gifItem.isAnimatedWebp()).isFalse();
173         assertThat(gifItem.isDate()).isFalse();
174         assertThat(gifItem.isVideo()).isFalse();
175 
176         final Item animatedWebpItem = generateSpecialFormatItem(id, mimeType, dateTaken,
177                 generationModified, duration, _SPECIAL_FORMAT_ANIMATED_WEBP);
178 
179         assertThat(animatedWebpItem.isGifOrAnimatedWebp()).isTrue();
180         assertThat(animatedWebpItem.isAnimatedWebp()).isTrue();
181         assertThat(animatedWebpItem.isImage()).isTrue();
182 
183         assertThat(animatedWebpItem.isGif()).isFalse();
184         assertThat(animatedWebpItem.isDate()).isFalse();
185         assertThat(animatedWebpItem.isVideo()).isFalse();
186     }
187 
188     @Test
testIsGifDoesNotUseMimeType()189     public void testIsGifDoesNotUseMimeType() {
190         final String id = "1";
191         final long dateTaken = 12345678L;
192         final long generationModified = 1L;
193         final String mimeType = "image/gif";
194         final long duration = 1000;
195         final Item item = generateSpecialFormatItem(id, mimeType, dateTaken, generationModified,
196                 duration, _SPECIAL_FORMAT_NONE);
197 
198         assertThat(item.isImage()).isTrue();
199 
200         assertThat(item.isGifOrAnimatedWebp()).isFalse();
201         assertThat(item.isDate()).isFalse();
202         assertThat(item.isVideo()).isFalse();
203         assertThat(item.isMotionPhoto()).isFalse();
204     }
205 
206     @Test
testCreateDateItem()207     public void testCreateDateItem() {
208         final long dateTaken = 12345678L;
209 
210         final Item item = Item.createDateItem(dateTaken);
211 
212         assertThat(item.getDateTaken()).isEqualTo(dateTaken);
213         assertThat(item.isDate()).isTrue();
214     }
215 
216     @Test
testCompareTo_differentDateTaken()217     public void testCompareTo_differentDateTaken() {
218         final String id1 = "1";
219         final long dateTaken1 = 1000000L;
220         final long generationModified1 = 1L;
221         final Item item1 = generateJpegItem(id1, dateTaken1, generationModified1);
222 
223         final String id2 = "2";
224         final long dateTaken2 = 20000000L;
225         final long generationModified2 = 2L;
226         final Item item2 = generateJpegItem(id2, dateTaken2, generationModified2);
227 
228         assertThat(item1.compareTo(item2)).isEqualTo(-1);
229         assertThat(item2.compareTo(item1)).isEqualTo(1);
230     }
231 
232     @Test
testCompareTo_sameDateTaken()233     public void testCompareTo_sameDateTaken() {
234         final long dateTaken = 12345678L;
235         final long generationModified = 1L;
236 
237         final String id1 = "1";
238         final Item item1 = generateJpegItem(id1, dateTaken, generationModified);
239 
240         final String id2 = "2";
241         final Item item2 = generateJpegItem(id2, dateTaken, generationModified);
242 
243         assertThat(item1.compareTo(item2)).isEqualTo(-1);
244         assertThat(item2.compareTo(item1)).isEqualTo(1);
245 
246         // Compare the same object
247         assertThat(item2.compareTo(item2)).isEqualTo(0);
248 
249         // Compare two items with same dateTaken and same id. This will never happen in real world
250         // use-case because ids are always unique.
251         final Item item2SameValues = generateJpegItem(id2, dateTaken, generationModified);
252         assertThat(item2SameValues.compareTo(item2)).isEqualTo(0);
253     }
254 
255     @Test
testGetContentDescription()256     public void testGetContentDescription() {
257         final String id = "1";
258         final long dateTaken = LocalDate.of(2020 /* year */, 7 /* month */, 7 /* dayOfMonth */)
259                 .atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
260         final long generationModified = 1L;
261         final long duration = 1000;
262         final Context context = InstrumentationRegistry.getTargetContext();
263 
264         Item item = generateItem(id, "image/jpeg", dateTaken, generationModified, duration);
265         assertThat(item.getContentDescription(context))
266                 .isEqualTo("Photo taken on Jul 7, 2020, 12:00:00 AM");
267 
268         item = generateItem(id, "video/mp4", dateTaken, generationModified, duration);
269         assertThat(item.getContentDescription(context)).isEqualTo(
270                 "Video taken on Jul 7, 2020, 12:00:00 AM with duration " + item.getDurationText());
271 
272         item = generateSpecialFormatItem(id, "image/gif", dateTaken, generationModified, duration,
273                 _SPECIAL_FORMAT_GIF);
274         assertThat(item.getContentDescription(context))
275                 .isEqualTo("GIF taken on Jul 7, 2020, 12:00:00 AM");
276 
277         item = generateSpecialFormatItem(id, "image/webp", dateTaken, generationModified, duration,
278                 _SPECIAL_FORMAT_ANIMATED_WEBP);
279         assertThat(item.getContentDescription(context))
280                 .isEqualTo("GIF taken on Jul 7, 2020, 12:00:00 AM");
281 
282         item = generateSpecialFormatItem(id, "image/jpeg", dateTaken, generationModified, duration,
283                 _SPECIAL_FORMAT_MOTION_PHOTO);
284         assertThat(item.getContentDescription(context))
285                 .isEqualTo("Motion Photo taken on Jul 7, 2020, 12:00:00 AM");
286     }
287 
288     @Test
testGetDurationText()289     public void testGetDurationText() {
290         final String id = "1";
291         final long dateTaken = LocalDate.of(2020 /* year */, 7 /* month */, 7 /* dayOfMonth */)
292                 .atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
293         final long generationModified = 1L;
294 
295         // no duration
296         Item item = generateItem(id, "video", dateTaken, generationModified, -1);
297         assertThat(item.getDurationText()).isEqualTo("");
298 
299         // duration = 1000 ms
300         item = generateItem(id, "video", dateTaken, generationModified, 1000);
301         assertThat(item.getDurationText()).isEqualTo("00:01");
302 
303         // duration = 10000 ms
304         item = generateItem(id, "video", dateTaken, generationModified, 10000);
305         assertThat(item.getDurationText()).isEqualTo("00:10");
306 
307         // duration = 60000 ms
308         item = generateItem(id, "video", dateTaken, generationModified, 60000);
309         assertThat(item.getDurationText()).isEqualTo("01:00");
310 
311         // duration = 600000 ms
312         item = generateItem(id, "video", dateTaken, generationModified, 600000);
313         assertThat(item.getDurationText()).isEqualTo("10:00");
314     }
315 
generateCursorForItem(String id, String mimeType, long dateTaken, long generationModified, long duration, int specialFormat)316     private static Cursor generateCursorForItem(String id, String mimeType, long dateTaken,
317             long generationModified, long duration, int specialFormat) {
318         final MatrixCursor cursor = new MatrixCursor(MediaColumns.ALL_PROJECTION);
319         cursor.addRow(new Object[] {
320                     id,
321                     dateTaken,
322                     generationModified,
323                     mimeType,
324                     specialFormat,
325                     "1", // size_bytes
326                     null, // media_store_uri
327                     duration,
328                     "0", // is_favorite
329                     "/storage/emulated/0/foo", // data
330                     PickerSyncController.LOCAL_PICKER_PROVIDER_AUTHORITY});
331         return cursor;
332     }
333 
generateJpegItem(String id, long dateTaken, long generationModified)334     private static Item generateJpegItem(String id, long dateTaken, long generationModified) {
335         final String mimeType = "image/jpeg";
336         final long duration = 1000;
337         return generateItem(id, mimeType, dateTaken, generationModified, duration);
338     }
339 
340     /**
341      * Generate the {@link Item}
342      * @param id the id
343      * @param mimeType the mime type
344      * @param dateTaken the time of date taken
345      * @param generationModified the generation number associated with the media
346      * @param duration the duration
347      * @return the Item
348      */
generateItem(String id, String mimeType, long dateTaken, long generationModified, long duration)349     public static Item generateItem(String id, String mimeType, long dateTaken,
350             long generationModified, long duration) {
351         return new Item(id, mimeType, dateTaken, generationModified, duration,
352                 MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL, Long.parseLong(id)),
353                 _SPECIAL_FORMAT_NONE);
354     }
355 
356     /**
357      * Generate the {@link Item}
358      * @param id the id
359      * @param mimeType the mime type
360      * @param dateTaken the time of date taken
361      * @param generationModified the generation number associated with the media
362      * @param duration the duration
363      * @param specialFormat the special format. See
364      * {@link MediaStore.Files.FileColumns#_SPECIAL_FORMAT}
365      * @return the Item
366      */
generateSpecialFormatItem(String id, String mimeType, long dateTaken, long generationModified, long duration, int specialFormat)367     public static Item generateSpecialFormatItem(String id, String mimeType, long dateTaken,
368             long generationModified, long duration, int specialFormat) {
369         return new Item(id, mimeType, dateTaken, generationModified, duration,
370                 MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL, Long.parseLong(id)),
371                 specialFormat);
372     }
373 }
374