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; 18 19 20 import android.content.ContentResolver; 21 import android.content.ContentValues; 22 import android.database.Cursor; 23 import android.database.SQLException; 24 import android.net.Uri; 25 import android.provider.MediaStore.Audio.Genres; 26 import android.provider.MediaStore.Audio.Media; 27 import android.provider.MediaStore.Audio.Genres.Members; 28 import android.provider.cts.MediaStoreAudioTestHelper.Audio1; 29 import android.provider.cts.MediaStoreAudioTestHelper.Audio2; 30 import android.test.InstrumentationTestCase; 31 32 public class MediaStore_Audio_Genres_MembersTest extends InstrumentationTestCase { 33 private ContentResolver mContentResolver; 34 35 private long mAudioIdOfJam; 36 37 private long mAudioIdOfJamLive; 38 39 @Override 40 protected void setUp() throws Exception { 41 super.setUp(); 42 43 mContentResolver = getInstrumentation().getContext().getContentResolver(); 44 Uri uri = Audio1.getInstance().insertToExternal(mContentResolver); 45 Cursor c = mContentResolver.query(uri, null, null, null, null); 46 c.moveToFirst(); 47 mAudioIdOfJam = c.getLong(c.getColumnIndex(Media._ID)); 48 c.close(); 49 50 uri = Audio2.getInstance().insertToExternal(mContentResolver); 51 c = mContentResolver.query(uri, null, null, null, null); 52 c.moveToFirst(); 53 mAudioIdOfJamLive = c.getLong(c.getColumnIndex(Media._ID)); 54 c.close(); 55 } 56 57 @Override 58 protected void tearDown() throws Exception { 59 // "jam" should already have been deleted as part of the test, but delete it again just 60 // in case the test failed and aborted before that. 61 mContentResolver.delete(Media.EXTERNAL_CONTENT_URI, Media._ID + "=" + mAudioIdOfJam, null); 62 mContentResolver.delete(Media.EXTERNAL_CONTENT_URI, Media._ID + "=" + mAudioIdOfJamLive, 63 null); 64 super.tearDown(); 65 } 66 67 public void testGetContentUri() { 68 Cursor c = null; 69 assertNotNull(c = mContentResolver.query( 70 Members.getContentUri(MediaStoreAudioTestHelper.EXTERNAL_VOLUME_NAME, 1), null, 71 null, null, null)); 72 c.close(); 73 74 try { 75 assertNotNull(c = mContentResolver.query( 76 Members.getContentUri(MediaStoreAudioTestHelper.INTERNAL_VOLUME_NAME, 1), null, 77 null, null, null)); 78 c.close(); 79 fail("Should throw SQLException as the internal datatbase has no genre"); 80 } catch (SQLException e) { 81 // expected 82 } 83 84 // can not accept any other volume names 85 String volume = "fakeVolume"; 86 assertNull(mContentResolver.query(Members.getContentUri(volume, 1), null, null, null, 87 null)); 88 } 89 90 public void testStoreAudioGenresMembersExternal() { 91 ContentValues values = new ContentValues(); 92 values.put(Genres.NAME, Audio1.GENRE); 93 Uri uri = mContentResolver.insert(Genres.EXTERNAL_CONTENT_URI, values); 94 Cursor c = mContentResolver.query(uri, null, null, null, null); 95 c.moveToFirst(); 96 97 long genreId = c.getLong(c.getColumnIndex(Genres._ID)); 98 long genre2Id = -1; // used later 99 c.close(); 100 101 // verify that the Uri has the correct format and genre value 102 assertEquals(uri.toString(), "content://media/external/audio/genres/" + genreId); 103 104 // insert audio as the member of the genre 105 values.clear(); 106 values.put(Members.AUDIO_ID, mAudioIdOfJam); 107 Uri membersUri = Members.getContentUri(MediaStoreAudioTestHelper.EXTERNAL_VOLUME_NAME, 108 genreId); 109 assertNotNull(mContentResolver.insert(membersUri, values)); 110 111 try { 112 // query, slow path 113 c = mContentResolver.query(membersUri, null, null, null, null); 114 115 assertEquals(1, c.getCount()); 116 c.moveToFirst(); 117 118 assertEquals(mAudioIdOfJam, c.getLong(c.getColumnIndex(Members.AUDIO_ID))); 119 assertEquals(genreId, c.getLong(c.getColumnIndex(Members.GENRE_ID))); 120 assertEquals(mAudioIdOfJam, c.getLong(c.getColumnIndex(Members._ID))); 121 assertEquals(Audio1.EXTERNAL_DATA, c.getString(c.getColumnIndex(Members.DATA))); 122 assertTrue(c.getLong(c.getColumnIndex(Members.DATE_ADDED)) > 0); 123 assertEquals(Audio1.DATE_MODIFIED, c.getLong(c.getColumnIndex(Members.DATE_MODIFIED))); 124 assertEquals(Audio1.FILE_NAME, c.getString(c.getColumnIndex(Members.DISPLAY_NAME))); 125 assertEquals(Audio1.MIME_TYPE, c.getString(c.getColumnIndex(Members.MIME_TYPE))); 126 assertEquals(Audio1.SIZE, c.getInt(c.getColumnIndex(Members.SIZE))); 127 assertEquals(Audio1.TITLE, c.getString(c.getColumnIndex(Members.TITLE))); 128 assertEquals(Audio1.ALBUM, c.getString(c.getColumnIndex(Members.ALBUM))); 129 assertEquals(Audio1.IS_DRM, c.getInt(c.getColumnIndex(Members.IS_DRM))); 130 String albumKey = c.getString(c.getColumnIndex(Members.ALBUM_KEY)); 131 assertNotNull(albumKey); 132 long albumId = c.getLong(c.getColumnIndex(Members.ALBUM_ID)); 133 assertTrue(albumId > 0); 134 assertEquals(Audio1.ARTIST, c.getString(c.getColumnIndex(Members.ARTIST))); 135 String artistKey = c.getString(c.getColumnIndex(Members.ARTIST_KEY)); 136 assertNotNull(artistKey); 137 long artistId = c.getLong(c.getColumnIndex(Members.ARTIST_ID)); 138 assertTrue(artistId > 0); 139 assertEquals(Audio1.COMPOSER, c.getString(c.getColumnIndex(Members.COMPOSER))); 140 assertEquals(Audio1.DURATION, c.getLong(c.getColumnIndex(Members.DURATION))); 141 assertEquals(Audio1.IS_ALARM, c.getInt(c.getColumnIndex(Members.IS_ALARM))); 142 assertEquals(Audio1.IS_MUSIC, c.getInt(c.getColumnIndex(Members.IS_MUSIC))); 143 assertEquals(Audio1.IS_NOTIFICATION, 144 c.getInt(c.getColumnIndex(Members.IS_NOTIFICATION))); 145 assertEquals(Audio1.IS_RINGTONE, c.getInt(c.getColumnIndex(Members.IS_RINGTONE))); 146 assertEquals(Audio1.TRACK, c.getInt(c.getColumnIndex(Members.TRACK))); 147 assertEquals(Audio1.YEAR, c.getInt(c.getColumnIndex(Members.YEAR))); 148 String titleKey = c.getString(c.getColumnIndex(Members.TITLE_KEY)); 149 assertNotNull(titleKey); 150 c.close(); 151 152 // query again, fast path 153 c = mContentResolver.query(membersUri, 154 new String[] { Members.AUDIO_ID, Members.GENRE_ID}, 155 null, null, null); 156 assertEquals(1, c.getCount()); 157 c.moveToFirst(); 158 assertEquals(mAudioIdOfJam, c.getLong(c.getColumnIndex(Members.AUDIO_ID))); 159 assertEquals(genreId, c.getLong(c.getColumnIndex(Members.GENRE_ID))); 160 c.close(); 161 162 // Query with a constraint on _id. Note that _id corresponds to the _id 163 // column in the audio table, not the one in the audio_genres_map table. 164 // We need to preserve this behavior for backward compatibility. 165 c = mContentResolver.query(membersUri, null, 166 Members._ID + "=?", new String[] {Long.toString(mAudioIdOfJam)}, null); 167 assertEquals(1, c.getCount()); 168 c.moveToFirst(); 169 assertEquals(mAudioIdOfJam, c.getLong(c.getColumnIndex(Members._ID))); 170 c.close(); 171 172 // Query members across all genres 173 Uri allMembersUri = Uri.parse("content://media/external/audio/genres/all/members"); 174 c = mContentResolver.query(allMembersUri, null, null, null, null); 175 int colidx = c.getColumnIndex(Members.AUDIO_ID); 176 int jamcnt = 0; 177 // The song should appear only once, for the genre we used when inserting it 178 while(c.moveToNext()) { 179 if (c.getLong(colidx) == mAudioIdOfJam) { 180 jamcnt++; 181 assertEquals(genreId, c.getLong(c.getColumnIndex(Members.GENRE_ID))); 182 } 183 } 184 assertEquals(1, jamcnt); 185 c.close(); 186 187 // Query the same Uri, but add a where clause to restrict it to the one entry we added 188 c = mContentResolver.query(allMembersUri, null, 189 Members.AUDIO_ID + "=?", new String[] {Long.toString(mAudioIdOfJam)}, null); 190 assertEquals(1, c.getCount()); 191 c.moveToFirst(); 192 assertEquals(genreId, c.getLong(c.getColumnIndex(Members.GENRE_ID))); 193 assertEquals(mAudioIdOfJam, c.getLong(c.getColumnIndex(Members.AUDIO_ID))); 194 c.close(); 195 196 // create another genre 197 values.clear(); 198 values.put(Genres.NAME, Audio1.GENRE + "-2"); 199 uri = mContentResolver.insert(Genres.EXTERNAL_CONTENT_URI, values); 200 c = mContentResolver.query(uri, null, null, null, null); 201 c.moveToFirst(); 202 genre2Id = c.getLong(c.getColumnIndex(Genres._ID)); 203 c.close(); 204 205 // insert the song into the second genre 206 values.clear(); 207 values.put(Members.AUDIO_ID, mAudioIdOfJam); 208 Uri members2Uri = Members.getContentUri(MediaStoreAudioTestHelper.EXTERNAL_VOLUME_NAME, 209 genre2Id); 210 assertNotNull(mContentResolver.insert(members2Uri, values)); 211 212 // Query members across all genres again 213 c = mContentResolver.query(allMembersUri, null, null, null, null); 214 colidx = c.getColumnIndex(Members.AUDIO_ID); 215 int jamcnt1 = 0; 216 int jamcnt2 = 0; 217 // This time the song should appear twice, once for each genre 218 while(c.moveToNext()) { 219 if (c.getLong(colidx) == mAudioIdOfJam) { 220 long g = c.getLong(c.getColumnIndex(Members.GENRE_ID)); 221 if (g == genreId) { 222 jamcnt1++; 223 } else if (g == genre2Id) { 224 jamcnt2++; 225 } else { 226 fail("wrong genre found"); 227 } 228 } 229 } 230 assertEquals(1, jamcnt1); 231 assertEquals(1, jamcnt2); 232 c.close(); 233 234 235 // update the member 236 values.clear(); 237 values.put(Members.AUDIO_ID, mAudioIdOfJamLive); 238 try { 239 mContentResolver.update(membersUri, values, null, null); 240 fail("Should throw SQLException because there is no column with name " 241 + "\"Members.AUDIO_ID\" in the table"); 242 } catch (SQLException e) { 243 // expected 244 } 245 246 // Delete the members, note that this does not delete the genre itself 247 assertEquals(1, mContentResolver.delete(membersUri, null, null)); // check number of rows deleted 248 249 // verify the genre is now empty 250 c = mContentResolver.query(membersUri, null, null, null, null); 251 assertEquals(0, c.getCount()); 252 c.close(); 253 254 // same for 2nd genre 255 assertEquals(1, mContentResolver.delete(members2Uri, null, null)); 256 c = mContentResolver.query(members2Uri, null, null, null, null); 257 assertEquals(0, c.getCount()); 258 c.close(); 259 260 // insert again, then verify that deleting the audio entry cleans up its genre member 261 // entry as well 262 values.put(Members.AUDIO_ID, mAudioIdOfJam); 263 membersUri = Members.getContentUri(MediaStoreAudioTestHelper.EXTERNAL_VOLUME_NAME, 264 genreId); 265 assertNotNull(mContentResolver.insert(membersUri, values)); 266 // Query members across all genres 267 c = mContentResolver.query(allMembersUri, 268 new String[] { Members.AUDIO_ID, Members.GENRE_ID}, null, null, null); 269 colidx = c.getColumnIndex(Members.AUDIO_ID); 270 jamcnt = 0; 271 // The song should appear only once, for the genre we used when inserting it 272 while(c.moveToNext()) { 273 if (c.getLong(colidx) == mAudioIdOfJam) { 274 jamcnt++; 275 assertEquals(genreId, c.getLong(c.getColumnIndex(Members.GENRE_ID))); 276 } 277 } 278 assertEquals(1, jamcnt); 279 c.close(); 280 mContentResolver.delete(Media.EXTERNAL_CONTENT_URI, 281 Media._ID + "=" + mAudioIdOfJam, null); 282 // Query members across all genres 283 c = mContentResolver.query(allMembersUri, 284 new String[] { Members.AUDIO_ID, Members.GENRE_ID}, null, null, null); 285 colidx = c.getColumnIndex(Members.AUDIO_ID); 286 jamcnt = 0; 287 // The song should no longer appear in the genre 288 while(c.moveToNext()) { 289 if (c.getLong(colidx) == mAudioIdOfJam) { 290 jamcnt++; 291 } 292 } 293 assertEquals(0, jamcnt); 294 c.close(); 295 } finally { 296 // the members are deleted when deleting the genre which they belong to 297 mContentResolver.delete(Genres.EXTERNAL_CONTENT_URI, Genres._ID + "=" + genreId, null); 298 if (genre2Id >= 0) { 299 mContentResolver.delete(Genres.EXTERNAL_CONTENT_URI, Genres._ID + "=" + genre2Id, null); 300 } 301 c = mContentResolver.query(membersUri, null, null, null, null); 302 assertEquals(0, c.getCount()); 303 c.close(); 304 } 305 } 306 307 public void testStoreAudioGenresMembersInternal() { 308 // the internal database can not have genres 309 ContentValues values = new ContentValues(); 310 values.put(Genres.NAME, Audio1.GENRE); 311 Uri uri = mContentResolver.insert(Genres.INTERNAL_CONTENT_URI, values); 312 assertNull(uri); 313 } 314 } 315