blob: ffccd32feb17a0416b81c7ef8243c1e34c97f9a7 [file] [log] [blame]
The Android Open Source Project792a2202009-03-03 19:32:30 -08001/*
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
17package com.android.music;
18
The Android Open Source Project792a2202009-03-03 19:32:30 -080019import android.app.ExpandableListActivity;
Marco Nelissenec0c57a2009-12-12 12:27:11 -080020import android.content.ComponentName;
The Android Open Source Project792a2202009-03-03 19:32:30 -080021import android.content.Intent;
Jack Hef02d3c62017-02-21 00:39:22 -050022import android.graphics.Bitmap;
The Android Open Source Project792a2202009-03-03 19:32:30 -080023import android.graphics.drawable.BitmapDrawable;
24import android.graphics.drawable.Drawable;
25import android.media.AudioManager;
Jack Hef02d3c62017-02-21 00:39:22 -050026import android.media.MediaDescription;
27import android.media.MediaMetadata;
28import android.media.browse.MediaBrowser;
29import android.media.session.MediaController;
The Android Open Source Project792a2202009-03-03 19:32:30 -080030import android.net.Uri;
31import android.os.Bundle;
The Android Open Source Project792a2202009-03-03 19:32:30 -080032import android.view.View;
33import android.view.ViewGroup;
34import android.view.Window;
The Android Open Source Project792a2202009-03-03 19:32:30 -080035import android.widget.ExpandableListView;
36import android.widget.ImageView;
Jack Hef02d3c62017-02-21 00:39:22 -050037import android.widget.SimpleExpandableListAdapter;
The Android Open Source Project792a2202009-03-03 19:32:30 -080038import android.widget.TextView;
Jack Hef02d3c62017-02-21 00:39:22 -050039import android.widget.Toast;
The Android Open Source Project792a2202009-03-03 19:32:30 -080040
Jack Hef02d3c62017-02-21 00:39:22 -050041import com.android.music.utils.LogHelper;
42import com.android.music.utils.MediaIDHelper;
The Android Open Source Project792a2202009-03-03 19:32:30 -080043
Jack Hef02d3c62017-02-21 00:39:22 -050044import java.util.ArrayList;
45import java.util.List;
46import java.util.Map;
47import java.util.concurrent.ConcurrentHashMap;
48
49public 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
The Android Open Source Project792a2202009-03-03 19:32:30 -080058 private ArtistAlbumListAdapter mAdapter;
Jack Hef02d3c62017-02-21 00:39:22 -050059 private MediaBrowser mMediaBrowser;
60 private MediaBrowser.MediaItem mParentItem;
The Android Open Source Project792a2202009-03-03 19:32:30 -080061
The Android Open Source Project792a2202009-03-03 19:32:30 -080062 /** Called when the activity is first created. */
63 @Override
64 public void onCreate(Bundle icicle) {
65 super.onCreate(icicle);
Jack Hef02d3c62017-02-21 00:39:22 -050066 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 }
Marco Nelissenec0c57a2009-12-12 12:27:11 -080076 requestWindowFeature(Window.FEATURE_NO_TITLE);
The Android Open Source Project792a2202009-03-03 19:32:30 -080077 setVolumeControlStream(AudioManager.STREAM_MUSIC);
The Android Open Source Project792a2202009-03-03 19:32:30 -080078
Jack Hef02d3c62017-02-21 00:39:22 -050079 // Init layout
The Android Open Source Project792a2202009-03-03 19:32:30 -080080 setContentView(R.layout.media_picker_activity_expanding);
Marco Nelissenec0c57a2009-12-12 12:27:11 -080081 MusicUtils.updateButtonBar(this, R.id.artisttab);
The Android Open Source Project792a2202009-03-03 19:32:30 -080082
Jack Hef02d3c62017-02-21 00:39:22 -050083 // Init expandable list
84 ExpandableListView lv = getExpandableListView();
85 lv.setTextFilterEnabled(true);
The Android Open Source Project792a2202009-03-03 19:32:30 -080086 mAdapter = (ArtistAlbumListAdapter) getLastNonConfigurationInstance();
87 if (mAdapter == null) {
Jack Heb0fba8b2017-01-26 15:54:38 -080088 // Log.i("@@@", "starting query");
Jack Hef02d3c62017-02-21 00:39:22 -050089 mAdapter = new ArtistAlbumListAdapter(this, new ArrayList<>(), new ArrayList<>());
The Android Open Source Project792a2202009-03-03 19:32:30 -080090 setListAdapter(mAdapter);
91 setTitle(R.string.working_artists);
The Android Open Source Project792a2202009-03-03 19:32:30 -080092 } else {
93 mAdapter.setActivity(this);
The Android Open Source Project792a2202009-03-03 19:32:30 -080094 }
Jack Hef02d3c62017-02-21 00:39:22 -050095 setListAdapter(mAdapter);
96 LogHelper.d(TAG, "Creating MediaBrowser");
97 mMediaBrowser = new MediaBrowser(this, new ComponentName(this, MediaPlaybackService.class),
98 mConnectionCallback, null);
The Android Open Source Project792a2202009-03-03 19:32:30 -080099 }
100
101 @Override
102 public Object onRetainNonConfigurationInstance() {
The Android Open Source Project792a2202009-03-03 19:32:30 -0800103 return mAdapter;
104 }
Jack Heb0fba8b2017-01-26 15:54:38 -0800105
The Android Open Source Project792a2202009-03-03 19:32:30 -0800106 @Override
107 public void onSaveInstanceState(Bundle outcicle) {
Jack Hef02d3c62017-02-21 00:39:22 -0500108 outcicle.putParcelable(MusicUtils.TAG_PARENT_ITEM, mParentItem);
The Android Open Source Project792a2202009-03-03 19:32:30 -0800109 super.onSaveInstanceState(outcicle);
110 }
111
112 @Override
113 public void onDestroy() {
Marco Nelissen0164ebf2009-08-13 09:58:43 -0700114 setListAdapter(null);
115 mAdapter = null;
Marco Nelissen9882f542009-08-14 10:06:15 -0700116 setListAdapter(null);
The Android Open Source Project792a2202009-03-03 19:32:30 -0800117 super.onDestroy();
118 }
Jack Heb0fba8b2017-01-26 15:54:38 -0800119
The Android Open Source Project792a2202009-03-03 19:32:30 -0800120 @Override
Jack Hef02d3c62017-02-21 00:39:22 -0500121 public void onStart() {
122 LogHelper.d(TAG, "onStart()");
123 super.onStart();
124 mMediaBrowser.connect();
The Android Open Source Project792a2202009-03-03 19:32:30 -0800125 }
126
Jack Hef02d3c62017-02-21 00:39:22 -0500127 @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() {
The Android Open Source Project792a2202009-03-03 19:32:30 -0800136 @Override
Jack Hef02d3c62017-02-21 00:39:22 -0500137 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);
Marco Nelissenec0c57a2009-12-12 12:27:11 -0800224 MusicUtils.updateNowPlaying(ArtistAlbumBrowserActivity.this);
The Android Open Source Project792a2202009-03-03 19:32:30 -0800225 }
226 };
Jack Heb0fba8b2017-01-26 15:54:38 -0800227
Jack Hef02d3c62017-02-21 00:39:22 -0500228 private class ArtistAlbumListAdapter extends SimpleExpandableListAdapter {
The Android Open Source Project792a2202009-03-03 19:32:30 -0800229 private final Drawable mNowPlayingOverlay;
230 private final BitmapDrawable mDefaultAlbumIcon;
The Android Open Source Project792a2202009-03-03 19:32:30 -0800231 private ArtistAlbumBrowserActivity mActivity;
Jack Hef02d3c62017-02-21 00:39:22 -0500232 private ArrayList<ConcurrentHashMap<String, MediaBrowser.MediaItem>> mGroupData;
233 private ArrayList < ArrayList
234 < ConcurrentHashMap<String, MediaBrowser.MediaItem>>> mChildData;
235 private ConcurrentHashMap<String, Integer> mArtistMap;
Jack Heb0fba8b2017-01-26 15:54:38 -0800236
Jack Hef02d3c62017-02-21 00:39:22 -0500237 private class ViewHolder {
The Android Open Source Project792a2202009-03-03 19:32:30 -0800238 TextView line1;
239 TextView line2;
240 ImageView play_indicator;
241 ImageView icon;
242 }
243
Jack Hef02d3c62017-02-21 00:39:22 -0500244 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());
The Android Open Source Project792a2202009-03-03 19:32:30 -0800258 // no filter or dither, it's a lot faster and we can't tell the difference
259 mDefaultAlbumIcon.setFilterBitmap(false);
260 mDefaultAlbumIcon.setDither(false);
Jack Hef02d3c62017-02-21 00:39:22 -0500261 mArtistMap = new ConcurrentHashMap<>();
The Android Open Source Project792a2202009-03-03 19:32:30 -0800262 }
Jack Heb0fba8b2017-01-26 15:54:38 -0800263
Jack Hef02d3c62017-02-21 00:39:22 -0500264 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;
The Android Open Source Project792a2202009-03-03 19:32:30 -0800275 }
Jack Heb0fba8b2017-01-26 15:54:38 -0800276
The Android Open Source Project792a2202009-03-03 19:32:30 -0800277 public void setActivity(ArtistAlbumBrowserActivity newactivity) {
278 mActivity = newactivity;
279 }
Jack Heb0fba8b2017-01-26 15:54:38 -0800280
The Android Open Source Project792a2202009-03-03 19:32:30 -0800281 @Override
Jack Hef02d3c62017-02-21 00:39:22 -0500282 public View newGroupView(boolean isExpanded, ViewGroup parent) {
283 View v = super.newGroupView(isExpanded, parent);
The Android Open Source Project792a2202009-03-03 19:32:30 -0800284 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
Jack Hef02d3c62017-02-21 00:39:22 -0500299 public View newChildView(boolean isLastChild, ViewGroup parent) {
300 View v = super.newChildView(isLastChild, parent);
The Android Open Source Project792a2202009-03-03 19:32:30 -0800301 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);
Jack Hef02d3c62017-02-21 00:39:22 -0500306 vh.icon.setBackground(mDefaultAlbumIcon);
The Android Open Source Project792a2202009-03-03 19:32:30 -0800307 vh.icon.setPadding(0, 0, 1, 0);
308 v.setTag(vh);
309 return v;
310 }
Jack Heb0fba8b2017-01-26 15:54:38 -0800311
The Android Open Source Project792a2202009-03-03 19:32:30 -0800312 @Override
Jack Hef02d3c62017-02-21 00:39:22 -0500313 public View getGroupView(
314 int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
315 if (convertView == null) {
316 convertView = newGroupView(isExpanded, parent);
The Android Open Source Project792a2202009-03-03 19:32:30 -0800317 }
Jack Hef02d3c62017-02-21 00:39:22 -0500318 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);
The Android Open Source Project792a2202009-03-03 19:32:30 -0800333 vh.line2.setText(songs_albums);
Jack Hef02d3c62017-02-21 00:39:22 -0500334 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) {
The Android Open Source Project792a2202009-03-03 19:32:30 -0800347 vh.play_indicator.setImageDrawable(mNowPlayingOverlay);
348 } else {
349 vh.play_indicator.setImageDrawable(null);
350 }
Jack Hef02d3c62017-02-21 00:39:22 -0500351 return convertView;
The Android Open Source Project792a2202009-03-03 19:32:30 -0800352 }
353
354 @Override
Jack Hef02d3c62017-02-21 00:39:22 -0500355 public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
356 View convertView, ViewGroup parent) {
357 if (convertView == null) {
358 convertView = newChildView(isLastChild, parent);
The Android Open Source Project792a2202009-03-03 19:32:30 -0800359 }
Jack Hef02d3c62017-02-21 00:39:22 -0500360 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);
The Android Open Source Project792a2202009-03-03 19:32:30 -0800370 } else {
Jack Hef02d3c62017-02-21 00:39:22 -0500371 vh.icon.setImageDrawable(MusicUtils.getDrawableBitmap(albumArt, mDefaultAlbumIcon));
The Android Open Source Project792a2202009-03-03 19:32:30 -0800372 }
Jack Hef02d3c62017-02-21 00:39:22 -0500373 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);
The Android Open Source Project792a2202009-03-03 19:32:30 -0800386 } else {
Jack Hef02d3c62017-02-21 00:39:22 -0500387 vh.play_indicator.setImageDrawable(null);
The Android Open Source Project792a2202009-03-03 19:32:30 -0800388 }
Jack Hef02d3c62017-02-21 00:39:22 -0500389 return convertView;
The Android Open Source Project792a2202009-03-03 19:32:30 -0800390 }
391 }
Jack Heb0fba8b2017-01-26 15:54:38 -0800392
Jack Hef02d3c62017-02-21 00:39:22 -0500393 @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;
Marco Nelissenec0c57a2009-12-12 12:27:11 -0800405 }
The Android Open Source Project792a2202009-03-03 19:32:30 -0800406}