• 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
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 
PlaylistBrowserActivity()78     public PlaylistBrowserActivity() {}
79 
80     /** Called when the activity is first created. */
81     @Override
onCreate(Bundle icicle)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
onRetainNonConfigurationInstance()170     public Object onRetainNonConfigurationInstance() {
171         PlaylistListAdapter a = mAdapter;
172         mAdapterSent = true;
173         return a;
174     }
175 
176     @Override
onDestroy()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
onResume()204     public void onResume() {
205         super.onResume();
206 
207         MusicUtils.setSpinnerState(this);
208         MusicUtils.updateNowPlaying(PlaylistBrowserActivity.this);
209     }
210     @Override
onPause()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     };
init(Cursor cursor)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 
setTitle()254     private void setTitle() {
255         setTitle(R.string.playlists_title);
256     }
257 
258     @Override
onCreateOptionsMenu(Menu menu)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
onPrepareOptionsMenu(Menu menu)268     public boolean onPrepareOptionsMenu(Menu menu) {
269         MusicUtils.setPartyShuffleMenuIcon(menu);
270         return super.onPrepareOptionsMenu(menu);
271     }
272 
273     @Override
onOptionsItemSelected(MenuItem item)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 
onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfoIn)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
onContextItemSelected(MenuItem item)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
onActivityResult(int requestCode, int resultCode, Intent intent)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
onListItemClick(ListView l, View v, int position, long id)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 
playRecentlyAdded()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 
playPodcasts()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 
getPlaylistCursor(AsyncQueryHandler async, String filterstring)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 
mergedCursor(Cursor c)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 {
QueryHandler(ContentResolver res)540             QueryHandler(ContentResolver res) {
541                 super(res);
542             }
543 
544             @Override
onQueryComplete(int token, Object cookie, Cursor cursor)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 
PlaylistListAdapter(Context context, PlaylistBrowserActivity currentactivity, int layout, Cursor cursor, String[] from, int[] to)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         }
getColumnIndices(Cursor cursor)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 
setActivity(PlaylistBrowserActivity newactivity)568         public void setActivity(PlaylistBrowserActivity newactivity) {
569             mActivity = newactivity;
570         }
571 
getQueryHandler()572         public AsyncQueryHandler getQueryHandler() {
573             return mQueryHandler;
574         }
575 
576         @Override
bindView(View view, Context context, Cursor cursor)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
changeCursor(Cursor cursor)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
runQueryOnBackgroundThread(CharSequence constraint)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