import android.database.AbstractCursor;
import android.database.CharArrayBuffer;
import android.database.Cursor;
+import android.graphics.Bitmap;
import android.media.AudioManager;
import android.media.MediaFile;
import android.net.Uri;
public class TrackBrowserActivity extends ListActivity
implements View.OnCreateContextMenuListener, MusicUtils.Defs, ServiceConnection
{
- private final int Q_SELECTED = CHILD_MENU_BASE;
- private final int Q_ALL = CHILD_MENU_BASE + 1;
- private final int SAVE_AS_PLAYLIST = CHILD_MENU_BASE + 2;
- private final int PLAY_ALL = CHILD_MENU_BASE + 3;
- private final int CLEAR_PLAYLIST = CHILD_MENU_BASE + 4;
- private final int REMOVE = CHILD_MENU_BASE + 5;
- private final int SEARCH = CHILD_MENU_BASE + 6;
+ private static final int Q_SELECTED = CHILD_MENU_BASE;
+ private static final int Q_ALL = CHILD_MENU_BASE + 1;
+ private static final int SAVE_AS_PLAYLIST = CHILD_MENU_BASE + 2;
+ private static final int PLAY_ALL = CHILD_MENU_BASE + 3;
+ private static final int CLEAR_PLAYLIST = CHILD_MENU_BASE + 4;
+ private static final int REMOVE = CHILD_MENU_BASE + 5;
+ private static final int SEARCH = CHILD_MENU_BASE + 6;
private static final String LOGTAG = "TrackBrowser";
private String mSortOrder;
private int mSelectedPosition;
private long mSelectedId;
+ private static int mLastListPosCourse = -1;
+ private static int mLastListPosFine = -1;
+ private boolean mUseLastListPos = false;
public TrackBrowserActivity()
{
{
super.onCreate(icicle);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ Intent intent = getIntent();
+ if (intent != null) {
+ if (intent.getBooleanExtra("withtabs", false)) {
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ }
+ }
setVolumeControlStream(AudioManager.STREAM_MUSIC);
if (icicle != null) {
mSelectedId = icicle.getLong("selectedtrack");
mGenre = icicle.getString("genre");
mEditMode = icicle.getBoolean("editmode", false);
} else {
- mAlbumId = getIntent().getStringExtra("album");
+ mAlbumId = intent.getStringExtra("album");
// If we have an album, show everything on the album, not just stuff
// by a particular artist.
- Intent intent = getIntent();
mArtistId = intent.getStringExtra("artist");
mPlaylist = intent.getStringExtra("playlist");
mGenre = intent.getStringExtra("genre");
MediaStore.Audio.Media.ARTIST_ID,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Playlists.Members.PLAY_ORDER,
- MediaStore.Audio.Playlists.Members.AUDIO_ID
+ MediaStore.Audio.Playlists.Members.AUDIO_ID,
+ MediaStore.Audio.Media.IS_MUSIC
};
+ setContentView(R.layout.media_picker_activity);
+ mUseLastListPos = MusicUtils.updateButtonBar(this, R.id.songtab);
+ mTrackList = getListView();
+ mTrackList.setOnCreateContextMenuListener(this);
+ if (mEditMode) {
+ ((TouchInterceptor) mTrackList).setDropListener(mDropListener);
+ ((TouchInterceptor) mTrackList).setRemoveListener(mRemoveListener);
+ mTrackList.setCacheColorHint(0);
+ } else {
+ mTrackList.setTextFilterEnabled(true);
+ }
+ mAdapter = (TrackListAdapter) getLastNonConfigurationInstance();
+
+ if (mAdapter != null) {
+ mAdapter.setActivity(this);
+ setListAdapter(mAdapter);
+ }
MusicUtils.bindToService(this, this);
+
+ // don't set the album art until after the view has been layed out
+ mTrackList.post(new Runnable() {
+
+ public void run() {
+ setAlbumArtBackground();
+ }
+ });
}
public void onServiceConnected(ComponentName name, IBinder service)
f.addDataScheme("file");
registerReceiver(mScanListener, f);
- setContentView(R.layout.media_picker_activity);
- mTrackList = getListView();
- mTrackList.setOnCreateContextMenuListener(this);
- if (mEditMode) {
- //((TouchInterceptor) mTrackList).setDragListener(mDragListener);
- ((TouchInterceptor) mTrackList).setDropListener(mDropListener);
- ((TouchInterceptor) mTrackList).setRemoveListener(mRemoveListener);
- mTrackList.setCacheColorHint(0);
- } else {
- mTrackList.setTextFilterEnabled(true);
- }
- mAdapter = (TrackListAdapter) getLastNonConfigurationInstance();
if (mAdapter == null) {
//Log.i("@@@", "starting query");
mAdapter = new TrackListAdapter(
!(mPlaylist.equals("podcasts") || mPlaylist.equals("recentlyadded")));
setListAdapter(mAdapter);
setTitle(R.string.working_songs);
- getTrackCursor(mAdapter.getQueryHandler(), null);
+ getTrackCursor(mAdapter.getQueryHandler(), null, true);
} else {
- mAdapter.setActivity(this);
- setListAdapter(mAdapter);
mTrackCursor = mAdapter.getCursor();
// If mTrackCursor is null, this can be because it doesn't have
// a cursor yet (because the initial query that sets its cursor
// first case, simply retry the query when the cursor is null.
// Worst case, we end up doing the same query twice.
if (mTrackCursor != null) {
- init(mTrackCursor);
+ init(mTrackCursor, false);
} else {
setTitle(R.string.working_songs);
- getTrackCursor(mAdapter.getQueryHandler(), null);
+ getTrackCursor(mAdapter.getQueryHandler(), null, true);
}
}
+ if (!mEditMode) {
+ MusicUtils.updateNowPlaying(this);
+ }
}
public void onServiceDisconnected(ComponentName name) {
@Override
public void onDestroy() {
+ ListView lv = getListView();
+ if (lv != null && mUseLastListPos) {
+ mLastListPosCourse = lv.getFirstVisiblePosition();
+ View cv = lv.getChildAt(0);
+ if (cv != null) {
+ mLastListPosFine = cv.getTop();
+ }
+ }
MusicUtils.unbindFromService(this);
try {
if ("nowplaying".equals(mPlaylist)) {
- unregisterReceiver(mNowPlayingListener);
+ unregisterReceiverSafe(mNowPlayingListener);
} else {
- unregisterReceiver(mTrackListListener);
+ unregisterReceiverSafe(mTrackListListener);
}
} catch (IllegalArgumentException ex) {
// we end up here in case we never registered the listeners
c.close();
}
}
- unregisterReceiver(mScanListener);
+ // Because we pass the adapter to the next activity, we need to make
+ // sure it doesn't keep a reference to this activity. We can do this
+ // by clearing its DatasetObservers, which setListAdapter(null) does.
+ setListAdapter(null);
+ mAdapter = null;
+ unregisterReceiverSafe(mScanListener);
super.onDestroy();
- }
+ }
+
+ /**
+ * Unregister a receiver, but eat the exception that is thrown if the
+ * receiver was never registered to begin with. This is a little easier
+ * than keeping track of whether the receivers have actually been
+ * registered by the time onDestroy() is called.
+ */
+ private void unregisterReceiverSafe(BroadcastReceiver receiver) {
+ try {
+ unregisterReceiver(receiver);
+ } catch (IllegalArgumentException e) {
+ // ignore
+ }
+ }
@Override
public void onResume() {
private Handler mReScanHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
- getTrackCursor(mAdapter.getQueryHandler(), null);
+ if (mAdapter != null) {
+ getTrackCursor(mAdapter.getQueryHandler(), null, true);
+ }
// if the query results in a null cursor, onQueryComplete() will
// call init(), which will post a delayed message to this handler
// in order to try again.
super.onSaveInstanceState(outcicle);
}
- public void init(Cursor newCursor) {
+ public void init(Cursor newCursor, boolean isLimited) {
+ if (mAdapter == null) {
+ return;
+ }
mAdapter.changeCursor(newCursor); // also sets mTrackCursor
if (mTrackCursor == null) {
mReScanHandler.sendEmptyMessageDelayed(0, 1000);
return;
}
-
+
MusicUtils.hideDatabaseError(this);
+ mUseLastListPos = MusicUtils.updateButtonBar(this, R.id.songtab);
setTitle();
+ // Restore previous position
+ if (mLastListPosCourse >= 0 && mUseLastListPos) {
+ ListView lv = getListView();
+ // this hack is needed because otherwise the position doesn't change
+ // for the 2nd (non-limited) cursor
+ lv.setAdapter(lv.getAdapter());
+ lv.setSelectionFromTop(mLastListPosCourse, mLastListPosFine);
+ if (!isLimited) {
+ mLastListPosCourse = -1;
+ }
+ }
+
// When showing the queue, position the selection on the currently playing track
// Otherwise, position the selection on the first matching artist, if any
IntentFilter f = new IntentFilter();
}
}
+ private void setAlbumArtBackground() {
+ try {
+ long albumid = Long.valueOf(mAlbumId);
+ Bitmap bm = MusicUtils.getArtwork(TrackBrowserActivity.this, -1, albumid, false);
+ if (bm != null) {
+ MusicUtils.setBackground(mTrackList, bm);
+ mTrackList.setCacheColorHint(0);
+ return;
+ }
+ } catch (Exception ex) {
+ }
+ mTrackList.setBackgroundResource(0);
+ mTrackList.setCacheColorHint(0xff000000);
+ }
+
private void setTitle() {
CharSequence fancyName = null;
}
cursor.deactivate();
}
- if (fancyName.equals(MediaFile.UNKNOWN_STRING)) {
+ if (fancyName == null || fancyName.equals(MediaFile.UNKNOWN_STRING)) {
fancyName = getString(R.string.unknown_album_name);
}
}
}
}
- private TouchInterceptor.DragListener mDragListener =
- new TouchInterceptor.DragListener() {
- public void drag(int from, int to) {
- if (mTrackCursor instanceof NowPlayingCursor) {
- NowPlayingCursor c = (NowPlayingCursor) mTrackCursor;
- c.moveItem(from, to);
- ((TrackListAdapter)getListAdapter()).notifyDataSetChanged();
- getListView().invalidateViews();
- mDeletedOneRow = true;
- }
- }
- };
private TouchInterceptor.DropListener mDropListener =
new TouchInterceptor.DropListener() {
public void drop(int from, int to) {
if (from < to) {
// move the item to somewhere later in the list
mTrackCursor.moveToPosition(to);
- int toidx = mTrackCursor.getInt(colidx);
+ long toidx = mTrackCursor.getLong(colidx);
mTrackCursor.moveToPosition(from);
values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, toidx);
wherearg[0] = mTrackCursor.getString(0);
} else if (from > to) {
// move the item to somewhere earlier in the list
mTrackCursor.moveToPosition(to);
- int toidx = mTrackCursor.getInt(colidx);
+ long toidx = mTrackCursor.getLong(colidx);
mTrackCursor.moveToPosition(from);
values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, toidx);
wherearg[0] = mTrackCursor.getString(0);
@Override
public void onReceive(Context context, Intent intent) {
getListView().invalidateViews();
+ if (!mEditMode) {
+ MusicUtils.updateNowPlaying(TrackBrowserActivity.this);
+ }
}
};
}
};
+ // Cursor should be positioned on the entry to be checked
+ // Returns false if the entry matches the naming pattern used for recordings,
+ // or if it is marked as not music in the database.
+ private boolean isMusic(Cursor c) {
+ int titleidx = c.getColumnIndex(MediaStore.Audio.Media.TITLE);
+ int albumidx = c.getColumnIndex(MediaStore.Audio.Media.ALBUM);
+ int artistidx = c.getColumnIndex(MediaStore.Audio.Media.ARTIST);
+
+ String title = c.getString(titleidx);
+ String album = c.getString(albumidx);
+ String artist = c.getString(artistidx);
+ if (MediaFile.UNKNOWN_STRING.equals(album) &&
+ MediaFile.UNKNOWN_STRING.equals(artist) &&
+ title != null &&
+ title.startsWith("recording")) {
+ // not music
+ return false;
+ }
+
+ int ismusic_idx = c.getColumnIndex(MediaStore.Audio.Media.IS_MUSIC);
+ boolean ismusic = true;
+ if (ismusic_idx >= 0) {
+ ismusic = mTrackCursor.getInt(ismusic_idx) != 0;
+ }
+ return ismusic;
+ }
+
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfoIn) {
menu.add(0, PLAY_SELECTION, 0, R.string.play_selection);
}
menu.add(0, USE_AS_RINGTONE, 0, R.string.ringtone_menu);
menu.add(0, DELETE_ITEM, 0, R.string.delete_item);
- menu.add(0, SEARCH, 0, R.string.search_title);
AdapterContextMenuInfo mi = (AdapterContextMenuInfo) menuInfoIn;
mSelectedPosition = mi.position;
mTrackCursor.moveToPosition(mSelectedPosition);
try {
int id_idx = mTrackCursor.getColumnIndexOrThrow(
MediaStore.Audio.Playlists.Members.AUDIO_ID);
- mSelectedId = mTrackCursor.getInt(id_idx);
+ mSelectedId = mTrackCursor.getLong(id_idx);
} catch (IllegalArgumentException ex) {
mSelectedId = mi.id;
}
+ // only add the 'search' menu if the selected item is music
+ if (isMusic(mTrackCursor)) {
+ menu.add(0, SEARCH, 0, R.string.search_title);
+ }
mCurrentAlbumName = mTrackCursor.getString(mTrackCursor.getColumnIndexOrThrow(
MediaStore.Audio.Media.ALBUM));
mCurrentArtistNameForAlbum = mTrackCursor.getString(mTrackCursor.getColumnIndexOrThrow(
}
case QUEUE: {
- int [] list = new int[] { (int) mSelectedId };
+ long [] list = new long[] { mSelectedId };
MusicUtils.addToCurrentPlaylist(this, list);
return true;
}
}
case PLAYLIST_SELECTED: {
- int [] list = new int[] { (int) mSelectedId };
- int playlist = item.getIntent().getIntExtra("playlist", 0);
+ long [] list = new long[] { mSelectedId };
+ long playlist = item.getIntent().getLongExtra("playlist", 0);
MusicUtils.addToPlaylist(this, list, playlist);
return true;
}
return true;
case DELETE_ITEM: {
- int [] list = new int[1];
+ long [] list = new long[1];
list[0] = (int) mSelectedId;
Bundle b = new Bundle();
String f = getString(R.string.delete_song_desc);
String desc = String.format(f, mCurrentTrackName);
b.putString("description", desc);
- b.putIntArray("items", list);
+ b.putLongArray("items", list);
Intent intent = new Intent();
intent.setClass(this, DeleteItems.class);
intent.putExtras(b);
Intent i = new Intent();
i.setAction(MediaStore.INTENT_ACTION_MEDIA_SEARCH);
+ i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- title = mCurrentAlbumName;
- query = mCurrentArtistNameForAlbum + " " + mCurrentAlbumName;
- i.putExtra(MediaStore.EXTRA_MEDIA_ARTIST, mCurrentArtistNameForAlbum);
- i.putExtra(MediaStore.EXTRA_MEDIA_ALBUM, mCurrentAlbumName);
+ title = mCurrentTrackName;
+ if (MediaFile.UNKNOWN_STRING.equals(mCurrentArtistNameForAlbum)) {
+ query = mCurrentTrackName;
+ } else {
+ query = mCurrentArtistNameForAlbum + " " + mCurrentTrackName;
+ i.putExtra(MediaStore.EXTRA_MEDIA_ARTIST, mCurrentArtistNameForAlbum);
+ }
+ if (MediaFile.UNKNOWN_STRING.equals(mCurrentAlbumName)) {
+ i.putExtra(MediaStore.EXTRA_MEDIA_ALBUM, mCurrentAlbumName);
+ }
i.putExtra(MediaStore.EXTRA_MEDIA_FOCUS, "audio/*");
title = getString(R.string.mediasearch, title);
i.putExtra(SearchManager.QUERY, query);
if (mTrackCursor.getCount() == 0) {
return;
}
+ // When selecting a track from the queue, just jump there instead of
+ // reloading the queue. This is both faster, and prevents accidentally
+ // dropping out of party shuffle.
+ if (mTrackCursor instanceof NowPlayingCursor) {
+ if (MusicUtils.sService != null) {
+ try {
+ MusicUtils.sService.setQueuePosition(position);
+ return;
+ } catch (RemoteException ex) {
+ }
+ }
+ }
MusicUtils.playAll(this, mTrackCursor, position);
}
if (mPlaylist == null) {
menu.add(0, PLAY_ALL, 0, R.string.play_all).setIcon(com.android.internal.R.drawable.ic_menu_play_clip);
}
- menu.add(0, GOTO_START, 0, R.string.goto_start).setIcon(R.drawable.ic_menu_music_library);
- menu.add(0, GOTO_PLAYBACK, 0, R.string.goto_playback).setIcon(R.drawable.ic_menu_playback)
- .setVisible(MusicUtils.isMusicLoaded());
+ menu.add(0, PARTY_SHUFFLE, 0, R.string.party_shuffle); // icon will be set in onPrepareOptionsMenu()
menu.add(0, SHUFFLE_ALL, 0, R.string.shuffle_all).setIcon(R.drawable.ic_menu_shuffle);
if (mPlaylist != null) {
menu.add(0, SAVE_AS_PLAYLIST, 0, R.string.save_as_playlist).setIcon(android.R.drawable.ic_menu_save);
}
@Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ MusicUtils.setPartyShuffleMenuIcon(menu);
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent intent;
Cursor cursor;
return true;
}
- case GOTO_START:
- intent = new Intent();
- intent.setClass(this, MusicBrowserActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(intent);
- return true;
-
- case GOTO_PLAYBACK:
- intent = new Intent("com.android.music.PLAYBACK_VIEWER");
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(intent);
- return true;
+ case PARTY_SHUFFLE:
+ MusicUtils.togglePartyShuffle();
+ break;
case SHUFFLE_ALL:
// Should 'shuffle all' shuffle ALL, or only the tracks shown?
if (resultCode == RESULT_CANCELED) {
finish();
} else {
- getTrackCursor(mAdapter.getQueryHandler(), null);
+ getTrackCursor(mAdapter.getQueryHandler(), null, true);
}
break;
if (resultCode == RESULT_OK) {
Uri uri = intent.getData();
if (uri != null) {
- int [] list = new int[] { (int) mSelectedId };
+ long [] list = new long[] { mSelectedId };
MusicUtils.addToPlaylist(this, list, Integer.valueOf(uri.getLastPathSegment()));
}
}
if (resultCode == RESULT_OK) {
Uri uri = intent.getData();
if (uri != null) {
- int [] list = MusicUtils.getSongListForCursor(mTrackCursor);
+ long [] list = MusicUtils.getSongListForCursor(mTrackCursor);
int plid = Integer.parseInt(uri.getLastPathSegment());
MusicUtils.addToPlaylist(this, list, plid);
}
}
}
- private Cursor getTrackCursor(AsyncQueryHandler async, String filter) {
+ private Cursor getTrackCursor(TrackListAdapter.TrackQueryHandler queryhandler, String filter,
+ boolean async) {
+
+ if (queryhandler == null) {
+ throw new IllegalArgumentException();
+ }
+
Cursor ret = null;
mSortOrder = MediaStore.Audio.Media.TITLE_KEY;
StringBuilder where = new StringBuilder();
where.append(MediaStore.Audio.Media.TITLE + " != ''");
-
+
// Add in the filtering constraints
String [] keywords = null;
if (filter != null) {
for (int i = 0; i < searchWords.length; i++) {
where.append(" AND ");
where.append(MediaStore.Audio.Media.ARTIST_KEY + "||");
- where.append(MediaStore.Audio.Media.ALBUM_KEY + "||");
where.append(MediaStore.Audio.Media.TITLE_KEY + " LIKE ?");
}
}
if (mGenre != null) {
mSortOrder = MediaStore.Audio.Genres.Members.DEFAULT_SORT_ORDER;
- if (async != null) {
- async.startQuery(0, null,
- MediaStore.Audio.Genres.Members.getContentUri("external",
- Integer.valueOf(mGenre)),
- mCursorCols, where.toString(), keywords, mSortOrder);
- ret = null;
- } else {
- ret = MusicUtils.query(this,
- MediaStore.Audio.Genres.Members.getContentUri("external", Integer.valueOf(mGenre)),
- mCursorCols, where.toString(), keywords, mSortOrder);
- }
+ ret = queryhandler.doQuery(MediaStore.Audio.Genres.Members.getContentUri("external",
+ Integer.valueOf(mGenre)),
+ mCursorCols, where.toString(), keywords, mSortOrder, async);
} else if (mPlaylist != null) {
if (mPlaylist.equals("nowplaying")) {
if (MusicUtils.sService != null) {
}
} else if (mPlaylist.equals("podcasts")) {
where.append(" AND " + MediaStore.Audio.Media.IS_PODCAST + "=1");
- if (async != null) {
- async.startQuery(0, null,
- MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, mCursorCols,
- where.toString(), keywords, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
- ret = null;
- } else {
- ret = MusicUtils.query(this,
- MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, mCursorCols,
- where.toString(), keywords, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
- }
+ ret = queryhandler.doQuery(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
+ mCursorCols, where.toString(), keywords,
+ MediaStore.Audio.Media.DEFAULT_SORT_ORDER, async);
} else if (mPlaylist.equals("recentlyadded")) {
// do a query for all songs added in the last X weeks
int X = MusicUtils.getIntPref(this, "numweeks", 2) * (3600 * 24 * 7);
where.append(" AND " + MediaStore.MediaColumns.DATE_ADDED + ">");
where.append(System.currentTimeMillis() / 1000 - X);
- if (async != null) {
- async.startQuery(0, null,
- MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, mCursorCols,
- where.toString(), keywords, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
- ret = null;
- } else {
- ret = MusicUtils.query(this,
- MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, mCursorCols,
- where.toString(), keywords, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
- }
+ ret = queryhandler.doQuery(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
+ mCursorCols, where.toString(), keywords,
+ MediaStore.Audio.Media.DEFAULT_SORT_ORDER, async);
} else {
mSortOrder = MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER;
- if (async != null) {
- async.startQuery(0, null,
- MediaStore.Audio.Playlists.Members.getContentUri("external", Long.valueOf(mPlaylist)),
- mPlaylistMemberCols, where.toString(), keywords, mSortOrder);
- ret = null;
- } else {
- ret = MusicUtils.query(this,
- MediaStore.Audio.Playlists.Members.getContentUri("external", Long.valueOf(mPlaylist)),
- mPlaylistMemberCols, where.toString(), keywords, mSortOrder);
- }
+ ret = queryhandler.doQuery(MediaStore.Audio.Playlists.Members.getContentUri("external",
+ Long.valueOf(mPlaylist)), mPlaylistMemberCols,
+ where.toString(), keywords, mSortOrder, async);
}
} else {
if (mAlbumId != null) {
where.append(" AND " + MediaStore.Audio.Media.ARTIST_ID + "=" + mArtistId);
}
where.append(" AND " + MediaStore.Audio.Media.IS_MUSIC + "=1");
- if (async != null) {
- async.startQuery(0, null,
- MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
- mCursorCols, where.toString() , keywords, mSortOrder);
- ret = null;
- } else {
- ret = MusicUtils.query(this, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
- mCursorCols, where.toString() , keywords, mSortOrder);
- }
+ ret = queryhandler.doQuery(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
+ mCursorCols, where.toString() , keywords, mSortOrder, async);
}
// This special case is for the "nowplaying" cursor, which cannot be handled
// asynchronously using AsyncQueryHandler, so we do some extra initialization here.
- if (ret != null && async != null) {
- init(ret);
+ if (ret != null && async) {
+ init(ret, false);
setTitle();
}
return ret;
try {
mNowPlaying = mService.getQueue();
} catch (RemoteException ex) {
- mNowPlaying = new int[0];
+ mNowPlaying = new long[0];
}
mSize = mNowPlaying.length;
if (mSize == 0) {
}
int size = mCurrentPlaylistCursor.getCount();
- mCursorIdxs = new int[size];
+ mCursorIdxs = new long[size];
mCurrentPlaylistCursor.moveToFirst();
int colidx = mCurrentPlaylistCursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID);
for (int i = 0; i < size; i++) {
- mCursorIdxs[i] = mCurrentPlaylistCursor.getInt(colidx);
+ mCursorIdxs[i] = mCurrentPlaylistCursor.getLong(colidx);
mCurrentPlaylistCursor.moveToNext();
}
mCurrentPlaylistCursor.moveToFirst();
try {
int removed = 0;
for (int i = mNowPlaying.length - 1; i >= 0; i--) {
- int trackid = mNowPlaying[i];
+ long trackid = mNowPlaying[i];
int crsridx = Arrays.binarySearch(mCursorIdxs, trackid);
if (crsridx < 0) {
//Log.i("@@@@@", "item no longer exists in db: " + trackid);
}
}
} catch (RemoteException ex) {
- mNowPlaying = new int[0];
+ mNowPlaying = new long[0];
}
}
// in queue-order, so we need to figure out where in the cursor we
// should be.
- int newid = mNowPlaying[newPosition];
+ long newid = mNowPlaying[newPosition];
int crsridx = Arrays.binarySearch(mCursorIdxs, newid);
mCurrentPlaylistCursor.moveToPosition(crsridx);
mCurPos = newPosition;
private String [] mCols;
private Cursor mCurrentPlaylistCursor; // updated in onMove
private int mSize; // size of the queue
- private int[] mNowPlaying;
- private int[] mCursorIdxs;
+ private long[] mNowPlaying;
+ private long[] mCursorIdxs;
private int mCurPos;
private IMediaPlaybackService mService;
}
int mTitleIdx;
int mArtistIdx;
- int mAlbumIdx;
int mDurationIdx;
int mAudioIdIdx;
private AlphabetIndexer mIndexer;
private TrackBrowserActivity mActivity = null;
- private AsyncQueryHandler mQueryHandler;
+ private TrackQueryHandler mQueryHandler;
+ private String mConstraint = null;
+ private boolean mConstraintIsValid = false;
- class ViewHolder {
+ static class ViewHolder {
TextView line1;
TextView line2;
TextView duration;
char [] buffer2;
}
- class QueryHandler extends AsyncQueryHandler {
- QueryHandler(ContentResolver res) {
+ class TrackQueryHandler extends AsyncQueryHandler {
+
+ class QueryArgs {
+ public Uri uri;
+ public String [] projection;
+ public String selection;
+ public String [] selectionArgs;
+ public String orderBy;
+ }
+
+ TrackQueryHandler(ContentResolver res) {
super(res);
}
+ public Cursor doQuery(Uri uri, String[] projection,
+ String selection, String[] selectionArgs,
+ String orderBy, boolean async) {
+ if (async) {
+ // Get 100 results first, which is enough to allow the user to start scrolling,
+ // while still being very fast.
+ Uri limituri = uri.buildUpon().appendQueryParameter("limit", "100").build();
+ QueryArgs args = new QueryArgs();
+ args.uri = uri;
+ args.projection = projection;
+ args.selection = selection;
+ args.selectionArgs = selectionArgs;
+ args.orderBy = orderBy;
+
+ startQuery(0, args, limituri, projection, selection, selectionArgs, orderBy);
+ return null;
+ }
+ return MusicUtils.query(mActivity,
+ uri, projection, selection, selectionArgs, orderBy);
+ }
+
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
//Log.i("@@@", "query complete: " + cursor.getCount() + " " + mActivity);
- mActivity.init(cursor);
+ mActivity.init(cursor, cookie != null);
+ if (token == 0 && cookie != null && cursor != null && cursor.getCount() >= 100) {
+ QueryArgs args = (QueryArgs) cookie;
+ startQuery(1, null, args.uri, args.projection, args.selection,
+ args.selectionArgs, args.orderBy);
+ }
}
}
mUnknownArtist = context.getString(R.string.unknown_artist_name);
mUnknownAlbum = context.getString(R.string.unknown_album_name);
- mQueryHandler = new QueryHandler(context.getContentResolver());
+ mQueryHandler = new TrackQueryHandler(context.getContentResolver());
}
public void setActivity(TrackBrowserActivity newactivity) {
mActivity = newactivity;
}
- public AsyncQueryHandler getQueryHandler() {
+ public TrackQueryHandler getQueryHandler() {
return mQueryHandler;
}
if (cursor != null) {
mTitleIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE);
mArtistIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST);
- mAlbumIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM);
mDurationIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION);
try {
mAudioIdIdx = cursor.getColumnIndexOrThrow(
vh.line2.setText(vh.buffer2, 0, len);
ImageView iv = vh.play_indicator;
- int id = -1;
+ long id = -1;
if (MusicUtils.sService != null) {
// TODO: IPC call on each bind??
try {
// playlist mode (except when you're viewing the "current playlist",
// which is not really a playlist)
if ( (mIsNowPlaying && cursor.getPosition() == id) ||
- (!mIsNowPlaying && !mDisableNowPlayingIndicator && cursor.getInt(mAudioIdIdx) == id)) {
+ (!mIsNowPlaying && !mDisableNowPlayingIndicator && cursor.getLong(mAudioIdIdx) == id)) {
iv.setImageResource(R.drawable.indicator_ic_mp_playing_list);
iv.setVisibility(View.VISIBLE);
} else {
@Override
public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
- return mActivity.getTrackCursor(null, constraint.toString());
+ String s = constraint.toString();
+ if (mConstraintIsValid && (
+ (s == null && mConstraint == null) ||
+ (s != null && s.equals(mConstraint)))) {
+ return getCursor();
+ }
+ Cursor c = mActivity.getTrackCursor(mQueryHandler, s, false);
+ mConstraint = s;
+ mConstraintIsValid = true;
+ return c;
}
// SectionIndexer methods