Home | History | Annotate | Download | only in music
      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 com.android.music.MusicUtils.ServiceToken;
     20 
     21 import android.app.ListActivity;
     22 import android.content.AsyncQueryHandler;
     23 import android.content.BroadcastReceiver;
     24 import android.content.ComponentName;
     25 import android.content.ContentResolver;
     26 import android.content.ContentUris;
     27 import android.content.Context;
     28 import android.content.Intent;
     29 import android.content.IntentFilter;
     30 import android.content.ServiceConnection;
     31 import android.database.Cursor;
     32 import android.database.MatrixCursor;
     33 import android.database.MergeCursor;
     34 import android.database.sqlite.SQLiteException;
     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.View;
     47 import android.view.ViewGroup;
     48 import android.view.Window;
     49 import android.view.ContextMenu.ContextMenuInfo;
     50 import android.widget.ImageView;
     51 import android.widget.ListView;
     52 import android.widget.SimpleCursorAdapter;
     53 import android.widget.TextView;
     54 import android.widget.Toast;
     55 import android.widget.AdapterView.AdapterContextMenuInfo;
     56 
     57 import java.text.Collator;
     58 import java.util.ArrayList;
     59 
     60 public class PlaylistBrowserActivity extends ListActivity
     61     implements View.OnCreateContextMenuListener, MusicUtils.Defs
     62 {
     63     private static final String TAG = "PlaylistBrowserActivity";
     64     private static final int DELETE_PLAYLIST = CHILD_MENU_BASE + 1;
     65     private static final int EDIT_PLAYLIST = CHILD_MENU_BASE + 2;
     66     private static final int RENAME_PLAYLIST = CHILD_MENU_BASE + 3;
     67     private static final int CHANGE_WEEKS = CHILD_MENU_BASE + 4;
     68     private static final long RECENTLY_ADDED_PLAYLIST = -1;
     69     private static final long ALL_SONGS_PLAYLIST = -2;
     70     private static final long PODCASTS_PLAYLIST = -3;
     71     private PlaylistListAdapter mAdapter;
     72     boolean mAdapterSent;
     73     private static int mLastListPosCourse = -1;
     74     private static int mLastListPosFine = -1;
     75 
     76     private boolean mCreateShortcut;
     77     private ServiceToken mToken;
     78 
     79     public PlaylistBrowserActivity()
     80     {
     81     }
     82 
     83     /** Called when the activity is first created. */
     84     @Override
     85     public void onCreate(Bundle icicle)
     86     {
     87         super.onCreate(icicle);
     88 
     89         final Intent intent = getIntent();
     90         final String action = intent.getAction();
     91         if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) {
     92             mCreateShortcut = true;
     93         }
     94 
     95         requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
     96         requestWindowFeature(Window.FEATURE_NO_TITLE);
     97         setVolumeControlStream(AudioManager.STREAM_MUSIC);
     98         mToken = MusicUtils.bindToService(this, new ServiceConnection() {
     99             public void onServiceConnected(ComponentName classname, IBinder obj) {
    100                 if (Intent.ACTION_VIEW.equals(action)) {
    101                     Bundle b = intent.getExtras();
    102                     if (b == null) {
    103                         Log.w(TAG, "Unexpected:getExtras() returns null.");
    104                     } else {
    105                         try {
    106                             long id = Long.parseLong(b.getString("playlist"));
    107                             if (id == RECENTLY_ADDED_PLAYLIST) {
    108                                 playRecentlyAdded();
    109                             } else if (id == PODCASTS_PLAYLIST) {
    110                                 playPodcasts();
    111                             } else if (id == ALL_SONGS_PLAYLIST) {
    112                                 long[] list = MusicUtils.getAllSongs(PlaylistBrowserActivity.this);
    113                                 if (list != null) {
    114                                     MusicUtils.playAll(PlaylistBrowserActivity.this, list, 0);
    115                                 }
    116                             } else {
    117                                 MusicUtils.playPlaylist(PlaylistBrowserActivity.this, id);
    118                             }
    119                         } catch (NumberFormatException e) {
    120                             Log.w(TAG, "Playlist id missing or broken");
    121                         }
    122                     }
    123                     finish();
    124                     return;
    125                 }
    126                 MusicUtils.updateNowPlaying(PlaylistBrowserActivity.this);
    127             }
    128 
    129             public void onServiceDisconnected(ComponentName classname) {
    130             }
    131 
    132         });
    133         IntentFilter f = new IntentFilter();
    134         f.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
    135         f.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
    136         f.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
    137         f.addDataScheme("file");
    138         registerReceiver(mScanListener, f);
    139 
    140         setContentView(R.layout.media_picker_activity);
    141         MusicUtils.updateButtonBar(this, R.id.playlisttab);
    142         ListView lv = getListView();
    143         lv.setOnCreateContextMenuListener(this);
    144         lv.setTextFilterEnabled(true);
    145 
    146         mAdapter = (PlaylistListAdapter) getLastNonConfigurationInstance();
    147         if (mAdapter == null) {
    148             //Log.i("@@@", "starting query");
    149             mAdapter = new PlaylistListAdapter(
    150                     getApplication(),
    151                     this,
    152                     R.layout.track_list_item,
    153                     mPlaylistCursor,
    154                     new String[] { MediaStore.Audio.Playlists.NAME},
    155                     new int[] { android.R.id.text1 });
    156             setListAdapter(mAdapter);
    157             setTitle(R.string.working_playlists);
    158             getPlaylistCursor(mAdapter.getQueryHandler(), null);
    159         } else {
    160             mAdapter.setActivity(this);
    161             setListAdapter(mAdapter);
    162             mPlaylistCursor = mAdapter.getCursor();
    163             // If mPlaylistCursor is null, this can be because it doesn't have
    164             // a cursor yet (because the initial query that sets its cursor
    165             // is still in progress), or because the query failed.
    166             // In order to not flash the error dialog at the user for the
    167             // first case, simply retry the query when the cursor is null.
    168             // Worst case, we end up doing the same query twice.
    169             if (mPlaylistCursor != null) {
    170                 init(mPlaylistCursor);
    171             } else {
    172                 setTitle(R.string.working_playlists);
    173                 getPlaylistCursor(mAdapter.getQueryHandler(), null);
    174             }
    175         }
    176     }
    177 
    178     @Override
    179     public Object onRetainNonConfigurationInstance() {
    180         PlaylistListAdapter a = mAdapter;
    181         mAdapterSent = true;
    182         return a;
    183     }
    184 
    185     @Override
    186     public void onDestroy() {
    187         ListView lv = getListView();
    188         if (lv != null) {
    189             mLastListPosCourse = lv.getFirstVisiblePosition();
    190             View cv = lv.getChildAt(0);
    191             if (cv != null) {
    192                 mLastListPosFine = cv.getTop();
    193             }
    194         }
    195         MusicUtils.unbindFromService(mToken);
    196         // If we have an adapter and didn't send it off to another activity yet, we should
    197         // close its cursor, which we do by assigning a null cursor to it. Doing this
    198         // instead of closing the cursor directly keeps the framework from accessing
    199         // the closed cursor later.
    200         if (!mAdapterSent && mAdapter != null) {
    201             mAdapter.changeCursor(null);
    202         }
    203         // Because we pass the adapter to the next activity, we need to make
    204         // sure it doesn't keep a reference to this activity. We can do this
    205         // by clearing its DatasetObservers, which setListAdapter(null) does.
    206         setListAdapter(null);
    207         mAdapter = null;
    208         unregisterReceiver(mScanListener);
    209         super.onDestroy();
    210     }
    211 
    212     @Override
    213     public void onResume() {
    214         super.onResume();
    215 
    216         MusicUtils.setSpinnerState(this);
    217         MusicUtils.updateNowPlaying(PlaylistBrowserActivity.this);
    218     }
    219     @Override
    220     public void onPause() {
    221         mReScanHandler.removeCallbacksAndMessages(null);
    222         super.onPause();
    223     }
    224     private BroadcastReceiver mScanListener = new BroadcastReceiver() {
    225         @Override
    226         public void onReceive(Context context, Intent intent) {
    227             MusicUtils.setSpinnerState(PlaylistBrowserActivity.this);
    228             mReScanHandler.sendEmptyMessage(0);
    229         }
    230     };
    231 
    232     private Handler mReScanHandler = new Handler() {
    233         @Override
    234         public void handleMessage(Message msg) {
    235             if (mAdapter != null) {
    236                 getPlaylistCursor(mAdapter.getQueryHandler(), null);
    237             }
    238         }
    239     };
    240     public void init(Cursor cursor) {
    241 
    242         if (mAdapter == null) {
    243             return;
    244         }
    245         mAdapter.changeCursor(cursor);
    246 
    247         if (mPlaylistCursor == null) {
    248             MusicUtils.displayDatabaseError(this);
    249             closeContextMenu();
    250             mReScanHandler.sendEmptyMessageDelayed(0, 1000);
    251             return;
    252         }
    253 
    254         // restore previous position
    255         if (mLastListPosCourse >= 0) {
    256             getListView().setSelectionFromTop(mLastListPosCourse, mLastListPosFine);
    257             mLastListPosCourse = -1;
    258         }
    259         MusicUtils.hideDatabaseError(this);
    260         MusicUtils.updateButtonBar(this, R.id.playlisttab);
    261         setTitle();
    262     }
    263 
    264     private void setTitle() {
    265         setTitle(R.string.playlists_title);
    266     }
    267 
    268     @Override
    269     public boolean onCreateOptionsMenu(Menu menu) {
    270         if (!mCreateShortcut) {
    271             menu.add(0, PARTY_SHUFFLE, 0, R.string.party_shuffle); // icon will be set in onPrepareOptionsMenu()
    272         }
    273         return super.onCreateOptionsMenu(menu);
    274     }
    275 
    276     @Override
    277     public boolean onPrepareOptionsMenu(Menu menu) {
    278         MusicUtils.setPartyShuffleMenuIcon(menu);
    279         return super.onPrepareOptionsMenu(menu);
    280     }
    281 
    282     @Override
    283     public boolean onOptionsItemSelected(MenuItem item) {
    284         Intent intent;
    285         switch (item.getItemId()) {
    286             case PARTY_SHUFFLE:
    287                 MusicUtils.togglePartyShuffle();
    288                 break;
    289         }
    290         return super.onOptionsItemSelected(item);
    291     }
    292 
    293     public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfoIn) {
    294         if (mCreateShortcut) {
    295             return;
    296         }
    297 
    298         AdapterContextMenuInfo mi = (AdapterContextMenuInfo) menuInfoIn;
    299 
    300         menu.add(0, PLAY_SELECTION, 0, R.string.play_selection);
    301 
    302         if (mi.id >= 0 /*|| mi.id == PODCASTS_PLAYLIST*/) {
    303             menu.add(0, DELETE_PLAYLIST, 0, R.string.delete_playlist_menu);
    304         }
    305 
    306         if (mi.id == RECENTLY_ADDED_PLAYLIST) {
    307             menu.add(0, EDIT_PLAYLIST, 0, R.string.edit_playlist_menu);
    308         }
    309 
    310         if (mi.id >= 0) {
    311             menu.add(0, RENAME_PLAYLIST, 0, R.string.rename_playlist_menu);
    312         }
    313 
    314         mPlaylistCursor.moveToPosition(mi.position);
    315         menu.setHeaderTitle(mPlaylistCursor.getString(mPlaylistCursor.getColumnIndexOrThrow(
    316                 MediaStore.Audio.Playlists.NAME)));
    317     }
    318 
    319     @Override
    320     public boolean onContextItemSelected(MenuItem item) {
    321         AdapterContextMenuInfo mi = (AdapterContextMenuInfo) item.getMenuInfo();
    322         switch (item.getItemId()) {
    323             case PLAY_SELECTION:
    324                 if (mi.id == RECENTLY_ADDED_PLAYLIST) {
    325                     playRecentlyAdded();
    326                 } else if (mi.id == PODCASTS_PLAYLIST) {
    327                     playPodcasts();
    328                 } else {
    329                     MusicUtils.playPlaylist(this, mi.id);
    330                 }
    331                 break;
    332             case DELETE_PLAYLIST:
    333                 Uri uri = ContentUris.withAppendedId(
    334                         MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, mi.id);
    335                 getContentResolver().delete(uri, null, null);
    336                 Toast.makeText(this, R.string.playlist_deleted_message, Toast.LENGTH_SHORT).show();
    337                 if (mPlaylistCursor.getCount() == 0) {
    338                     setTitle(R.string.no_playlists_title);
    339                 }
    340                 break;
    341             case EDIT_PLAYLIST:
    342                 if (mi.id == RECENTLY_ADDED_PLAYLIST) {
    343                     Intent intent = new Intent();
    344                     intent.setClass(this, WeekSelector.class);
    345                     startActivityForResult(intent, CHANGE_WEEKS);
    346                     return true;
    347                 } else {
    348                     Log.e(TAG, "should not be here");
    349                 }
    350                 break;
    351             case RENAME_PLAYLIST:
    352                 Intent intent = new Intent();
    353                 intent.setClass(this, RenamePlaylist.class);
    354                 intent.putExtra("rename", mi.id);
    355                 startActivityForResult(intent, RENAME_PLAYLIST);
    356                 break;
    357         }
    358         return true;
    359     }
    360 
    361     @Override
    362     protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    363         switch (requestCode) {
    364             case SCAN_DONE:
    365                 if (resultCode == RESULT_CANCELED) {
    366                     finish();
    367                 } else if (mAdapter != null) {
    368                     getPlaylistCursor(mAdapter.getQueryHandler(), null);
    369                 }
    370                 break;
    371         }
    372     }
    373 
    374     @Override
    375     protected void onListItemClick(ListView l, View v, int position, long id)
    376     {
    377         if (mCreateShortcut) {
    378             final Intent shortcut = new Intent();
    379             shortcut.setAction(Intent.ACTION_VIEW);
    380             shortcut.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/playlist");
    381             shortcut.putExtra("playlist", String.valueOf(id));
    382 
    383             final Intent intent = new Intent();
    384             intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcut);
    385             intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, ((TextView) v.findViewById(R.id.line1)).getText());
    386             intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext(
    387                     this, R.drawable.ic_launcher_shortcut_music_playlist));
    388 
    389             setResult(RESULT_OK, intent);
    390             finish();
    391             return;
    392         }
    393         if (id == RECENTLY_ADDED_PLAYLIST) {
    394             Intent intent = new Intent(Intent.ACTION_PICK);
    395             intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track");
    396             intent.putExtra("playlist", "recentlyadded");
    397             startActivity(intent);
    398         } else if (id == PODCASTS_PLAYLIST) {
    399             Intent intent = new Intent(Intent.ACTION_PICK);
    400             intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track");
    401             intent.putExtra("playlist", "podcasts");
    402             startActivity(intent);
    403         } else {
    404             Intent intent = new Intent(Intent.ACTION_EDIT);
    405             intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track");
    406             intent.putExtra("playlist", Long.valueOf(id).toString());
    407             startActivity(intent);
    408         }
    409     }
    410 
    411     private void playRecentlyAdded() {
    412         // do a query for all songs added in the last X weeks
    413         int X = MusicUtils.getIntPref(this, "numweeks", 2) * (3600 * 24 * 7);
    414         final String[] ccols = new String[] { MediaStore.Audio.Media._ID};
    415         String where = MediaStore.MediaColumns.DATE_ADDED + ">" + (System.currentTimeMillis() / 1000 - X);
    416         Cursor cursor = MusicUtils.query(this, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
    417                 ccols, where, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
    418 
    419         if (cursor == null) {
    420             // Todo: show a message
    421             return;
    422         }
    423         try {
    424             int len = cursor.getCount();
    425             long [] list = new long[len];
    426             for (int i = 0; i < len; i++) {
    427                 cursor.moveToNext();
    428                 list[i] = cursor.getLong(0);
    429             }
    430             MusicUtils.playAll(this, list, 0);
    431         } catch (SQLiteException ex) {
    432         } finally {
    433             cursor.close();
    434         }
    435     }
    436 
    437     private void playPodcasts() {
    438         // do a query for all files that are podcasts
    439         final String[] ccols = new String[] { MediaStore.Audio.Media._ID};
    440         Cursor cursor = MusicUtils.query(this, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
    441                 ccols, MediaStore.Audio.Media.IS_PODCAST + "=1",
    442                 null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
    443 
    444         if (cursor == null) {
    445             // Todo: show a message
    446             return;
    447         }
    448         try {
    449             int len = cursor.getCount();
    450             long [] list = new long[len];
    451             for (int i = 0; i < len; i++) {
    452                 cursor.moveToNext();
    453                 list[i] = cursor.getLong(0);
    454             }
    455             MusicUtils.playAll(this, list, 0);
    456         } catch (SQLiteException ex) {
    457         } finally {
    458             cursor.close();
    459         }
    460     }
    461 
    462 
    463     String[] mCols = new String[] {
    464             MediaStore.Audio.Playlists._ID,
    465             MediaStore.Audio.Playlists.NAME
    466     };
    467 
    468     private Cursor getPlaylistCursor(AsyncQueryHandler async, String filterstring) {
    469 
    470         StringBuilder where = new StringBuilder();
    471         where.append(MediaStore.Audio.Playlists.NAME + " != ''");
    472 
    473         // Add in the filtering constraints
    474         String [] keywords = null;
    475         if (filterstring != null) {
    476             String [] searchWords = filterstring.split(" ");
    477             keywords = new String[searchWords.length];
    478             Collator col = Collator.getInstance();
    479             col.setStrength(Collator.PRIMARY);
    480             for (int i = 0; i < searchWords.length; i++) {
    481                 keywords[i] = '%' + searchWords[i] + '%';
    482             }
    483             for (int i = 0; i < searchWords.length; i++) {
    484                 where.append(" AND ");
    485                 where.append(MediaStore.Audio.Playlists.NAME + " LIKE ?");
    486             }
    487         }
    488 
    489         String whereclause = where.toString();
    490 
    491 
    492         if (async != null) {
    493             async.startQuery(0, null, MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
    494                     mCols, whereclause, keywords, MediaStore.Audio.Playlists.NAME);
    495             return null;
    496         }
    497         Cursor c = null;
    498         c = MusicUtils.query(this, MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
    499                 mCols, whereclause, keywords, MediaStore.Audio.Playlists.NAME);
    500 
    501         return mergedCursor(c);
    502     }
    503 
    504     private Cursor mergedCursor(Cursor c) {
    505         if (c == null) {
    506             return null;
    507         }
    508         if (c instanceof MergeCursor) {
    509             // this shouldn't happen, but fail gracefully
    510             Log.d("PlaylistBrowserActivity", "Already wrapped");
    511             return c;
    512         }
    513         MatrixCursor autoplaylistscursor = new MatrixCursor(mCols);
    514         if (mCreateShortcut) {
    515             ArrayList<Object> all = new ArrayList<Object>(2);
    516             all.add(ALL_SONGS_PLAYLIST);
    517             all.add(getString(R.string.play_all));
    518             autoplaylistscursor.addRow(all);
    519         }
    520         ArrayList<Object> recent = new ArrayList<Object>(2);
    521         recent.add(RECENTLY_ADDED_PLAYLIST);
    522         recent.add(getString(R.string.recentlyadded));
    523         autoplaylistscursor.addRow(recent);
    524 
    525         // check if there are any podcasts
    526         Cursor counter = MusicUtils.query(this, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
    527                 new String[] {"count(*)"}, "is_podcast=1", null, null);
    528         if (counter != null) {
    529             counter.moveToFirst();
    530             int numpodcasts = counter.getInt(0);
    531             counter.close();
    532             if (numpodcasts > 0) {
    533                 ArrayList<Object> podcasts = new ArrayList<Object>(2);
    534                 podcasts.add(PODCASTS_PLAYLIST);
    535                 podcasts.add(getString(R.string.podcasts_listitem));
    536                 autoplaylistscursor.addRow(podcasts);
    537             }
    538         }
    539 
    540         Cursor cc = new MergeCursor(new Cursor [] {autoplaylistscursor, c});
    541         return cc;
    542     }
    543 
    544     static class PlaylistListAdapter extends SimpleCursorAdapter {
    545         int mTitleIdx;
    546         int mIdIdx;
    547         private PlaylistBrowserActivity mActivity = null;
    548         private AsyncQueryHandler mQueryHandler;
    549         private String mConstraint = null;
    550         private boolean mConstraintIsValid = false;
    551 
    552         class QueryHandler extends AsyncQueryHandler {
    553             QueryHandler(ContentResolver res) {
    554                 super(res);
    555             }
    556 
    557             @Override
    558             protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
    559                 //Log.i("@@@", "query complete: " + cursor.getCount() + "   " + mActivity);
    560                 if (cursor != null) {
    561                     cursor = mActivity.mergedCursor(cursor);
    562                 }
    563                 mActivity.init(cursor);
    564             }
    565         }
    566 
    567         PlaylistListAdapter(Context context, PlaylistBrowserActivity currentactivity,
    568                 int layout, Cursor cursor, String[] from, int[] to) {
    569             super(context, layout, cursor, from, to);
    570             mActivity = currentactivity;
    571             getColumnIndices(cursor);
    572             mQueryHandler = new QueryHandler(context.getContentResolver());
    573         }
    574         private void getColumnIndices(Cursor cursor) {
    575             if (cursor != null) {
    576                 mTitleIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists.NAME);
    577                 mIdIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists._ID);
    578             }
    579         }
    580 
    581         public void setActivity(PlaylistBrowserActivity newactivity) {
    582             mActivity = newactivity;
    583         }
    584 
    585         public AsyncQueryHandler getQueryHandler() {
    586             return mQueryHandler;
    587         }
    588 
    589         @Override
    590         public void bindView(View view, Context context, Cursor cursor) {
    591 
    592             TextView tv = (TextView) view.findViewById(R.id.line1);
    593 
    594             String name = cursor.getString(mTitleIdx);
    595             tv.setText(name);
    596 
    597             long id = cursor.getLong(mIdIdx);
    598 
    599             ImageView iv = (ImageView) view.findViewById(R.id.icon);
    600             if (id == RECENTLY_ADDED_PLAYLIST) {
    601                 iv.setImageResource(R.drawable.ic_mp_playlist_recently_added_list);
    602             } else {
    603                 iv.setImageResource(R.drawable.ic_mp_playlist_list);
    604             }
    605             ViewGroup.LayoutParams p = iv.getLayoutParams();
    606             p.width = ViewGroup.LayoutParams.WRAP_CONTENT;
    607             p.height = ViewGroup.LayoutParams.WRAP_CONTENT;
    608 
    609             iv = (ImageView) view.findViewById(R.id.play_indicator);
    610             iv.setVisibility(View.GONE);
    611 
    612             view.findViewById(R.id.line2).setVisibility(View.GONE);
    613         }
    614 
    615         @Override
    616         public void changeCursor(Cursor cursor) {
    617             if (mActivity.isFinishing() && cursor != null) {
    618                 cursor.close();
    619                 cursor = null;
    620             }
    621             if (cursor != mActivity.mPlaylistCursor) {
    622                 mActivity.mPlaylistCursor = cursor;
    623                 super.changeCursor(cursor);
    624                 getColumnIndices(cursor);
    625             }
    626         }
    627 
    628         @Override
    629         public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
    630             String s = constraint.toString();
    631             if (mConstraintIsValid && (
    632                     (s == null && mConstraint == null) ||
    633                     (s != null && s.equals(mConstraint)))) {
    634                 return getCursor();
    635             }
    636             Cursor c = mActivity.getPlaylistCursor(null, s);
    637             mConstraint = s;
    638             mConstraintIsValid = true;
    639             return c;
    640         }
    641     }
    642 
    643     private Cursor mPlaylistCursor;
    644 }
    645 
    646