From da087bd3acbe5533b87e96a1829d27b2406e0fbc Mon Sep 17 00:00:00 2001 From: Christopher Eby Date: Tue, 9 Mar 2010 19:51:33 -0600 Subject: [PATCH] Hook up clicks on albums and artists --- AndroidManifest.xml | 2 +- res/values/ids.xml | 5 + src/org/kreed/vanilla/AbstractAdapter.java | 9 +- src/org/kreed/vanilla/AlbumAdapter.java | 8 ++ src/org/kreed/vanilla/ArtistAdapter.java | 8 ++ src/org/kreed/vanilla/PlaybackService.java | 133 +++++++++++++++------ src/org/kreed/vanilla/Song.java | 55 ++++++--- src/org/kreed/vanilla/SongAdapter.java | 8 ++ src/org/kreed/vanilla/SongSelector.java | 52 ++++---- 9 files changed, 195 insertions(+), 85 deletions(-) create mode 100644 res/values/ids.xml diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 98f3e84f..d36e00c8 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -40,4 +40,4 @@ - \ No newline at end of file + diff --git a/res/values/ids.xml b/res/values/ids.xml new file mode 100644 index 00000000..abd10379 --- /dev/null +++ b/res/values/ids.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/org/kreed/vanilla/AbstractAdapter.java b/src/org/kreed/vanilla/AbstractAdapter.java index 0d91dc34..7ed95914 100644 --- a/src/org/kreed/vanilla/AbstractAdapter.java +++ b/src/org/kreed/vanilla/AbstractAdapter.java @@ -235,6 +235,8 @@ public abstract class AbstractAdapter extends BaseAdapter implements Filterable return null; return mAllObjects[i]; } + if (i >= mObjects.size()) + return null; return mObjects.get(i); } @@ -242,11 +244,4 @@ public abstract class AbstractAdapter extends BaseAdapter implements Filterable { return get(i); } - - public long getItemId(int i) - { - if (mObjects != null && mObjects.isEmpty()) - return 0; - return get(i).id; - } } \ No newline at end of file diff --git a/src/org/kreed/vanilla/AlbumAdapter.java b/src/org/kreed/vanilla/AlbumAdapter.java index d04edbf6..81245454 100644 --- a/src/org/kreed/vanilla/AlbumAdapter.java +++ b/src/org/kreed/vanilla/AlbumAdapter.java @@ -16,4 +16,12 @@ public class AlbumAdapter extends AbstractAdapter { upper.setText(song.album); lower.setText(song.artist); } + + public long getItemId(int i) + { + Song song = get(i); + if (song == null) + return 0; + return song.albumId; + } } \ No newline at end of file diff --git a/src/org/kreed/vanilla/ArtistAdapter.java b/src/org/kreed/vanilla/ArtistAdapter.java index 1f7f27c6..c4fc6dd6 100644 --- a/src/org/kreed/vanilla/ArtistAdapter.java +++ b/src/org/kreed/vanilla/ArtistAdapter.java @@ -33,4 +33,12 @@ public class ArtistAdapter extends AbstractAdapter { Song song = get(position); upper.setText(song.artist); } + + public long getItemId(int i) + { + Song song = get(i); + if (song == null) + return 0; + return song.artistId; + } } \ No newline at end of file diff --git a/src/org/kreed/vanilla/PlaybackService.java b/src/org/kreed/vanilla/PlaybackService.java index e94427e6..5700bbf3 100644 --- a/src/org/kreed/vanilla/PlaybackService.java +++ b/src/org/kreed/vanilla/PlaybackService.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.List; import java.util.Random; import org.kreed.vanilla.IPlaybackService; @@ -48,6 +49,7 @@ import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.preference.PreferenceManager; +import android.provider.MediaStore; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.util.Log; @@ -65,8 +67,12 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On public static final String EVENT_STATE_CHANGED = "org.kreed.vanilla.event.STATE_CHANGED"; public static final String EVENT_SONG_CHANGED = "org.kreed.vanilla.event.SONG_CHANGED"; - public static int ACTION_PLAY = 0; - public static int ACTION_ENQUEUE = 1; + public static final int ACTION_PLAY = 0; + public static final int ACTION_ENQUEUE = 1; + + public static final int TYPE_SONG = 0; + public static final int TYPE_ALBUM = 1; + public static final int TYPE_ARTIST = 2; public static final int STATE_NORMAL = 0; public static final int STATE_NO_MEDIA = 1; @@ -339,6 +345,7 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On in.close(); Song song = new Song(ids[mCurrentSong]); + song.populate(); if (song.path == null) { stateLoaded = false; } else { @@ -488,7 +495,7 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On private void retrieveSongs() { - mSongs = Song.getAllSongIds(); + mSongs = Song.getAllSongIds(null); if (mSongs == null) updateState(STATE_NO_MEDIA); else if (mState == STATE_NO_MEDIA) @@ -633,9 +640,9 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On return true; } - private Song randomSong() + private int randomSong() { - return new Song(mSongs[mRandom.nextInt(mSongs.length)]); + return mSongs[mRandom.nextInt(mSongs.length)]; } private Song getSong(int delta) @@ -643,9 +650,10 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On if (mSongTimeline == null) return null; + Song song; + synchronized (mSongTimeline) { int pos = mCurrentSong + delta; - if (pos < 0) return null; @@ -656,18 +664,18 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On if (pos == size) { if (mSongs == null) return null; - mSongTimeline.add(randomSong()); + mSongTimeline.add(new Song(randomSong())); } - Song song = mSongTimeline.get(pos); - - if (song.path == null) { - song = randomSong(); - mSongTimeline.set(pos, song); - } - - return song; + song = mSongTimeline.get(pos); } + + if (!song.populate()) { + song.id = randomSong(); + song.populate(); + } + + return song; } private void updateWidgets(Song song) @@ -714,42 +722,93 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On if (id == -1) { mQueuePos = 0; } else { - int action = intent.getIntExtra("action", ACTION_PLAY); - int actionRes; + int type = intent.getIntExtra("type", TYPE_SONG); + boolean enqueue = intent.getIntExtra("action", ACTION_PLAY) == ACTION_ENQUEUE; - Song song = new Song(id); + int[] songs; + Song first; + + if (type == TYPE_SONG) + songs = new int[] { id }; + else if (type == TYPE_ALBUM) + songs = Song.getAllSongIds(MediaStore.Audio.Media.ALBUM_ID + "=" + id); + else if (type == TYPE_ARTIST) + songs = Song.getAllSongIds(MediaStore.Audio.Media.ARTIST_ID + "=" + id); + else + break; + + if (songs.length == 0) + break; + + for (int i = songs.length; --i != 0; ) { + int j = mRandom.nextInt(i + 1); + int tmp = songs[j]; + songs[j] = songs[i]; + songs[i] = tmp; + } synchronized (mSongTimeline) { - int i; + if (enqueue) { + int i = mCurrentSong + mQueuePos + 1; - if (action == ACTION_ENQUEUE) { - i = mCurrentSong + 1 + mQueuePos++; - actionRes = R.string.enqueued; + for (int j = 0; j != songs.length; ++i, ++j) { + Song song = new Song(songs[j]); + if (i < mSongTimeline.size()) + mSongTimeline.set(i, song); + else + mSongTimeline.add(song); + } + + first = mSongTimeline.get(mCurrentSong + mQueuePos + 1); + + mQueuePos += songs.length; } else { - i = mCurrentSong; - actionRes = R.string.playing; + List view = mSongTimeline.subList(mCurrentSong + 1, mSongTimeline.size()); + List queue = mQueuePos == 0 ? null : new ArrayList(view); + view.clear(); + + for (int i = 0; i != songs.length; ++i) + mSongTimeline.add(new Song(songs[i])); + + if (queue != null) + mSongTimeline.addAll(queue); + + mQueuePos += songs.length - 1; + + first = mSongTimeline.get(mCurrentSong + 1); } - - if (i < mSongTimeline.size()) - mSongTimeline.set(i, song); - else - mSongTimeline.add(song); } - String text = getResources().getString(actionRes, song.title); - Toast.makeText(ContextApplication.getContext(), text, Toast.LENGTH_SHORT).show(); - - if (action == ACTION_PLAY) { - setCurrentSong(0); - if (mState != STATE_PLAYING) - play(); + first.populate(); + String title; + switch (type) { + case TYPE_ARTIST: + title = first.artist; + break; + case TYPE_SONG: + title = first.title; + break; + case TYPE_ALBUM: + title = first.album; + break; + default: + title = null; } + String text = getResources().getString(enqueue ? R.string.enqueued : R.string.playing, title); + Toast.makeText(PlaybackService.this, text, Toast.LENGTH_SHORT).show(); + + if (!enqueue) + mHandler.sendEmptyMessage(TRACK_CHANGED); + + mHandler.removeMessages(SAVE_STATE); mHandler.sendEmptyMessageDelayed(SAVE_STATE, 5000); } break; case TRACK_CHANGED: setCurrentSong(+1); + if (mState != STATE_PLAYING) + play(); break; case RELEASE_WAKE_LOCK: if (mWakeLock != null && mWakeLock.isHeld()) @@ -802,4 +861,4 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On } } } -} \ No newline at end of file +} diff --git a/src/org/kreed/vanilla/Song.java b/src/org/kreed/vanilla/Song.java index 8d66ae99..f10c3b72 100644 --- a/src/org/kreed/vanilla/Song.java +++ b/src/org/kreed/vanilla/Song.java @@ -54,6 +54,14 @@ public class Song implements Parcelable { public Song(int id) { this.id = id; + } + + public boolean populate() + { + if (path != null) + return true; + if (id == -1) + return false; Uri media = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; String[] projection = { @@ -68,31 +76,40 @@ public class Song implements Parcelable { ContentResolver resolver = ContextApplication.getContext().getContentResolver(); Cursor cursor = resolver.query(media, projection, selection, null, null); - if (cursor != null && cursor.moveToNext()) { - path = cursor.getString(0); - title = cursor.getString(1); - album = cursor.getString(2); - artist = cursor.getString(3); - albumId = cursor.getInt(4); - cursor.close(); - - media = MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI; - String[] albumProjection = { MediaStore.Audio.Albums.ALBUM_ART }; - String albumSelection = MediaStore.Audio.Albums._ID + "==" + albumId; - - cursor = resolver.query(media, albumProjection, albumSelection, null, null); - if (cursor != null && cursor.moveToNext()) { - coverPath = cursor.getString(0); - cursor.close(); - } + if (cursor == null || !cursor.moveToNext()) { + id = -1; + return false; } + + path = cursor.getString(0); + title = cursor.getString(1); + album = cursor.getString(2); + artist = cursor.getString(3); + albumId = cursor.getInt(4); + cursor.close(); + + media = MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI; + String[] albumProjection = { MediaStore.Audio.Albums.ALBUM_ART }; + String albumSelection = MediaStore.Audio.Albums._ID + "==" + albumId; + + cursor = resolver.query(media, albumProjection, albumSelection, null, null); + if (cursor != null && cursor.moveToNext()) { + coverPath = cursor.getString(0); + cursor.close(); + } + + return true; } - public static int[] getAllSongIds() + public static int[] getAllSongIds(String selection) { Uri media = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; String[] projection = { MediaStore.Audio.Media._ID }; - String selection = MediaStore.Audio.Media.IS_MUSIC + "!=0"; + String isMusic = MediaStore.Audio.Media.IS_MUSIC + "!=0"; + if (selection == null) + selection = isMusic; + else + selection += " AND " + isMusic; ContentResolver resolver = ContextApplication.getContext().getContentResolver(); Cursor cursor = resolver.query(media, projection, selection, null, null); diff --git a/src/org/kreed/vanilla/SongAdapter.java b/src/org/kreed/vanilla/SongAdapter.java index fb7111e0..b28f2818 100644 --- a/src/org/kreed/vanilla/SongAdapter.java +++ b/src/org/kreed/vanilla/SongAdapter.java @@ -42,4 +42,12 @@ public class SongAdapter extends AbstractAdapter { upper.setText(song.title); lower.setText(song.artist); } + + public long getItemId(int i) + { + Song song = get(i); + if (song == null) + return 0; + return song.id; + } } \ No newline at end of file diff --git a/src/org/kreed/vanilla/SongSelector.java b/src/org/kreed/vanilla/SongSelector.java index 5b057001..225286f5 100644 --- a/src/org/kreed/vanilla/SongSelector.java +++ b/src/org/kreed/vanilla/SongSelector.java @@ -47,12 +47,25 @@ public class SongSelector extends TabActivity implements AdapterView.OnItemClick private TextView mTextFilter; private AbstractAdapter[] mAdapters = new AbstractAdapter[3]; - private void initializeListView(int id, BaseAdapter adapter) + private ListView mArtistView; + private ListView mAlbumView; + + private int listToMediaType(Object list) + { + if (list == mArtistView) + return PlaybackService.TYPE_ARTIST; + if (list == mAlbumView) + return PlaybackService.TYPE_ALBUM; + return PlaybackService.TYPE_SONG; + } + + private ListView initializeListView(int id, BaseAdapter adapter) { ListView view = (ListView)findViewById(id); view.setOnItemClickListener(this); view.setOnCreateContextMenuListener(this); view.setAdapter(adapter); + return view; } @Override @@ -75,11 +88,11 @@ public class SongSelector extends TabActivity implements AdapterView.OnItemClick mAdapters[0] = new ArtistAdapter(this, songs); mAdapters[0].setExpanderListener(this); - initializeListView(R.id.artist_list, mAdapters[0]); + mArtistView = initializeListView(R.id.artist_list, mAdapters[0]); mTextFilter = (TextView)findViewById(R.id.filter_text); mTextFilter.addTextChangedListener(this); - + View clearButton = findViewById(R.id.clear_button); clearButton.setOnClickListener(this); @@ -98,7 +111,7 @@ public class SongSelector extends TabActivity implements AdapterView.OnItemClick { mAdapters[1] = new AlbumAdapter(SongSelector.this, songs); mAdapters[1].setExpanderListener(SongSelector.this); - initializeListView(R.id.album_list, mAdapters[1]); + mAlbumView = initializeListView(R.id.album_list, mAdapters[1]); mAdapters[2] = new SongAdapter(SongSelector.this, songs); initializeListView(R.id.song_list, mAdapters[2]); @@ -116,19 +129,20 @@ public class SongSelector extends TabActivity implements AdapterView.OnItemClick return mTextFilter.onKeyDown(keyCode, event); } - private void pushSong(int action, int id) + private Intent buildSongIntent(int action, int type, int id) { Intent intent = new Intent(this, PlaybackService.class); - intent.putExtra("id", id); + intent.putExtra("type", type); intent.putExtra("action", action); - startService(intent); + intent.putExtra("id", id); + return intent; } public void onItemClick(AdapterView list, View view, int pos, long id) { if (mHandler.hasMessages(MSG_ITEM_CLICK, view)) { mHandler.removeMessages(MSG_ITEM_CLICK, view); - pushSong(PlaybackService.ACTION_ENQUEUE, (int)id); + startService(buildSongIntent(PlaybackService.ACTION_ENQUEUE, listToMediaType(list), (int)id)); } else { Message message = mHandler.obtainMessage(MSG_ITEM_CLICK, view); message.arg1 = (int)id; @@ -170,7 +184,9 @@ public class SongSelector extends TabActivity implements AdapterView.OnItemClick { switch (message.what) { case MSG_ITEM_CLICK: - pushSong(PlaybackService.ACTION_PLAY, message.arg1); + int type = listToMediaType(((View)message.obj).getParent()); + int id = message.arg1; + startService(buildSongIntent(PlaybackService.ACTION_PLAY, type, id)); break; } } @@ -180,24 +196,18 @@ public class SongSelector extends TabActivity implements AdapterView.OnItemClick private static final int MENU_ENQUEUE = 1; @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) + public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info) { - menu.add(0, MENU_PLAY, 0, R.string.play); - menu.add(0, MENU_ENQUEUE, 0, R.string.enqueue); + int type = listToMediaType(view); + int id = (int)((AdapterView.AdapterContextMenuInfo)info).id; + menu.add(0, MENU_PLAY, 0, R.string.play).setIntent(buildSongIntent(PlaybackService.ACTION_PLAY, type, id)); + menu.add(0, MENU_ENQUEUE, 0, R.string.enqueue).setIntent(buildSongIntent(PlaybackService.ACTION_ENQUEUE, type, id)); } @Override public boolean onContextItemSelected(MenuItem item) { - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo(); - switch (item.getItemId()) { - case MENU_PLAY: - pushSong(PlaybackService.ACTION_PLAY, (int)info.id); - break; - case MENU_ENQUEUE: - pushSong(PlaybackService.ACTION_ENQUEUE, (int)info.id); - break; - } + startService(item.getIntent()); return true; } } \ No newline at end of file