1 /*
2  * Copyright (C) 2009 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 android.provider.cts.media;
18 
19 import static android.provider.cts.media.MediaStoreTest.TAG;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertNotEquals;
23 import static org.junit.Assert.assertNotNull;
24 import static org.junit.Assert.assertTrue;
25 
26 import android.content.ContentResolver;
27 import android.content.ContentValues;
28 import android.content.Context;
29 import android.database.Cursor;
30 import android.net.Uri;
31 import android.os.Build;
32 import android.provider.MediaStore;
33 import android.provider.MediaStore.Audio.Playlists;
34 import android.provider.MediaStore.MediaColumns;
35 import android.util.Log;
36 
37 import androidx.test.InstrumentationRegistry;
38 import androidx.test.filters.SdkSuppress;
39 
40 import org.junit.Before;
41 import org.junit.Test;
42 import org.junit.runner.RunWith;
43 import org.junit.runners.Parameterized;
44 import org.junit.runners.Parameterized.Parameter;
45 import org.junit.runners.Parameterized.Parameters;
46 
47 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
48 @RunWith(Parameterized.class)
49 public class MediaStore_Audio_PlaylistsTest {
50     private Context mContext;
51     private ContentResolver mContentResolver;
52 
53     @Parameter(0)
54     public String mVolumeName;
55 
56     @Parameters
data()57     public static Iterable<? extends Object> data() {
58         return MediaProviderTestUtils.getSharedVolumeNames();
59     }
60 
61     @Before
setUp()62     public void setUp() throws Exception {
63         mContext = InstrumentationRegistry.getTargetContext();
64         mContentResolver = mContext.getContentResolver();
65 
66         Log.d(TAG, "Using volume " + mVolumeName);
67     }
68 
69     @Test
testGetContentUri()70     public void testGetContentUri() {
71         Cursor c = null;
72         assertNotNull(c = mContentResolver.query(
73                 Playlists.getContentUri(mVolumeName), null, null,
74                 null, null));
75         c.close();
76     }
77 
78     @Test
testStoreAudioPlaylistsExternal()79     public void testStoreAudioPlaylistsExternal() throws Exception {
80         ContentValues values = new ContentValues();
81         values.put(Playlists.NAME, "My favourites " + System.nanoTime());
82         long dateAdded = System.currentTimeMillis() / 1000;
83         long dateModified = System.currentTimeMillis() / 1000;
84         values.put(Playlists.DATE_MODIFIED, dateModified);
85         // insert
86         Uri uri = mContentResolver.insert(Playlists.getContentUri(mVolumeName), values);
87         assertNotNull(uri);
88 
89         try {
90             // query
91             Cursor c = mContentResolver.query(uri, null, null, null, null);
92             assertEquals(1, c.getCount());
93             c.moveToFirst();
94             assertEquals(values.getAsString(Playlists.NAME),
95                     c.getString(c.getColumnIndex(Playlists.NAME)));
96 
97             long realDateAdded = c.getLong(c.getColumnIndex(Playlists.DATE_ADDED));
98             long realDateModified = c.getLong(c.getColumnIndex(Playlists.DATE_MODIFIED));
99             assertTrue(realDateAdded >= dateAdded);
100             // Sometimes the realDateModified is less than dateModified by exactly one second.
101             // We've never seen any real issues with that and now the Playlists are deprecated.
102             // Just changing the test to remove flakiness.
103             assertTrue(Math.abs(dateModified - realDateModified) <= 1);
104             assertTrue(c.getLong(c.getColumnIndex(Playlists._ID)) > 0);
105             c.close();
106         } finally {
107             assertEquals(1, mContentResolver.delete(uri, null, null));
108         }
109     }
110 
111     /**
112      * Verify that creating playlists using only {@link Playlists#NAME} defined
113      * will flow into the {@link MediaColumns#DISPLAY_NAME}, both during initial
114      * insert and subsequent updates.
115      */
116     @Test
testName()117     public void testName() throws Exception {
118         final String name1 = "Playlist " + System.nanoTime();
119         final String name2 = "Playlist " + System.nanoTime();
120         assertNotEquals(name1, name2);
121 
122         final ContentValues values = new ContentValues();
123         values.clear();
124         values.put(Playlists.NAME, name1);
125         final Uri playlist = mContentResolver
126                 .insert(MediaStore.Audio.Playlists.getContentUri(mVolumeName), values);
127         MediaStore.waitForIdle(mContentResolver);
128         try (Cursor c = mContentResolver.query(playlist,
129                 new String[] { Playlists.NAME, MediaColumns.DISPLAY_NAME }, null, null)) {
130             assertTrue(c.moveToFirst());
131             assertTrue(c.getString(0).startsWith(name1));
132             assertTrue(c.getString(1).startsWith(name1));
133         }
134 
135         values.clear();
136         values.put(Playlists.NAME, name2);
137         mContentResolver.update(playlist, values, null);
138         MediaStore.waitForIdle(mContentResolver);
139         try (Cursor c = mContentResolver.query(playlist,
140                 new String[] { Playlists.NAME, MediaColumns.DISPLAY_NAME }, null, null)) {
141             assertTrue(c.moveToFirst());
142             assertTrue(c.getString(0).startsWith(name2));
143             assertTrue(c.getString(1).startsWith(name2));
144         }
145     }
146 }
147