AlbumBrowserActivity.java revision d99bc1e9481c68514a4e5eea4c3f429843b701b4
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 android.app.ListActivity; 20import android.app.SearchManager; 21import android.content.AsyncQueryHandler; 22import android.content.BroadcastReceiver; 23import android.content.ContentResolver; 24import android.content.Context; 25import android.content.Intent; 26import android.content.IntentFilter; 27import android.content.res.Resources; 28import android.database.Cursor; 29import android.graphics.Bitmap; 30import android.graphics.BitmapFactory; 31import android.graphics.drawable.BitmapDrawable; 32import android.graphics.drawable.Drawable; 33import android.media.AudioManager; 34import android.media.MediaFile; 35import android.net.Uri; 36import android.os.Bundle; 37import android.os.Handler; 38import android.os.Message; 39import android.provider.MediaStore; 40import android.util.Log; 41import android.view.ContextMenu; 42import android.view.Menu; 43import android.view.MenuItem; 44import android.view.SubMenu; 45import android.view.View; 46import android.view.ViewGroup; 47import android.view.Window; 48import android.view.ContextMenu.ContextMenuInfo; 49import android.widget.Adapter; 50import android.widget.AlphabetIndexer; 51import android.widget.CursorAdapter; 52import android.widget.ImageView; 53import android.widget.ListAdapter; 54import android.widget.ListView; 55import android.widget.SectionIndexer; 56import android.widget.SimpleCursorAdapter; 57import android.widget.TextView; 58import android.widget.AdapterView.AdapterContextMenuInfo; 59 60import java.text.Collator; 61 62public class AlbumBrowserActivity extends ListActivity 63 implements View.OnCreateContextMenuListener, MusicUtils.Defs 64{ 65 private String mCurrentAlbumId; 66 private String mCurrentAlbumName; 67 private String mCurrentArtistNameForAlbum; 68 boolean mIsUnknownArtist; 69 boolean mIsUnknownAlbum; 70 private AlbumListAdapter mAdapter; 71 private boolean mAdapterSent; 72 private final static int SEARCH = CHILD_MENU_BASE; 73 74 public AlbumBrowserActivity() 75 { 76 } 77 78 /** Called when the activity is first created. */ 79 @Override 80 public void onCreate(Bundle icicle) 81 { 82 if (icicle != null) { 83 mCurrentAlbumId = icicle.getString("selectedalbum"); 84 mArtistId = icicle.getString("artist"); 85 } else { 86 mArtistId = getIntent().getStringExtra("artist"); 87 } 88 super.onCreate(icicle); 89 requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); 90 setVolumeControlStream(AudioManager.STREAM_MUSIC); 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); 101 ListView lv = getListView(); 102 lv.setFastScrollEnabled(true); 103 lv.setOnCreateContextMenuListener(this); 104 lv.setTextFilterEnabled(true); 105 106 mAdapter = (AlbumListAdapter) getLastNonConfigurationInstance(); 107 if (mAdapter == null) { 108 //Log.i("@@@", "starting query"); 109 mAdapter = new AlbumListAdapter( 110 getApplication(), 111 this, 112 R.layout.track_list_item, 113 mAlbumCursor, 114 new String[] {}, 115 new int[] {}); 116 setListAdapter(mAdapter); 117 setTitle(R.string.working_albums); 118 getAlbumCursor(mAdapter.getQueryHandler(), null); 119 } else { 120 mAdapter.setActivity(this); 121 setListAdapter(mAdapter); 122 mAlbumCursor = mAdapter.getCursor(); 123 if (mAlbumCursor != null) { 124 init(mAlbumCursor); 125 } else { 126 getAlbumCursor(mAdapter.getQueryHandler(), null); 127 } 128 } 129 } 130 131 @Override 132 public Object onRetainNonConfigurationInstance() { 133 mAdapterSent = true; 134 return mAdapter; 135 } 136 137 @Override 138 public void onSaveInstanceState(Bundle outcicle) { 139 // need to store the selected item so we don't lose it in case 140 // of an orientation switch. Otherwise we could lose it while 141 // in the middle of specifying a playlist to add the item to. 142 outcicle.putString("selectedalbum", mCurrentAlbumId); 143 outcicle.putString("artist", mArtistId); 144 super.onSaveInstanceState(outcicle); 145 } 146 147 @Override 148 public void onDestroy() { 149 MusicUtils.unbindFromService(this); 150 // If we have an adapter and didn't send it off to another activity yet, we should 151 // close its cursor, which we do by assigning a null cursor to it. Doing this 152 // instead of closing the cursor directly keeps the framework from accessing 153 // the closed cursor later. 154 if (!mAdapterSent && mAdapter != null) { 155 mAdapter.changeCursor(null); 156 } 157 // Because we pass the adapter to the next activity, we need to make 158 // sure it doesn't keep a reference to this activity. We can do this 159 // by clearing its DatasetObservers, which setListAdapter(null) does. 160 setListAdapter(null); 161 mAdapter = null; 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 getListView().invalidateViews(); 182 } 183 }; 184 private BroadcastReceiver mScanListener = new BroadcastReceiver() { 185 @Override 186 public void onReceive(Context context, Intent intent) { 187 MusicUtils.setSpinnerState(AlbumBrowserActivity.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 if (mAdapter != null) { 199 getAlbumCursor(mAdapter.getQueryHandler(), null); 200 } 201 } 202 }; 203 204 @Override 205 public void onPause() { 206 unregisterReceiver(mTrackListListener); 207 mReScanHandler.removeCallbacksAndMessages(null); 208 super.onPause(); 209 } 210 211 public void init(Cursor c) { 212 213 if (mAdapter == null) { 214 return; 215 } 216 mAdapter.changeCursor(c); // also sets mAlbumCursor 217 218 if (mAlbumCursor == null) { 219 MusicUtils.displayDatabaseError(this); 220 closeContextMenu(); 221 mReScanHandler.sendEmptyMessageDelayed(0, 1000); 222 return; 223 } 224 225 MusicUtils.hideDatabaseError(this); 226 setTitle(); 227 } 228 229 private void setTitle() { 230 CharSequence fancyName = ""; 231 if (mAlbumCursor != null && mAlbumCursor.getCount() > 0) { 232 mAlbumCursor.moveToFirst(); 233 fancyName = mAlbumCursor.getString( 234 mAlbumCursor.getColumnIndex(MediaStore.Audio.Albums.ARTIST)); 235 if (fancyName == null || fancyName.equals(MediaFile.UNKNOWN_STRING)) 236 fancyName = getText(R.string.unknown_artist_name); 237 } 238 239 if (mArtistId != null && fancyName != null) 240 setTitle(fancyName); 241 else 242 setTitle(R.string.albums_title); 243 } 244 245 @Override 246 public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfoIn) { 247 menu.add(0, PLAY_SELECTION, 0, R.string.play_selection); 248 SubMenu sub = menu.addSubMenu(0, ADD_TO_PLAYLIST, 0, R.string.add_to_playlist); 249 MusicUtils.makePlaylistMenu(this, sub); 250 menu.add(0, DELETE_ITEM, 0, R.string.delete_item); 251 252 AdapterContextMenuInfo mi = (AdapterContextMenuInfo) menuInfoIn; 253 mAlbumCursor.moveToPosition(mi.position); 254 mCurrentAlbumId = mAlbumCursor.getString(mAlbumCursor.getColumnIndexOrThrow(MediaStore.Audio.Albums._ID)); 255 mCurrentAlbumName = mAlbumCursor.getString(mAlbumCursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM)); 256 mCurrentArtistNameForAlbum = mAlbumCursor.getString( 257 mAlbumCursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ARTIST)); 258 mIsUnknownArtist = mCurrentArtistNameForAlbum == null || 259 mCurrentArtistNameForAlbum.equals(MediaFile.UNKNOWN_STRING); 260 mIsUnknownAlbum = mCurrentAlbumName == null || 261 mCurrentAlbumName.equals(MediaFile.UNKNOWN_STRING); 262 if (mIsUnknownAlbum) { 263 menu.setHeaderTitle(getString(R.string.unknown_album_name)); 264 } else { 265 menu.setHeaderTitle(mCurrentAlbumName); 266 } 267 if (!mIsUnknownAlbum || !mIsUnknownArtist) { 268 menu.add(0, SEARCH, 0, R.string.search_title); 269 } 270 } 271 272 @Override 273 public boolean onContextItemSelected(MenuItem item) { 274 switch (item.getItemId()) { 275 case PLAY_SELECTION: { 276 // play the selected album 277 long [] list = MusicUtils.getSongListForAlbum(this, Long.parseLong(mCurrentAlbumId)); 278 MusicUtils.playAll(this, list, 0); 279 return true; 280 } 281 282 case QUEUE: { 283 long [] list = MusicUtils.getSongListForAlbum(this, Long.parseLong(mCurrentAlbumId)); 284 MusicUtils.addToCurrentPlaylist(this, list); 285 return true; 286 } 287 288 case NEW_PLAYLIST: { 289 Intent intent = new Intent(); 290 intent.setClass(this, CreatePlaylist.class); 291 startActivityForResult(intent, NEW_PLAYLIST); 292 return true; 293 } 294 295 case PLAYLIST_SELECTED: { 296 long [] list = MusicUtils.getSongListForAlbum(this, Long.parseLong(mCurrentAlbumId)); 297 long playlist = item.getIntent().getLongExtra("playlist", 0); 298 MusicUtils.addToPlaylist(this, list, playlist); 299 return true; 300 } 301 case DELETE_ITEM: { 302 long [] list = MusicUtils.getSongListForAlbum(this, Long.parseLong(mCurrentAlbumId)); 303 String f = getString(R.string.delete_album_desc); 304 String desc = String.format(f, mCurrentAlbumName); 305 Bundle b = new Bundle(); 306 b.putString("description", desc); 307 b.putLongArray("items", list); 308 Intent intent = new Intent(); 309 intent.setClass(this, DeleteItems.class); 310 intent.putExtras(b); 311 startActivityForResult(intent, -1); 312 return true; 313 } 314 case SEARCH: 315 doSearch(); 316 return true; 317 318 } 319 return super.onContextItemSelected(item); 320 } 321 322 void doSearch() { 323 CharSequence title = null; 324 String query = ""; 325 326 Intent i = new Intent(); 327 i.setAction(MediaStore.INTENT_ACTION_MEDIA_SEARCH); 328 i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 329 330 title = ""; 331 if (!mIsUnknownAlbum) { 332 query = mCurrentAlbumName; 333 i.putExtra(MediaStore.EXTRA_MEDIA_ALBUM, mCurrentAlbumName); 334 title = mCurrentAlbumName; 335 } 336 if(!mIsUnknownArtist) { 337 query = query + " " + mCurrentArtistNameForAlbum; 338 i.putExtra(MediaStore.EXTRA_MEDIA_ARTIST, mCurrentArtistNameForAlbum); 339 title = title + " " + mCurrentArtistNameForAlbum; 340 } 341 // Since we hide the 'search' menu item when both album and artist are 342 // unknown, the query and title strings will have at least one of those. 343 i.putExtra(MediaStore.EXTRA_MEDIA_FOCUS, MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE); 344 title = getString(R.string.mediasearch, title); 345 i.putExtra(SearchManager.QUERY, query); 346 347 startActivity(Intent.createChooser(i, title)); 348 } 349 350 @Override 351 protected void onActivityResult(int requestCode, int resultCode, Intent intent) { 352 switch (requestCode) { 353 case SCAN_DONE: 354 if (resultCode == RESULT_CANCELED) { 355 finish(); 356 } else { 357 getAlbumCursor(mAdapter.getQueryHandler(), null); 358 } 359 break; 360 361 case NEW_PLAYLIST: 362 if (resultCode == RESULT_OK) { 363 Uri uri = intent.getData(); 364 if (uri != null) { 365 long [] list = MusicUtils.getSongListForAlbum(this, Long.parseLong(mCurrentAlbumId)); 366 MusicUtils.addToPlaylist(this, list, Long.parseLong(uri.getLastPathSegment())); 367 } 368 } 369 break; 370 } 371 } 372 373 @Override 374 protected void onListItemClick(ListView l, View v, int position, long id) 375 { 376 Intent intent = new Intent(Intent.ACTION_PICK); 377 intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track"); 378 intent.putExtra("album", Long.valueOf(id).toString()); 379 intent.putExtra("artist", mArtistId); 380 startActivity(intent); 381 } 382 383 @Override 384 public boolean onCreateOptionsMenu(Menu menu) { 385 super.onCreateOptionsMenu(menu); 386 menu.add(0, GOTO_START, 0, R.string.goto_start).setIcon(R.drawable.ic_menu_music_library); 387 menu.add(0, GOTO_PLAYBACK, 0, R.string.goto_playback).setIcon(R.drawable.ic_menu_playback); 388 menu.add(0, SHUFFLE_ALL, 0, R.string.shuffle_all).setIcon(R.drawable.ic_menu_shuffle); 389 return true; 390 } 391 392 @Override 393 public boolean onPrepareOptionsMenu(Menu menu) { 394 menu.findItem(GOTO_PLAYBACK).setVisible(MusicUtils.isMusicLoaded()); 395 return super.onPrepareOptionsMenu(menu); 396 } 397 398 @Override 399 public boolean onOptionsItemSelected(MenuItem item) { 400 Intent intent; 401 Cursor cursor; 402 switch (item.getItemId()) { 403 case GOTO_START: 404 intent = new Intent(); 405 intent.setClass(this, MusicBrowserActivity.class); 406 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 407 startActivity(intent); 408 return true; 409 410 case GOTO_PLAYBACK: 411 intent = new Intent("com.android.music.PLAYBACK_VIEWER"); 412 startActivity(intent); 413 return true; 414 415 case SHUFFLE_ALL: 416 cursor = MusicUtils.query(this, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, 417 new String [] { MediaStore.Audio.Media._ID}, 418 MediaStore.Audio.Media.IS_MUSIC + "=1", null, 419 MediaStore.Audio.Media.DEFAULT_SORT_ORDER); 420 if (cursor != null) { 421 MusicUtils.shuffleAll(this, cursor); 422 cursor.close(); 423 } 424 return true; 425 } 426 return super.onOptionsItemSelected(item); 427 } 428 429 private Cursor getAlbumCursor(AsyncQueryHandler async, String filter) { 430 StringBuilder where = new StringBuilder(); 431 where.append(MediaStore.Audio.Albums.ALBUM + " != ''"); 432 433 // Add in the filtering constraints 434 String [] keywords = null; 435 if (filter != null) { 436 String [] searchWords = filter.split(" "); 437 keywords = new String[searchWords.length]; 438 Collator col = Collator.getInstance(); 439 col.setStrength(Collator.PRIMARY); 440 for (int i = 0; i < searchWords.length; i++) { 441 keywords[i] = '%' + MediaStore.Audio.keyFor(searchWords[i]) + '%'; 442 } 443 for (int i = 0; i < searchWords.length; i++) { 444 where.append(" AND "); 445 where.append(MediaStore.Audio.Media.ARTIST_KEY + "||"); 446 where.append(MediaStore.Audio.Media.ALBUM_KEY + " LIKE ?"); 447 } 448 } 449 450 String whereclause = where.toString(); 451 452 String[] cols = new String[] { 453 MediaStore.Audio.Albums._ID, 454 MediaStore.Audio.Albums.ARTIST, 455 MediaStore.Audio.Albums.ALBUM, 456 MediaStore.Audio.Albums.ALBUM_ART 457 }; 458 Cursor ret = null; 459 if (mArtistId != null) { 460 if (async != null) { 461 async.startQuery(0, null, 462 MediaStore.Audio.Artists.Albums.getContentUri("external", 463 Long.valueOf(mArtistId)), 464 cols, whereclause, keywords, MediaStore.Audio.Albums.DEFAULT_SORT_ORDER); 465 } else { 466 ret = MusicUtils.query(this, 467 MediaStore.Audio.Artists.Albums.getContentUri("external", 468 Long.valueOf(mArtistId)), 469 cols, whereclause, keywords, MediaStore.Audio.Albums.DEFAULT_SORT_ORDER); 470 } 471 } else { 472 if (async != null) { 473 async.startQuery(0, null, 474 MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, 475 cols, whereclause, keywords, MediaStore.Audio.Albums.DEFAULT_SORT_ORDER); 476 } else { 477 ret = MusicUtils.query(this, MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, 478 cols, whereclause, keywords, MediaStore.Audio.Albums.DEFAULT_SORT_ORDER); 479 } 480 } 481 return ret; 482 } 483 484 static class AlbumListAdapter extends SimpleCursorAdapter implements SectionIndexer { 485 486 private final Drawable mNowPlayingOverlay; 487 private final BitmapDrawable mDefaultAlbumIcon; 488 private int mAlbumIdx; 489 private int mArtistIdx; 490 private int mAlbumArtIndex; 491 private final Resources mResources; 492 private final StringBuilder mStringBuilder = new StringBuilder(); 493 private final String mUnknownAlbum; 494 private final String mUnknownArtist; 495 private final String mAlbumSongSeparator; 496 private final Object[] mFormatArgs = new Object[1]; 497 private AlphabetIndexer mIndexer; 498 private AlbumBrowserActivity mActivity; 499 private AsyncQueryHandler mQueryHandler; 500 private String mConstraint = null; 501 private boolean mConstraintIsValid = false; 502 503 static class ViewHolder { 504 TextView line1; 505 TextView line2; 506 ImageView play_indicator; 507 ImageView icon; 508 } 509 510 class QueryHandler extends AsyncQueryHandler { 511 QueryHandler(ContentResolver res) { 512 super(res); 513 } 514 515 @Override 516 protected void onQueryComplete(int token, Object cookie, Cursor cursor) { 517 //Log.i("@@@", "query complete"); 518 mActivity.init(cursor); 519 } 520 } 521 522 AlbumListAdapter(Context context, AlbumBrowserActivity currentactivity, 523 int layout, Cursor cursor, String[] from, int[] to) { 524 super(context, layout, cursor, from, to); 525 526 mActivity = currentactivity; 527 mQueryHandler = new QueryHandler(context.getContentResolver()); 528 529 mUnknownAlbum = context.getString(R.string.unknown_album_name); 530 mUnknownArtist = context.getString(R.string.unknown_artist_name); 531 mAlbumSongSeparator = context.getString(R.string.albumsongseparator); 532 533 Resources r = context.getResources(); 534 mNowPlayingOverlay = r.getDrawable(R.drawable.indicator_ic_mp_playing_list); 535 536 Bitmap b = BitmapFactory.decodeResource(r, R.drawable.albumart_mp_unknown_list); 537 mDefaultAlbumIcon = new BitmapDrawable(context.getResources(), b); 538 // no filter or dither, it's a lot faster and we can't tell the difference 539 mDefaultAlbumIcon.setFilterBitmap(false); 540 mDefaultAlbumIcon.setDither(false); 541 getColumnIndices(cursor); 542 mResources = context.getResources(); 543 } 544 545 private void getColumnIndices(Cursor cursor) { 546 if (cursor != null) { 547 mAlbumIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM); 548 mArtistIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ARTIST); 549 mAlbumArtIndex = cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM_ART); 550 551 if (mIndexer != null) { 552 mIndexer.setCursor(cursor); 553 } else { 554 mIndexer = new MusicAlphabetIndexer(cursor, mAlbumIdx, mResources.getString( 555 com.android.internal.R.string.fast_scroll_alphabet)); 556 } 557 } 558 } 559 560 public void setActivity(AlbumBrowserActivity newactivity) { 561 mActivity = newactivity; 562 } 563 564 public AsyncQueryHandler getQueryHandler() { 565 return mQueryHandler; 566 } 567 568 @Override 569 public View newView(Context context, Cursor cursor, ViewGroup parent) { 570 View v = super.newView(context, cursor, parent); 571 ViewHolder vh = new ViewHolder(); 572 vh.line1 = (TextView) v.findViewById(R.id.line1); 573 vh.line2 = (TextView) v.findViewById(R.id.line2); 574 vh.play_indicator = (ImageView) v.findViewById(R.id.play_indicator); 575 vh.icon = (ImageView) v.findViewById(R.id.icon); 576 vh.icon.setBackgroundDrawable(mDefaultAlbumIcon); 577 vh.icon.setPadding(0, 0, 1, 0); 578 v.setTag(vh); 579 return v; 580 } 581 582 @Override 583 public void bindView(View view, Context context, Cursor cursor) { 584 585 ViewHolder vh = (ViewHolder) view.getTag(); 586 587 String name = cursor.getString(mAlbumIdx); 588 String displayname = name; 589 boolean unknown = name == null || name.equals(MediaFile.UNKNOWN_STRING); 590 if (unknown) { 591 displayname = mUnknownAlbum; 592 } 593 vh.line1.setText(displayname); 594 595 name = cursor.getString(mArtistIdx); 596 displayname = name; 597 if (name == null || name.equals(MediaFile.UNKNOWN_STRING)) { 598 displayname = mUnknownArtist; 599 } 600 vh.line2.setText(displayname); 601 602 ImageView iv = vh.icon; 603 // We don't actually need the path to the thumbnail file, 604 // we just use it to see if there is album art or not 605 String art = cursor.getString(mAlbumArtIndex); 606 long aid = cursor.getLong(0); 607 if (unknown || art == null || art.length() == 0) { 608 iv.setImageDrawable(null); 609 } else { 610 Drawable d = MusicUtils.getCachedArtwork(context, aid, mDefaultAlbumIcon); 611 iv.setImageDrawable(d); 612 } 613 614 long currentalbumid = MusicUtils.getCurrentAlbumId(); 615 iv = vh.play_indicator; 616 if (currentalbumid == aid) { 617 iv.setImageDrawable(mNowPlayingOverlay); 618 } else { 619 iv.setImageDrawable(null); 620 } 621 } 622 623 @Override 624 public void changeCursor(Cursor cursor) { 625 if (mActivity.isFinishing() && cursor != null) { 626 cursor.close(); 627 cursor = null; 628 } 629 if (cursor != mActivity.mAlbumCursor) { 630 mActivity.mAlbumCursor = cursor; 631 getColumnIndices(cursor); 632 super.changeCursor(cursor); 633 } 634 } 635 636 @Override 637 public Cursor runQueryOnBackgroundThread(CharSequence constraint) { 638 String s = constraint.toString(); 639 if (mConstraintIsValid && ( 640 (s == null && mConstraint == null) || 641 (s != null && s.equals(mConstraint)))) { 642 return getCursor(); 643 } 644 Cursor c = mActivity.getAlbumCursor(null, s); 645 mConstraint = s; 646 mConstraintIsValid = true; 647 return c; 648 } 649 650 public Object[] getSections() { 651 return mIndexer.getSections(); 652 } 653 654 public int getPositionForSection(int section) { 655 return mIndexer.getPositionForSection(section); 656 } 657 658 public int getSectionForPosition(int position) { 659 return 0; 660 } 661 } 662 663 private Cursor mAlbumCursor; 664 private String mArtistId; 665} 666 667