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