Home | History | Annotate | Download | only in music
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.music;
     18 
     19 import android.app.ExpandableListActivity;
     20 import android.content.ComponentName;
     21 import android.content.Intent;
     22 import android.graphics.Bitmap;
     23 import android.graphics.drawable.BitmapDrawable;
     24 import android.graphics.drawable.Drawable;
     25 import android.media.AudioManager;
     26 import android.media.MediaDescription;
     27 import android.media.MediaMetadata;
     28 import android.media.browse.MediaBrowser;
     29 import android.media.session.MediaController;
     30 import android.net.Uri;
     31 import android.os.Bundle;
     32 import android.view.View;
     33 import android.view.ViewGroup;
     34 import android.view.Window;
     35 import android.widget.ExpandableListView;
     36 import android.widget.ImageView;
     37 import android.widget.SimpleExpandableListAdapter;
     38 import android.widget.TextView;
     39 import android.widget.Toast;
     40 
     41 import com.android.music.utils.LogHelper;
     42 import com.android.music.utils.MediaIDHelper;
     43 
     44 import java.util.ArrayList;
     45 import java.util.List;
     46 import java.util.Map;
     47 import java.util.concurrent.ConcurrentHashMap;
     48 
     49 public class ArtistAlbumBrowserActivity extends ExpandableListActivity {
     50     private static final String TAG = LogHelper.makeLogTag(ArtistAlbumBrowserActivity.class);
     51     private static final String KEY_NUM_ALBUMS = "__NUM_ALBUMS__";
     52     private static final MediaBrowser.MediaItem DEFAULT_PARENT_ITEM =
     53             new MediaBrowser.MediaItem(new MediaDescription.Builder()
     54                                                .setMediaId(MediaIDHelper.MEDIA_ID_MUSICS_BY_ARTIST)
     55                                                .build(),
     56                     MediaBrowser.MediaItem.FLAG_BROWSABLE);
     57 
     58     private ArtistAlbumListAdapter mAdapter;
     59     private MediaBrowser mMediaBrowser;
     60     private MediaBrowser.MediaItem mParentItem;
     61 
     62     /** Called when the activity is first created. */
     63     @Override
     64     public void onCreate(Bundle icicle) {
     65         super.onCreate(icicle);
     66         LogHelper.d(TAG, "onCreate()");
     67         // Handle past states
     68         if (icicle != null) {
     69             mParentItem = icicle.getParcelable(MusicUtils.TAG_PARENT_ITEM);
     70         } else if (getIntent() != null) {
     71             mParentItem = getIntent().getExtras().getParcelable(MusicUtils.TAG_PARENT_ITEM);
     72         }
     73         if (mParentItem == null) {
     74             mParentItem = DEFAULT_PARENT_ITEM;
     75         }
     76         requestWindowFeature(Window.FEATURE_NO_TITLE);
     77         setVolumeControlStream(AudioManager.STREAM_MUSIC);
     78 
     79         // Init layout
     80         setContentView(R.layout.media_picker_activity_expanding);
     81         MusicUtils.updateButtonBar(this, R.id.artisttab);
     82 
     83         // Init expandable list
     84         ExpandableListView lv = getExpandableListView();
     85         lv.setTextFilterEnabled(true);
     86         mAdapter = (ArtistAlbumListAdapter) getLastNonConfigurationInstance();
     87         if (mAdapter == null) {
     88             // Log.i("@@@", "starting query");
     89             mAdapter = new ArtistAlbumListAdapter(this, new ArrayList<>(), new ArrayList<>());
     90             setListAdapter(mAdapter);
     91             setTitle(R.string.working_artists);
     92         } else {
     93             mAdapter.setActivity(this);
     94         }
     95         setListAdapter(mAdapter);
     96         LogHelper.d(TAG, "Creating MediaBrowser");
     97         mMediaBrowser = new MediaBrowser(this, new ComponentName(this, MediaPlaybackService.class),
     98                 mConnectionCallback, null);
     99     }
    100 
    101     @Override
    102     public Object onRetainNonConfigurationInstance() {
    103         return mAdapter;
    104     }
    105 
    106     @Override
    107     public void onSaveInstanceState(Bundle outcicle) {
    108         outcicle.putParcelable(MusicUtils.TAG_PARENT_ITEM, mParentItem);
    109         super.onSaveInstanceState(outcicle);
    110     }
    111 
    112     @Override
    113     public void onDestroy() {
    114         setListAdapter(null);
    115         mAdapter = null;
    116         setListAdapter(null);
    117         super.onDestroy();
    118     }
    119 
    120     @Override
    121     public void onStart() {
    122         LogHelper.d(TAG, "onStart()");
    123         super.onStart();
    124         mMediaBrowser.connect();
    125     }
    126 
    127     @Override
    128     public void onStop() {
    129         LogHelper.d(TAG, "onStop()");
    130         super.onStop();
    131         mMediaBrowser.disconnect();
    132     }
    133 
    134     private MediaBrowser
    135             .SubscriptionCallback mSubscriptionCallback = new MediaBrowser.SubscriptionCallback() {
    136         @Override
    137         public void onChildrenLoaded(String parentId, List<MediaBrowser.MediaItem> children) {
    138             if (parentId.equals(MediaIDHelper.MEDIA_ID_MUSICS_BY_ARTIST)) {
    139                 mAdapter.getArtistMap().clear();
    140                 mAdapter.getGroupData().clear();
    141                 mAdapter.notifyDataSetInvalidated();
    142                 for (MediaBrowser.MediaItem item : children) {
    143                     ConcurrentHashMap<String, MediaBrowser.MediaItem> entry =
    144                             new ConcurrentHashMap<>();
    145                     entry.put(MediaIDHelper.MEDIA_ID_MUSICS_BY_ARTIST, item);
    146                     synchronized (this) {
    147                         mAdapter.getArtistMap().put(item.getDescription().getTitle().toString(),
    148                                 mAdapter.getGroupData().size());
    149                         mAdapter.getGroupData().add(entry);
    150                         mAdapter.getChildData().add(new ArrayList<>());
    151                     }
    152                     mMediaBrowser.subscribe(item.getMediaId(), this);
    153                 }
    154                 mAdapter.notifyDataSetChanged();
    155             } else if (parentId.startsWith(MediaIDHelper.MEDIA_ID_MUSICS_BY_ARTIST)) {
    156                 String artist = MediaIDHelper.getHierarchy(parentId)[1];
    157                 if (!mAdapter.getArtistMap().containsKey(artist)) {
    158                     return;
    159                 }
    160                 int artistIndex = mAdapter.getArtistMap().get(artist);
    161                 mAdapter.getChildData().get(artistIndex).clear();
    162                 mAdapter.notifyDataSetInvalidated();
    163                 Bundle extras = new Bundle();
    164                 extras.putLong(KEY_NUM_ALBUMS, children.size());
    165                 MediaBrowser.MediaItem newArtistItem =
    166                         new MediaBrowser.MediaItem(new MediaDescription.Builder()
    167                                                            .setMediaId("Count")
    168                                                            .setExtras(extras)
    169                                                            .build(),
    170                                 0);
    171                 mAdapter.getGroupData().get(artistIndex).put(KEY_NUM_ALBUMS, newArtistItem);
    172                 for (MediaBrowser.MediaItem item : children) {
    173                     ConcurrentHashMap<String, MediaBrowser.MediaItem> entry =
    174                             new ConcurrentHashMap<>();
    175                     entry.put(MediaIDHelper.MEDIA_ID_MUSICS_BY_ALBUM, item);
    176                     mAdapter.getChildData().get(artistIndex).add(entry);
    177                 }
    178                 mAdapter.notifyDataSetChanged();
    179             }
    180         }
    181 
    182         @Override
    183         public void onError(String id) {
    184             Toast.makeText(getApplicationContext(), R.string.error_loading_media, Toast.LENGTH_LONG)
    185                     .show();
    186         }
    187     };
    188 
    189     private MediaBrowser.ConnectionCallback mConnectionCallback =
    190             new MediaBrowser.ConnectionCallback() {
    191                 @Override
    192                 public void onConnected() {
    193                     LogHelper.d(
    194                             TAG, "onConnected: session token ", mMediaBrowser.getSessionToken());
    195                     mMediaBrowser.subscribe(mParentItem.getMediaId(), mSubscriptionCallback);
    196                     if (mMediaBrowser.getSessionToken() == null) {
    197                         throw new IllegalArgumentException("No Session token");
    198                     }
    199                     MediaController mediaController = new MediaController(
    200                             ArtistAlbumBrowserActivity.this, mMediaBrowser.getSessionToken());
    201                     mediaController.registerCallback(mMediaControllerCallback);
    202                     ArtistAlbumBrowserActivity.this.setMediaController(mediaController);
    203                     if (mediaController.getMetadata() != null) {
    204                         MusicUtils.updateNowPlaying(ArtistAlbumBrowserActivity.this);
    205                     }
    206                 }
    207 
    208                 @Override
    209                 public void onConnectionFailed() {
    210                     LogHelper.d(TAG, "onConnectionFailed");
    211                 }
    212 
    213                 @Override
    214                 public void onConnectionSuspended() {
    215                     LogHelper.d(TAG, "onConnectionSuspended");
    216                     ArtistAlbumBrowserActivity.this.setMediaController(null);
    217                 }
    218             };
    219 
    220     private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
    221         @Override
    222         public void onMetadataChanged(MediaMetadata metadata) {
    223             super.onMetadataChanged(metadata);
    224             MusicUtils.updateNowPlaying(ArtistAlbumBrowserActivity.this);
    225         }
    226     };
    227 
    228     private class ArtistAlbumListAdapter extends SimpleExpandableListAdapter {
    229         private final Drawable mNowPlayingOverlay;
    230         private final BitmapDrawable mDefaultAlbumIcon;
    231         private ArtistAlbumBrowserActivity mActivity;
    232         private ArrayList<ConcurrentHashMap<String, MediaBrowser.MediaItem>> mGroupData;
    233         private ArrayList < ArrayList
    234                 < ConcurrentHashMap<String, MediaBrowser.MediaItem>>> mChildData;
    235         private ConcurrentHashMap<String, Integer> mArtistMap;
    236 
    237         private class ViewHolder {
    238             TextView line1;
    239             TextView line2;
    240             ImageView play_indicator;
    241             ImageView icon;
    242         }
    243 
    244         ArtistAlbumListAdapter(ArtistAlbumBrowserActivity currentActivity,
    245                 ArrayList<ConcurrentHashMap<String, MediaBrowser.MediaItem>> groupData,
    246                 ArrayList < ArrayList
    247                         < ConcurrentHashMap<String, MediaBrowser.MediaItem>>> childData) {
    248             super(currentActivity, groupData, R.layout.track_list_item_group, new String[] {},
    249                     new int[] {}, childData, R.layout.track_list_item_child, new String[] {},
    250                     new int[] {});
    251             mGroupData = groupData;
    252             mChildData = childData;
    253             mActivity = currentActivity;
    254             mNowPlayingOverlay = currentActivity.getResources().getDrawable(
    255                     R.drawable.indicator_ic_mp_playing_list, currentActivity.getTheme());
    256             mDefaultAlbumIcon = (BitmapDrawable) currentActivity.getResources().getDrawable(
    257                     R.drawable.albumart_mp_unknown_list, currentActivity.getTheme());
    258             // no filter or dither, it's a lot faster and we can't tell the difference
    259             mDefaultAlbumIcon.setFilterBitmap(false);
    260             mDefaultAlbumIcon.setDither(false);
    261             mArtistMap = new ConcurrentHashMap<>();
    262         }
    263 
    264         public ArrayList<ConcurrentHashMap<String, MediaBrowser.MediaItem>> getGroupData() {
    265             return mGroupData;
    266         }
    267 
    268         public ArrayList < ArrayList
    269                 < ConcurrentHashMap<String, MediaBrowser.MediaItem>>> getChildData() {
    270             return mChildData;
    271         }
    272 
    273         public Map<String, Integer> getArtistMap() {
    274             return mArtistMap;
    275         }
    276 
    277         public void setActivity(ArtistAlbumBrowserActivity newactivity) {
    278             mActivity = newactivity;
    279         }
    280 
    281         @Override
    282         public View newGroupView(boolean isExpanded, ViewGroup parent) {
    283             View v = super.newGroupView(isExpanded, parent);
    284             ImageView iv = (ImageView) v.findViewById(R.id.icon);
    285             ViewGroup.LayoutParams p = iv.getLayoutParams();
    286             p.width = ViewGroup.LayoutParams.WRAP_CONTENT;
    287             p.height = ViewGroup.LayoutParams.WRAP_CONTENT;
    288             ViewHolder vh = new ViewHolder();
    289             vh.line1 = (TextView) v.findViewById(R.id.line1);
    290             vh.line2 = (TextView) v.findViewById(R.id.line2);
    291             vh.play_indicator = (ImageView) v.findViewById(R.id.play_indicator);
    292             vh.icon = (ImageView) v.findViewById(R.id.icon);
    293             vh.icon.setPadding(0, 0, 1, 0);
    294             v.setTag(vh);
    295             return v;
    296         }
    297 
    298         @Override
    299         public View newChildView(boolean isLastChild, ViewGroup parent) {
    300             View v = super.newChildView(isLastChild, parent);
    301             ViewHolder vh = new ViewHolder();
    302             vh.line1 = (TextView) v.findViewById(R.id.line1);
    303             vh.line2 = (TextView) v.findViewById(R.id.line2);
    304             vh.play_indicator = (ImageView) v.findViewById(R.id.play_indicator);
    305             vh.icon = (ImageView) v.findViewById(R.id.icon);
    306             vh.icon.setBackground(mDefaultAlbumIcon);
    307             vh.icon.setPadding(0, 0, 1, 0);
    308             v.setTag(vh);
    309             return v;
    310         }
    311 
    312         @Override
    313         public View getGroupView(
    314                 int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
    315             if (convertView == null) {
    316                 convertView = newGroupView(isExpanded, parent);
    317             }
    318             Map<String, MediaBrowser.MediaItem> artistEntry =
    319                     (Map<String, MediaBrowser.MediaItem>) getGroup(groupPosition);
    320             MediaBrowser.MediaItem artistItem =
    321                     artistEntry.get(MediaIDHelper.MEDIA_ID_MUSICS_BY_ARTIST);
    322             MediaBrowser.MediaItem countItem = artistEntry.get(KEY_NUM_ALBUMS);
    323             ViewHolder vh = (ViewHolder) convertView.getTag();
    324             vh.line1.setText(artistItem.getDescription().getTitle());
    325             int numalbums = -1;
    326             if (countItem != null) {
    327                 Bundle extras = countItem.getDescription().getExtras();
    328                 if (extras != null) {
    329                     numalbums = (int) extras.getLong(KEY_NUM_ALBUMS);
    330                 }
    331             }
    332             String songs_albums = MusicUtils.makeAlbumsLabel(mActivity, numalbums, -1, false);
    333             vh.line2.setText(songs_albums);
    334             MediaController mediaController = mActivity.getMediaController();
    335             if (mediaController == null) {
    336                 vh.play_indicator.setImageDrawable(null);
    337                 return convertView;
    338             }
    339             MediaMetadata metadata = mediaController.getMetadata();
    340             if (metadata == null) {
    341                 vh.play_indicator.setImageDrawable(null);
    342                 return convertView;
    343             }
    344             if (metadata.getString(MediaMetadata.METADATA_KEY_ARTIST)
    345                             .equals(artistItem.getDescription().getTitle())
    346                     && !isExpanded) {
    347                 vh.play_indicator.setImageDrawable(mNowPlayingOverlay);
    348             } else {
    349                 vh.play_indicator.setImageDrawable(null);
    350             }
    351             return convertView;
    352         }
    353 
    354         @Override
    355         public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
    356                 View convertView, ViewGroup parent) {
    357             if (convertView == null) {
    358                 convertView = newChildView(isLastChild, parent);
    359             }
    360             Map<String, MediaBrowser.MediaItem> albumEntry =
    361                     (Map<String, MediaBrowser.MediaItem>) getChild(groupPosition, childPosition);
    362             MediaBrowser.MediaItem albumItem =
    363                     albumEntry.get(MediaIDHelper.MEDIA_ID_MUSICS_BY_ALBUM);
    364             ViewHolder vh = (ViewHolder) convertView.getTag();
    365             vh.line1.setText(albumItem.getDescription().getTitle());
    366             vh.line2.setText(albumItem.getDescription().getDescription());
    367             Bitmap albumArt = albumItem.getDescription().getIconBitmap();
    368             if (albumArt == null) {
    369                 vh.icon.setBackground(mDefaultAlbumIcon);
    370             } else {
    371                 vh.icon.setImageDrawable(MusicUtils.getDrawableBitmap(albumArt, mDefaultAlbumIcon));
    372             }
    373             MediaController mediaController = mActivity.getMediaController();
    374             if (mediaController == null) {
    375                 vh.play_indicator.setImageDrawable(null);
    376                 return convertView;
    377             }
    378             MediaMetadata metadata = mediaController.getMetadata();
    379             if (metadata == null) {
    380                 vh.play_indicator.setImageDrawable(null);
    381                 return convertView;
    382             }
    383             if (albumItem.getDescription().getTitle().equals(
    384                         metadata.getString(MediaMetadata.METADATA_KEY_ALBUM))) {
    385                 vh.play_indicator.setImageDrawable(mNowPlayingOverlay);
    386             } else {
    387                 vh.play_indicator.setImageDrawable(null);
    388             }
    389             return convertView;
    390         }
    391     }
    392 
    393     @Override
    394     public boolean onChildClick(
    395             ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
    396         Map<String, MediaBrowser.MediaItem> albumEntry =
    397                 (Map<String, MediaBrowser.MediaItem>) mAdapter.getChild(
    398                         groupPosition, childPosition);
    399         Intent intent = new Intent(Intent.ACTION_PICK);
    400         intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track");
    401         intent.putExtra(
    402                 MusicUtils.TAG_PARENT_ITEM, albumEntry.get(MediaIDHelper.MEDIA_ID_MUSICS_BY_ALBUM));
    403         startActivity(intent);
    404         return true;
    405     }
    406 }
    407