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