Unittest/mediaprovider (#251)

Implemented integration tests for music items
This commit is contained in:
Martijn Brekhof 2016-09-23 20:08:22 +02:00 committed by Synced Synapse
parent d746f6643f
commit 080b5809f3
18 changed files with 1229 additions and 158 deletions

View File

@ -30,6 +30,7 @@ import org.xbmc.kore.jsonrpc.type.LibraryType;
import org.xbmc.kore.jsonrpc.type.VideoType;
import org.xbmc.kore.provider.MediaContract;
import org.xbmc.kore.provider.MediaProvider;
import org.xbmc.kore.service.library.SyncMusic;
import org.xbmc.kore.service.library.SyncUtils;
import org.xbmc.kore.utils.LogUtils;
@ -45,12 +46,12 @@ public class Database {
mediaProvider.onCreate();
HostInfo hostInfo = addHost(context);
SyncMusic syncMusic = new SyncMusic(hostInfo.getId(), null);
insertMovies(context, hostInfo.getId());
insertArtists(context, hostInfo.getId());
insertGenres(context, hostInfo.getId());
insertAlbums(context, hostInfo.getId());
insertSongs(context, hostInfo.getId());
insertArtists(context, syncMusic);
insertGenres(context, syncMusic);
insertAlbums(context, syncMusic);
insertSongs(context, syncMusic);
return hostInfo;
}
@ -96,86 +97,34 @@ public class Database {
context.getContentResolver().bulkInsert(MediaContract.MovieCast.CONTENT_URI, movieCastValuesBatch);
}
private static void insertArtists(Context context, int hostId) throws ApiException, IOException {
private static void insertArtists(Context context, SyncMusic syncMusic) throws ApiException, IOException {
AudioLibrary.GetArtists getArtists = new AudioLibrary.GetArtists(false);
String result = Utils.readFile(context, "AudioLibrary.GetArtists.json");
ArrayList<AudioType.DetailsArtist> artistList = (ArrayList) getArtists.resultFromJson(result).items;
ContentValues artistValuesBatch[] = new ContentValues[artistList.size()];
for (int i = 0; i < artistList.size(); i++) {
AudioType.DetailsArtist artist = artistList.get(i);
artistValuesBatch[i] = SyncUtils.contentValuesFromArtist(hostId, artist);
}
context.getContentResolver().bulkInsert(MediaContract.Artists.CONTENT_URI, artistValuesBatch);
syncMusic.insertArtists(artistList, context.getContentResolver());
}
private static void insertGenres(Context context, int hostId) throws ApiException, IOException {
private static void insertGenres(Context context, SyncMusic syncMusic) throws ApiException, IOException {
AudioLibrary.GetGenres getGenres = new AudioLibrary.GetGenres();
ArrayList<LibraryType.DetailsGenre> genreList = (ArrayList) getGenres.resultFromJson(Utils.readFile(context, "AudioLibrary.GetGenres.json"));
ContentValues genresValuesBatch[] = new ContentValues[genreList.size()];
for (int i = 0; i < genreList.size(); i++) {
LibraryType.DetailsGenre genre = genreList.get(i);
genresValuesBatch[i] = SyncUtils.contentValuesFromAudioGenre(hostId, genre);
}
context.getContentResolver().bulkInsert(MediaContract.AudioGenres.CONTENT_URI, genresValuesBatch);
syncMusic.insertGenresItems(genreList, context.getContentResolver());
}
private static void insertAlbums(Context context, int hostId) throws ApiException, IOException {
private static void insertAlbums(Context context, SyncMusic syncMusic) throws ApiException, IOException {
AudioLibrary.GetAlbums getAlbums = new AudioLibrary.GetAlbums();
String result = Utils.readFile(context, "AudioLibrary.GetAlbums.json");
ArrayList<AudioType.DetailsAlbum> albumList = (ArrayList) getAlbums.resultFromJson(result).items;
ContentResolver contentResolver = context.getContentResolver();
ContentValues albumValuesBatch[] = new ContentValues[albumList.size()];
int artistsCount = 0, genresCount = 0;
for (int i = 0; i < albumList.size(); i++) {
AudioType.DetailsAlbum album = albumList.get(i);
albumValuesBatch[i] = SyncUtils.contentValuesFromAlbum(hostId, album);
artistsCount += album.artistid.size();
genresCount += album.genreid.size();
}
contentResolver.bulkInsert(MediaContract.Albums.CONTENT_URI, albumValuesBatch);
// Iterate on each album, collect the artists and the genres and insert them
ContentValues albumArtistsValuesBatch[] = new ContentValues[artistsCount];
ContentValues albumGenresValuesBatch[] = new ContentValues[genresCount];
int artistCount = 0, genreCount = 0;
for (AudioType.DetailsAlbum album : albumList) {
for (int artistId : album.artistid) {
albumArtistsValuesBatch[artistCount] = new ContentValues();
albumArtistsValuesBatch[artistCount].put(MediaContract.AlbumArtists.HOST_ID, hostId);
albumArtistsValuesBatch[artistCount].put(MediaContract.AlbumArtists.ALBUMID, album.albumid);
albumArtistsValuesBatch[artistCount].put(MediaContract.AlbumArtists.ARTISTID, artistId);
artistCount++;
}
for (int genreId : album.genreid) {
albumGenresValuesBatch[genreCount] = new ContentValues();
albumGenresValuesBatch[genreCount].put(MediaContract.AlbumGenres.HOST_ID, hostId);
albumGenresValuesBatch[genreCount].put(MediaContract.AlbumGenres.ALBUMID, album.albumid);
albumGenresValuesBatch[genreCount].put(MediaContract.AlbumGenres.GENREID, genreId);
genreCount++;
}
}
contentResolver.bulkInsert(MediaContract.AlbumArtists.CONTENT_URI, albumArtistsValuesBatch);
contentResolver.bulkInsert(MediaContract.AlbumGenres.CONTENT_URI, albumGenresValuesBatch);
syncMusic.insertAlbumsItems(albumList, context.getContentResolver());
}
private static void insertSongs(Context context, int hostId) throws ApiException, IOException {
private static void insertSongs(Context context, SyncMusic syncMusic) throws ApiException, IOException {
AudioLibrary.GetSongs getSongs = new AudioLibrary.GetSongs();
ArrayList<AudioType.DetailsSong> songList = (ArrayList) getSongs.resultFromJson(Utils.readFile(context, "AudioLibrary.GetSongs.json")).items;
ArrayList<AudioType.DetailsSong> songList = (ArrayList)
getSongs.resultFromJson(Utils.readFile(context, "AudioLibrary.GetSongs.json")).items;
ContentValues songValuesBatch[] = new ContentValues[songList.size()];
for (int i = 0; i < songList.size(); i++) {
AudioType.DetailsSong song = songList.get(i);
songValuesBatch[i] = SyncUtils.contentValuesFromSong(hostId, song);
}
context.getContentResolver().bulkInsert(MediaContract.Songs.CONTENT_URI, songValuesBatch);
syncMusic.insertSongsItems(songList, context.getContentResolver());
}
}

View File

@ -0,0 +1,77 @@
/*
* Copyright 2016 Martijn Brekhof. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.xbmc.kore.testhelpers;
import android.database.Cursor;
import org.xbmc.kore.ui.SongsListFragment;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
public class TestUtils {
/**
* Tests if cursor contains all numbers from ids given column index.
* @param cursor
* @param columnIndex
* @param numbers
*/
public static void testCursorContainsNumbers(Cursor cursor, int columnIndex, int... numbers) {
HashMap<Integer, Boolean> idsFound = new HashMap<>();
for(int number : numbers) {
idsFound.put(number, false);
}
assertTrue(cursor.moveToFirst());
do {
idsFound.put(cursor.getInt(columnIndex), true);
} while(cursor.moveToNext());
for(Map.Entry<Integer, Boolean> entry : idsFound.entrySet() ) {
int key = entry.getKey();
assertTrue("Id " + key + " not found", entry.getValue());
}
}
/**
* Tests if cursor contains all numbers from start until end for given column index.
* @param columnIndex
* @param cursor
* @param start
* @param end
*/
public static void testCursorContainsRange(Cursor cursor, int columnIndex, int start, int end) {
HashMap<Integer, Boolean> idsFound = new HashMap<>();
for(int i = start; i <= end; i++) {
idsFound.put(i, false);
}
assertTrue(cursor.moveToFirst());
do {
idsFound.put(cursor.getInt(columnIndex), true);
} while(cursor.moveToNext());
for(Map.Entry<Integer, Boolean> entry : idsFound.entrySet() ) {
int key = entry.getKey();
assertTrue("Id " + key + " not found", entry.getValue());
}
}
}

View File

@ -18,6 +18,7 @@ package org.xbmc.kore.testhelpers;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.IBinder;
import android.support.test.rule.ActivityTestRule;
import android.support.v4.widget.DrawerLayout;
@ -92,6 +93,15 @@ public class Utils {
isInitialized = false;
}
public static String cursorToString(Cursor cursor) {
StringBuffer stringBuffer = new StringBuffer();
for (String name : cursor.getColumnNames()) {
int index = cursor.getColumnIndex(name);
stringBuffer.append(name + "=" + cursor.getString(index) + "\n");
}
return stringBuffer.toString();
}
private static void disableAnimations() {
int permStatus = context.checkCallingOrSelfPermission(ANIMATION_PERMISSION);
if (permStatus == PackageManager.PERMISSION_GRANTED) {
@ -127,4 +137,16 @@ public class Utils {
Log.e("SystemAnimations", "Could not change animation scale to " + animationScale + " :'(");
}
}
public static boolean moveCursorTo(Cursor cursor, int index, int item) {
if (( cursor == null ) || ( ! cursor.moveToFirst() ))
return false;
do {
if ( cursor.getInt(index) == item )
return true;
} while (cursor.moveToNext());
return false;
}
}

View File

@ -0,0 +1,335 @@
/*
* Copyright 2016 Martijn Brekhof. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.xbmc.kore.tests.mediaprovider;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.xbmc.kore.host.HostInfo;
import org.xbmc.kore.provider.MediaContract;
import org.xbmc.kore.testhelpers.Database;
import org.xbmc.kore.testhelpers.TestUtils;
import org.xbmc.kore.testhelpers.Utils;
import org.xbmc.kore.ui.MoviesActivity;
import org.xbmc.kore.utils.LogUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@RunWith(AndroidJUnit4.class)
public class MediaProviderMusicTest {
private static HostInfo hostInfo;
private static Context context;
private ContentResolver contentResolver;
/**
* Note that the activity MoviesActivity is only needed for context and is not tested
*/
@Rule
public ActivityTestRule<MoviesActivity> mActivityRule = new ActivityTestRule<>(
MoviesActivity.class);
@Before
public void setUp() throws Exception {
context = mActivityRule.getActivity();
if (hostInfo == null) // We only need to fill the database the first time
hostInfo = Database.fill(context);
contentResolver = mActivityRule.getActivity().getContentResolver();
}
@After
public void tearDown() throws Exception {
}
@AfterClass
public static void cleanup() {
Database.flush(context, hostInfo);
}
@Test
public void queryAllArtistsTest() {
Uri uri = MediaContract.Artists.buildArtistsListUri(hostInfo.getId());
Cursor cursor = contentResolver.query(uri, TestValues.Artist.PROJECTION, null, null, null);
assertNotNull(cursor);
assertEquals("cursor size ", 227, cursor.getCount());
TestUtils.testCursorContainsRange(cursor, cursor.getColumnIndex(MediaContract.ArtistsColumns.ARTISTID),
1, 94);
//Artist id 95 should be missing
TestUtils.testCursorContainsRange(cursor, cursor.getColumnIndex(MediaContract.ArtistsColumns.ARTISTID),
96, 228);
}
@Test
public void queryArtistTest() {
Uri uri = MediaContract.Artists.buildArtistUri(hostInfo.getId(), TestValues.Artist.artistId);
Cursor cursor = contentResolver.query(uri, TestValues.Artist.PROJECTION, null, null, null);
assertNotNull(cursor);
assertEquals("cursor size ", 1, cursor.getCount());
assertTrue(cursor.moveToFirst());
TestValues.Artist.test(cursor);
}
@Test
public void queryAllAlbumsTest() {
Uri uri = MediaContract.Albums.buildAlbumsListUri(hostInfo.getId());
Cursor cursor = contentResolver.query(uri, TestValues.Album.PROJECTION, null, null, null);
assertNotNull(cursor);
assertEquals("cursor size ", 232, cursor.getCount());
int columnIndex = cursor.getColumnIndex(MediaContract.AlbumsColumns.ALBUMID);
TestUtils.testCursorContainsRange(cursor, columnIndex, 1, 75);
TestUtils.testCursorContainsRange(cursor, columnIndex, 77, 82);
TestUtils.testCursorContainsRange(cursor, columnIndex, 84, 234);
}
@Test
public void queryAlbumTest() {
Uri uri = MediaContract.Albums.buildAlbumUri(hostInfo.getId(), TestValues.Album.albumId);
Cursor cursor = contentResolver.query(uri, TestValues.Album.PROJECTION, null, null, null);
assertNotNull(cursor);
assertEquals("cursor size ", 1, cursor.getCount());
assertTrue(cursor.moveToFirst());
TestValues.Album.test(cursor);
}
@Test
public void queryAlbumsForArtistTest() {
Uri uri = MediaContract.AlbumArtists.buildAlbumsForArtistListUri(hostInfo.getId(),
TestValues.Artist.artistId);
Cursor cursor = contentResolver.query(uri, TestValues.Album.PROJECTION, null, null, null);
assertNotNull(cursor);
assertEquals("cursor size ", 1, cursor.getCount());
assertTrue(cursor.moveToFirst());
TestValues.Album.test(cursor);
}
@Test
public void queryAlbumsForGenreTest() {
int genreId = 13;
Uri uri = MediaContract.AlbumGenres.buildAlbumsForGenreListUri(hostInfo.getId(), genreId);
Cursor cursor = contentResolver.query(uri, TestValues.Album.PROJECTION, null, null, null);
assertNotNull(cursor);
assertEquals("cursor size ", 31, cursor.getCount());
TestUtils.testCursorContainsNumbers(cursor, cursor.getColumnIndex(MediaContract.Albums.ALBUMID),
28, 43, 47, 66, 100);
TestUtils.testCursorContainsRange(cursor, cursor.getColumnIndex(MediaContract.Albums.ALBUMID),
50, 55);
TestUtils.testCursorContainsRange(cursor, cursor.getColumnIndex(MediaContract.Albums.ALBUMID),
201, 220);
}
@Test
public void queryAlbumSongsTest() {
Uri uri = MediaContract.Songs.buildAlbumSongsListUri(hostInfo.getId(), TestValues.Album.albumId);
Cursor cursor = contentResolver.query(uri, new String[] {MediaContract.Songs.SONGID}, null, null, null);
assertNotNull(cursor);
assertEquals("cursor size ", 17, cursor.getCount());
TestUtils.testCursorContainsRange(cursor, cursor.getColumnIndex(MediaContract.SongsColumns.SONGID),
96, 112);
}
@Test
public void queryAlbumWithoutArtist() {
Uri uri = MediaContract.Albums.buildAlbumUri(hostInfo.getId(),
TestValues.AlbumWithoutArtist.albumId);
Cursor cursor = contentResolver.query(uri, TestValues.AlbumWithoutArtist.PROJECTION, null, null, null);
assertNotNull(cursor);
assertEquals("cursor size ", 1, cursor.getCount());
assertTrue(cursor.moveToFirst());
TestValues.AlbumWithoutArtist.test(cursor);
}
@Test
public void queryAlbumWithMultipleArtists() {
Uri uri = MediaContract.Albums.buildAlbumUri(hostInfo.getId(),
TestValues.AlbumWithMultipleArtists.albumId);
Cursor cursor = contentResolver.query(uri, TestValues.AlbumWithMultipleArtists.PROJECTION,
null, null, null);
assertNotNull(cursor);
assertEquals("cursor size ", 1, cursor.getCount());
assertTrue(cursor.moveToFirst());
TestValues.AlbumWithMultipleArtists.test(cursor);
}
@Test
public void queryArtistSongsTest() {
Uri uri = MediaContract.Songs.buildArtistSongsListUri(hostInfo.getId(), TestValues.ArtistSong.artistId);
Cursor cursor = contentResolver.query(uri, TestValues.ArtistSong.PROJECTION, null, null, null);
assertNotNull(cursor);
assertEquals("cursor size ", 17, cursor.getCount());
TestUtils.testCursorContainsRange(cursor, cursor.getColumnIndex(MediaContract.SongsColumns.SONGID),
96, 112);
assertTrue(Utils.moveCursorTo(cursor, cursor.getColumnIndex(MediaContract.Songs.SONGID),
TestValues.ArtistSong.songId));
}
@Test
public void querySongWithArtistWithoutAlbumTest() {
Uri uri = MediaContract.Songs.buildArtistSongsListUri(hostInfo.getId(),
TestValues.SongWithArtistWithoutAlbum.artistId);
Cursor cursor = contentResolver.query(uri, TestValues.SongWithArtistWithoutAlbum.PROJECTION,
null, null, null);
assertNotNull(cursor);
assertEquals("cursor size ", 1, cursor.getCount());
assertTrue(cursor.moveToFirst());
Utils.cursorToString(cursor);
TestValues.SongWithArtistWithoutAlbum.test(cursor);
}
@Test
public void queryFirstArtistSongWithMultipleArtistsTest() {
Uri uri = MediaContract.Songs.buildArtistSongsListUri(hostInfo.getId(),
TestValues.SongWithMultipleArtists.firstArtistId);
Cursor cursor = contentResolver.query(uri, TestValues.SongWithMultipleArtists.PROJECTION,
null, null, null);
assertNotNull(cursor);
assertEquals("cursor size ", 1, cursor.getCount());
assertTrue(cursor.moveToFirst());
TestValues.SongWithMultipleArtists.test(cursor);
}
@Test
public void querySecondArtistSongWithMultipleArtistsTest() {
Uri uri = MediaContract.Songs.buildArtistSongsListUri(hostInfo.getId(),
TestValues.SongWithMultipleArtists.secondArtistId);
Cursor cursor = contentResolver.query(uri, TestValues.SongWithMultipleArtists.PROJECTION,
null, null, null);
assertNotNull(cursor);
assertEquals("cursor size ", 1, cursor.getCount());
assertTrue(cursor.moveToFirst());
TestValues.SongWithMultipleArtists.test(cursor);
}
@Test
public void queryThirdArtistSongWithMultipleArtistsTest() {
Uri uri = MediaContract.Songs.buildArtistSongsListUri(hostInfo.getId(),
TestValues.SongWithMultipleArtists.thirdArtistId);
Cursor cursor = contentResolver.query(uri,
TestValues.SongWithMultipleArtists.PROJECTION,
null, null, null);
assertNotNull(cursor);
assertEquals("cursor size ", 1, cursor.getCount());
assertTrue(cursor.moveToFirst());
TestValues.SongWithMultipleArtists.test(cursor);
}
@Test
public void queryAllSongsTest() {
Uri uri = MediaContract.Songs.buildSongsListUri(hostInfo.getId());
Cursor cursor = contentResolver.query(uri,
TestValues.ArtistSong.PROJECTION,
null, null, null);
assertNotNull(cursor);
assertEquals("cursor size ", 1804, cursor.getCount());
TestUtils.testCursorContainsRange(cursor, cursor.getColumnIndex(MediaContract.Songs.SONGID),
1, 1804);
//Test if list also contains a song WITH an album AND an artist
assertTrue(Utils.moveCursorTo(cursor, cursor.getColumnIndex(MediaContract.Songs.SONGID),
TestValues.SongWithAlbumAndArtist.songId));
TestValues.SongWithAlbumAndArtist.test(cursor);
//Test if list also contains a song WITHOUT an album but WITH an artist
assertTrue(Utils.moveCursorTo(cursor, cursor.getColumnIndex(MediaContract.Songs.SONGID),
TestValues.SongWithArtistWithoutAlbum.songId));
TestValues.SongWithArtistWithoutAlbum.test(cursor);
//Test if list also contains a song WITH an album but WITHOUT an artist
assertTrue(Utils.moveCursorTo(cursor, cursor.getColumnIndex(MediaContract.Songs.SONGID),
TestValues.SongWithAlbumWithoutArtist.songId));
TestValues.SongWithAlbumWithoutArtist.test(cursor);
//Test if list contains a song WITH MULTIPLE artists
assertTrue(Utils.moveCursorTo(cursor, cursor.getColumnIndex(MediaContract.Songs.SONGID),
TestValues.SongWithMultipleArtists.songId));
TestValues.SongWithMultipleArtists.test(cursor);
}
@Test
public void queryAlbumWithMultipleArtistsTest() {
Uri uri = MediaContract.Albums.buildAlbumUri(hostInfo.getId(),
TestValues.AlbumWithMultipleArtists.albumId);
Cursor cursor = contentResolver.query(uri,
TestValues.AlbumWithMultipleArtists.PROJECTION,
null, null, null);
assertNotNull(cursor);
assertEquals("cursor size ", 1, cursor.getCount());
assertTrue(cursor.moveToFirst());
LogUtils.LOGD("MediaProviderMusicTest", Utils.cursorToString(cursor));
TestValues.AlbumWithMultipleArtists.test(cursor);
}
@Test
public void queryAllGenresTest() {
Uri uri = MediaContract.AudioGenres.buildAudioGenresListUri(hostInfo.getId());
Cursor cursor = contentResolver.query(uri,
new String[] {MediaContract.AudioGenresColumns.GENREID},
null, null, null);
assertNotNull(cursor);
assertEquals("cursor size ", 39, cursor.getCount());
TestUtils.testCursorContainsRange(cursor,
cursor.getColumnIndex(MediaContract.AudioGenresColumns.GENREID),
1, 39);
}
}

View File

@ -0,0 +1,203 @@
/*
* Copyright 2016 Martijn Brekhof. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.xbmc.kore.tests.mediaprovider;
import android.database.Cursor;
import org.xbmc.kore.provider.MediaContract;
import org.xbmc.kore.provider.MediaDatabase;
import org.xbmc.kore.provider.MediaProvider;
import org.xbmc.kore.ui.AlbumListFragment;
import org.xbmc.kore.ui.ArtistListFragment;
import org.xbmc.kore.ui.ArtistOverviewFragment;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import static org.junit.Assert.assertEquals;
public class TestValues {
public static class Artist {
public static int artistId = 13;
public static String artist = "Bernstein, Charles";
public static String[] PROJECTION = MediaContract.Artists.ALL_COLUMNS;
public static void test(Cursor cursor) {
assertEquals(TestValues.Artist.artistId, cursor.getInt(cursor.getColumnIndex(MediaContract.ArtistsColumns.ARTISTID)));
assertEquals(TestValues.Artist.artist, cursor.getString(cursor.getColumnIndex(MediaContract.ArtistsColumns.ARTIST)));
}
}
public static class Album {
public static int albumId = 13;
public static String title = "The Entity";
public static String displayArtist = "Bernstein, Charles";
public static int year = 1982;
public static String genre = "Soundtrack";
public static String[] PROJECTION = MediaContract.Albums.ALL_COLUMNS;
public static void test(Cursor cursor) {
int resultAlbumId = cursor.getInt(cursor.getColumnIndex(MediaContract.AlbumsColumns.ALBUMID));
assertEquals(albumId, resultAlbumId);
String resultTitle = cursor.getString(cursor.getColumnIndex(MediaContract.AlbumsColumns.TITLE));
assertEquals(title, resultTitle);
String resultArtist = cursor.getString(cursor.getColumnIndex(MediaContract.AlbumsColumns.DISPLAYARTIST));
assertEquals(displayArtist, resultArtist);
String resultGenre = cursor.getString(cursor.getColumnIndex(MediaContract.AlbumsColumns.GENRE));
assertEquals(genre, resultGenre);
int resultYear = cursor.getInt(cursor.getColumnIndex(MediaContract.AlbumsColumns.YEAR));
assertEquals(year, resultYear);
}
}
public static class AlbumWithoutArtist {
public static int albumId = 82;
public static String title = "The Album";
public static String displayArtist = "";
public static int year = 0;
public static String genre = "";
public static String[] PROJECTION = MediaContract.Albums.ALL_COLUMNS;
public static void test(Cursor cursor) {
int resultAlbumId = cursor.getInt(cursor.getColumnIndex(MediaContract.AlbumsColumns.ALBUMID));
assertEquals(albumId, resultAlbumId);
String resultTitle = cursor.getString(cursor.getColumnIndex(MediaContract.AlbumsColumns.TITLE));
assertEquals(title, resultTitle);
String resultArtist = cursor.getString(cursor.getColumnIndex(MediaContract.AlbumsColumns.DISPLAYARTIST));
assertEquals(displayArtist, resultArtist);
String resultGenre = cursor.getString(cursor.getColumnIndex(MediaContract.AlbumsColumns.GENRE));
assertEquals(genre, resultGenre);
int resultYear = cursor.getInt(cursor.getColumnIndex(MediaContract.AlbumsColumns.YEAR));
assertEquals(year, resultYear);
}
}
public static class AlbumWithMultipleArtists {
public static int albumId = 234;
public static String title = "ThreeArtistsAlbum";
public static String displayArtist = "First artist / Second artist / Third artist";
public static int year = 0;
public static String genre = "";
public static String[] PROJECTION = MediaContract.Albums.ALL_COLUMNS;
public static void test(Cursor cursor) {
int resultAlbumId = cursor.getInt(cursor.getColumnIndex(MediaContract.AlbumsColumns.ALBUMID));
assertEquals(albumId, resultAlbumId);
String resultTitle = cursor.getString(cursor.getColumnIndex(MediaContract.AlbumsColumns.TITLE));
assertEquals(title, resultTitle);
String resultArtist = cursor.getString(cursor.getColumnIndex(MediaContract.AlbumsColumns.DISPLAYARTIST));
assertEquals(displayArtist, resultArtist);
String resultGenre = cursor.getString(cursor.getColumnIndex(MediaContract.AlbumsColumns.GENRE));
assertEquals(genre, resultGenre);
int resultYear = cursor.getInt(cursor.getColumnIndex(MediaContract.AlbumsColumns.YEAR));
assertEquals(year, resultYear);
}
}
public static class ArtistSong {
public static int songId = 96;
public static int artistId = Artist.artistId;
public static int albumId = Album.albumId;
public static String title = "Intro & Main Title";
public static String[] PROJECTION = new String[] { MediaContract.Songs.SONGID,
MediaContract.Songs.TITLE,
MediaContract.Songs.ALBUMID,
MediaContract.SongArtists.ARTISTID,
MediaContract.Artists.ARTIST };
public static void test(Cursor cursor) {
assertEquals(songId, cursor.getInt(cursor.getColumnIndex(MediaContract.Songs.SONGID)));
assertEquals(title, cursor.getString(cursor.getColumnIndex(MediaContract.Songs.TITLE)));
assertEquals(albumId, cursor.getInt(cursor.getColumnIndex(MediaContract.Songs.ALBUMID)));
assertEquals(artistId, cursor.getInt(cursor.getColumnIndex(MediaContract.SongArtists.ARTISTID)));
}
}
public static class SongWithAlbumAndArtist {
public static int songId = 1487;
public static int artistId = 195;
public static int albumId = 201;
public static String title = "The Lone Ranger (William Tell Overture)";
public static String[] PROJECTION = ArtistSong.PROJECTION;
public static void test(Cursor cursor) {
assertEquals(songId, cursor.getInt(cursor.getColumnIndex(MediaContract.Songs.SONGID)));
assertEquals(title, cursor.getString(cursor.getColumnIndex(MediaContract.Songs.TITLE)));
assertEquals(albumId, cursor.getInt(cursor.getColumnIndex(MediaContract.Songs.ALBUMID)));
assertEquals(artistId, cursor.getInt(cursor.getColumnIndex(MediaContract.SongArtists.ARTISTID)));
}
}
public static class SongWithAlbumWithoutArtist {
public static int songId = 1219;
public static int artistId = 0;
public static String title = "Unknown";
public static int albumId = 82;
public static String[] PROJECTION = ArtistSong.PROJECTION;
public static void test(Cursor cursor) {
assertEquals(songId, cursor.getInt(cursor.getColumnIndex(MediaContract.Songs.SONGID)));
assertEquals(title, cursor.getString(cursor.getColumnIndex(MediaContract.Songs.TITLE)));
assertEquals(albumId, cursor.getInt(cursor.getColumnIndex(MediaContract.Songs.ALBUMID)));
assertEquals(artistId, cursor.getInt(cursor.getColumnIndex(MediaContract.SongArtists.ARTISTID)));
}
}
public static class SongWithArtistWithoutAlbum {
public static int songId = 1128;
public static int artistId = 73;
public static int albumId = 76;
public static String title = "Unknown";
public static String[] PROJECTION = ArtistSong.PROJECTION;
public static void test(Cursor cursor) {
assertEquals(songId, cursor.getInt(cursor.getColumnIndex(MediaContract.Songs.SONGID)));
assertEquals(title, cursor.getString(cursor.getColumnIndex(MediaContract.Songs.TITLE)));
assertEquals(albumId, cursor.getInt(cursor.getColumnIndex(MediaContract.Songs.ALBUMID)));
assertEquals(artistId, cursor.getInt(cursor.getColumnIndex(MediaContract.SongArtists.ARTISTID)));
}
}
public static class SongWithMultipleArtists {
public static int songId = 1804;
public static int firstArtistId = 226;
public static int secondArtistId = 227;
public static int thirdArtistId = 228;
public static int albumId = 234;
public static String title = "threeartists";
public static String[] PROJECTION = ArtistSong.PROJECTION;
public static void test(Cursor cursor) {
assertEquals(songId, cursor.getInt(cursor.getColumnIndex(MediaContract.Songs.SONGID)));
assertEquals(title, cursor.getString(cursor.getColumnIndex(MediaContract.Songs.TITLE)));
assertEquals(albumId, cursor.getInt(cursor.getColumnIndex(MediaContract.Songs.ALBUMID)));
}
}
}

View File

@ -49,8 +49,8 @@ public class RestoreSearchQueryViewPagerTest {
private final int ARTIST_SEARCH_QUERY_LIST_SIZE = 2;
private final String ALBUMS_SEARCH_QUERY = "tes";
private final int ALBUM_SEARCH_QUERY_LIST_SIZE = 3;
private final int ARTIST_COMPLETE_LIST_SIZE = 224;
private final int ALBUM_COMPLETE_LIST_SIZE = 231;
private final int ARTIST_COMPLETE_LIST_SIZE = 227;
private final int ALBUM_COMPLETE_LIST_SIZE = 232;
private LoaderIdlingResource loaderIdlingResource;

View File

@ -3,9 +3,9 @@
"jsonrpc" : "2.0",
"result" : {
"limits" : {
"total" : 231,
"total" : 232,
"start" : 0,
"end" : 231
"end" : 234
},
"albums" : [
{
@ -7538,6 +7538,41 @@
"theme" : [],
"musicbrainzalbumid" : "",
"playcount" : 0
},
{
"musicbrainzalbumid" : "",
"description" : "",
"artist" : [
"First artist",
"Second artist",
"Third artist"
],
"type" : "",
"title" : "ThreeArtistsAlbum",
"label" : "ThreeArtistsAlbum",
"rating" : 0,
"albumlabel" : "",
"playcount" : 0,
"albumid" : 234,
"thumbnail" : "",
"genreid" : [],
"artistid" : [
226,
227,
228
],
"mood" : [],
"theme" : [],
"genre" : [],
"displayartist" : "First artist / Second artist / Third artist",
"style" : [],
"fanart" : "",
"year" : 0,
"musicbrainzalbumartistid" : [
"",
"",
""
]
}
]
}

View File

@ -4482,11 +4482,71 @@
"fanart" : "",
"mood" : [],
"style" : []
},
{
"description" : "",
"disbanded" : "",
"artist" : "First artist",
"instrument" : [],
"label" : "First artist",
"born" : "",
"yearsactive" : [],
"genre" : [],
"thumbnail" : "",
"mood" : [],
"artistid" : 226,
"musicbrainzartistid" : [
""
],
"died" : "",
"formed" : "",
"style" : [],
"fanart" : ""
},
{
"description" : "",
"disbanded" : "",
"artist" : "Second artist",
"instrument" : [],
"label" : "Second artist",
"born" : "",
"yearsactive" : [],
"genre" : [],
"thumbnail" : "",
"mood" : [],
"artistid" : 227,
"musicbrainzartistid" : [
""
],
"died" : "",
"formed" : "",
"style" : [],
"fanart" : ""
},
{
"description" : "",
"disbanded" : "",
"artist" : "Third artist",
"instrument" : [],
"label" : "Third artist",
"born" : "",
"yearsactive" : [],
"genre" : [],
"thumbnail" : "",
"mood" : [],
"artistid" : 228,
"musicbrainzartistid" : [
""
],
"died" : "",
"formed" : "",
"style" : [],
"fanart" : ""
}
],
"limits" : {
"total" : 224,
"end" : 224,
"total" : 227,
"end" : 228,
"start" : 0
}
}

View File

@ -75109,12 +75109,58 @@
"songid" : 1618,
"title" : "Reel - Upstairs in a Tent",
"album" : "Ireland's Best Fiddle Tunes Disk 2"
},
{
"musicbrainzalbumartistid" : [],
"year" : 0,
"albumartistid" : [
226,
227,
228
],
"disc" : 0,
"musicbrainztrackid" : "",
"fanart" : "",
"file" : "/Users/martijn/Projects/dummymediafiles/media/music/ThreeArtists/ThreeArtistsAlbum/01-threeartists.mp3",
"genre" : [],
"displayartist" : "First artist / Second artist / Third artist",
"comment" : "",
"musicbrainzartistid" : [],
"artistid" : [
226,
227,
228
],
"lastplayed" : "",
"songid" : 1804,
"playcount" : 0,
"thumbnail" : "",
"albumartist" : [
"First artist",
"Second artist",
"Third artist"
],
"albumid" : 234,
"genreid" : [],
"track" : 1,
"label" : "threeartists",
"title" : "threeartists",
"rating" : 0,
"artist" : [
"First artist",
"Second artist",
"Third artist"
],
"lyrics" : "",
"duration" : 5,
"album" : "ThreeArtistsAlbum",
"musicbrainzalbumid" : ""
}
],
"limits" : {
"end" : 1803,
"end" : 1804,
"start" : 0,
"total" : 1803
"total" : 1804
}
},
"jsonrpc" : "2.0"

View File

@ -805,7 +805,7 @@ public class MediaProvider extends ContentProvider {
* {@link MediaContract} fields that are fully qualified with a specific
* parent {@link MediaDatabase.Tables}. Used when needed to work around SQL ambiguity.
*/
private interface Qualified {
public interface Qualified {
String ALBUM_ARTISTS_HOST_ID =
MediaDatabase.Tables.ALBUM_ARTISTS + "." + MediaContract.AlbumArtists.HOST_ID;
String ALBUM_ARTISTS_ARTISTID =

View File

@ -86,6 +86,7 @@ public class SyncMusic extends SyncItem {
AudioType.FieldsArtists.FANART,
AudioType.FieldsArtists.THUMBNAIL
};
/**
* Gets all artists recursively and forwards the call to Genres
* Genres->Albums->Songs
@ -115,13 +116,7 @@ public class SyncMusic extends SyncItem {
// First delete all music info
if (startIdx == 0) deleteMusicInfo(contentResolver, hostId);
// Insert artists
ContentValues artistValuesBatch[] = new ContentValues[items.size()];
for (int i = 0; i < items.size(); i++) {
AudioType.DetailsArtist artist = items.get(i);
artistValuesBatch[i] = SyncUtils.contentValuesFromArtist(hostId, artist);
}
contentResolver.bulkInsert(MediaContract.Artists.CONTENT_URI, artistValuesBatch);
insertArtists(items, contentResolver);
if (moreItemsAvailable(limitsReturned)) {
LogUtils.LOGD(TAG, "chainCallSyncArtists: More results on media center, recursing.");
@ -151,6 +146,8 @@ public class SyncMusic extends SyncItem {
where, new String[]{String.valueOf(hostId)});
contentResolver.delete(MediaContract.AlbumGenres.CONTENT_URI,
where, new String[]{String.valueOf(hostId)});
contentResolver.delete(MediaContract.SongArtists.CONTENT_URI,
where, new String[]{String.valueOf(hostId)});
contentResolver.delete(MediaContract.Songs.CONTENT_URI,
where, new String[]{String.valueOf(hostId)});
contentResolver.delete(MediaContract.AudioGenres.CONTENT_URI,
@ -178,16 +175,9 @@ public class SyncMusic extends SyncItem {
action.execute(hostConnection, new ApiCallback<List<LibraryType.DetailsGenre>>() {
@Override
public void onSuccess(List<LibraryType.DetailsGenre> result) {
if (result == null) result = new ArrayList<>(0); // Safeguard
ContentValues genresValuesBatch[] = new ContentValues[result.size()];
if (result != null)
insertGenresItems(result, contentResolver);
for (int i = 0; i < result.size(); i++) {
LibraryType.DetailsGenre genre = result.get(i);
genresValuesBatch[i] = SyncUtils.contentValuesFromAudioGenre(hostId, genre);
}
// Insert the genres and proceed to albums
contentResolver.bulkInsert(MediaContract.AudioGenres.CONTENT_URI, genresValuesBatch);
chainCallSyncAlbums(orchestrator, hostConnection, callbackHandler, contentResolver, 0);
}
@ -240,44 +230,7 @@ public class SyncMusic extends SyncItem {
}
// Insert the partial results
ContentValues albumValuesBatch[] = new ContentValues[items.size()];
int artistsCount = 0, genresCount = 0;
for (int i = 0; i < items.size(); i++) {
AudioType.DetailsAlbum album = items.get(i);
albumValuesBatch[i] = SyncUtils.contentValuesFromAlbum(hostId, album);
artistsCount += album.artistid.size();
genresCount += album.genreid.size();
}
contentResolver.bulkInsert(MediaContract.Albums.CONTENT_URI, albumValuesBatch);
LogUtils.LOGD(TAG, "Finished inserting albums in: " +
(System.currentTimeMillis() - albumSyncStartTime));
// Iterate on each album, collect the artists and the genres and insert them
ContentValues albumArtistsValuesBatch[] = new ContentValues[artistsCount];
ContentValues albumGenresValuesBatch[] = new ContentValues[genresCount];
int artistCount = 0, genreCount = 0;
for (AudioType.DetailsAlbum album : items) {
for (int artistId : album.artistid) {
albumArtistsValuesBatch[artistCount] = new ContentValues();
albumArtistsValuesBatch[artistCount].put(MediaContract.AlbumArtists.HOST_ID, hostId);
albumArtistsValuesBatch[artistCount].put(MediaContract.AlbumArtists.ALBUMID, album.albumid);
albumArtistsValuesBatch[artistCount].put(MediaContract.AlbumArtists.ARTISTID, artistId);
artistCount++;
}
for (int genreId : album.genreid) {
albumGenresValuesBatch[genreCount] = new ContentValues();
albumGenresValuesBatch[genreCount].put(MediaContract.AlbumGenres.HOST_ID, hostId);
albumGenresValuesBatch[genreCount].put(MediaContract.AlbumGenres.ALBUMID, album.albumid);
albumGenresValuesBatch[genreCount].put(MediaContract.AlbumGenres.GENREID, genreId);
genreCount++;
}
}
contentResolver.bulkInsert(MediaContract.AlbumArtists.CONTENT_URI, albumArtistsValuesBatch);
contentResolver.bulkInsert(MediaContract.AlbumGenres.CONTENT_URI, albumGenresValuesBatch);
insertAlbumsItems(items, contentResolver);
LogUtils.LOGD(TAG, "Finished inserting artists and genres in: " +
(System.currentTimeMillis() - albumSyncStartTime));
@ -346,29 +299,8 @@ public class SyncMusic extends SyncItem {
limitsReturned = result.limits;
}
int totalArtistsCount = 0;
// Save partial results to DB
ContentValues songValuesBatch[] = new ContentValues[items.size()];
for (int i = 0; i < items.size(); i++) {
AudioType.DetailsSong song = items.get(i);
songValuesBatch[i] = SyncUtils.contentValuesFromSong(hostId, song);
totalArtistsCount += song.artistid.size();
}
contentResolver.bulkInsert(MediaContract.Songs.CONTENT_URI, songValuesBatch);
// Iterate on each song, collect the artists and insert them
ContentValues songArtistsValuesBatch[] = new ContentValues[totalArtistsCount];
int artistCount = 0;
for (AudioType.DetailsSong song : items) {
for (int artistId : song.artistid) {
songArtistsValuesBatch[artistCount] = new ContentValues();
songArtistsValuesBatch[artistCount].put(MediaContract.SongArtists.HOST_ID, hostId);
songArtistsValuesBatch[artistCount].put(MediaContract.SongArtists.SONGID, song.songid);
songArtistsValuesBatch[artistCount].put(MediaContract.SongArtists.ARTISTID, artistId);
artistCount++;
}
}
contentResolver.bulkInsert(MediaContract.SongArtists.CONTENT_URI, songArtistsValuesBatch);
insertSongsItems(items, contentResolver);
if (moreItemsAvailable(limitsReturned)) {
LogUtils.LOGD(TAG, "chainCallSyncSongs: More results on media center, recursing.");
@ -384,12 +316,98 @@ public class SyncMusic extends SyncItem {
@Override
public void onError(int errorCode, String description) {
// Ok, something bad happend, just quit
// Ok, something bad happened, just quit
orchestrator.syncItemFailed(errorCode, description);
}
}, callbackHandler);
}
public void insertArtists(List<AudioType.DetailsArtist> items, ContentResolver contentResolver) {
ContentValues artistValuesBatch[] = new ContentValues[items.size()];
for (int i = 0; i < items.size(); i++) {
AudioType.DetailsArtist artist = items.get(i);
artistValuesBatch[i] = SyncUtils.contentValuesFromArtist(hostId, artist);
}
contentResolver.bulkInsert(MediaContract.Artists.CONTENT_URI, artistValuesBatch);
}
public void insertGenresItems(List<LibraryType.DetailsGenre> items, ContentResolver contentResolver) {
ContentValues genresValuesBatch[] = new ContentValues[items.size()];
for (int i = 0; i < items.size(); i++) {
LibraryType.DetailsGenre genre = items.get(i);
genresValuesBatch[i] = SyncUtils.contentValuesFromAudioGenre(hostId, genre);
}
// Insert the genres and proceed to albums
contentResolver.bulkInsert(MediaContract.AudioGenres.CONTENT_URI, genresValuesBatch);
}
public void insertAlbumsItems(List<AudioType.DetailsAlbum> items, ContentResolver contentResolver) {
ContentValues albumValuesBatch[] = new ContentValues[items.size()];
int artistsCount = 0, genresCount = 0;
for (int i = 0; i < items.size(); i++) {
AudioType.DetailsAlbum album = items.get(i);
albumValuesBatch[i] = SyncUtils.contentValuesFromAlbum(hostId, album);
artistsCount += album.artistid.size();
genresCount += album.genreid.size();
}
contentResolver.bulkInsert(MediaContract.Albums.CONTENT_URI, albumValuesBatch);
// Iterate on each album, collect the artists and the genres and insert them
ContentValues albumArtistsValuesBatch[] = new ContentValues[artistsCount];
ContentValues albumGenresValuesBatch[] = new ContentValues[genresCount];
int artistCount = 0, genreCount = 0;
for (AudioType.DetailsAlbum album : items) {
for (int artistId : album.artistid) {
albumArtistsValuesBatch[artistCount] = new ContentValues();
albumArtistsValuesBatch[artistCount].put(MediaContract.AlbumArtists.HOST_ID, hostId);
albumArtistsValuesBatch[artistCount].put(MediaContract.AlbumArtists.ALBUMID, album.albumid);
albumArtistsValuesBatch[artistCount].put(MediaContract.AlbumArtists.ARTISTID, artistId);
artistCount++;
}
for (int genreId : album.genreid) {
albumGenresValuesBatch[genreCount] = new ContentValues();
albumGenresValuesBatch[genreCount].put(MediaContract.AlbumGenres.HOST_ID, hostId);
albumGenresValuesBatch[genreCount].put(MediaContract.AlbumGenres.ALBUMID, album.albumid);
albumGenresValuesBatch[genreCount].put(MediaContract.AlbumGenres.GENREID, genreId);
genreCount++;
}
}
contentResolver.bulkInsert(MediaContract.AlbumArtists.CONTENT_URI, albumArtistsValuesBatch);
contentResolver.bulkInsert(MediaContract.AlbumGenres.CONTENT_URI, albumGenresValuesBatch);
}
public void insertSongsItems(List<AudioType.DetailsSong> items, ContentResolver contentResolver) {
ContentValues songValuesBatch[] = new ContentValues[items.size()];
int totalArtistsCount = 0;
for (int i = 0; i < items.size(); i++) {
AudioType.DetailsSong song = items.get(i);
songValuesBatch[i] = SyncUtils.contentValuesFromSong(hostId, song);
totalArtistsCount += song.artistid.size();
}
contentResolver.bulkInsert(MediaContract.Songs.CONTENT_URI, songValuesBatch);
// Iterate on each song, collect the artists and insert them
ContentValues songArtistsValuesBatch[] = new ContentValues[totalArtistsCount];
int artistCount = 0;
for (AudioType.DetailsSong song : items) {
for (int artistId : song.artistid) {
songArtistsValuesBatch[artistCount] = new ContentValues();
songArtistsValuesBatch[artistCount].put(MediaContract.SongArtists.HOST_ID, hostId);
songArtistsValuesBatch[artistCount].put(MediaContract.SongArtists.SONGID, song.songid);
songArtistsValuesBatch[artistCount].put(MediaContract.SongArtists.ARTISTID, artistId);
artistCount++;
}
}
contentResolver.bulkInsert(MediaContract.SongArtists.CONTENT_URI, songArtistsValuesBatch);
}
private boolean moreItemsAvailable(ListType.LimitsReturned limitsReturned) {
boolean moreItemsAvailable = false;
if (limitsReturned != null) {