OSDN Git Service

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