package com.simplecity.amp_library.ui.activities; import android.app.SearchManager; import android.content.ComponentName; import android.content.Intent; import android.os.Bundle; import android.os.IBinder; import android.widget.Toast; import com.annimon.stream.Stream; import com.simplecity.amp_library.R; import com.simplecity.amp_library.model.Album; import com.simplecity.amp_library.model.AlbumArtist; import com.simplecity.amp_library.utils.ComparisonUtils; import com.simplecity.amp_library.utils.DataManager; import com.simplecity.amp_library.utils.MusicUtils; import java.util.Collections; import java.util.Locale; import rx.Observable; import rx.android.schedulers.AndroidSchedulers; import static com.simplecity.amp_library.utils.StringUtils.containsIgnoreCase; public class VoiceSearchActivity extends BaseActivity { private static final String TAG = "VoiceSearchActivity"; private String filterString; private Intent mIntent; private int position = -1; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mIntent = getIntent(); filterString = mIntent.getStringExtra(SearchManager.QUERY); } @Override public void onServiceConnected(ComponentName name, IBinder service) { super.onServiceConnected(name, service); if (mIntent != null && mIntent.getAction() != null && mIntent.getAction().equals("android.media.action.MEDIA_PLAY_FROM_SEARCH")) { searchAndPlaySongs(); } } @Override public void onServiceDisconnected(ComponentName name) { } private void searchAndPlaySongs() { //Search for album-artists, albums & songs matching our filter. Then, create an Observable emitting List<Song> for each type of result. //Then we concat the results, and return the first one which is non-empty. Order is important here, we want album-artist first, if it's //available, then albums, then songs. Observable.concat( //If we have an album artist matching our query, then play the songs by that album artist DataManager.getInstance().getAlbumArtistsRelay() .first() .flatMap(Observable::from) .filter(albumArtist -> albumArtist.name.toLowerCase(Locale.getDefault()).contains(filterString.toLowerCase())) .flatMap(AlbumArtist::getSongsObservable) .map(songs -> { Collections.sort(songs, (a, b) -> a.getAlbumArtist().compareTo(b.getAlbumArtist())); Collections.sort(songs, (a, b) -> a.getAlbum().compareTo(b.getAlbum())); Collections.sort(songs, (a, b) -> ComparisonUtils.compareInt(a.track, b.track)); Collections.sort(songs, (a, b) -> ComparisonUtils.compareInt(a.discNumber, b.discNumber)); return songs; }), //If we have an album matching our query, then play the songs from that album DataManager.getInstance().getAlbumsRelay() .first() .flatMap(Observable::from) .filter(album -> containsIgnoreCase(album.name, filterString) || containsIgnoreCase(album.name, filterString) || (Stream.of(album.artists).anyMatch(artist -> containsIgnoreCase(artist.name, filterString))) || containsIgnoreCase(album.albumArtistName, filterString)) .flatMap(Album::getSongsObservable) .map(songs -> { Collections.sort(songs, (a, b) -> a.getAlbum().compareTo(b.getAlbum())); Collections.sort(songs, (a, b) -> ComparisonUtils.compareInt(a.track, b.track)); Collections.sort(songs, (a, b) -> ComparisonUtils.compareInt(a.discNumber, b.discNumber)); return songs; }), //If have a song, play that song, as well as others from the same album. DataManager.getInstance().getSongsRelay() .first() .flatMap(Observable::from) .filter(song -> containsIgnoreCase(song.name, filterString) || containsIgnoreCase(song.albumName, filterString) || containsIgnoreCase(song.artistName, filterString) || containsIgnoreCase(song.albumArtistName, filterString)) .flatMap(song -> song.getAlbum().getSongsObservable() .map(songs -> { Collections.sort(songs, (a, b) -> ComparisonUtils.compareInt(a.track, b.track)); Collections.sort(songs, (a, b) -> ComparisonUtils.compareInt(a.discNumber, b.discNumber)); position = songs.indexOf(song); return songs; })) ) .first(songs -> !songs.isEmpty()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(songs -> { if (songs != null) { MusicUtils.playAll(songs, position, () -> { final String message = getString(R.string.emptyplaylist); Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); }); } finish(); }); } @Override protected String screenName() { return TAG; } }