• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PlaylistBrowserActivity()79     public PlaylistBrowserActivity()
80     {
81     }
82 
83     /** Called when the activity is first created. */
84     @Override
onCreate(Bundle icicle)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
onRetainNonConfigurationInstance()179     public Object onRetainNonConfigurationInstance() {
180         PlaylistListAdapter a = mAdapter;
181         mAdapterSent = true;
182         return a;
183     }
184 
185     @Override
onDestroy()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
onResume()213     public void onResume() {
214         super.onResume();
215 
216         MusicUtils.setSpinnerState(this);
217         MusicUtils.updateNowPlaying(PlaylistBrowserActivity.this);
218     }
219     @Override
onPause()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     };
init(Cursor cursor)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 
setTitle()264     private void setTitle() {
265         setTitle(R.string.playlists_title);
266     }
267 
268     @Override
onCreateOptionsMenu(Menu menu)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
onPrepareOptionsMenu(Menu menu)277     public boolean onPrepareOptionsMenu(Menu menu) {
278         MusicUtils.setPartyShuffleMenuIcon(menu);
279         return super.onPrepareOptionsMenu(menu);
280     }
281 
282     @Override
onOptionsItemSelected(MenuItem item)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 
onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfoIn)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
onContextItemSelected(MenuItem item)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
onActivityResult(int requestCode, int resultCode, Intent intent)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
onListItemClick(ListView l, View v, int position, long id)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 
playRecentlyAdded()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 
playPodcasts()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 
getPlaylistCursor(AsyncQueryHandler async, String filterstring)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 
mergedCursor(Cursor c)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 {
QueryHandler(ContentResolver res)553             QueryHandler(ContentResolver res) {
554                 super(res);
555             }
556 
557             @Override
onQueryComplete(int token, Object cookie, Cursor cursor)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 
PlaylistListAdapter(Context context, PlaylistBrowserActivity currentactivity, int layout, Cursor cursor, String[] from, int[] to)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         }
getColumnIndices(Cursor cursor)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 
setActivity(PlaylistBrowserActivity newactivity)581         public void setActivity(PlaylistBrowserActivity newactivity) {
582             mActivity = newactivity;
583         }
584 
getQueryHandler()585         public AsyncQueryHandler getQueryHandler() {
586             return mQueryHandler;
587         }
588 
589         @Override
bindView(View view, Context context, Cursor cursor)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
changeCursor(Cursor cursor)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
runQueryOnBackgroundThread(CharSequence constraint)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