blob: 0932f12de323ac0e074a3326215b301fd2aa0400 [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
19import com.android.music.QueryBrowserActivity.QueryListAdapter.QueryHandler;
20
21import android.app.ExpandableListActivity;
22import android.app.SearchManager;
23import android.content.AsyncQueryHandler;
24import android.content.BroadcastReceiver;
25import android.content.ContentResolver;
26import android.content.Context;
27import android.content.Intent;
28import android.content.IntentFilter;
29import android.content.res.Resources;
30import android.database.Cursor;
31import android.database.CursorWrapper;
32import android.graphics.drawable.BitmapDrawable;
33import android.graphics.drawable.Drawable;
34import android.media.AudioManager;
35import android.media.MediaFile;
36import android.net.Uri;
37import android.os.Bundle;
38import android.os.Handler;
39import android.os.Message;
40import android.provider.MediaStore;
41import android.util.Log;
42import android.view.ContextMenu;
43import android.view.Menu;
44import android.view.MenuItem;
45import android.view.SubMenu;
46import android.view.View;
47import android.view.ViewGroup;
48import android.view.Window;
49import android.view.ContextMenu.ContextMenuInfo;
50import android.widget.CursorAdapter;
51import android.widget.CursorTreeAdapter;
52import android.widget.ExpandableListAdapter;
53import android.widget.ExpandableListView;
54import android.widget.ImageView;
55import android.widget.SectionIndexer;
56import android.widget.SimpleCursorTreeAdapter;
57import android.widget.TextView;
58import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
59
60import java.text.Collator;
61
62
63public class ArtistAlbumBrowserActivity extends ExpandableListActivity
64 implements View.OnCreateContextMenuListener, MusicUtils.Defs
65{
66 private String mCurrentArtistId;
67 private String mCurrentArtistName;
68 private String mCurrentAlbumId;
69 private String mCurrentAlbumName;
70 private String mCurrentArtistNameForAlbum;
71 private ArtistAlbumListAdapter mAdapter;
72 private boolean mAdapterSent;
73 private final static int SEARCH = CHILD_MENU_BASE;
74
75 public ArtistAlbumBrowserActivity()
76 {
77 }
78
79 /** Called when the activity is first created. */
80 @Override
81 public void onCreate(Bundle icicle) {
82 super.onCreate(icicle);
83 requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
84 setVolumeControlStream(AudioManager.STREAM_MUSIC);
85 if (icicle != null) {
86 mCurrentAlbumId = icicle.getString("selectedalbum");
87 mCurrentAlbumName = icicle.getString("selectedalbumname");
88 mCurrentArtistId = icicle.getString("selectedartist");
89 mCurrentArtistName = icicle.getString("selectedartistname");
90 }
91 MusicUtils.bindToService(this);
92
93 IntentFilter f = new IntentFilter();
94 f.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
95 f.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
96 f.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
97 f.addDataScheme("file");
98 registerReceiver(mScanListener, f);
99
100 setContentView(R.layout.media_picker_activity_expanding);
101 ExpandableListView lv = getExpandableListView();
102 lv.setFastScrollEnabled(true);
103 lv.setOnCreateContextMenuListener(this);
104 lv.setTextFilterEnabled(true);
105
106 mAdapter = (ArtistAlbumListAdapter) getLastNonConfigurationInstance();
107 if (mAdapter == null) {
108 //Log.i("@@@", "starting query");
109 mAdapter = new ArtistAlbumListAdapter(
110 getApplication(),
111 this,
112 null, // cursor
113 R.layout.track_list_item_group,
114 new String[] {},
115 new int[] {},
116 R.layout.track_list_item_child,
117 new String[] {},
118 new int[] {});
119 setListAdapter(mAdapter);
120 setTitle(R.string.working_artists);
121 getArtistCursor(mAdapter.getQueryHandler(), null);
122 } else {
123 mAdapter.setActivity(this);
124 setListAdapter(mAdapter);
125 mArtistCursor = mAdapter.getCursor();
126 if (mArtistCursor != null) {
127 init(mArtistCursor);
128 } else {
129 getArtistCursor(mAdapter.getQueryHandler(), null);
130 }
131 }
132 }
133
134 @Override
135 public Object onRetainNonConfigurationInstance() {
136 mAdapterSent = true;
137 return mAdapter;
138 }
139
140 @Override
141 public void onSaveInstanceState(Bundle outcicle) {
142 // need to store the selected item so we don't lose it in case
143 // of an orientation switch. Otherwise we could lose it while
144 // in the middle of specifying a playlist to add the item to.
145 outcicle.putString("selectedalbum", mCurrentAlbumId);
146 outcicle.putString("selectedalbumname", mCurrentAlbumName);
147 outcicle.putString("selectedartist", mCurrentArtistId);
148 outcicle.putString("selectedartistname", mCurrentArtistName);
149 super.onSaveInstanceState(outcicle);
150 }
151
152 @Override
153 public void onDestroy() {
154 MusicUtils.unbindFromService(this);
155 if (!mAdapterSent) {
156 Cursor c = mAdapter.getCursor();
157 if (c != null) {
158 c.close();
159 }
160 }
Marco Nelissen0164ebf2009-08-13 09:58:43 -0700161 // Because we pass the adapter to the next activity, we need to make
162 // sure it doesn't keep a reference to this activity. We can do this
163 // by clearing its DatasetObservers, which setListAdapter(null) does.
164 setListAdapter(null);
165 mAdapter = null;
The Android Open Source Project792a2202009-03-03 19:32:30 -0800166 unregisterReceiver(mScanListener);
167 super.onDestroy();
168 }
169
170 @Override
171 public void onResume() {
172 super.onResume();
173 IntentFilter f = new IntentFilter();
174 f.addAction(MediaPlaybackService.META_CHANGED);
175 f.addAction(MediaPlaybackService.QUEUE_CHANGED);
176 registerReceiver(mTrackListListener, f);
177 mTrackListListener.onReceive(null, null);
178
179 MusicUtils.setSpinnerState(this);
180 }
181
182 private BroadcastReceiver mTrackListListener = new BroadcastReceiver() {
183 @Override
184 public void onReceive(Context context, Intent intent) {
185 getExpandableListView().invalidateViews();
186 }
187 };
188 private BroadcastReceiver mScanListener = new BroadcastReceiver() {
189 @Override
190 public void onReceive(Context context, Intent intent) {
191 MusicUtils.setSpinnerState(ArtistAlbumBrowserActivity.this);
192 mReScanHandler.sendEmptyMessage(0);
193 if (intent.getAction().equals(Intent.ACTION_MEDIA_UNMOUNTED)) {
194 MusicUtils.clearAlbumArtCache();
195 }
196 }
197 };
198
199 private Handler mReScanHandler = new Handler() {
200 @Override
201 public void handleMessage(Message msg) {
202 getArtistCursor(mAdapter.getQueryHandler(), null);
203 }
204 };
205
206 @Override
207 public void onPause() {
208 unregisterReceiver(mTrackListListener);
209 mReScanHandler.removeCallbacksAndMessages(null);
210 super.onPause();
211 }
212
213 public void init(Cursor c) {
214
215 mAdapter.changeCursor(c); // also sets mArtistCursor
216
217 if (mArtistCursor == null) {
218 MusicUtils.displayDatabaseError(this);
219 closeContextMenu();
220 mReScanHandler.sendEmptyMessageDelayed(0, 1000);
221 return;
222 }
223
224 MusicUtils.hideDatabaseError(this);
225 setTitle();
226 }
227
228 private void setTitle() {
229 setTitle(R.string.artists_title);
230 }
231
232 @Override
233 public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
234
235 mCurrentAlbumId = Long.valueOf(id).toString();
236
237 Intent intent = new Intent(Intent.ACTION_PICK);
238 intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track");
239 intent.putExtra("album", mCurrentAlbumId);
240 Cursor c = (Cursor) getExpandableListAdapter().getChild(groupPosition, childPosition);
241 String album = c.getString(c.getColumnIndex(MediaStore.Audio.Albums.ALBUM));
The Android Open Source Project6a9c41c2009-03-09 11:52:14 -0700242 if (album == null || album.equals(MediaFile.UNKNOWN_STRING)) {
The Android Open Source Project792a2202009-03-03 19:32:30 -0800243 // unknown album, so we should include the artist ID to limit the songs to songs only by that artist
244 mArtistCursor.moveToPosition(groupPosition);
245 mCurrentArtistId = mArtistCursor.getString(mArtistCursor.getColumnIndex(MediaStore.Audio.Artists._ID));
246 intent.putExtra("artist", mCurrentArtistId);
247 }
248 startActivity(intent);
249 return true;
250 }
251
252 @Override
253 public boolean onCreateOptionsMenu(Menu menu) {
254 super.onCreateOptionsMenu(menu);
255 menu.add(0, GOTO_START, 0, R.string.goto_start).setIcon(R.drawable.ic_menu_music_library);
256 menu.add(0, GOTO_PLAYBACK, 0, R.string.goto_playback).setIcon(R.drawable.ic_menu_playback);
257 menu.add(0, SHUFFLE_ALL, 0, R.string.shuffle_all).setIcon(R.drawable.ic_menu_shuffle);
258 return true;
259 }
260
261 @Override
262 public boolean onPrepareOptionsMenu(Menu menu) {
263 menu.findItem(GOTO_PLAYBACK).setVisible(MusicUtils.isMusicLoaded());
264 return super.onPrepareOptionsMenu(menu);
265 }
266
267 @Override
268 public boolean onOptionsItemSelected(MenuItem item) {
269 Intent intent;
270 Cursor cursor;
271 switch (item.getItemId()) {
272 case GOTO_START:
273 intent = new Intent();
274 intent.setClass(this, MusicBrowserActivity.class);
275 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
276 startActivity(intent);
277 return true;
278
279 case GOTO_PLAYBACK:
280 intent = new Intent("com.android.music.PLAYBACK_VIEWER");
281 startActivity(intent);
282 return true;
283
284 case SHUFFLE_ALL:
285 cursor = MusicUtils.query(this, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
286 new String [] { MediaStore.Audio.Media._ID},
287 MediaStore.Audio.Media.IS_MUSIC + "=1", null,
288 MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
289 if (cursor != null) {
290 MusicUtils.shuffleAll(this, cursor);
291 cursor.close();
292 }
293 return true;
294 }
295 return super.onOptionsItemSelected(item);
296 }
297
298 @Override
299 public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfoIn) {
300 menu.add(0, PLAY_SELECTION, 0, R.string.play_selection);
301 SubMenu sub = menu.addSubMenu(0, ADD_TO_PLAYLIST, 0, R.string.add_to_playlist);
302 MusicUtils.makePlaylistMenu(this, sub);
303 menu.add(0, DELETE_ITEM, 0, R.string.delete_item);
304 menu.add(0, SEARCH, 0, R.string.search_title);
305
306 ExpandableListContextMenuInfo mi = (ExpandableListContextMenuInfo) menuInfoIn;
307
308 int itemtype = ExpandableListView.getPackedPositionType(mi.packedPosition);
309 int gpos = ExpandableListView.getPackedPositionGroup(mi.packedPosition);
310 int cpos = ExpandableListView.getPackedPositionChild(mi.packedPosition);
311 if (itemtype == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
312 if (gpos == -1) {
313 // this shouldn't happen
314 Log.d("Artist/Album", "no group");
315 return;
316 }
317 gpos = gpos - getExpandableListView().getHeaderViewsCount();
318 mArtistCursor.moveToPosition(gpos);
319 mCurrentArtistId = mArtistCursor.getString(mArtistCursor.getColumnIndexOrThrow(MediaStore.Audio.Artists._ID));
320 mCurrentArtistName = mArtistCursor.getString(mArtistCursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.ARTIST));
321 mCurrentAlbumId = null;
Eric Fischerc8aa8372009-06-17 16:34:12 -0700322 if (mCurrentArtistName == null || mCurrentArtistName.equals(MediaFile.UNKNOWN_STRING)) {
323 menu.setHeaderTitle(getString(R.string.unknown_artist_name));
324 } else {
325 menu.setHeaderTitle(mCurrentArtistName);
326 }
The Android Open Source Project792a2202009-03-03 19:32:30 -0800327 return;
328 } else if (itemtype == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
329 if (cpos == -1) {
330 // this shouldn't happen
331 Log.d("Artist/Album", "no child");
332 return;
333 }
334 Cursor c = (Cursor) getExpandableListAdapter().getChild(gpos, cpos);
335 c.moveToPosition(cpos);
336 mCurrentArtistId = null;
337 mCurrentAlbumId = Long.valueOf(mi.id).toString();
338 mCurrentAlbumName = c.getString(c.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM));
339 gpos = gpos - getExpandableListView().getHeaderViewsCount();
340 mArtistCursor.moveToPosition(gpos);
341 mCurrentArtistNameForAlbum = mArtistCursor.getString(
342 mArtistCursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.ARTIST));
Eric Fischerc8aa8372009-06-17 16:34:12 -0700343 if (mCurrentAlbumName == null || mCurrentAlbumName.equals(MediaFile.UNKNOWN_STRING)) {
344 menu.setHeaderTitle(getString(R.string.unknown_album_name));
345 } else {
346 menu.setHeaderTitle(mCurrentAlbumName);
347 }
The Android Open Source Project792a2202009-03-03 19:32:30 -0800348 }
349 }
350
351 @Override
352 public boolean onContextItemSelected(MenuItem item) {
353 switch (item.getItemId()) {
354 case PLAY_SELECTION: {
355 // play everything by the selected artist
356 int [] list =
357 mCurrentArtistId != null ?
358 MusicUtils.getSongListForArtist(this, Integer.parseInt(mCurrentArtistId))
359 : MusicUtils.getSongListForAlbum(this, Integer.parseInt(mCurrentAlbumId));
360
361 MusicUtils.playAll(this, list, 0);
362 return true;
363 }
364
365 case QUEUE: {
366 int [] list =
367 mCurrentArtistId != null ?
368 MusicUtils.getSongListForArtist(this, Integer.parseInt(mCurrentArtistId))
369 : MusicUtils.getSongListForAlbum(this, Integer.parseInt(mCurrentAlbumId));
370 MusicUtils.addToCurrentPlaylist(this, list);
371 return true;
372 }
373
374 case NEW_PLAYLIST: {
375 Intent intent = new Intent();
376 intent.setClass(this, CreatePlaylist.class);
377 startActivityForResult(intent, NEW_PLAYLIST);
378 return true;
379 }
380
381 case PLAYLIST_SELECTED: {
382 int [] list =
383 mCurrentArtistId != null ?
384 MusicUtils.getSongListForArtist(this, Integer.parseInt(mCurrentArtistId))
385 : MusicUtils.getSongListForAlbum(this, Integer.parseInt(mCurrentAlbumId));
386 int playlist = item.getIntent().getIntExtra("playlist", 0);
387 MusicUtils.addToPlaylist(this, list, playlist);
388 return true;
389 }
390
391 case DELETE_ITEM: {
392 int [] list;
393 String desc;
394 if (mCurrentArtistId != null) {
395 list = MusicUtils.getSongListForArtist(this, Integer.parseInt(mCurrentArtistId));
396 String f = getString(R.string.delete_artist_desc);
397 desc = String.format(f, mCurrentArtistName);
398 } else {
399 list = MusicUtils.getSongListForAlbum(this, Integer.parseInt(mCurrentAlbumId));
400 String f = getString(R.string.delete_album_desc);
401 desc = String.format(f, mCurrentAlbumName);
402 }
403 Bundle b = new Bundle();
404 b.putString("description", desc);
405 b.putIntArray("items", list);
406 Intent intent = new Intent();
407 intent.setClass(this, DeleteItems.class);
408 intent.putExtras(b);
409 startActivityForResult(intent, -1);
410 return true;
411 }
412
413 case SEARCH:
414 doSearch();
415 return true;
416 }
417 return super.onContextItemSelected(item);
418 }
419
420 void doSearch() {
421 CharSequence title = null;
422 String query = null;
423
424 Intent i = new Intent();
425 i.setAction(MediaStore.INTENT_ACTION_MEDIA_SEARCH);
Marco Nelissen4341b502009-05-06 14:57:37 -0700426 i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
The Android Open Source Project792a2202009-03-03 19:32:30 -0800427
428 if (mCurrentArtistId != null) {
429 title = mCurrentArtistName;
430 query = mCurrentArtistName;
431 i.putExtra(MediaStore.EXTRA_MEDIA_ARTIST, mCurrentArtistName);
432 i.putExtra(MediaStore.EXTRA_MEDIA_FOCUS, MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE);
433 } else {
434 title = mCurrentAlbumName;
435 query = mCurrentArtistNameForAlbum + " " + mCurrentAlbumName;
436 i.putExtra(MediaStore.EXTRA_MEDIA_ARTIST, mCurrentArtistNameForAlbum);
437 i.putExtra(MediaStore.EXTRA_MEDIA_ALBUM, mCurrentAlbumName);
438 i.putExtra(MediaStore.EXTRA_MEDIA_FOCUS, MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE);
439 }
440 title = getString(R.string.mediasearch, title);
441 i.putExtra(SearchManager.QUERY, query);
442
443 startActivity(Intent.createChooser(i, title));
444 }
445
446 @Override
447 protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
448 switch (requestCode) {
449 case SCAN_DONE:
450 if (resultCode == RESULT_CANCELED) {
451 finish();
452 } else {
453 getArtistCursor(mAdapter.getQueryHandler(), null);
454 }
455 break;
456
457 case NEW_PLAYLIST:
458 if (resultCode == RESULT_OK) {
459 Uri uri = intent.getData();
460 if (uri != null) {
461 int [] list = null;
462 if (mCurrentArtistId != null) {
463 list = MusicUtils.getSongListForArtist(this, Integer.parseInt(mCurrentArtistId));
464 } else if (mCurrentAlbumId != null) {
465 list = MusicUtils.getSongListForAlbum(this, Integer.parseInt(mCurrentAlbumId));
466 }
467 MusicUtils.addToPlaylist(this, list, Integer.parseInt(uri.getLastPathSegment()));
468 }
469 }
470 break;
471 }
472 }
473
474 private Cursor getArtistCursor(AsyncQueryHandler async, String filter) {
475
476 StringBuilder where = new StringBuilder();
477 where.append(MediaStore.Audio.Artists.ARTIST + " != ''");
478
479 // Add in the filtering constraints
480 String [] keywords = null;
481 if (filter != null) {
482 String [] searchWords = filter.split(" ");
483 keywords = new String[searchWords.length];
484 Collator col = Collator.getInstance();
485 col.setStrength(Collator.PRIMARY);
486 for (int i = 0; i < searchWords.length; i++) {
487 keywords[i] = '%' + MediaStore.Audio.keyFor(searchWords[i]) + '%';
488 }
489 for (int i = 0; i < searchWords.length; i++) {
490 where.append(" AND ");
491 where.append(MediaStore.Audio.Media.ARTIST_KEY + " LIKE ?");
492 }
493 }
494
495 String whereclause = where.toString();
496 String[] cols = new String[] {
497 MediaStore.Audio.Artists._ID,
498 MediaStore.Audio.Artists.ARTIST,
499 MediaStore.Audio.Artists.NUMBER_OF_ALBUMS,
500 MediaStore.Audio.Artists.NUMBER_OF_TRACKS
501 };
502 Cursor ret = null;
503 if (async != null) {
504 async.startQuery(0, null, MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
505 cols, whereclause , keywords, MediaStore.Audio.Artists.ARTIST_KEY);
506 } else {
507 ret = MusicUtils.query(this, MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
508 cols, whereclause , keywords, MediaStore.Audio.Artists.ARTIST_KEY);
509 }
510 return ret;
511 }
512
513 static class ArtistAlbumListAdapter extends SimpleCursorTreeAdapter implements SectionIndexer {
514
515 private final Drawable mNowPlayingOverlay;
516 private final BitmapDrawable mDefaultAlbumIcon;
517 private int mGroupArtistIdIdx;
518 private int mGroupArtistIdx;
519 private int mGroupAlbumIdx;
520 private int mGroupSongIdx;
521 private final Context mContext;
522 private final Resources mResources;
523 private final String mAlbumSongSeparator;
524 private final String mUnknownAlbum;
525 private final String mUnknownArtist;
526 private final StringBuilder mBuffer = new StringBuilder();
527 private final Object[] mFormatArgs = new Object[1];
528 private final Object[] mFormatArgs3 = new Object[3];
529 private MusicAlphabetIndexer mIndexer;
530 private ArtistAlbumBrowserActivity mActivity;
531 private AsyncQueryHandler mQueryHandler;
532 private String mConstraint = null;
533 private boolean mConstraintIsValid = false;
534
Marco Nelissen756c3f52009-05-14 10:07:23 -0700535 static class ViewHolder {
The Android Open Source Project792a2202009-03-03 19:32:30 -0800536 TextView line1;
537 TextView line2;
538 ImageView play_indicator;
539 ImageView icon;
540 }
541
542 class QueryHandler extends AsyncQueryHandler {
543 QueryHandler(ContentResolver res) {
544 super(res);
545 }
546
547 @Override
548 protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
549 //Log.i("@@@", "query complete");
550 mActivity.init(cursor);
551 }
552 }
553
554 ArtistAlbumListAdapter(Context context, ArtistAlbumBrowserActivity currentactivity,
555 Cursor cursor, int glayout, String[] gfrom, int[] gto,
556 int clayout, String[] cfrom, int[] cto) {
557 super(context, cursor, glayout, gfrom, gto, clayout, cfrom, cto);
558 mActivity = currentactivity;
559 mQueryHandler = new QueryHandler(context.getContentResolver());
560
561 Resources r = context.getResources();
562 mNowPlayingOverlay = r.getDrawable(R.drawable.indicator_ic_mp_playing_list);
563 mDefaultAlbumIcon = (BitmapDrawable) r.getDrawable(R.drawable.albumart_mp_unknown_list);
564 // no filter or dither, it's a lot faster and we can't tell the difference
565 mDefaultAlbumIcon.setFilterBitmap(false);
566 mDefaultAlbumIcon.setDither(false);
567
568 mContext = context;
569 getColumnIndices(cursor);
570 mResources = context.getResources();
571 mAlbumSongSeparator = context.getString(R.string.albumsongseparator);
572 mUnknownAlbum = context.getString(R.string.unknown_album_name);
573 mUnknownArtist = context.getString(R.string.unknown_artist_name);
574 }
575
576 private void getColumnIndices(Cursor cursor) {
577 if (cursor != null) {
578 mGroupArtistIdIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists._ID);
579 mGroupArtistIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.ARTIST);
580 mGroupAlbumIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.NUMBER_OF_ALBUMS);
581 mGroupSongIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.NUMBER_OF_TRACKS);
582 if (mIndexer != null) {
583 mIndexer.setCursor(cursor);
584 } else {
585 mIndexer = new MusicAlphabetIndexer(cursor, mGroupArtistIdx,
586 mResources.getString(com.android.internal.R.string.fast_scroll_alphabet));
587 }
588 }
589 }
590
591 public void setActivity(ArtistAlbumBrowserActivity newactivity) {
592 mActivity = newactivity;
593 }
594
595 public AsyncQueryHandler getQueryHandler() {
596 return mQueryHandler;
597 }
598
599 @Override
600 public View newGroupView(Context context, Cursor cursor, boolean isExpanded, ViewGroup parent) {
601 View v = super.newGroupView(context, cursor, isExpanded, parent);
602 ImageView iv = (ImageView) v.findViewById(R.id.icon);
603 ViewGroup.LayoutParams p = iv.getLayoutParams();
604 p.width = ViewGroup.LayoutParams.WRAP_CONTENT;
605 p.height = ViewGroup.LayoutParams.WRAP_CONTENT;
606 ViewHolder vh = new ViewHolder();
607 vh.line1 = (TextView) v.findViewById(R.id.line1);
608 vh.line2 = (TextView) v.findViewById(R.id.line2);
609 vh.play_indicator = (ImageView) v.findViewById(R.id.play_indicator);
610 vh.icon = (ImageView) v.findViewById(R.id.icon);
611 vh.icon.setPadding(0, 0, 1, 0);
612 v.setTag(vh);
613 return v;
614 }
615
616 @Override
617 public View newChildView(Context context, Cursor cursor, boolean isLastChild,
618 ViewGroup parent) {
619 View v = super.newChildView(context, cursor, isLastChild, parent);
620 ViewHolder vh = new ViewHolder();
621 vh.line1 = (TextView) v.findViewById(R.id.line1);
622 vh.line2 = (TextView) v.findViewById(R.id.line2);
623 vh.play_indicator = (ImageView) v.findViewById(R.id.play_indicator);
624 vh.icon = (ImageView) v.findViewById(R.id.icon);
625 vh.icon.setBackgroundDrawable(mDefaultAlbumIcon);
626 vh.icon.setPadding(0, 0, 1, 0);
627 v.setTag(vh);
628 return v;
629 }
630
631 @Override
632 public void bindGroupView(View view, Context context, Cursor cursor, boolean isexpanded) {
633
634 ViewHolder vh = (ViewHolder) view.getTag();
635
636 String artist = cursor.getString(mGroupArtistIdx);
637 String displayartist = artist;
The Android Open Source Project6a9c41c2009-03-09 11:52:14 -0700638 boolean unknown = artist == null || artist.equals(MediaFile.UNKNOWN_STRING);
The Android Open Source Project792a2202009-03-03 19:32:30 -0800639 if (unknown) {
640 displayartist = mUnknownArtist;
641 }
642 vh.line1.setText(displayartist);
643
644 int numalbums = cursor.getInt(mGroupAlbumIdx);
645 int numsongs = cursor.getInt(mGroupSongIdx);
646
647 String songs_albums = MusicUtils.makeAlbumsLabel(context,
648 numalbums, numsongs, unknown);
649
650 vh.line2.setText(songs_albums);
651
652 int currentartistid = MusicUtils.getCurrentArtistId();
653 int artistid = cursor.getInt(mGroupArtistIdIdx);
654 if (currentartistid == artistid && !isexpanded) {
655 vh.play_indicator.setImageDrawable(mNowPlayingOverlay);
656 } else {
657 vh.play_indicator.setImageDrawable(null);
658 }
659 }
660
661 @Override
662 public void bindChildView(View view, Context context, Cursor cursor, boolean islast) {
663
664 ViewHolder vh = (ViewHolder) view.getTag();
665
666 String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM));
667 String displayname = name;
The Android Open Source Project6a9c41c2009-03-09 11:52:14 -0700668 boolean unknown = name == null || name.equals(MediaFile.UNKNOWN_STRING);
The Android Open Source Project792a2202009-03-03 19:32:30 -0800669 if (unknown) {
670 displayname = mUnknownAlbum;
671 }
672 vh.line1.setText(displayname);
673
674 int numsongs = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.NUMBER_OF_SONGS));
675 int numartistsongs = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST));
The Android Open Source Project792a2202009-03-03 19:32:30 -0800676
677 final StringBuilder builder = mBuffer;
678 builder.delete(0, builder.length());
679 if (unknown) {
680 numsongs = numartistsongs;
681 }
682
683 if (numsongs == 1) {
684 builder.append(context.getString(R.string.onesong));
685 } else {
686 if (numsongs == numartistsongs) {
687 final Object[] args = mFormatArgs;
688 args[0] = numsongs;
689 builder.append(mResources.getQuantityString(R.plurals.Nsongs, numsongs, args));
690 } else {
691 final Object[] args = mFormatArgs3;
692 args[0] = numsongs;
693 args[1] = numartistsongs;
694 args[2] = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.ARTIST));
695 builder.append(mResources.getQuantityString(R.plurals.Nsongscomp, numsongs, args));
696 }
697 }
698 vh.line2.setText(builder.toString());
699
700 ImageView iv = vh.icon;
701 // We don't actually need the path to the thumbnail file,
702 // we just use it to see if there is album art or not
703 String art = cursor.getString(cursor.getColumnIndexOrThrow(
704 MediaStore.Audio.Albums.ALBUM_ART));
705 if (unknown || art == null || art.length() == 0) {
706 iv.setBackgroundDrawable(mDefaultAlbumIcon);
707 iv.setImageDrawable(null);
708 } else {
709 int artIndex = cursor.getInt(0);
710 Drawable d = MusicUtils.getCachedArtwork(context, artIndex, mDefaultAlbumIcon);
711 iv.setImageDrawable(d);
712 }
713
714 int currentalbumid = MusicUtils.getCurrentAlbumId();
715 int aid = cursor.getInt(0);
716 iv = vh.play_indicator;
717 if (currentalbumid == aid) {
718 iv.setImageDrawable(mNowPlayingOverlay);
719 } else {
720 iv.setImageDrawable(null);
721 }
722 }
723
724
725 @Override
726 protected Cursor getChildrenCursor(Cursor groupCursor) {
727
728 int id = groupCursor.getInt(groupCursor.getColumnIndexOrThrow(MediaStore.Audio.Artists._ID));
729
730 String[] cols = new String[] {
731 MediaStore.Audio.Albums._ID,
732 MediaStore.Audio.Albums.ALBUM,
733 MediaStore.Audio.Albums.NUMBER_OF_SONGS,
734 MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST,
The Android Open Source Project792a2202009-03-03 19:32:30 -0800735 MediaStore.Audio.Albums.ALBUM_ART
736 };
737 Cursor c = MusicUtils.query(mActivity,
738 MediaStore.Audio.Artists.Albums.getContentUri("external", id),
739 cols, null, null, MediaStore.Audio.Albums.DEFAULT_SORT_ORDER);
740
741 class MyCursorWrapper extends CursorWrapper {
742 String mArtistName;
743 int mMagicColumnIdx;
744 MyCursorWrapper(Cursor c, String artist) {
745 super(c);
746 mArtistName = artist;
The Android Open Source Project6a9c41c2009-03-09 11:52:14 -0700747 if (mArtistName == null || mArtistName.equals(MediaFile.UNKNOWN_STRING)) {
The Android Open Source Project792a2202009-03-03 19:32:30 -0800748 mArtistName = mUnknownArtist;
749 }
750 mMagicColumnIdx = c.getColumnCount();
751 }
752
753 @Override
754 public String getString(int columnIndex) {
755 if (columnIndex != mMagicColumnIdx) {
756 return super.getString(columnIndex);
757 }
758 return mArtistName;
759 }
760
761 @Override
762 public int getColumnIndexOrThrow(String name) {
The Android Open Source Project6a9c41c2009-03-09 11:52:14 -0700763 if (MediaStore.Audio.Albums.ARTIST.equals(name)) {
The Android Open Source Project792a2202009-03-03 19:32:30 -0800764 return mMagicColumnIdx;
765 }
766 return super.getColumnIndexOrThrow(name);
767 }
768
769 @Override
770 public String getColumnName(int idx) {
771 if (idx != mMagicColumnIdx) {
772 return super.getColumnName(idx);
773 }
774 return MediaStore.Audio.Albums.ARTIST;
775 }
776
777 @Override
778 public int getColumnCount() {
779 return super.getColumnCount() + 1;
780 }
781 }
782 return new MyCursorWrapper(c, groupCursor.getString(mGroupArtistIdx));
783 }
784
785 @Override
786 public void changeCursor(Cursor cursor) {
787 if (cursor != mActivity.mArtistCursor) {
788 mActivity.mArtistCursor = cursor;
789 getColumnIndices(cursor);
790 super.changeCursor(cursor);
791 }
792 }
793
794 @Override
795 public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
796 String s = constraint.toString();
797 if (mConstraintIsValid && (
798 (s == null && mConstraint == null) ||
799 (s != null && s.equals(mConstraint)))) {
800 return getCursor();
801 }
802 Cursor c = mActivity.getArtistCursor(null, s);
803 mConstraint = s;
804 mConstraintIsValid = true;
805 return c;
806 }
807
808 public Object[] getSections() {
809 return mIndexer.getSections();
810 }
811
812 public int getPositionForSection(int sectionIndex) {
813 return mIndexer.getPositionForSection(sectionIndex);
814 }
815
816 public int getSectionForPosition(int position) {
817 return 0;
818 }
819 }
820
821 private Cursor mArtistCursor;
822}
823