Hook up clicks on albums and artists

This commit is contained in:
Christopher Eby 2010-03-09 19:51:33 -06:00
parent 565c4a42cc
commit da087bd3ac
9 changed files with 195 additions and 85 deletions

View File

@ -40,4 +40,4 @@
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<supports-screens android:smallScreens="true" />
</manifest>
</manifest>

5
res/values/ids.xml Normal file
View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="id" name="list" />
<item type="id" name="song" />
</resources>

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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<Song> view = mSongTimeline.subList(mCurrentSong + 1, mSongTimeline.size());
List<Song> queue = mQueuePos == 0 ? null : new ArrayList<Song>(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
}
}
}
}
}

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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;
}
}