ArtistAlbumBrowserActivity.java revision 722ca0becdfb955ce36e24f86de9f7a899c74c5e
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 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 setTitle(); 129 } else { 130 getArtistCursor(mAdapter.getQueryHandler(), null); 131 } 132 } 133 } 134 135 @Override 136 public Object onRetainNonConfigurationInstance() { 137 mAdapterSent = true; 138 return mAdapter; 139 } 140 141 @Override 142 public void onSaveInstanceState(Bundle outcicle) { 143 // need to store the selected item so we don't lose it in case 144 // of an orientation switch. Otherwise we could lose it while 145 // in the middle of specifying a playlist to add the item to. 146 outcicle.putString("selectedalbum", mCurrentAlbumId); 147 outcicle.putString("selectedalbumname", mCurrentAlbumName); 148 outcicle.putString("selectedartist", mCurrentArtistId); 149 outcicle.putString("selectedartistname", mCurrentArtistName); 150 super.onSaveInstanceState(outcicle); 151 } 152 153 @Override 154 public void onDestroy() { 155 MusicUtils.unbindFromService(this); 156 if (!mAdapterSent) { 157 Cursor c = mAdapter.getCursor(); 158 if (c != null) { 159 c.close(); 160 } 161 } 162 unregisterReceiver(mScanListener); 163 super.onDestroy(); 164 } 165 166 @Override 167 public void onResume() { 168 super.onResume(); 169 IntentFilter f = new IntentFilter(); 170 f.addAction(MediaPlaybackService.META_CHANGED); 171 f.addAction(MediaPlaybackService.QUEUE_CHANGED); 172 registerReceiver(mTrackListListener, f); 173 mTrackListListener.onReceive(null, null); 174 175 MusicUtils.setSpinnerState(this); 176 } 177 178 private BroadcastReceiver mTrackListListener = new BroadcastReceiver() { 179 @Override 180 public void onReceive(Context context, Intent intent) { 181 getExpandableListView().invalidateViews(); 182 } 183 }; 184 private BroadcastReceiver mScanListener = new BroadcastReceiver() { 185 @Override 186 public void onReceive(Context context, Intent intent) { 187 MusicUtils.setSpinnerState(ArtistAlbumBrowserActivity.this); 188 mReScanHandler.sendEmptyMessage(0); 189 if (intent.getAction().equals(Intent.ACTION_MEDIA_UNMOUNTED)) { 190 MusicUtils.clearAlbumArtCache(); 191 } 192 } 193 }; 194 195 private Handler mReScanHandler = new Handler() { 196 @Override 197 public void handleMessage(Message msg) { 198 setTitle(); 199 getArtistCursor(mAdapter.getQueryHandler(), null); 200 } 201 }; 202 203 @Override 204 public void onPause() { 205 unregisterReceiver(mTrackListListener); 206 mReScanHandler.removeCallbacksAndMessages(null); 207 super.onPause(); 208 } 209 210 public void init(Cursor c) { 211 212 mAdapter.changeCursor(c); // also sets mArtistCursor 213 214 if (mArtistCursor == null) { 215 MusicUtils.displayDatabaseError(this); 216 closeContextMenu(); 217 mReScanHandler.sendEmptyMessageDelayed(0, 1000); 218 return; 219 } 220 221 MusicUtils.hideDatabaseError(this); 222 } 223 224 private void setTitle() { 225 if (mArtistCursor != null && mArtistCursor.getCount() > 0) { 226 setTitle(R.string.artists_title); 227 } else { 228 setTitle(R.string.no_artists_title); 229 } 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)); 242 if (album.equals(MediaFile.UNKNOWN_STRING)) { 243 // 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; 322 menu.setHeaderTitle(mCurrentArtistName); 323 return; 324 } else if (itemtype == ExpandableListView.PACKED_POSITION_TYPE_CHILD) { 325 if (cpos == -1) { 326 // this shouldn't happen 327 Log.d("Artist/Album", "no child"); 328 return; 329 } 330 Cursor c = (Cursor) getExpandableListAdapter().getChild(gpos, cpos); 331 c.moveToPosition(cpos); 332 mCurrentArtistId = null; 333 mCurrentAlbumId = Long.valueOf(mi.id).toString(); 334 mCurrentAlbumName = c.getString(c.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM)); 335 gpos = gpos - getExpandableListView().getHeaderViewsCount(); 336 mArtistCursor.moveToPosition(gpos); 337 mCurrentArtistNameForAlbum = mArtistCursor.getString( 338 mArtistCursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.ARTIST)); 339 menu.setHeaderTitle(mCurrentAlbumName); 340 } 341 } 342 343 @Override 344 public boolean onContextItemSelected(MenuItem item) { 345 switch (item.getItemId()) { 346 case PLAY_SELECTION: { 347 // play everything by the selected artist 348 int [] list = 349 mCurrentArtistId != null ? 350 MusicUtils.getSongListForArtist(this, Integer.parseInt(mCurrentArtistId)) 351 : MusicUtils.getSongListForAlbum(this, Integer.parseInt(mCurrentAlbumId)); 352 353 MusicUtils.playAll(this, list, 0); 354 return true; 355 } 356 357 case QUEUE: { 358 int [] list = 359 mCurrentArtistId != null ? 360 MusicUtils.getSongListForArtist(this, Integer.parseInt(mCurrentArtistId)) 361 : MusicUtils.getSongListForAlbum(this, Integer.parseInt(mCurrentAlbumId)); 362 MusicUtils.addToCurrentPlaylist(this, list); 363 return true; 364 } 365 366 case NEW_PLAYLIST: { 367 Intent intent = new Intent(); 368 intent.setClass(this, CreatePlaylist.class); 369 startActivityForResult(intent, NEW_PLAYLIST); 370 return true; 371 } 372 373 case PLAYLIST_SELECTED: { 374 int [] list = 375 mCurrentArtistId != null ? 376 MusicUtils.getSongListForArtist(this, Integer.parseInt(mCurrentArtistId)) 377 : MusicUtils.getSongListForAlbum(this, Integer.parseInt(mCurrentAlbumId)); 378 int playlist = item.getIntent().getIntExtra("playlist", 0); 379 MusicUtils.addToPlaylist(this, list, playlist); 380 return true; 381 } 382 383 case DELETE_ITEM: { 384 int [] list; 385 String desc; 386 if (mCurrentArtistId != null) { 387 list = MusicUtils.getSongListForArtist(this, Integer.parseInt(mCurrentArtistId)); 388 String f = getString(R.string.delete_artist_desc); 389 desc = String.format(f, mCurrentArtistName); 390 } else { 391 list = MusicUtils.getSongListForAlbum(this, Integer.parseInt(mCurrentAlbumId)); 392 String f = getString(R.string.delete_album_desc); 393 desc = String.format(f, mCurrentAlbumName); 394 } 395 Bundle b = new Bundle(); 396 b.putString("description", desc); 397 b.putIntArray("items", list); 398 Intent intent = new Intent(); 399 intent.setClass(this, DeleteItems.class); 400 intent.putExtras(b); 401 startActivityForResult(intent, -1); 402 return true; 403 } 404 405 case SEARCH: 406 doSearch(); 407 return true; 408 } 409 return super.onContextItemSelected(item); 410 } 411 412 void doSearch() { 413 CharSequence title = null; 414 String query = null; 415 416 Intent i = new Intent(); 417 i.setAction(MediaStore.INTENT_ACTION_MEDIA_SEARCH); 418 419 if (mCurrentArtistId != null) { 420 title = mCurrentArtistName; 421 query = mCurrentArtistName; 422 i.putExtra(MediaStore.EXTRA_MEDIA_ARTIST, mCurrentArtistName); 423 i.putExtra(MediaStore.EXTRA_MEDIA_FOCUS, MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE); 424 } else { 425 title = mCurrentAlbumName; 426 query = mCurrentArtistNameForAlbum + " " + mCurrentAlbumName; 427 i.putExtra(MediaStore.EXTRA_MEDIA_ARTIST, mCurrentArtistNameForAlbum); 428 i.putExtra(MediaStore.EXTRA_MEDIA_ALBUM, mCurrentAlbumName); 429 i.putExtra(MediaStore.EXTRA_MEDIA_FOCUS, MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE); 430 } 431 title = getString(R.string.mediasearch, title); 432 i.putExtra(SearchManager.QUERY, query); 433 434 startActivity(Intent.createChooser(i, title)); 435 } 436 437 @Override 438 protected void onActivityResult(int requestCode, int resultCode, Intent intent) { 439 switch (requestCode) { 440 case SCAN_DONE: 441 if (resultCode == RESULT_CANCELED) { 442 finish(); 443 } else { 444 getArtistCursor(mAdapter.getQueryHandler(), null); 445 } 446 break; 447 448 case NEW_PLAYLIST: 449 if (resultCode == RESULT_OK) { 450 Uri uri = intent.getData(); 451 if (uri != null) { 452 int [] list = null; 453 if (mCurrentArtistId != null) { 454 list = MusicUtils.getSongListForArtist(this, Integer.parseInt(mCurrentArtistId)); 455 } else if (mCurrentAlbumId != null) { 456 list = MusicUtils.getSongListForAlbum(this, Integer.parseInt(mCurrentAlbumId)); 457 } 458 MusicUtils.addToPlaylist(this, list, Integer.parseInt(uri.getLastPathSegment())); 459 } 460 } 461 break; 462 } 463 } 464 465 private Cursor getArtistCursor(AsyncQueryHandler async, String filter) { 466 467 StringBuilder where = new StringBuilder(); 468 where.append(MediaStore.Audio.Artists.ARTIST + " != ''"); 469 470 // Add in the filtering constraints 471 String [] keywords = null; 472 if (filter != null) { 473 String [] searchWords = filter.split(" "); 474 keywords = new String[searchWords.length]; 475 Collator col = Collator.getInstance(); 476 col.setStrength(Collator.PRIMARY); 477 for (int i = 0; i < searchWords.length; i++) { 478 keywords[i] = '%' + MediaStore.Audio.keyFor(searchWords[i]) + '%'; 479 } 480 for (int i = 0; i < searchWords.length; i++) { 481 where.append(" AND "); 482 where.append(MediaStore.Audio.Media.ARTIST_KEY + " LIKE ?"); 483 } 484 } 485 486 String whereclause = where.toString(); 487 String[] cols = new String[] { 488 MediaStore.Audio.Artists._ID, 489 MediaStore.Audio.Artists.ARTIST, 490 MediaStore.Audio.Artists.NUMBER_OF_ALBUMS, 491 MediaStore.Audio.Artists.NUMBER_OF_TRACKS 492 }; 493 Cursor ret = null; 494 if (async != null) { 495 async.startQuery(0, null, MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, 496 cols, whereclause , keywords, MediaStore.Audio.Artists.ARTIST_KEY); 497 } else { 498 ret = MusicUtils.query(this, MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, 499 cols, whereclause , keywords, MediaStore.Audio.Artists.ARTIST_KEY); 500 } 501 return ret; 502 } 503 504 static class ArtistAlbumListAdapter extends SimpleCursorTreeAdapter implements SectionIndexer { 505 506 private final Drawable mNowPlayingOverlay; 507 private final BitmapDrawable mDefaultAlbumIcon; 508 private int mGroupArtistIdIdx; 509 private int mGroupArtistIdx; 510 private int mGroupAlbumIdx; 511 private int mGroupSongIdx; 512 private final Context mContext; 513 private final Resources mResources; 514 private final String mAlbumSongSeparator; 515 private final String mUnknownAlbum; 516 private final String mUnknownArtist; 517 private final StringBuilder mBuffer = new StringBuilder(); 518 private final Object[] mFormatArgs = new Object[1]; 519 private final Object[] mFormatArgs3 = new Object[3]; 520 private MusicAlphabetIndexer mIndexer; 521 private ArtistAlbumBrowserActivity mActivity; 522 private AsyncQueryHandler mQueryHandler; 523 524 class ViewHolder { 525 TextView line1; 526 TextView line2; 527 ImageView play_indicator; 528 ImageView icon; 529 } 530 531 class QueryHandler extends AsyncQueryHandler { 532 QueryHandler(ContentResolver res) { 533 super(res); 534 } 535 536 @Override 537 protected void onQueryComplete(int token, Object cookie, Cursor cursor) { 538 //Log.i("@@@", "query complete"); 539 mActivity.init(cursor); 540 mActivity.setTitle(); 541 } 542 } 543 544 ArtistAlbumListAdapter(Context context, ArtistAlbumBrowserActivity currentactivity, 545 Cursor cursor, int glayout, String[] gfrom, int[] gto, 546 int clayout, String[] cfrom, int[] cto) { 547 super(context, cursor, glayout, gfrom, gto, clayout, cfrom, cto); 548 mActivity = currentactivity; 549 mQueryHandler = new QueryHandler(context.getContentResolver()); 550 551 Resources r = context.getResources(); 552 mNowPlayingOverlay = r.getDrawable(R.drawable.indicator_ic_mp_playing_list); 553 mDefaultAlbumIcon = (BitmapDrawable) r.getDrawable(R.drawable.albumart_mp_unknown_list); 554 // no filter or dither, it's a lot faster and we can't tell the difference 555 mDefaultAlbumIcon.setFilterBitmap(false); 556 mDefaultAlbumIcon.setDither(false); 557 558 mContext = context; 559 getColumnIndices(cursor); 560 mResources = context.getResources(); 561 mAlbumSongSeparator = context.getString(R.string.albumsongseparator); 562 mUnknownAlbum = context.getString(R.string.unknown_album_name); 563 mUnknownArtist = context.getString(R.string.unknown_artist_name); 564 } 565 566 private void getColumnIndices(Cursor cursor) { 567 if (cursor != null) { 568 mGroupArtistIdIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists._ID); 569 mGroupArtistIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.ARTIST); 570 mGroupAlbumIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.NUMBER_OF_ALBUMS); 571 mGroupSongIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.NUMBER_OF_TRACKS); 572 if (mIndexer != null) { 573 mIndexer.setCursor(cursor); 574 } else { 575 mIndexer = new MusicAlphabetIndexer(cursor, mGroupArtistIdx, 576 mResources.getString(com.android.internal.R.string.fast_scroll_alphabet)); 577 } 578 } 579 } 580 581 public void setActivity(ArtistAlbumBrowserActivity newactivity) { 582 mActivity = newactivity; 583 } 584 585 public AsyncQueryHandler getQueryHandler() { 586 return mQueryHandler; 587 } 588 589 @Override 590 public View newGroupView(Context context, Cursor cursor, boolean isExpanded, ViewGroup parent) { 591 View v = super.newGroupView(context, cursor, isExpanded, parent); 592 ImageView iv = (ImageView) v.findViewById(R.id.icon); 593 ViewGroup.LayoutParams p = iv.getLayoutParams(); 594 p.width = ViewGroup.LayoutParams.WRAP_CONTENT; 595 p.height = ViewGroup.LayoutParams.WRAP_CONTENT; 596 ViewHolder vh = new ViewHolder(); 597 vh.line1 = (TextView) v.findViewById(R.id.line1); 598 vh.line2 = (TextView) v.findViewById(R.id.line2); 599 vh.play_indicator = (ImageView) v.findViewById(R.id.play_indicator); 600 vh.icon = (ImageView) v.findViewById(R.id.icon); 601 vh.icon.setPadding(1, 1, 1, 1); 602 v.setTag(vh); 603 return v; 604 } 605 606 @Override 607 public View newChildView(Context context, Cursor cursor, boolean isLastChild, 608 ViewGroup parent) { 609 View v = super.newChildView(context, cursor, isLastChild, parent); 610 ViewHolder vh = new ViewHolder(); 611 vh.line1 = (TextView) v.findViewById(R.id.line1); 612 vh.line2 = (TextView) v.findViewById(R.id.line2); 613 vh.play_indicator = (ImageView) v.findViewById(R.id.play_indicator); 614 vh.icon = (ImageView) v.findViewById(R.id.icon); 615 vh.icon.setBackgroundDrawable(mDefaultAlbumIcon); 616 vh.icon.setPadding(1, 1, 1, 1); 617 v.setTag(vh); 618 return v; 619 } 620 621 @Override 622 public void bindGroupView(View view, Context context, Cursor cursor, boolean isexpanded) { 623 624 ViewHolder vh = (ViewHolder) view.getTag(); 625 626 String artist = cursor.getString(mGroupArtistIdx); 627 String displayartist = artist; 628 boolean unknown = MediaFile.UNKNOWN_STRING.equals(artist); 629 if (unknown) { 630 displayartist = mUnknownArtist; 631 } 632 vh.line1.setText(displayartist); 633 634 int numalbums = cursor.getInt(mGroupAlbumIdx); 635 int numsongs = cursor.getInt(mGroupSongIdx); 636 637 String songs_albums = MusicUtils.makeAlbumsSongsLabel(context, 638 numalbums, numsongs, unknown); 639 640 vh.line2.setText(songs_albums); 641 642 int currentartistid = MusicUtils.getCurrentArtistId(); 643 int artistid = cursor.getInt(mGroupArtistIdIdx); 644 if (currentartistid == artistid && !isexpanded) { 645 vh.play_indicator.setImageDrawable(mNowPlayingOverlay); 646 } else { 647 vh.play_indicator.setImageDrawable(null); 648 } 649 } 650 651 @Override 652 public void bindChildView(View view, Context context, Cursor cursor, boolean islast) { 653 654 ViewHolder vh = (ViewHolder) view.getTag(); 655 656 String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM)); 657 String displayname = name; 658 boolean unknown = name.equals(MediaFile.UNKNOWN_STRING); 659 if (unknown) { 660 displayname = mUnknownAlbum; 661 } 662 vh.line1.setText(displayname); 663 664 int numsongs = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.NUMBER_OF_SONGS)); 665 int numartistsongs = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST)); 666 int first = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.FIRST_YEAR)); 667 int last = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.LAST_YEAR)); 668 669 if (first == 0) { 670 first = last; 671 } 672 673 final StringBuilder builder = mBuffer; 674 builder.delete(0, builder.length()); 675 if (unknown) { 676 numsongs = numartistsongs; 677 } 678 679 if (numsongs == 1) { 680 builder.append(context.getString(R.string.onesong)); 681 } else { 682 if (numsongs == numartistsongs) { 683 final Object[] args = mFormatArgs; 684 args[0] = numsongs; 685 builder.append(mResources.getQuantityString(R.plurals.Nsongs, numsongs, args)); 686 } else { 687 final Object[] args = mFormatArgs3; 688 args[0] = numsongs; 689 args[1] = numartistsongs; 690 args[2] = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Artists.ARTIST)); 691 builder.append(mResources.getQuantityString(R.plurals.Nsongscomp, numsongs, args)); 692 } 693 } 694 // If this is the unknown album, we don't really have any information about the year, 695 // since the year info is be for the entire collection of unknown album songs, not 696 // just the ones belonging to this artist. 697 if (!unknown && first != 0 && last != 0) { 698 builder.append("\n"); 699 700 builder.append(first); 701 if (first != last) { 702 builder.append('-'); 703 builder.append(last); 704 } else { 705 } 706 } 707 vh.line2.setText(builder.toString()); 708 709 ImageView iv = vh.icon; 710 // We don't actually need the path to the thumbnail file, 711 // we just use it to see if there is album art or not 712 String art = cursor.getString(cursor.getColumnIndexOrThrow( 713 MediaStore.Audio.Albums.ALBUM_ART)); 714 if (art == null || art.length() == 0) { 715 iv.setBackgroundDrawable(mDefaultAlbumIcon); 716 iv.setImageDrawable(null); 717 } else { 718 int artIndex = cursor.getInt(0); 719 Drawable d = MusicUtils.getCachedArtwork(context, artIndex, mDefaultAlbumIcon); 720 iv.setImageDrawable(d); 721 } 722 723 int currentalbumid = MusicUtils.getCurrentAlbumId(); 724 int aid = cursor.getInt(0); 725 iv = vh.play_indicator; 726 if (currentalbumid == aid) { 727 iv.setImageDrawable(mNowPlayingOverlay); 728 } else { 729 iv.setImageDrawable(null); 730 } 731 } 732 733 734 @Override 735 protected Cursor getChildrenCursor(Cursor groupCursor) { 736 737 int id = groupCursor.getInt(groupCursor.getColumnIndexOrThrow(MediaStore.Audio.Artists._ID)); 738 739 String[] cols = new String[] { 740 MediaStore.Audio.Albums._ID, 741 MediaStore.Audio.Albums.ALBUM, 742 MediaStore.Audio.Albums.NUMBER_OF_SONGS, 743 MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST, 744 MediaStore.Audio.Albums.FIRST_YEAR, 745 MediaStore.Audio.Albums.LAST_YEAR, 746 MediaStore.Audio.Albums.ALBUM_ART 747 }; 748 Cursor c = MusicUtils.query(mActivity, 749 MediaStore.Audio.Artists.Albums.getContentUri("external", id), 750 cols, null, null, MediaStore.Audio.Albums.DEFAULT_SORT_ORDER); 751 752 class MyCursorWrapper extends CursorWrapper { 753 String mArtistName; 754 int mMagicColumnIdx; 755 MyCursorWrapper(Cursor c, String artist) { 756 super(c); 757 mArtistName = artist; 758 if (MediaFile.UNKNOWN_STRING.equals(mArtistName)) { 759 mArtistName = mUnknownArtist; 760 } 761 mMagicColumnIdx = c.getColumnCount(); 762 } 763 764 @Override 765 public String getString(int columnIndex) { 766 if (columnIndex != mMagicColumnIdx) { 767 return super.getString(columnIndex); 768 } 769 return mArtistName; 770 } 771 772 @Override 773 public int getColumnIndexOrThrow(String name) { 774 if (name.equals(MediaStore.Audio.Albums.ARTIST)) { 775 return mMagicColumnIdx; 776 } 777 return super.getColumnIndexOrThrow(name); 778 } 779 780 @Override 781 public String getColumnName(int idx) { 782 if (idx != mMagicColumnIdx) { 783 return super.getColumnName(idx); 784 } 785 return MediaStore.Audio.Albums.ARTIST; 786 } 787 788 @Override 789 public int getColumnCount() { 790 return super.getColumnCount() + 1; 791 } 792 } 793 return new MyCursorWrapper(c, groupCursor.getString(mGroupArtistIdx)); 794 } 795 796 @Override 797 public void changeCursor(Cursor cursor) { 798 if (cursor != mActivity.mArtistCursor) { 799 mActivity.mArtistCursor = cursor; 800 getColumnIndices(cursor); 801 super.changeCursor(cursor); 802 } 803 } 804 805 @Override 806 public Cursor runQueryOnBackgroundThread(CharSequence constraint) { 807 return mActivity.getArtistCursor(null, constraint.toString()); 808 } 809 810 public Object[] getSections() { 811 return mIndexer.getSections(); 812 } 813 814 public int getPositionForSection(int sectionIndex) { 815 return mIndexer.getPositionForSection(sectionIndex); 816 } 817 818 public int getSectionForPosition(int position) { 819 return 0; 820 } 821 } 822 823 private Cursor mArtistCursor; 824} 825 826