Support MediaBrowserService in AOSP Music
* Use MediaSession and MediaController to interact between playback
service and playback applications
* Introduced MusicProvdier to scan music resources on local disk
* Removed unnecessary intents and unused activities
* Disabled playlist add, edit, delete function temporarily
Bug: 34748293
Test: make, playing music, browse through Bluetooth on Carkit
Change-Id: Ic88847aa0b3dd4ef5e13afcb839c78544ac05a2a
diff --git a/src/com/android/music/ArtistAlbumBrowserActivity.java b/src/com/android/music/ArtistAlbumBrowserActivity.java
index 474ff37..ffccd32 100644
--- a/src/com/android/music/ArtistAlbumBrowserActivity.java
+++ b/src/com/android/music/ArtistAlbumBrowserActivity.java
@@ -16,617 +16,271 @@
package com.android.music;
-import com.android.music.MusicUtils.ServiceToken;
-import com.android.music.QueryBrowserActivity.QueryListAdapter.QueryHandler;
-
import android.app.ExpandableListActivity;
-import android.app.SearchManager;
-import android.content.AsyncQueryHandler;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.database.CursorWrapper;
+import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
+import android.media.MediaDescription;
+import android.media.MediaMetadata;
+import android.media.browse.MediaBrowser;
+import android.media.session.MediaController;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.provider.MediaStore;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.ContextMenu;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.SubMenu;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
-import android.view.ContextMenu.ContextMenuInfo;
import android.widget.ExpandableListView;
import android.widget.ImageView;
-import android.widget.SectionIndexer;
-import android.widget.SimpleCursorTreeAdapter;
+import android.widget.SimpleExpandableListAdapter;
import android.widget.TextView;
-import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
+import android.widget.Toast;
-import java.text.Collator;
+import com.android.music.utils.LogHelper;
+import com.android.music.utils.MediaIDHelper;
-public class ArtistAlbumBrowserActivity extends ExpandableListActivity
- implements View.OnCreateContextMenuListener, MusicUtils.Defs, ServiceConnection {
- private String mCurrentArtistId;
- private String mCurrentArtistName;
- private String mCurrentAlbumId;
- private String mCurrentAlbumName;
- private String mCurrentArtistNameForAlbum;
- boolean mIsUnknownArtist;
- boolean mIsUnknownAlbum;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class ArtistAlbumBrowserActivity extends ExpandableListActivity {
+ private static final String TAG = LogHelper.makeLogTag(ArtistAlbumBrowserActivity.class);
+ private static final String KEY_NUM_ALBUMS = "__NUM_ALBUMS__";
+ private static final MediaBrowser.MediaItem DEFAULT_PARENT_ITEM =
+ new MediaBrowser.MediaItem(new MediaDescription.Builder()
+ .setMediaId(MediaIDHelper.MEDIA_ID_MUSICS_BY_ARTIST)
+ .build(),
+ MediaBrowser.MediaItem.FLAG_BROWSABLE);
+
private ArtistAlbumListAdapter mAdapter;
- private boolean mAdapterSent;
- private final static int SEARCH = CHILD_MENU_BASE;
- private static int mLastListPosCourse = -1;
- private static int mLastListPosFine = -1;
- private ServiceToken mToken;
+ private MediaBrowser mMediaBrowser;
+ private MediaBrowser.MediaItem mParentItem;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ LogHelper.d(TAG, "onCreate()");
+ // Handle past states
+ if (icicle != null) {
+ mParentItem = icicle.getParcelable(MusicUtils.TAG_PARENT_ITEM);
+ } else if (getIntent() != null) {
+ mParentItem = getIntent().getExtras().getParcelable(MusicUtils.TAG_PARENT_ITEM);
+ }
+ if (mParentItem == null) {
+ mParentItem = DEFAULT_PARENT_ITEM;
+ }
requestWindowFeature(Window.FEATURE_NO_TITLE);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
- if (icicle != null) {
- mCurrentAlbumId = icicle.getString("selectedalbum");
- mCurrentAlbumName = icicle.getString("selectedalbumname");
- mCurrentArtistId = icicle.getString("selectedartist");
- mCurrentArtistName = icicle.getString("selectedartistname");
- }
- mToken = MusicUtils.bindToService(this, this);
- IntentFilter f = new IntentFilter();
- f.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
- f.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
- f.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
- f.addDataScheme("file");
- registerReceiver(mScanListener, f);
-
+ // Init layout
setContentView(R.layout.media_picker_activity_expanding);
MusicUtils.updateButtonBar(this, R.id.artisttab);
- ExpandableListView lv = getExpandableListView();
- lv.setOnCreateContextMenuListener(this);
- lv.setTextFilterEnabled(true);
+ // Init expandable list
+ ExpandableListView lv = getExpandableListView();
+ lv.setTextFilterEnabled(true);
mAdapter = (ArtistAlbumListAdapter) getLastNonConfigurationInstance();
if (mAdapter == null) {
// Log.i("@@@", "starting query");
- mAdapter = new ArtistAlbumListAdapter(getApplication(), this,
- null, // cursor
- R.layout.track_list_item_group, new String[] {}, new int[] {},
- R.layout.track_list_item_child, new String[] {}, new int[] {});
+ mAdapter = new ArtistAlbumListAdapter(this, new ArrayList<>(), new ArrayList<>());
setListAdapter(mAdapter);
setTitle(R.string.working_artists);
- getArtistCursor(mAdapter.getQueryHandler(), null);
} else {
mAdapter.setActivity(this);
- setListAdapter(mAdapter);
- mArtistCursor = mAdapter.getCursor();
- if (mArtistCursor != null) {
- init(mArtistCursor);
- } else {
- getArtistCursor(mAdapter.getQueryHandler(), null);
- }
}
+ setListAdapter(mAdapter);
+ LogHelper.d(TAG, "Creating MediaBrowser");
+ mMediaBrowser = new MediaBrowser(this, new ComponentName(this, MediaPlaybackService.class),
+ mConnectionCallback, null);
}
@Override
public Object onRetainNonConfigurationInstance() {
- mAdapterSent = true;
return mAdapter;
}
@Override
public void onSaveInstanceState(Bundle outcicle) {
- // need to store the selected item so we don't lose it in case
- // of an orientation switch. Otherwise we could lose it while
- // in the middle of specifying a playlist to add the item to.
- outcicle.putString("selectedalbum", mCurrentAlbumId);
- outcicle.putString("selectedalbumname", mCurrentAlbumName);
- outcicle.putString("selectedartist", mCurrentArtistId);
- outcicle.putString("selectedartistname", mCurrentArtistName);
+ outcicle.putParcelable(MusicUtils.TAG_PARENT_ITEM, mParentItem);
super.onSaveInstanceState(outcicle);
}
@Override
public void onDestroy() {
- ExpandableListView lv = getExpandableListView();
- if (lv != null) {
- mLastListPosCourse = lv.getFirstVisiblePosition();
- View cv = lv.getChildAt(0);
- if (cv != null) {
- mLastListPosFine = cv.getTop();
- }
- }
-
- MusicUtils.unbindFromService(mToken);
- // If we have an adapter and didn't send it off to another activity yet, we should
- // close its cursor, which we do by assigning a null cursor to it. Doing this
- // instead of closing the cursor directly keeps the framework from accessing
- // the closed cursor later.
- if (!mAdapterSent && mAdapter != null) {
- mAdapter.changeCursor(null);
- }
- // 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;
- unregisterReceiver(mScanListener);
setListAdapter(null);
super.onDestroy();
}
@Override
- public void onResume() {
- super.onResume();
- IntentFilter f = new IntentFilter();
- f.addAction(MediaPlaybackService.META_CHANGED);
- f.addAction(MediaPlaybackService.QUEUE_CHANGED);
- registerReceiver(mTrackListListener, f);
- mTrackListListener.onReceive(null, null);
-
- MusicUtils.setSpinnerState(this);
+ public void onStart() {
+ LogHelper.d(TAG, "onStart()");
+ super.onStart();
+ mMediaBrowser.connect();
}
- private BroadcastReceiver mTrackListListener = new BroadcastReceiver() {
+ @Override
+ public void onStop() {
+ LogHelper.d(TAG, "onStop()");
+ super.onStop();
+ mMediaBrowser.disconnect();
+ }
+
+ private MediaBrowser
+ .SubscriptionCallback mSubscriptionCallback = new MediaBrowser.SubscriptionCallback() {
@Override
- public void onReceive(Context context, Intent intent) {
- getExpandableListView().invalidateViews();
+ public void onChildrenLoaded(String parentId, List<MediaBrowser.MediaItem> children) {
+ if (parentId.equals(MediaIDHelper.MEDIA_ID_MUSICS_BY_ARTIST)) {
+ mAdapter.getArtistMap().clear();
+ mAdapter.getGroupData().clear();
+ mAdapter.notifyDataSetInvalidated();
+ for (MediaBrowser.MediaItem item : children) {
+ ConcurrentHashMap<String, MediaBrowser.MediaItem> entry =
+ new ConcurrentHashMap<>();
+ entry.put(MediaIDHelper.MEDIA_ID_MUSICS_BY_ARTIST, item);
+ synchronized (this) {
+ mAdapter.getArtistMap().put(item.getDescription().getTitle().toString(),
+ mAdapter.getGroupData().size());
+ mAdapter.getGroupData().add(entry);
+ mAdapter.getChildData().add(new ArrayList<>());
+ }
+ mMediaBrowser.subscribe(item.getMediaId(), this);
+ }
+ mAdapter.notifyDataSetChanged();
+ } else if (parentId.startsWith(MediaIDHelper.MEDIA_ID_MUSICS_BY_ARTIST)) {
+ String artist = MediaIDHelper.getHierarchy(parentId)[1];
+ if (!mAdapter.getArtistMap().containsKey(artist)) {
+ return;
+ }
+ int artistIndex = mAdapter.getArtistMap().get(artist);
+ mAdapter.getChildData().get(artistIndex).clear();
+ mAdapter.notifyDataSetInvalidated();
+ Bundle extras = new Bundle();
+ extras.putLong(KEY_NUM_ALBUMS, children.size());
+ MediaBrowser.MediaItem newArtistItem =
+ new MediaBrowser.MediaItem(new MediaDescription.Builder()
+ .setMediaId("Count")
+ .setExtras(extras)
+ .build(),
+ 0);
+ mAdapter.getGroupData().get(artistIndex).put(KEY_NUM_ALBUMS, newArtistItem);
+ for (MediaBrowser.MediaItem item : children) {
+ ConcurrentHashMap<String, MediaBrowser.MediaItem> entry =
+ new ConcurrentHashMap<>();
+ entry.put(MediaIDHelper.MEDIA_ID_MUSICS_BY_ALBUM, item);
+ mAdapter.getChildData().get(artistIndex).add(entry);
+ }
+ mAdapter.notifyDataSetChanged();
+ }
+ }
+
+ @Override
+ public void onError(String id) {
+ Toast.makeText(getApplicationContext(), R.string.error_loading_media, Toast.LENGTH_LONG)
+ .show();
+ }
+ };
+
+ private MediaBrowser.ConnectionCallback mConnectionCallback =
+ new MediaBrowser.ConnectionCallback() {
+ @Override
+ public void onConnected() {
+ LogHelper.d(
+ TAG, "onConnected: session token ", mMediaBrowser.getSessionToken());
+ mMediaBrowser.subscribe(mParentItem.getMediaId(), mSubscriptionCallback);
+ if (mMediaBrowser.getSessionToken() == null) {
+ throw new IllegalArgumentException("No Session token");
+ }
+ MediaController mediaController = new MediaController(
+ ArtistAlbumBrowserActivity.this, mMediaBrowser.getSessionToken());
+ mediaController.registerCallback(mMediaControllerCallback);
+ ArtistAlbumBrowserActivity.this.setMediaController(mediaController);
+ if (mediaController.getMetadata() != null) {
+ MusicUtils.updateNowPlaying(ArtistAlbumBrowserActivity.this);
+ }
+ }
+
+ @Override
+ public void onConnectionFailed() {
+ LogHelper.d(TAG, "onConnectionFailed");
+ }
+
+ @Override
+ public void onConnectionSuspended() {
+ LogHelper.d(TAG, "onConnectionSuspended");
+ ArtistAlbumBrowserActivity.this.setMediaController(null);
+ }
+ };
+
+ private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
+ @Override
+ public void onMetadataChanged(MediaMetadata metadata) {
+ super.onMetadataChanged(metadata);
MusicUtils.updateNowPlaying(ArtistAlbumBrowserActivity.this);
}
};
- private BroadcastReceiver mScanListener = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- MusicUtils.setSpinnerState(ArtistAlbumBrowserActivity.this);
- mReScanHandler.sendEmptyMessage(0);
- if (intent.getAction().equals(Intent.ACTION_MEDIA_UNMOUNTED)) {
- MusicUtils.clearAlbumArtCache();
- }
- }
- };
- private Handler mReScanHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (mAdapter != null) {
- getArtistCursor(mAdapter.getQueryHandler(), null);
- }
- }
- };
-
- @Override
- public void onPause() {
- unregisterReceiver(mTrackListListener);
- mReScanHandler.removeCallbacksAndMessages(null);
- super.onPause();
- }
-
- public void init(Cursor c) {
- if (mAdapter == null) {
- return;
- }
- mAdapter.changeCursor(c); // also sets mArtistCursor
-
- if (mArtistCursor == null) {
- MusicUtils.displayDatabaseError(this);
- closeContextMenu();
- mReScanHandler.sendEmptyMessageDelayed(0, 1000);
- return;
- }
-
- // restore previous position
- if (mLastListPosCourse >= 0) {
- ExpandableListView elv = getExpandableListView();
- elv.setSelectionFromTop(mLastListPosCourse, mLastListPosFine);
- mLastListPosCourse = -1;
- }
-
- MusicUtils.hideDatabaseError(this);
- MusicUtils.updateButtonBar(this, R.id.artisttab);
- setTitle();
- }
-
- private void setTitle() {
- setTitle(R.string.artists_title);
- }
-
- @Override
- public boolean onChildClick(
- ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
- mCurrentAlbumId = Long.valueOf(id).toString();
-
- Intent intent = new Intent(Intent.ACTION_PICK);
- intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track");
- intent.putExtra("album", mCurrentAlbumId);
- Cursor c = (Cursor) getExpandableListAdapter().getChild(groupPosition, childPosition);
- String album = c.getString(c.getColumnIndex(MediaStore.Audio.Albums.ALBUM));
- if (album == null || album.equals(MediaStore.UNKNOWN_STRING)) {
- // unknown album, so we should include the artist ID to limit the songs to songs only by
- // that artist
- mArtistCursor.moveToPosition(groupPosition);
- mCurrentArtistId = mArtistCursor.getString(
- mArtistCursor.getColumnIndex(MediaStore.Audio.Artists._ID));
- intent.putExtra("artist", mCurrentArtistId);
- }
- startActivity(intent);
- return true;
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- 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);
- return true;
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- MusicUtils.setPartyShuffleMenuIcon(menu);
- return super.onPrepareOptionsMenu(menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- Intent intent;
- Cursor cursor;
- switch (item.getItemId()) {
- case PARTY_SHUFFLE:
- MusicUtils.togglePartyShuffle();
- break;
-
- case SHUFFLE_ALL:
- cursor = MusicUtils.query(this, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
- new String[] {MediaStore.Audio.Media._ID},
- MediaStore.Audio.Media.IS_MUSIC + "=1", null,
- MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
- if (cursor != null) {
- MusicUtils.shuffleAll(this, cursor);
- cursor.close();
- }
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfoIn) {
- menu.add(0, PLAY_SELECTION, 0, R.string.play_selection);
- SubMenu sub = menu.addSubMenu(0, ADD_TO_PLAYLIST, 0, R.string.add_to_playlist);
- MusicUtils.makePlaylistMenu(this, sub);
- menu.add(0, DELETE_ITEM, 0, R.string.delete_item);
-
- ExpandableListContextMenuInfo mi = (ExpandableListContextMenuInfo) menuInfoIn;
-
- int itemtype = ExpandableListView.getPackedPositionType(mi.packedPosition);
- int gpos = ExpandableListView.getPackedPositionGroup(mi.packedPosition);
- int cpos = ExpandableListView.getPackedPositionChild(mi.packedPosition);
- if (itemtype == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
- if (gpos == -1) {
- // this shouldn't happen
- Log.d("Artist/Album", "no group");
- return;
- }
- gpos = gpos - getExpandableListView().getHeaderViewsCount();
- mArtistCursor.moveToPosition(gpos);
- mCurrentArtistId = mArtistCursor.getString(
- mArtistCursor.getColumnIndexOrThrow(MediaStore.Audio.Artists._ID));
- mCurrentArtistName = mArtistCursor.getString(
- mArtistCursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.ARTIST));
- mCurrentAlbumId = null;
- mIsUnknownArtist = mCurrentArtistName == null
- || mCurrentArtistName.equals(MediaStore.UNKNOWN_STRING);
- mIsUnknownAlbum = true;
- if (mIsUnknownArtist) {
- menu.setHeaderTitle(getString(R.string.unknown_artist_name));
- } else {
- menu.setHeaderTitle(mCurrentArtistName);
- menu.add(0, SEARCH, 0, R.string.search_title);
- }
- return;
- } else if (itemtype == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
- if (cpos == -1) {
- // this shouldn't happen
- Log.d("Artist/Album", "no child");
- return;
- }
- Cursor c = (Cursor) getExpandableListAdapter().getChild(gpos, cpos);
- c.moveToPosition(cpos);
- mCurrentArtistId = null;
- mCurrentAlbumId = Long.valueOf(mi.id).toString();
- mCurrentAlbumName = c.getString(c.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM));
- gpos = gpos - getExpandableListView().getHeaderViewsCount();
- mArtistCursor.moveToPosition(gpos);
- mCurrentArtistNameForAlbum = mArtistCursor.getString(
- mArtistCursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.ARTIST));
- mIsUnknownArtist = mCurrentArtistNameForAlbum == null
- || mCurrentArtistNameForAlbum.equals(MediaStore.UNKNOWN_STRING);
- mIsUnknownAlbum = mCurrentAlbumName == null
- || mCurrentAlbumName.equals(MediaStore.UNKNOWN_STRING);
- if (mIsUnknownAlbum) {
- menu.setHeaderTitle(getString(R.string.unknown_album_name));
- } else {
- menu.setHeaderTitle(mCurrentAlbumName);
- }
- if (!mIsUnknownAlbum || !mIsUnknownArtist) {
- menu.add(0, SEARCH, 0, R.string.search_title);
- }
- }
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case PLAY_SELECTION: {
- // play everything by the selected artist
- long[] list = mCurrentArtistId != null
- ? MusicUtils.getSongListForArtist(this, Long.parseLong(mCurrentArtistId))
- : MusicUtils.getSongListForAlbum(this, Long.parseLong(mCurrentAlbumId));
-
- MusicUtils.playAll(this, list, 0);
- return true;
- }
-
- case QUEUE: {
- long[] list = mCurrentArtistId != null
- ? MusicUtils.getSongListForArtist(this, Long.parseLong(mCurrentArtistId))
- : MusicUtils.getSongListForAlbum(this, Long.parseLong(mCurrentAlbumId));
- MusicUtils.addToCurrentPlaylist(this, list);
- return true;
- }
-
- case NEW_PLAYLIST: {
- Intent intent = new Intent();
- intent.setClass(this, CreatePlaylist.class);
- startActivityForResult(intent, NEW_PLAYLIST);
- return true;
- }
-
- case PLAYLIST_SELECTED: {
- long[] list = mCurrentArtistId != null
- ? MusicUtils.getSongListForArtist(this, Long.parseLong(mCurrentArtistId))
- : MusicUtils.getSongListForAlbum(this, Long.parseLong(mCurrentAlbumId));
- long playlist = item.getIntent().getLongExtra("playlist", 0);
- MusicUtils.addToPlaylist(this, list, playlist);
- return true;
- }
-
- case DELETE_ITEM: {
- long[] list;
- String desc;
- if (mCurrentArtistId != null) {
- list = MusicUtils.getSongListForArtist(this, Long.parseLong(mCurrentArtistId));
- String f;
- if (android.os.Environment.isExternalStorageRemovable()) {
- f = getString(R.string.delete_artist_desc);
- } else {
- f = getString(R.string.delete_artist_desc_nosdcard);
- }
- desc = String.format(f, mCurrentArtistName);
- } else {
- list = MusicUtils.getSongListForAlbum(this, Long.parseLong(mCurrentAlbumId));
- String f;
- if (android.os.Environment.isExternalStorageRemovable()) {
- f = getString(R.string.delete_album_desc);
- } else {
- f = getString(R.string.delete_album_desc_nosdcard);
- }
-
- desc = String.format(f, mCurrentAlbumName);
- }
- Bundle b = new Bundle();
- b.putString("description", desc);
- b.putLongArray("items", list);
- Intent intent = new Intent();
- intent.setClass(this, DeleteItems.class);
- intent.putExtras(b);
- startActivityForResult(intent, -1);
- return true;
- }
-
- case SEARCH:
- doSearch();
- return true;
- }
- return super.onContextItemSelected(item);
- }
-
- void doSearch() {
- CharSequence title = null;
- String query = null;
-
- Intent i = new Intent();
- i.setAction(MediaStore.INTENT_ACTION_MEDIA_SEARCH);
- i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- if (mCurrentArtistId != null) {
- title = mCurrentArtistName;
- query = mCurrentArtistName;
- i.putExtra(MediaStore.EXTRA_MEDIA_ARTIST, mCurrentArtistName);
- i.putExtra(MediaStore.EXTRA_MEDIA_FOCUS, MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE);
- } else {
- if (mIsUnknownAlbum) {
- title = query = mCurrentArtistNameForAlbum;
- } else {
- title = query = mCurrentAlbumName;
- if (!mIsUnknownArtist) {
- query = query + " " + mCurrentArtistNameForAlbum;
- }
- }
- i.putExtra(MediaStore.EXTRA_MEDIA_ARTIST, mCurrentArtistNameForAlbum);
- i.putExtra(MediaStore.EXTRA_MEDIA_ALBUM, mCurrentAlbumName);
- i.putExtra(MediaStore.EXTRA_MEDIA_FOCUS, MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE);
- }
- title = getString(R.string.mediasearch, title);
- i.putExtra(SearchManager.QUERY, query);
-
- startActivity(Intent.createChooser(i, title));
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
- switch (requestCode) {
- case SCAN_DONE:
- if (resultCode == RESULT_CANCELED) {
- finish();
- } else {
- getArtistCursor(mAdapter.getQueryHandler(), null);
- }
- break;
-
- case NEW_PLAYLIST:
- if (resultCode == RESULT_OK) {
- Uri uri = intent.getData();
- if (uri != null) {
- long[] list = null;
- if (mCurrentArtistId != null) {
- list = MusicUtils.getSongListForArtist(
- this, Long.parseLong(mCurrentArtistId));
- } else if (mCurrentAlbumId != null) {
- list = MusicUtils.getSongListForAlbum(
- this, Long.parseLong(mCurrentAlbumId));
- }
- MusicUtils.addToPlaylist(
- this, list, Long.parseLong(uri.getLastPathSegment()));
- }
- }
- break;
- }
- }
-
- private Cursor getArtistCursor(AsyncQueryHandler async, String filter) {
- String[] cols = new String[] {MediaStore.Audio.Artists._ID, MediaStore.Audio.Artists.ARTIST,
- MediaStore.Audio.Artists.NUMBER_OF_ALBUMS,
- MediaStore.Audio.Artists.NUMBER_OF_TRACKS};
-
- Uri uri = MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI;
- if (!TextUtils.isEmpty(filter)) {
- uri = uri.buildUpon().appendQueryParameter("filter", Uri.encode(filter)).build();
- }
-
- Cursor ret = null;
- if (async != null) {
- async.startQuery(0, null, uri, cols, null, null, MediaStore.Audio.Artists.ARTIST_KEY);
- } else {
- ret = MusicUtils.query(
- this, uri, cols, null, null, MediaStore.Audio.Artists.ARTIST_KEY);
- }
- return ret;
- }
-
- static class ArtistAlbumListAdapter extends SimpleCursorTreeAdapter implements SectionIndexer {
+ private class ArtistAlbumListAdapter extends SimpleExpandableListAdapter {
private final Drawable mNowPlayingOverlay;
private final BitmapDrawable mDefaultAlbumIcon;
- private int mGroupArtistIdIdx;
- private int mGroupArtistIdx;
- private int mGroupAlbumIdx;
- private int mGroupSongIdx;
- private final Context mContext;
- private final Resources mResources;
- private final String mAlbumSongSeparator;
- private final String mUnknownAlbum;
- private final String mUnknownArtist;
- private final StringBuilder mBuffer = new StringBuilder();
- private final Object[] mFormatArgs = new Object[1];
- private final Object[] mFormatArgs3 = new Object[3];
- private MusicAlphabetIndexer mIndexer;
private ArtistAlbumBrowserActivity mActivity;
- private AsyncQueryHandler mQueryHandler;
- private String mConstraint = null;
- private boolean mConstraintIsValid = false;
+ private ArrayList<ConcurrentHashMap<String, MediaBrowser.MediaItem>> mGroupData;
+ private ArrayList < ArrayList
+ < ConcurrentHashMap<String, MediaBrowser.MediaItem>>> mChildData;
+ private ConcurrentHashMap<String, Integer> mArtistMap;
- static class ViewHolder {
+ private class ViewHolder {
TextView line1;
TextView line2;
ImageView play_indicator;
ImageView icon;
}
- class QueryHandler extends AsyncQueryHandler {
- QueryHandler(ContentResolver res) {
- super(res);
- }
-
- @Override
- protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
- // Log.i("@@@", "query complete");
- mActivity.init(cursor);
- }
- }
-
- ArtistAlbumListAdapter(Context context, ArtistAlbumBrowserActivity currentactivity,
- Cursor cursor, int glayout, String[] gfrom, int[] gto, int clayout, String[] cfrom,
- int[] cto) {
- super(context, cursor, glayout, gfrom, gto, clayout, cfrom, cto);
- mActivity = currentactivity;
- mQueryHandler = new QueryHandler(context.getContentResolver());
-
- Resources r = context.getResources();
- mNowPlayingOverlay = r.getDrawable(R.drawable.indicator_ic_mp_playing_list);
- mDefaultAlbumIcon = (BitmapDrawable) r.getDrawable(R.drawable.albumart_mp_unknown_list);
+ ArtistAlbumListAdapter(ArtistAlbumBrowserActivity currentActivity,
+ ArrayList<ConcurrentHashMap<String, MediaBrowser.MediaItem>> groupData,
+ ArrayList < ArrayList
+ < ConcurrentHashMap<String, MediaBrowser.MediaItem>>> childData) {
+ super(currentActivity, groupData, R.layout.track_list_item_group, new String[] {},
+ new int[] {}, childData, R.layout.track_list_item_child, new String[] {},
+ new int[] {});
+ mGroupData = groupData;
+ mChildData = childData;
+ mActivity = currentActivity;
+ mNowPlayingOverlay = currentActivity.getResources().getDrawable(
+ R.drawable.indicator_ic_mp_playing_list, currentActivity.getTheme());
+ mDefaultAlbumIcon = (BitmapDrawable) currentActivity.getResources().getDrawable(
+ R.drawable.albumart_mp_unknown_list, currentActivity.getTheme());
// no filter or dither, it's a lot faster and we can't tell the difference
mDefaultAlbumIcon.setFilterBitmap(false);
mDefaultAlbumIcon.setDither(false);
-
- mContext = context;
- getColumnIndices(cursor);
- mResources = context.getResources();
- mAlbumSongSeparator = context.getString(R.string.albumsongseparator);
- mUnknownAlbum = context.getString(R.string.unknown_album_name);
- mUnknownArtist = context.getString(R.string.unknown_artist_name);
+ mArtistMap = new ConcurrentHashMap<>();
}
- private void getColumnIndices(Cursor cursor) {
- if (cursor != null) {
- mGroupArtistIdIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists._ID);
- mGroupArtistIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.ARTIST);
- mGroupAlbumIdx =
- cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.NUMBER_OF_ALBUMS);
- mGroupSongIdx =
- cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.NUMBER_OF_TRACKS);
- if (mIndexer != null) {
- mIndexer.setCursor(cursor);
- } else {
- mIndexer = new MusicAlphabetIndexer(cursor, mGroupArtistIdx,
- mResources.getString(R.string.fast_scroll_alphabet));
- }
- }
+ public ArrayList<ConcurrentHashMap<String, MediaBrowser.MediaItem>> getGroupData() {
+ return mGroupData;
+ }
+
+ public ArrayList < ArrayList
+ < ConcurrentHashMap<String, MediaBrowser.MediaItem>>> getChildData() {
+ return mChildData;
+ }
+
+ public Map<String, Integer> getArtistMap() {
+ return mArtistMap;
}
public void setActivity(ArtistAlbumBrowserActivity newactivity) {
mActivity = newactivity;
}
- public AsyncQueryHandler getQueryHandler() {
- return mQueryHandler;
- }
-
@Override
- public View newGroupView(
- Context context, Cursor cursor, boolean isExpanded, ViewGroup parent) {
- View v = super.newGroupView(context, cursor, isExpanded, parent);
+ public View newGroupView(boolean isExpanded, ViewGroup parent) {
+ View v = super.newGroupView(isExpanded, parent);
ImageView iv = (ImageView) v.findViewById(R.id.icon);
ViewGroup.LayoutParams p = iv.getLayoutParams();
p.width = ViewGroup.LayoutParams.WRAP_CONTENT;
@@ -642,218 +296,111 @@
}
@Override
- public View newChildView(
- Context context, Cursor cursor, boolean isLastChild, ViewGroup parent) {
- View v = super.newChildView(context, cursor, isLastChild, parent);
+ public View newChildView(boolean isLastChild, ViewGroup parent) {
+ View v = super.newChildView(isLastChild, parent);
ViewHolder vh = new ViewHolder();
vh.line1 = (TextView) v.findViewById(R.id.line1);
vh.line2 = (TextView) v.findViewById(R.id.line2);
vh.play_indicator = (ImageView) v.findViewById(R.id.play_indicator);
vh.icon = (ImageView) v.findViewById(R.id.icon);
- vh.icon.setBackgroundDrawable(mDefaultAlbumIcon);
+ vh.icon.setBackground(mDefaultAlbumIcon);
vh.icon.setPadding(0, 0, 1, 0);
v.setTag(vh);
return v;
}
@Override
- public void bindGroupView(View view, Context context, Cursor cursor, boolean isexpanded) {
- ViewHolder vh = (ViewHolder) view.getTag();
-
- String artist = cursor.getString(mGroupArtistIdx);
- String displayartist = artist;
- boolean unknown = artist == null || artist.equals(MediaStore.UNKNOWN_STRING);
- if (unknown) {
- displayartist = mUnknownArtist;
+ public View getGroupView(
+ int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = newGroupView(isExpanded, parent);
}
- vh.line1.setText(displayartist);
-
- int numalbums = cursor.getInt(mGroupAlbumIdx);
- int numsongs = cursor.getInt(mGroupSongIdx);
-
- String songs_albums = MusicUtils.makeAlbumsLabel(context, numalbums, numsongs, unknown);
-
+ Map<String, MediaBrowser.MediaItem> artistEntry =
+ (Map<String, MediaBrowser.MediaItem>) getGroup(groupPosition);
+ MediaBrowser.MediaItem artistItem =
+ artistEntry.get(MediaIDHelper.MEDIA_ID_MUSICS_BY_ARTIST);
+ MediaBrowser.MediaItem countItem = artistEntry.get(KEY_NUM_ALBUMS);
+ ViewHolder vh = (ViewHolder) convertView.getTag();
+ vh.line1.setText(artistItem.getDescription().getTitle());
+ int numalbums = -1;
+ if (countItem != null) {
+ Bundle extras = countItem.getDescription().getExtras();
+ if (extras != null) {
+ numalbums = (int) extras.getLong(KEY_NUM_ALBUMS);
+ }
+ }
+ String songs_albums = MusicUtils.makeAlbumsLabel(mActivity, numalbums, -1, false);
vh.line2.setText(songs_albums);
-
- long currentartistid = MusicUtils.getCurrentArtistId();
- long artistid = cursor.getLong(mGroupArtistIdIdx);
- if (currentartistid == artistid && !isexpanded) {
+ MediaController mediaController = mActivity.getMediaController();
+ if (mediaController == null) {
+ vh.play_indicator.setImageDrawable(null);
+ return convertView;
+ }
+ MediaMetadata metadata = mediaController.getMetadata();
+ if (metadata == null) {
+ vh.play_indicator.setImageDrawable(null);
+ return convertView;
+ }
+ if (metadata.getString(MediaMetadata.METADATA_KEY_ARTIST)
+ .equals(artistItem.getDescription().getTitle())
+ && !isExpanded) {
vh.play_indicator.setImageDrawable(mNowPlayingOverlay);
} else {
vh.play_indicator.setImageDrawable(null);
}
+ return convertView;
}
@Override
- public void bindChildView(View view, Context context, Cursor cursor, boolean islast) {
- ViewHolder vh = (ViewHolder) view.getTag();
-
- String name =
- cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM));
- String displayname = name;
- boolean unknown = name == null || name.equals(MediaStore.UNKNOWN_STRING);
- if (unknown) {
- displayname = mUnknownAlbum;
+ public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
+ View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = newChildView(isLastChild, parent);
}
- vh.line1.setText(displayname);
-
- int numsongs = cursor.getInt(
- cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.NUMBER_OF_SONGS));
- int numartistsongs = cursor.getInt(cursor.getColumnIndexOrThrow(
- MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST));
-
- final StringBuilder builder = mBuffer;
- builder.delete(0, builder.length());
- if (unknown) {
- numsongs = numartistsongs;
- }
-
- if (numsongs == 1) {
- builder.append(context.getString(R.string.onesong));
+ Map<String, MediaBrowser.MediaItem> albumEntry =
+ (Map<String, MediaBrowser.MediaItem>) getChild(groupPosition, childPosition);
+ MediaBrowser.MediaItem albumItem =
+ albumEntry.get(MediaIDHelper.MEDIA_ID_MUSICS_BY_ALBUM);
+ ViewHolder vh = (ViewHolder) convertView.getTag();
+ vh.line1.setText(albumItem.getDescription().getTitle());
+ vh.line2.setText(albumItem.getDescription().getDescription());
+ Bitmap albumArt = albumItem.getDescription().getIconBitmap();
+ if (albumArt == null) {
+ vh.icon.setBackground(mDefaultAlbumIcon);
} else {
- if (numsongs == numartistsongs) {
- final Object[] args = mFormatArgs;
- args[0] = numsongs;
- builder.append(mResources.getQuantityString(R.plurals.Nsongs, numsongs, args));
- } else {
- final Object[] args = mFormatArgs3;
- args[0] = numsongs;
- args[1] = numartistsongs;
- args[2] = cursor.getString(
- cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.ARTIST));
- builder.append(
- mResources.getQuantityString(R.plurals.Nsongscomp, numsongs, args));
- }
+ vh.icon.setImageDrawable(MusicUtils.getDrawableBitmap(albumArt, mDefaultAlbumIcon));
}
- vh.line2.setText(builder.toString());
-
- ImageView iv = vh.icon;
- // We don't actually need the path to the thumbnail file,
- // we just use it to see if there is album art or not
- String art = cursor.getString(
- cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM_ART));
- if (unknown || art == null || art.length() == 0) {
- iv.setBackgroundDrawable(mDefaultAlbumIcon);
- iv.setImageDrawable(null);
+ MediaController mediaController = mActivity.getMediaController();
+ if (mediaController == null) {
+ vh.play_indicator.setImageDrawable(null);
+ return convertView;
+ }
+ MediaMetadata metadata = mediaController.getMetadata();
+ if (metadata == null) {
+ vh.play_indicator.setImageDrawable(null);
+ return convertView;
+ }
+ if (albumItem.getDescription().getTitle().equals(
+ metadata.getString(MediaMetadata.METADATA_KEY_ALBUM))) {
+ vh.play_indicator.setImageDrawable(mNowPlayingOverlay);
} else {
- long artIndex = cursor.getLong(0);
- Drawable d = MusicUtils.getCachedArtwork(context, artIndex, mDefaultAlbumIcon);
- iv.setImageDrawable(d);
+ vh.play_indicator.setImageDrawable(null);
}
-
- long currentalbumid = MusicUtils.getCurrentAlbumId();
- long aid = cursor.getLong(0);
- iv = vh.play_indicator;
- if (currentalbumid == aid) {
- iv.setImageDrawable(mNowPlayingOverlay);
- } else {
- iv.setImageDrawable(null);
- }
- }
-
- @Override
- protected Cursor getChildrenCursor(Cursor groupCursor) {
- long id = groupCursor.getLong(
- groupCursor.getColumnIndexOrThrow(MediaStore.Audio.Artists._ID));
-
- String[] cols = new String[] {MediaStore.Audio.Albums._ID,
- MediaStore.Audio.Albums.ALBUM, MediaStore.Audio.Albums.NUMBER_OF_SONGS,
- MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST,
- MediaStore.Audio.Albums.ALBUM_ART};
- Cursor c = MusicUtils.query(mActivity,
- MediaStore.Audio.Artists.Albums.getContentUri("external", id), cols, null, null,
- MediaStore.Audio.Albums.DEFAULT_SORT_ORDER);
-
- class MyCursorWrapper extends CursorWrapper {
- String mArtistName;
- int mMagicColumnIdx;
- MyCursorWrapper(Cursor c, String artist) {
- super(c);
- mArtistName = artist;
- if (mArtistName == null || mArtistName.equals(MediaStore.UNKNOWN_STRING)) {
- mArtistName = mUnknownArtist;
- }
- mMagicColumnIdx = c.getColumnCount();
- }
-
- @Override
- public String getString(int columnIndex) {
- if (columnIndex != mMagicColumnIdx) {
- return super.getString(columnIndex);
- }
- return mArtistName;
- }
-
- @Override
- public int getColumnIndexOrThrow(String name) {
- if (MediaStore.Audio.Albums.ARTIST.equals(name)) {
- return mMagicColumnIdx;
- }
- return super.getColumnIndexOrThrow(name);
- }
-
- @Override
- public String getColumnName(int idx) {
- if (idx != mMagicColumnIdx) {
- return super.getColumnName(idx);
- }
- return MediaStore.Audio.Albums.ARTIST;
- }
-
- @Override
- public int getColumnCount() {
- return super.getColumnCount() + 1;
- }
- }
- return new MyCursorWrapper(c, groupCursor.getString(mGroupArtistIdx));
- }
-
- @Override
- public void changeCursor(Cursor cursor) {
- if (mActivity.isFinishing() && cursor != null) {
- cursor.close();
- cursor = null;
- }
- if (cursor != mActivity.mArtistCursor) {
- mActivity.mArtistCursor = cursor;
- getColumnIndices(cursor);
- super.changeCursor(cursor);
- }
- }
-
- @Override
- public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
- String s = constraint.toString();
- if (mConstraintIsValid && ((s == null && mConstraint == null)
- || (s != null && s.equals(mConstraint)))) {
- return getCursor();
- }
- Cursor c = mActivity.getArtistCursor(null, s);
- mConstraint = s;
- mConstraintIsValid = true;
- return c;
- }
-
- public Object[] getSections() {
- return mIndexer.getSections();
- }
-
- public int getPositionForSection(int sectionIndex) {
- return mIndexer.getPositionForSection(sectionIndex);
- }
-
- public int getSectionForPosition(int position) {
- return 0;
+ return convertView;
}
}
- private Cursor mArtistCursor;
-
- public void onServiceConnected(ComponentName name, IBinder service) {
- MusicUtils.updateNowPlaying(this);
- }
-
- public void onServiceDisconnected(ComponentName name) {
- finish();
+ @Override
+ public boolean onChildClick(
+ ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
+ Map<String, MediaBrowser.MediaItem> albumEntry =
+ (Map<String, MediaBrowser.MediaItem>) mAdapter.getChild(
+ groupPosition, childPosition);
+ Intent intent = new Intent(Intent.ACTION_PICK);
+ intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track");
+ intent.putExtra(
+ MusicUtils.TAG_PARENT_ITEM, albumEntry.get(MediaIDHelper.MEDIA_ID_MUSICS_BY_ALBUM));
+ startActivity(intent);
+ return true;
}
}