AlbumBrowserActivity.java revision f4d4b342061ade12eb7903f454df62814179906f
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.ComponentName;
24import android.content.ContentResolver;
25import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.content.ServiceConnection;
29import android.content.res.Resources;
30import android.database.Cursor;
31import android.graphics.Bitmap;
32import android.graphics.BitmapFactory;
33import android.graphics.drawable.BitmapDrawable;
34import android.graphics.drawable.Drawable;
35import android.media.AudioManager;
36import android.net.Uri;
37import android.os.Bundle;
38import android.os.Handler;
39import android.os.IBinder;
40import android.os.Message;
41import android.provider.MediaStore;
42import android.util.Log;
43import android.view.ContextMenu;
44import android.view.Menu;
45import android.view.MenuItem;
46import android.view.SubMenu;
47import android.view.View;
48import android.view.ViewGroup;
49import android.view.Window;
50import android.view.ContextMenu.ContextMenuInfo;
51import android.widget.Adapter;
52import android.widget.AlphabetIndexer;
53import android.widget.CursorAdapter;
54import android.widget.ExpandableListView;
55import android.widget.ImageView;
56import android.widget.ListAdapter;
57import android.widget.ListView;
58import android.widget.SectionIndexer;
59import android.widget.SimpleCursorAdapter;
60import android.widget.TextView;
61import android.widget.AdapterView.AdapterContextMenuInfo;
62
63import java.text.Collator;
64
65public 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                            com.android.internal.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
688