OSDN Git Service

theme engine fixes
[android-x86/packages-apps-Eleven.git] / src / com / android / music / TrackBrowserActivity.java
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 java.util.Arrays;
20
21 import android.app.ActionBar;
22 import android.app.ListActivity;
23 import android.app.SearchManager;
24 import android.content.AsyncQueryHandler;
25 import android.content.BroadcastReceiver;
26 import android.content.ComponentName;
27 import android.content.ContentResolver;
28 import android.content.ContentUris;
29 import android.content.ContentValues;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.IntentFilter;
33 import android.content.ServiceConnection;
34 import android.content.SharedPreferences;
35 import android.content.pm.PackageManager;
36 import android.content.pm.PackageManager.NameNotFoundException;
37 import android.content.res.Configuration;
38 import android.content.res.Resources;
39 import android.database.AbstractCursor;
40 import android.database.CharArrayBuffer;
41 import android.database.Cursor;
42 import android.database.sqlite.SQLiteException;
43 import android.graphics.Bitmap;
44 import android.graphics.drawable.AnimationDrawable;
45 import android.media.AudioManager;
46 import android.net.Uri;
47 import android.os.Bundle;
48 import android.os.Handler;
49 import android.os.IBinder;
50 import android.os.Message;
51 import android.os.RemoteException;
52 import android.provider.BaseColumns;
53 import android.provider.MediaStore;
54 import android.provider.MediaStore.Audio.AudioColumns;
55 import android.provider.MediaStore.Audio.Playlists;
56 import android.text.TextUtils;
57 import android.util.Log;
58 import android.view.ContextMenu;
59 import android.view.ContextMenu.ContextMenuInfo;
60 import android.view.GestureDetector;
61 import android.view.GestureDetector.SimpleOnGestureListener;
62 import android.view.KeyEvent;
63 import android.view.Menu;
64 import android.view.MenuItem;
65 import android.view.MotionEvent;
66 import android.view.SubMenu;
67 import android.view.View;
68 import android.view.ViewGroup;
69 import android.widget.AdapterView.AdapterContextMenuInfo;
70 import android.widget.AlphabetIndexer;
71 import android.widget.FrameLayout;
72 import android.widget.ImageButton;
73 import android.widget.ImageView;
74 import android.widget.LinearLayout;
75 import android.widget.ListView;
76 import android.widget.ProgressBar;
77 import android.widget.RelativeLayout;
78 import android.widget.SectionIndexer;
79 import android.widget.SimpleCursorAdapter;
80 import android.widget.TabWidget;
81 import android.widget.TextView;
82
83 import com.android.music.MusicUtils.ServiceToken;
84
85 public class TrackBrowserActivity extends ListActivity implements
86                 View.OnCreateContextMenuListener, MusicUtils.Defs, ServiceConnection {
87         private static final int Q_SELECTED = CHILD_MENU_BASE;
88         private static final int Q_ALL = CHILD_MENU_BASE + 1;
89         private static final int SAVE_AS_PLAYLIST = CHILD_MENU_BASE + 2;
90         private static final int PLAY_ALL = CHILD_MENU_BASE + 3;
91         private static final int CLEAR_PLAYLIST = CHILD_MENU_BASE + 4;
92         private static final int REMOVE = CHILD_MENU_BASE + 5;
93         private static final int SEARCH = CHILD_MENU_BASE + 6;
94
95         private static final String LOGTAG = "TrackBrowser";
96
97         private String[] mCursorCols;
98         private String[] mPlaylistMemberCols;
99         private boolean mDeletedOneRow = false;
100         private boolean mEditMode = false;
101         private String mCurrentTrackName;
102         private String mCurrentAlbumName;
103         private String mCurrentArtistNameForAlbum;
104         private ListView mTrackList;
105         private Cursor mTrackCursor;
106         private TrackListAdapter mAdapter;
107         private boolean mAdapterSent = false;
108         private String mAlbumId;
109         private String mArtistId;
110         private String mPlaylist;
111         private String mGenre;
112         private String mSortOrder;
113         private int mSelectedPosition;
114         private long mSelectedId;
115         private static int mLastListPosCourse = -1;
116         private static int mLastListPosFine = -1;
117         private boolean mUseLastListPos = false;
118         private ServiceToken mToken;
119         private ServiceToken mOSC;
120         private IMediaPlaybackService mService = null;
121         private SharedPreferences mPreferences;
122         // Artist tab layout
123         public LinearLayout mSongTab;
124         public TabWidget mButtonBar;
125         public TextView mButtonBarArtist;
126         public TextView mButtonBarAlbum;
127         public TextView mButtonBarSong;
128         public TextView mButtonBarPlaylist;
129         public TextView mButtonBarNP;
130         public RelativeLayout mGroup;
131         public RelativeLayout mChild;
132         // Smaller now playing window buttons
133         private LinearLayout mNowPlaying;
134         private ImageView mInfoDivider;
135         private ProgressBar mProgress;
136         private ImageButton mDoSearch;
137         private ImageButton mMarket;
138         private ImageButton mNext;
139         private ImageButton mPlay;
140         private ImageButton mPlusPlaylist;
141         private ImageButton mPrev;
142         private ImageButton mShare;
143         private ImageButton mFlow;
144         // Back button long press
145         public String back_button_db;
146         // Smaller now playing window swipe gesture
147         public GestureDetector gestureDetector;
148         private static final int SWIPE_MIN_DISTANCE = 120;
149         private static final int SWIPE_MAX_OFF_PATH = 250;
150         private static final int SWIPE_THRESHOLD_VELOCITY = 200;
151         private String np_swipe_gesture_db;
152         // Swipe tabs
153         private GestureDetector swipetabs;
154         // ADW Theme constants
155         public static final int THEME_ITEM_BACKGROUND = 0;
156         public static final int THEME_ITEM_FOREGROUND = 1;
157         public static final int THEME_ITEM_TEXT_DRAWABLE = 2;
158
159         public TrackBrowserActivity() {
160         }
161
162         /** Called when the activity is first created. */
163         @Override
164         public void onCreate(Bundle icicle) {
165                 super.onCreate(icicle);
166                 ActionBar bar = getActionBar();
167                 try {
168                         bar.setTitle(mService.getArtistName());
169                         bar.setBackgroundDrawable(getResources().getDrawable(
170                                         R.drawable.solid_dark_pressed));
171                 } catch (Exception e) {
172                         // TODO Auto-generated catch block
173                         e.printStackTrace();
174                 }
175                 bar.setDisplayHomeAsUpEnabled(true);
176
177                 mPreferences = getSharedPreferences(
178                                 MusicSettingsActivity.PREFERENCES_FILE, MODE_PRIVATE);
179                 Intent intent = getIntent();
180                 if (intent != null) {
181                         if (intent.getBooleanExtra("withtabs", false)) {
182                                 bar.hide();
183                         }
184                 }
185                 setVolumeControlStream(AudioManager.STREAM_MUSIC);
186                 if (icicle != null) {
187                         mSelectedId = icicle.getLong("selectedtrack");
188                         mAlbumId = icicle.getString("album");
189                         mArtistId = icicle.getString("artist");
190                         mPlaylist = icicle.getString("playlist");
191                         mGenre = icicle.getString("genre");
192                         mEditMode = icicle.getBoolean("editmode", false);
193                 } else {
194                         mAlbumId = intent.getStringExtra("album");
195                         // If we have an album, show everything on the album, not just stuff
196                         // by a particular artist.
197                         mArtistId = intent.getStringExtra("artist");
198                         mPlaylist = intent.getStringExtra("playlist");
199                         mGenre = intent.getStringExtra("genre");
200                         mEditMode = intent.getAction().equals(Intent.ACTION_EDIT);
201                 }
202
203                 mCursorCols = new String[] { MediaStore.Audio.Media._ID,
204                                 MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DATA,
205                                 MediaStore.Audio.Media.ALBUM, MediaStore.Audio.Media.ARTIST,
206                                 MediaStore.Audio.Media.ARTIST_ID,
207                                 MediaStore.Audio.Media.DURATION };
208                 mPlaylistMemberCols = new String[] {
209                                 MediaStore.Audio.Playlists.Members._ID,
210                                 MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DATA,
211                                 MediaStore.Audio.Media.ALBUM, MediaStore.Audio.Media.ARTIST,
212                                 MediaStore.Audio.Media.ARTIST_ID,
213                                 MediaStore.Audio.Media.DURATION,
214                                 MediaStore.Audio.Playlists.Members.PLAY_ORDER,
215                                 MediaStore.Audio.Playlists.Members.AUDIO_ID,
216                                 MediaStore.Audio.Media.IS_MUSIC };
217
218                 setContentView(R.layout.media_picker_activity);
219
220                 mToken = MusicUtils.bindToService(this, this);
221                 // We have to bind to osc to control the music, but we need to keep the
222                 // previous line to load the list view.
223                 mOSC = MusicUtils.bindToService(this, osc);
224
225                 mUseLastListPos = MusicUtils.updateButtonBar(this, R.id.songtab);
226                 mTrackList = getListView();
227                 mTrackList.setOnCreateContextMenuListener(this);
228                 mTrackList.setCacheColorHint(0);
229                 if (mEditMode) {
230                         LinearLayout nowPlaying = (LinearLayout) findViewById(R.id.nowplaying);
231                         if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
232                                 nowPlaying.setVisibility(View.GONE);
233                         }
234                         ((TouchInterceptor) mTrackList).setDropListener(mDropListener);
235                         ((TouchInterceptor) mTrackList).setRemoveListener(mRemoveListener);
236                         mTrackList.setDivider(null);
237                         mTrackList.setSelector(R.drawable.list_selector_background);
238                         // ADW: Load the specified theme
239                         String themePackage = MusicUtils.getThemePackageName(this,
240                                         MusicSettingsActivity.THEME_DEFAULT);
241                         PackageManager pm = getPackageManager();
242                         Resources themeResources = null;
243                         if (!themePackage.equals(MusicSettingsActivity.THEME_DEFAULT)) {
244                                 try {
245                                         themeResources = pm
246                                                         .getResourcesForApplication(themePackage);
247                                 } catch (NameNotFoundException e) {
248                                         // ADW The saved theme was uninstalled so we save the
249                                         // default one
250                                         MusicUtils.setThemePackageName(this,
251                                                         MusicSettingsActivity.THEME_DEFAULT);
252                                 }
253                         }
254                         // Set Views for themes
255                         if (themeResources != null) {
256                                 int lS = themeResources.getIdentifier("queue_selector",
257                                                 "drawable", themePackage);
258                                 if (lS != 0) {
259                                         mTrackList.setSelector(themeResources.getDrawable(lS));
260                                 }
261                         }
262                 } else {
263                         mTrackList.setTextFilterEnabled(true);
264                 }
265                 mAdapter = (TrackListAdapter) getLastNonConfigurationInstance();
266
267                 if (mAdapter != null) {
268                         mAdapter.setActivity(this);
269                         setListAdapter(mAdapter);
270                 }
271
272                 // Swipe up gesture
273                 gestureDetector = new GestureDetector(new NowPlayingGesture());
274                 View nowplayingview = (View) findViewById(R.id.nowplaying);
275                 // Tab swipe
276                 swipetabs = new GestureDetector(new TabSwipe());
277                 View mainview = (View) findViewById(android.R.id.list);
278
279                 // Set the touch listener for the main view to be our custom gesture
280                 // listener
281                 if (!mEditMode) {
282                         mainview.setOnTouchListener(new View.OnTouchListener() {
283                                 public boolean onTouch(View v, MotionEvent event) {
284                                         if (swipetabs.onTouchEvent(event)) {
285                                                 return false;
286                                         }
287                                         return false;
288                                 }
289                         });
290                 } else {
291
292                 }
293                 // Smaller now playing window buttons
294                 mShare = (ImageButton) findViewById(R.id.share_song);
295                 mPlay = (ImageButton) findViewById(R.id.media_play);
296                 mNext = (ImageButton) findViewById(R.id.media_next);
297                 mPrev = (ImageButton) findViewById(R.id.media_prev);
298                 mMarket = (ImageButton) findViewById(R.id.market_music);
299                 mDoSearch = (ImageButton) findViewById(R.id.doSearch);
300                 mPlusPlaylist = (ImageButton) findViewById(R.id.plus_playlist);
301                 mFlow = (ImageButton) findViewById(R.id.overFlow);
302                 // I found that without setting the onClickListeners in Portrait mode
303                 // only, flipping into Landscape force closes.
304                 if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
305                         // Smaller now playing window actions
306                         mDoSearch.setOnClickListener(mDoSearchListener);
307                         mMarket.setOnClickListener(mMarketSearch);
308                         mPlay.setOnClickListener(mMediaPlay);
309                         mNext.setOnClickListener(mMediaNext);
310                         mPrev.setOnClickListener(mMediaPrev);
311                         mShare.setOnClickListener(mShareSong);
312                         mFlow.setOnClickListener(mOverFlow);
313                         // I only want this to show in the Playlist activity
314                         mPlusPlaylist.setVisibility(View.GONE);
315                         // Swipe gesture
316                         nowplayingview.setOnTouchListener(new View.OnTouchListener() {
317                                 public boolean onTouch(View vee, MotionEvent nowplayingevent) {
318                                         if (gestureDetector.onTouchEvent(nowplayingevent)) {
319                                                 return false;
320                                         }
321                                         return false;
322                                 }
323                         });
324                 }
325                 // ADW: Load the specified theme
326                 String themePackage = MusicUtils.getThemePackageName(this,
327                                 MusicSettingsActivity.THEME_DEFAULT);
328                 PackageManager pm = getPackageManager();
329                 Resources themeResources = null;
330                 if (!themePackage.equals(MusicSettingsActivity.THEME_DEFAULT)) {
331                         try {
332                                 themeResources = pm.getResourcesForApplication(themePackage);
333                         } catch (NameNotFoundException e) {
334                                 // ADW The saved theme was uninstalled so we save the
335                                 // default one
336                                 MusicUtils.setThemePackageName(this,
337                                                 MusicSettingsActivity.THEME_DEFAULT);
338                         }
339                 }
340                 // Set Views for themes
341                 if (themeResources != null) {
342                         // Artist tab
343                         mSongTab = (LinearLayout) findViewById(R.id.album_tab);
344                         mButtonBar = (TabWidget) findViewById(R.id.buttonbar);
345                         mButtonBarArtist = (TextView) findViewById(R.id.artisttab);
346                         mButtonBarAlbum = (TextView) findViewById(R.id.albumtab);
347                         mButtonBarSong = (TextView) findViewById(R.id.songtab);
348                         mButtonBarPlaylist = (TextView) findViewById(R.id.playlisttab);
349                         mButtonBarNP = (TextView) findViewById(R.id.nowplayingtab);
350                         ArtistAlbumBrowserActivity.loadThemeResource(themeResources,
351                                         themePackage, "tab_song", mSongTab, THEME_ITEM_BACKGROUND);
352                         ArtistAlbumBrowserActivity.loadThemeResource(themeResources,
353                                         themePackage, "buttonbar", mButtonBar,
354                                         THEME_ITEM_BACKGROUND);
355                         ArtistAlbumBrowserActivity.loadThemeResource(themeResources,
356                                         themePackage, "tab_bg_artist", mButtonBarArtist,
357                                         THEME_ITEM_BACKGROUND);
358                         ArtistAlbumBrowserActivity.loadThemeResource(themeResources,
359                                         themePackage, "tab_bg_album", mButtonBarAlbum,
360                                         THEME_ITEM_BACKGROUND);
361                         ArtistAlbumBrowserActivity.loadThemeResource(themeResources,
362                                         themePackage, "tab_bg_song", mButtonBarSong,
363                                         THEME_ITEM_BACKGROUND);
364                         ArtistAlbumBrowserActivity.loadThemeResource(themeResources,
365                                         themePackage, "tab_bg_playlist", mButtonBarPlaylist,
366                                         THEME_ITEM_BACKGROUND);
367                         ArtistAlbumBrowserActivity.loadThemeResource(themeResources,
368                                         themePackage, "tab_bg_nowplaying", mButtonBarNP,
369                                         THEME_ITEM_BACKGROUND);
370                         // Small now playing window
371                         mNowPlaying = (LinearLayout) findViewById(R.id.nowplaying);
372                         mInfoDivider = (ImageView) findViewById(R.id.info_divider);
373                         mProgress = (ProgressBar) findViewById(R.id.progress);
374                         mShare = (ImageButton) findViewById(R.id.share_song);
375                         mPlay = (ImageButton) findViewById(R.id.media_play);
376                         mNext = (ImageButton) findViewById(R.id.media_next);
377                         mPrev = (ImageButton) findViewById(R.id.media_prev);
378                         mMarket = (ImageButton) findViewById(R.id.market_music);
379                         mDoSearch = (ImageButton) findViewById(R.id.doSearch);
380                         mFlow = (ImageButton) findViewById(R.id.overFlow);
381                         if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
382                                 ArtistAlbumBrowserActivity.loadThemeResource(themeResources,
383                                                 themePackage, "snp_background", mNowPlaying,
384                                                 THEME_ITEM_BACKGROUND);
385                                 ArtistAlbumBrowserActivity.loadThemeResource(themeResources,
386                                                 themePackage, "snp_progress", mProgress,
387                                                 THEME_ITEM_BACKGROUND);
388                                 ArtistAlbumBrowserActivity.loadThemeResource(themeResources,
389                                                 themePackage, "snp_info_divider", mInfoDivider,
390                                                 THEME_ITEM_BACKGROUND);
391                                 ArtistAlbumBrowserActivity.loadThemeResource(themeResources,
392                                                 themePackage, "snp_share", mShare,
393                                                 THEME_ITEM_FOREGROUND);
394                                 ArtistAlbumBrowserActivity.loadThemeResource(themeResources,
395                                                 themePackage, "snp_play", mPlay, THEME_ITEM_FOREGROUND);
396                                 ArtistAlbumBrowserActivity.loadThemeResource(themeResources,
397                                                 themePackage, "snp_next", mNext, THEME_ITEM_FOREGROUND);
398                                 ArtistAlbumBrowserActivity.loadThemeResource(themeResources,
399                                                 themePackage, "snp_prev", mPrev, THEME_ITEM_FOREGROUND);
400                                 ArtistAlbumBrowserActivity.loadThemeResource(themeResources,
401                                                 themePackage, "snp_market", mMarket,
402                                                 THEME_ITEM_FOREGROUND);
403                                 ArtistAlbumBrowserActivity.loadThemeResource(themeResources,
404                                                 themePackage, "snp_search", mDoSearch,
405                                                 THEME_ITEM_FOREGROUND);
406                                 ArtistAlbumBrowserActivity.loadThemeResource(themeResources,
407                                                 themePackage, "snp_flow", mFlow, THEME_ITEM_FOREGROUND);
408                         }
409                 }
410                 // don't set the album art until after the view has been layed out
411                 mTrackList.post(new Runnable() {
412
413                         public void run() {
414                                 setAlbumArtBackground();
415                         }
416                 });
417         }
418
419         public void onServiceConnected(ComponentName name, IBinder service) {
420                 IntentFilter f = new IntentFilter();
421                 f.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
422                 f.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
423                 f.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
424                 f.addDataScheme("file");
425                 registerReceiver(mScanListener, f);
426
427                 if (mAdapter == null) {
428                         // Log.i("@@@", "starting query");
429                         mAdapter = new TrackListAdapter(
430                                         getApplication(), // need to use application context to
431                                                                                 // avoid leaks
432                                         this,
433                                         mEditMode ? R.layout.edit_track_list_item
434                                                         : R.layout.track_list_item,
435                                         null, // cursor
436                                         new String[] {}, new int[] {},
437                                         "nowplaying".equals(mPlaylist),
438                                         mPlaylist != null
439                                                         && !(mPlaylist.equals("podcasts") || mPlaylist
440                                                                         .equals("recentlyadded")));
441                         setListAdapter(mAdapter);
442                         setTitle(R.string.working_songs);
443                         getTrackCursor(mAdapter.getQueryHandler(), null, true);
444                 } else {
445                         mTrackCursor = mAdapter.getCursor();
446                         // If mTrackCursor is null, this can be because it doesn't have
447                         // a cursor yet (because the initial query that sets its cursor
448                         // is still in progress), or because the query failed.
449                         // In order to not flash the error dialog at the user for the
450                         // first case, simply retry the query when the cursor is null.
451                         // Worst case, we end up doing the same query twice.
452                         if (mTrackCursor != null) {
453                                 init(mTrackCursor, false);
454                         } else {
455                                 setTitle(R.string.working_songs);
456                                 getTrackCursor(mAdapter.getQueryHandler(), null, true);
457                         }
458                 }
459                 if (!mEditMode) {
460                         MusicUtils.updateNowPlaying(this);
461                 }
462         }
463
464         public void onServiceDisconnected(ComponentName name) {
465                 // we can't really function without the service, so don't
466                 finish();
467         }
468
469         @Override
470         public Object onRetainNonConfigurationInstance() {
471                 TrackListAdapter a = mAdapter;
472                 mAdapterSent = true;
473                 return a;
474         }
475
476         // Tab Swipe
477         class TabSwipe extends SimpleOnGestureListener {
478                 @Override
479                 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
480                                 float velocityY) {
481                         Intent intent = new Intent(Intent.ACTION_PICK);
482
483                         try {
484                                 if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
485                                         return false;
486                                 if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
487                                                 && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
488                                         intent.setDataAndType(Uri.EMPTY,
489                                                         MediaStore.Audio.Playlists.CONTENT_TYPE);
490                                         intent.putExtra("withtabs", true);
491                                         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
492                                         startActivity(intent);
493                                         finish();
494                                         TrackBrowserActivity.this.overridePendingTransition(
495                                                         R.anim.slide_in_right, R.anim.slide_out_left);
496                                         return true;
497                                 } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
498                                                 && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
499                                         intent.setDataAndType(Uri.EMPTY,
500                                                         "vnd.android.cursor.dir/album");
501                                         intent.putExtra("withtabs", true);
502                                         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
503                                         startActivity(intent);
504                                         finish();
505                                         TrackBrowserActivity.this.overridePendingTransition(
506                                                         R.anim.slide_in_left, R.anim.slide_out_right);
507                                         return true;
508
509                                 }
510
511                         } catch (Exception e) {
512                                 Log.e("Fling", "There was an error processing the Fling event:"
513                                                 + e.getMessage());
514                         }
515                         return true;
516                 }
517
518                 // It is necessary to return true from onDown for the onFling event to
519                 // register
520                 @Override
521                 public boolean onDown(MotionEvent e) {
522                         return true;
523                 }
524         }
525
526         // Swipe gesture
527         class NowPlayingGesture extends SimpleOnGestureListener {
528                 @Override
529                 public boolean onFling(MotionEvent e3, MotionEvent e4, float vX,
530                                 float vY) {
531                         np_swipe_gesture_db = mPreferences.getString("np_swipe_gesture",
532                                         "0");
533                         if (np_swipe_gesture_db.equals("0")) {
534                                 if (e3.getY() - e4.getY() > SWIPE_MIN_DISTANCE
535                                                 && Math.abs(vY) > SWIPE_THRESHOLD_VELOCITY) {
536                                         // NONE
537                                 }
538                         }
539
540                         np_swipe_gesture_db = mPreferences.getString("np_swipe_gesture",
541                                         "1");
542                         if (np_swipe_gesture_db.equals("1")) {
543                                 if (e3.getY() - e4.getY() > SWIPE_MIN_DISTANCE
544                                                 && Math.abs(vY) > SWIPE_THRESHOLD_VELOCITY) {
545                                         doPauseResume();
546                                 }
547                         }
548
549                         np_swipe_gesture_db = mPreferences.getString("np_swipe_gesture",
550                                         "2");
551                         if (np_swipe_gesture_db.equals("2")) {
552                                 if (e3.getY() - e4.getY() > SWIPE_MIN_DISTANCE
553                                                 && Math.abs(vY) > SWIPE_THRESHOLD_VELOCITY) {
554                                         doNext();
555                                 }
556                         }
557                         np_swipe_gesture_db = mPreferences.getString("np_swipe_gesture",
558                                         "3");
559                         if (np_swipe_gesture_db.equals("3")) {
560                                 if (e3.getY() - e4.getY() > SWIPE_MIN_DISTANCE
561                                                 && Math.abs(vY) > SWIPE_THRESHOLD_VELOCITY) {
562                                         doPrev();
563                                 }
564                         }
565                         return false;
566
567                 }
568
569                 @Override
570                 public boolean onDown(MotionEvent f) {
571                         return true;
572                 }
573         }
574
575         // Smaller now playing window OnClickListerners
576         private View.OnClickListener mMarketSearch = new View.OnClickListener() {
577                 public void onClick(View v) {
578                         Uri marketUri = null;
579                         try {
580                                 marketUri = Uri.parse("market://search?q= "
581                                                 + mService.getArtistName());
582                         } catch (RemoteException e) {
583                                 // TODO Auto-generated catch block
584                                 e.printStackTrace();
585                         }
586                         Intent marketIntent = new Intent(Intent.ACTION_VIEW)
587                                         .setData(marketUri);
588                         startActivity(marketIntent);
589                         finish();
590
591                 }
592         };
593         private View.OnClickListener mShareSong = new View.OnClickListener() {
594
595                 @Override
596                 public void onClick(View v) {
597                         // TODO Auto-generated method stub
598                         try {
599                                 shareCurrentTrack();
600                         } catch (RemoteException e) {
601                                 // TODO Auto-generated catch block
602                                 e.printStackTrace();
603                         }
604
605                 }
606
607         };
608
609         private String shareCurrentTrack() throws RemoteException {
610                 if (mService.getTrackName() == null || mService.getArtistName() == null) {
611
612                 }
613
614                 Intent shareIntent = new Intent();
615                 String currentTrackMessage = "Now listening to: "
616                                 + mService.getTrackName() + " by " + mService.getArtistName();
617
618                 shareIntent.setAction(Intent.ACTION_SEND);
619                 shareIntent.setType("text/plain");
620                 shareIntent.putExtra(Intent.EXTRA_TEXT, currentTrackMessage);
621
622                 startActivity(Intent.createChooser(shareIntent, "Share track using"));
623                 return currentTrackMessage;
624         }
625
626         private View.OnClickListener mOverFlow = new View.OnClickListener() {
627                 public void onClick(View v) {
628                         openOptionsMenu();
629                 }
630         };
631         private View.OnClickListener mDoSearchListener = new View.OnClickListener() {
632                 public void onClick(View v) {
633                         onSearchRequested();
634                 }
635         };
636         private View.OnClickListener mMediaPlay = new View.OnClickListener() {
637                 public void onClick(View v) {
638                         doPauseResume();
639                 }
640         };
641         private View.OnClickListener mMediaNext = new View.OnClickListener() {
642                 public void onClick(View v) {
643                         doNext();
644                 }
645         };
646         private View.OnClickListener mMediaPrev = new View.OnClickListener() {
647                 public void onClick(View v) {
648                         doPrev();
649                 }
650         };
651
652         @Override
653         public void onDestroy() {
654                 ListView lv = getListView();
655                 if (lv != null) {
656                         if (mUseLastListPos) {
657                                 mLastListPosCourse = lv.getFirstVisiblePosition();
658                                 View cv = lv.getChildAt(0);
659                                 if (cv != null) {
660                                         mLastListPosFine = cv.getTop();
661                                 }
662                         }
663                         if (mEditMode) {
664                                 // clear the listeners so we won't get any more callbacks
665                                 ((TouchInterceptor) lv).setDropListener(null);
666                                 ((TouchInterceptor) lv).setRemoveListener(null);
667                         }
668                 }
669
670                 MusicUtils.unbindFromService(mToken);
671                 MusicUtils.unbindFromService(mOSC);
672                 try {
673                         if ("nowplaying".equals(mPlaylist)) {
674                                 unregisterReceiverSafe(mNowPlayingListener);
675                         } else {
676                                 unregisterReceiverSafe(mTrackListListener);
677                         }
678                 } catch (IllegalArgumentException ex) {
679                         // we end up here in case we never registered the listeners
680                 }
681
682                 // If we have an adapter and didn't send it off to another activity yet,
683                 // we should
684                 // close its cursor, which we do by assigning a null cursor to it. Doing
685                 // this
686                 // instead of closing the cursor directly keeps the framework from
687                 // accessing
688                 // the closed cursor later.
689                 if (!mAdapterSent && mAdapter != null) {
690                         mAdapter.changeCursor(null);
691                 }
692                 // Because we pass the adapter to the next activity, we need to make
693                 // sure it doesn't keep a reference to this activity. We can do this
694                 // by clearing its DatasetObservers, which setListAdapter(null) does.
695                 setListAdapter(null);
696                 mAdapter = null;
697                 unregisterReceiverSafe(mScanListener);
698                 super.onDestroy();
699         }
700
701         /**
702          * Unregister a receiver, but eat the exception that is thrown if the
703          * receiver was never registered to begin with. This is a little easier than
704          * keeping track of whether the receivers have actually been registered by
705          * the time onDestroy() is called.
706          */
707         private void unregisterReceiverSafe(BroadcastReceiver receiver) {
708                 try {
709                         unregisterReceiver(receiver);
710                 } catch (IllegalArgumentException e) {
711                         // ignore
712                 }
713         }
714
715         private void startPlayback() {
716
717                 if (mService == null)
718                         return;
719                 Intent intent = getIntent();
720                 String filename = "";
721                 Uri uri = intent.getData();
722                 if (uri != null && uri.toString().length() > 0) {
723                         // If this is a file:// URI, just use the path directly instead
724                         // of going through the open-from-filedescriptor codepath.
725                         String scheme = uri.getScheme();
726                         if ("file".equals(scheme)) {
727                                 filename = uri.getPath();
728                         } else {
729                                 filename = uri.toString();
730                         }
731                         try {
732                                 refreshProgress();
733                                 mService.stop();
734                                 mService.openFile(filename);
735                                 mService.play();
736                                 setIntent(new Intent());
737                         } catch (Exception ex) {
738                                 Log.d("MediaPlaybackActivity", "couldn't start playback: " + ex);
739                         }
740                 }
741         }
742
743         private ServiceConnection osc = new ServiceConnection() {
744                 public void onServiceConnected(ComponentName classname, IBinder obj) {
745                         mService = IMediaPlaybackService.Stub.asInterface(obj);
746                         startPlayback();
747                         // This is for orientation changes or entering the tab from a
748                         // different activity
749                         if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
750                                 setPauseButtonImage();
751                                 // This is so the controls will load correctly according to the
752                                 // user's settings
753                                 MusicUtils.updateNowPlaying(TrackBrowserActivity.this);
754                         }
755                         try {
756                                 if (mService.getAudioId() >= 0 || mService.isPlaying()
757                                                 || mService.getPath() != null) {
758                                         return;
759                                 }
760                         } catch (RemoteException ex) {
761                         }
762                         if (getIntent().getData() == null) {
763                                 Intent intent = new Intent(Intent.ACTION_MAIN);
764                                 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
765                                 intent.setClass(TrackBrowserActivity.this,
766                                                 MusicBrowserActivity.class);
767                                 startActivity(intent);
768                         }
769                 }
770
771                 public void onServiceDisconnected(ComponentName classname) {
772                         mService = null;
773                 }
774         };
775
776         @Override
777         public void onResume() {
778                 super.onResume();
779                 if (mTrackCursor != null) {
780                         getListView().invalidateViews();
781                 }
782                 MusicUtils.setSpinnerState(this);
783         }
784
785         @Override
786         public void onPause() {
787                 mReScanHandler.removeCallbacksAndMessages(null);
788                 super.onPause();
789         }
790
791         /*
792          * This listener gets called when the media scanner starts up or finishes,
793          * and when the sd card is unmounted.
794          */
795         private BroadcastReceiver mScanListener = new BroadcastReceiver() {
796                 @Override
797                 public void onReceive(Context context, Intent intent) {
798                         String action = intent.getAction();
799                         if (Intent.ACTION_MEDIA_SCANNER_STARTED.equals(action)
800                                         || Intent.ACTION_MEDIA_SCANNER_FINISHED.equals(action)) {
801                                 MusicUtils.setSpinnerState(TrackBrowserActivity.this);
802                         }
803                         mReScanHandler.sendEmptyMessage(0);
804                 }
805         };
806
807         private Handler mReScanHandler = new Handler() {
808                 @Override
809                 public void handleMessage(Message msg) {
810                         if (mAdapter != null) {
811                                 getTrackCursor(mAdapter.getQueryHandler(), null, true);
812                         }
813                         // if the query results in a null cursor, onQueryComplete() will
814                         // call init(), which will post a delayed message to this handler
815                         // in order to try again.
816                 }
817         };
818
819         public void onSaveInstanceState(Bundle outcicle) {
820                 // need to store the selected item so we don't lose it in case
821                 // of an orientation switch. Otherwise we could lose it while
822                 // in the middle of specifying a playlist to add the item to.
823                 outcicle.putLong("selectedtrack", mSelectedId);
824                 outcicle.putString("artist", mArtistId);
825                 outcicle.putString("album", mAlbumId);
826                 outcicle.putString("playlist", mPlaylist);
827                 outcicle.putString("genre", mGenre);
828                 outcicle.putBoolean("editmode", mEditMode);
829                 super.onSaveInstanceState(outcicle);
830         }
831
832         public void init(Cursor newCursor, boolean isLimited) {
833
834                 if (mAdapter == null) {
835                         return;
836                 }
837                 mAdapter.changeCursor(newCursor); // also sets mTrackCursor
838
839                 if (mTrackCursor == null) {
840                         MusicUtils.displayDatabaseError(this);
841                         closeContextMenu();
842                         mReScanHandler.sendEmptyMessageDelayed(0, 1000);
843                         return;
844                 }
845
846                 MusicUtils.hideDatabaseError(this);
847                 mUseLastListPos = MusicUtils.updateButtonBar(this, R.id.songtab);
848                 setTitle();
849
850                 // Restore previous position
851                 if (mLastListPosCourse >= 0 && mUseLastListPos) {
852                         ListView lv = getListView();
853                         // this hack is needed because otherwise the position doesn't change
854                         // for the 2nd (non-limited) cursor
855                         lv.setAdapter(lv.getAdapter());
856                         lv.setSelectionFromTop(mLastListPosCourse, mLastListPosFine);
857                         if (!isLimited) {
858                                 mLastListPosCourse = -1;
859                         }
860                 }
861
862                 // When showing the queue, position the selection on the currently
863                 // playing track
864                 // Otherwise, position the selection on the first matching artist, if
865                 // any
866                 IntentFilter f = new IntentFilter();
867                 f.addAction(MediaPlaybackService.META_CHANGED);
868                 f.addAction(MediaPlaybackService.QUEUE_CHANGED);
869                 f.addAction(MediaPlaybackService.PLAYSTATE_CHANGED);
870                 f.addAction(MediaPlaybackService.PROGRESSBAR_CHANGED);
871                 if ("nowplaying".equals(mPlaylist)) {
872                         try {
873                                 int cur = MusicUtils.sService.getQueuePosition();
874                                 setSelection(cur);
875                                 registerReceiver(mNowPlayingListener, new IntentFilter(f));
876                                 mNowPlayingListener.onReceive(this, new Intent(
877                                                 MediaPlaybackService.META_CHANGED));
878                         } catch (RemoteException ex) {
879                         }
880                 } else {
881                         String key = getIntent().getStringExtra("artist");
882                         if (key != null) {
883                                 int keyidx = mTrackCursor
884                                                 .getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST_ID);
885                                 mTrackCursor.moveToFirst();
886                                 while (!mTrackCursor.isAfterLast()) {
887                                         String artist = mTrackCursor.getString(keyidx);
888                                         if (artist.equals(key)) {
889                                                 setSelection(mTrackCursor.getPosition());
890                                                 break;
891                                         }
892                                         mTrackCursor.moveToNext();
893                                 }
894                         }
895                         registerReceiver(mTrackListListener, new IntentFilter(f));
896                         mTrackListListener.onReceive(this, new Intent(
897                                         MediaPlaybackService.META_CHANGED));
898                 }
899         }
900
901         private void setAlbumArtBackground() {
902                 if (!mEditMode) {
903                         try {
904                                 long albumid = Long.valueOf(mAlbumId);
905                                 Bitmap bm = MusicUtils.getArtwork(TrackBrowserActivity.this,
906                                                 -1, albumid, false);
907                                 if (bm != null) {
908                                         MusicUtils.setBackground(mTrackList, bm);
909                                         mTrackList.setCacheColorHint(0);
910                                         return;
911                                 }
912                         } catch (Exception ex) {
913                         }
914                 }
915                 mTrackList.setCacheColorHint(0);
916         }
917
918         private void setTitle() {
919
920                 CharSequence fancyName = null;
921                 if (mAlbumId != null) {
922                         int numresults = mTrackCursor != null ? mTrackCursor.getCount() : 0;
923                         if (numresults > 0) {
924                                 mTrackCursor.moveToFirst();
925                                 int idx = mTrackCursor
926                                                 .getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM);
927                                 fancyName = mTrackCursor.getString(idx);
928                                 // For compilation albums show only the album title,
929                                 // but for regular albums show "artist - album".
930                                 // To determine whether something is a compilation
931                                 // album, do a query for the artist + album of the
932                                 // first item, and see if it returns the same number
933                                 // of results as the album query.
934                                 String where = MediaStore.Audio.Media.ALBUM_ID
935                                                 + "='"
936                                                 + mAlbumId
937                                                 + "' AND "
938                                                 + MediaStore.Audio.Media.ARTIST_ID
939                                                 + "="
940                                                 + mTrackCursor
941                                                                 .getLong(mTrackCursor
942                                                                                 .getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST_ID));
943                                 Cursor cursor = MusicUtils.query(this,
944                                                 MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
945                                                 new String[] { MediaStore.Audio.Media.ALBUM }, where,
946                                                 null, null);
947                                 if (cursor != null) {
948                                         if (cursor.getCount() != numresults) {
949                                                 // compilation album
950                                                 fancyName = mTrackCursor.getString(idx);
951                                         }
952                                         cursor.deactivate();
953                                 }
954                                 if (fancyName == null
955                                                 || fancyName.equals(MediaStore.UNKNOWN_STRING)) {
956                                         fancyName = getString(R.string.unknown_album_name);
957                                 }
958                         }
959                 } else if (mPlaylist != null) {
960                         if (mPlaylist.equals("nowplaying")) {
961                                 if (MusicUtils.getCurrentShuffleMode() == MediaPlaybackService.SHUFFLE_AUTO) {
962                                         fancyName = getText(R.string.party_shuffle);
963                                 } else {
964                                         fancyName = getText(R.string.nowplaying_title);
965                                 }
966                         } else if (mPlaylist.equals("podcasts")) {
967                                 fancyName = getText(R.string.podcasts_title);
968                         } else if (mPlaylist.equals("recentlyadded")) {
969                                 fancyName = getText(R.string.recentlyadded_title);
970                         } else {
971                                 String[] cols = new String[] { MediaStore.Audio.Playlists.NAME };
972                                 Cursor cursor = MusicUtils.query(this, ContentUris
973                                                 .withAppendedId(Playlists.EXTERNAL_CONTENT_URI,
974                                                                 Long.valueOf(mPlaylist)), cols, null, null,
975                                                 null);
976                                 if (cursor != null) {
977                                         if (cursor.getCount() != 0) {
978                                                 cursor.moveToFirst();
979                                                 fancyName = cursor.getString(0);
980                                         }
981                                         cursor.deactivate();
982                                 }
983                         }
984                 } else if (mGenre != null) {
985                         String[] cols = new String[] { MediaStore.Audio.Genres.NAME };
986                         Cursor cursor = MusicUtils.query(this, ContentUris.withAppendedId(
987                                         MediaStore.Audio.Genres.EXTERNAL_CONTENT_URI,
988                                         Long.valueOf(mGenre)), cols, null, null, null);
989                         if (cursor != null) {
990                                 if (cursor.getCount() != 0) {
991                                         cursor.moveToFirst();
992                                         fancyName = cursor.getString(0);
993                                 }
994                                 cursor.deactivate();
995                         }
996                 }
997
998                 if (fancyName != null) {
999                         setTitle(fancyName);
1000                 } else {
1001                         try {
1002
1003                                 setTitle(mService.getArtistName());
1004                         } catch (Exception e) {
1005                                 // TODO Auto-generated catch block
1006                                 e.printStackTrace();
1007                         }
1008                 }
1009         }
1010
1011         private TouchInterceptor.DropListener mDropListener = new TouchInterceptor.DropListener() {
1012                 public void drop(int from, int to) {
1013                         if (mTrackCursor instanceof NowPlayingCursor) {
1014                                 // update the currently playing list
1015                                 NowPlayingCursor c = (NowPlayingCursor) mTrackCursor;
1016                                 c.moveItem(from, to);
1017                                 ((TrackListAdapter) getListAdapter()).notifyDataSetChanged();
1018                                 getListView().invalidateViews();
1019                                 mDeletedOneRow = true;
1020                         } else {
1021                                 // update a saved playlist
1022                                 Uri baseUri = MediaStore.Audio.Playlists.Members.getContentUri(
1023                                                 "external", Long.valueOf(mPlaylist));
1024                                 ContentValues values = new ContentValues();
1025                                 String where = MediaStore.Audio.Playlists.Members._ID + "=?";
1026                                 String[] wherearg = new String[1];
1027                                 ContentResolver res = getContentResolver();
1028                                 int colidx = mTrackCursor
1029                                                 .getColumnIndexOrThrow(MediaStore.Audio.Playlists.Members.PLAY_ORDER);
1030                                 if (from < to) {
1031                                         // move the item to somewhere later in the list
1032                                         mTrackCursor.moveToPosition(to);
1033                                         long toidx = mTrackCursor.getLong(colidx);
1034                                         mTrackCursor.moveToPosition(from);
1035                                         values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER,
1036                                                         toidx);
1037                                         wherearg[0] = mTrackCursor.getString(0);
1038                                         res.update(baseUri, values, where, wherearg);
1039                                         for (int i = from + 1; i <= to; i++) {
1040                                                 mTrackCursor.moveToPosition(i);
1041                                                 values.put(
1042                                                                 MediaStore.Audio.Playlists.Members.PLAY_ORDER,
1043                                                                 i - 1);
1044                                                 wherearg[0] = mTrackCursor.getString(0);
1045                                                 res.update(baseUri, values, where, wherearg);
1046                                         }
1047                                 } else if (from > to) {
1048                                         // move the item to somewhere earlier in the list
1049                                         mTrackCursor.moveToPosition(to);
1050                                         long toidx = mTrackCursor.getLong(colidx);
1051                                         mTrackCursor.moveToPosition(from);
1052                                         values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER,
1053                                                         toidx);
1054                                         wherearg[0] = mTrackCursor.getString(0);
1055                                         res.update(baseUri, values, where, wherearg);
1056                                         for (int i = from - 1; i >= to; i--) {
1057                                                 mTrackCursor.moveToPosition(i);
1058                                                 values.put(
1059                                                                 MediaStore.Audio.Playlists.Members.PLAY_ORDER,
1060                                                                 i + 1);
1061                                                 wherearg[0] = mTrackCursor.getString(0);
1062                                                 res.update(baseUri, values, where, wherearg);
1063                                         }
1064                                 }
1065
1066                         }
1067                 }
1068         };
1069
1070         private TouchInterceptor.RemoveListener mRemoveListener = new TouchInterceptor.RemoveListener() {
1071                 public void remove(int which) {
1072                         removePlaylistItem(which);
1073                 }
1074         };
1075
1076         private void removePlaylistItem(int which) {
1077                 View v = mTrackList.getChildAt(which
1078                                 - mTrackList.getFirstVisiblePosition());
1079                 if (v == null) {
1080                         Log.d(LOGTAG, "No view when removing playlist item " + which);
1081                         return;
1082                 }
1083                 try {
1084                         if (MusicUtils.sService != null
1085                                         && which != MusicUtils.sService.getQueuePosition()) {
1086                                 mDeletedOneRow = true;
1087                         }
1088                 } catch (RemoteException e) {
1089                         // Service died, so nothing playing.
1090                         mDeletedOneRow = true;
1091                 }
1092                 v.setVisibility(View.GONE);
1093                 mTrackList.invalidateViews();
1094                 if (mTrackCursor instanceof NowPlayingCursor) {
1095                         ((NowPlayingCursor) mTrackCursor).removeItem(which);
1096                 } else {
1097                         int colidx = mTrackCursor
1098                                         .getColumnIndexOrThrow(MediaStore.Audio.Playlists.Members._ID);
1099                         mTrackCursor.moveToPosition(which);
1100                         long id = mTrackCursor.getLong(colidx);
1101                         Uri uri = MediaStore.Audio.Playlists.Members.getContentUri(
1102                                         "external", Long.valueOf(mPlaylist));
1103                         getContentResolver().delete(ContentUris.withAppendedId(uri, id),
1104                                         null, null);
1105                 }
1106                 v.setVisibility(View.VISIBLE);
1107                 mTrackList.invalidateViews();
1108         }
1109
1110         private BroadcastReceiver mTrackListListener = new BroadcastReceiver() {
1111                 @Override
1112                 public void onReceive(Context context, Intent intent) {
1113                         String action = intent.getAction();
1114                         getListView().invalidateViews();
1115                         if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
1116                                 refreshProgress();
1117                                 if (action.equals(MediaPlaybackService.PLAYSTATE_CHANGED)) {
1118                                         setPauseButtonImage();
1119                                 }
1120                                 if (!mEditMode) {
1121                                         MusicUtils.updateNowPlaying(TrackBrowserActivity.this);
1122                                 }
1123                         }
1124                 }
1125         };
1126
1127         private BroadcastReceiver mNowPlayingListener = new BroadcastReceiver() {
1128                 @Override
1129                 public void onReceive(Context context, Intent intent) {
1130                         if (intent.getAction().equals(MediaPlaybackService.META_CHANGED)) {
1131                                 getListView().invalidateViews();
1132                         } else if (intent.getAction().equals(
1133                                         MediaPlaybackService.QUEUE_CHANGED)) {
1134                                 if (mDeletedOneRow) {
1135                                         // This is the notification for a single row that was
1136                                         // deleted previously, which is already reflected in
1137                                         // the UI.
1138                                         mDeletedOneRow = false;
1139                                         return;
1140                                 }
1141                                 // The service could disappear while the broadcast was in
1142                                 // flight,
1143                                 // so check to see if it's still valid
1144                                 if (MusicUtils.sService == null) {
1145                                         finish();
1146                                         return;
1147                                 }
1148                                 if (mAdapter != null) {
1149                                         Cursor c = new NowPlayingCursor(MusicUtils.sService,
1150                                                         mCursorCols);
1151                                         if (c.getCount() == 0) {
1152                                                 finish();
1153                                                 return;
1154                                         }
1155                                         mAdapter.changeCursor(c);
1156                                 }
1157                         }
1158                 }
1159         };
1160
1161         // Cursor should be positioned on the entry to be checked
1162         // Returns false if the entry matches the naming pattern used for
1163         // recordings,
1164         // or if it is marked as not music in the database.
1165         private boolean isMusic(Cursor c) {
1166                 int titleidx = c.getColumnIndex(MediaStore.Audio.Media.TITLE);
1167                 int albumidx = c.getColumnIndex(MediaStore.Audio.Media.ALBUM);
1168                 int artistidx = c.getColumnIndex(MediaStore.Audio.Media.ARTIST);
1169
1170                 String title = c.getString(titleidx);
1171                 String album = c.getString(albumidx);
1172                 String artist = c.getString(artistidx);
1173                 if (MediaStore.UNKNOWN_STRING.equals(album)
1174                                 && MediaStore.UNKNOWN_STRING.equals(artist) && title != null
1175                                 && title.startsWith("recording")) {
1176                         // not music
1177                         return false;
1178                 }
1179
1180                 int ismusic_idx = c.getColumnIndex(MediaStore.Audio.Media.IS_MUSIC);
1181                 boolean ismusic = true;
1182                 if (ismusic_idx >= 0) {
1183                         ismusic = mTrackCursor.getInt(ismusic_idx) != 0;
1184                 }
1185                 return ismusic;
1186         }
1187
1188         @Override
1189         public void onCreateContextMenu(ContextMenu menu, View view,
1190                         ContextMenuInfo menuInfoIn) {
1191                 menu.add(0, PLAY_SELECTION, 0, R.string.play_selection);
1192                 SubMenu sub = menu.addSubMenu(0, ADD_TO_PLAYLIST, 0,
1193                                 R.string.add_to_playlist);
1194                 MusicUtils.makePlaylistMenu(this, sub);
1195                 if (mEditMode) {
1196                         menu.add(0, REMOVE, 0, R.string.remove_from_playlist);
1197                 }
1198                 menu.add(0, USE_AS_RINGTONE, 0, R.string.ringtone_menu);
1199                 menu.add(0, DELETE_ITEM, 0, R.string.delete_item);
1200                 AdapterContextMenuInfo mi = (AdapterContextMenuInfo) menuInfoIn;
1201                 mSelectedPosition = mi.position;
1202                 mTrackCursor.moveToPosition(mSelectedPosition);
1203                 try {
1204                         int id_idx = mTrackCursor
1205                                         .getColumnIndexOrThrow(MediaStore.Audio.Playlists.Members.AUDIO_ID);
1206                         mSelectedId = mTrackCursor.getLong(id_idx);
1207                 } catch (IllegalArgumentException ex) {
1208                         mSelectedId = mi.id;
1209                 }
1210                 // only add the 'search' menu if the selected item is music
1211                 if (isMusic(mTrackCursor)) {
1212                         menu.add(0, SEARCH, 0, R.string.search_title);
1213                 }
1214                 mCurrentAlbumName = mTrackCursor.getString(mTrackCursor
1215                                 .getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));
1216                 mCurrentArtistNameForAlbum = mTrackCursor.getString(mTrackCursor
1217                                 .getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
1218                 mCurrentTrackName = mTrackCursor.getString(mTrackCursor
1219                                 .getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
1220                 menu.setHeaderTitle(mCurrentTrackName);
1221         }
1222
1223         @Override
1224         public boolean onContextItemSelected(MenuItem item) {
1225                 switch (item.getItemId()) {
1226                 case PLAY_SELECTION: {
1227                         // play the track
1228                         int position = mSelectedPosition;
1229                         MusicUtils.playAll(this, mTrackCursor, position);
1230                         return true;
1231                 }
1232
1233                 case QUEUE: {
1234                         long[] list = new long[] { mSelectedId };
1235                         MusicUtils.addToCurrentPlaylist(this, list);
1236                         return true;
1237                 }
1238
1239                 case NEW_PLAYLIST: {
1240                         Intent intent = new Intent();
1241                         intent.setClass(this, CreatePlaylist.class);
1242                         startActivityForResult(intent, NEW_PLAYLIST);
1243                         return true;
1244                 }
1245
1246                 case PLAYLIST_SELECTED: {
1247                         long[] list = new long[] { mSelectedId };
1248                         long playlist = item.getIntent().getLongExtra("playlist", 0);
1249                         MusicUtils.addToPlaylist(this, list, playlist);
1250                         return true;
1251                 }
1252
1253                 case USE_AS_RINGTONE:
1254                         // Set the system setting to make this the current ringtone
1255                         MusicUtils.setRingtone(this, mSelectedId);
1256                         return true;
1257
1258                 case DELETE_ITEM: {
1259                         long[] list = new long[1];
1260                         list[0] = (int) mSelectedId;
1261                         Bundle b = new Bundle();
1262                         String f;
1263                         if (android.os.Environment.isExternalStorageRemovable()) {
1264                                 f = getString(R.string.delete_song_desc);
1265                         } else {
1266                                 f = getString(R.string.delete_song_desc_nosdcard);
1267                         }
1268                         String desc = String.format(f, mCurrentTrackName);
1269                         b.putString("description", desc);
1270                         b.putLongArray("items", list);
1271                         Intent intent = new Intent();
1272                         intent.setClass(this, DeleteItems.class);
1273                         intent.putExtras(b);
1274                         startActivityForResult(intent, -1);
1275                         return true;
1276                 }
1277
1278                 case REMOVE:
1279                         removePlaylistItem(mSelectedPosition);
1280                         return true;
1281
1282                 case SEARCH:
1283                         doSearch();
1284                         return true;
1285                 }
1286                 return super.onContextItemSelected(item);
1287         }
1288
1289         void doSearch() {
1290                 CharSequence title = null;
1291                 String query = null;
1292
1293                 Intent i = new Intent();
1294                 i.setAction(MediaStore.INTENT_ACTION_MEDIA_SEARCH);
1295                 i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1296
1297                 title = mCurrentTrackName;
1298                 if (MediaStore.UNKNOWN_STRING.equals(mCurrentArtistNameForAlbum)) {
1299                         query = mCurrentTrackName;
1300                 } else {
1301                         query = mCurrentArtistNameForAlbum + " " + mCurrentTrackName;
1302                         i.putExtra(MediaStore.EXTRA_MEDIA_ARTIST,
1303                                         mCurrentArtistNameForAlbum);
1304                 }
1305                 if (MediaStore.UNKNOWN_STRING.equals(mCurrentAlbumName)) {
1306                         i.putExtra(MediaStore.EXTRA_MEDIA_ALBUM, mCurrentAlbumName);
1307                 }
1308                 i.putExtra(MediaStore.EXTRA_MEDIA_FOCUS, "audio/*");
1309                 title = getString(R.string.mediasearch, title);
1310                 i.putExtra(SearchManager.QUERY, query);
1311
1312                 startActivity(Intent.createChooser(i, title));
1313         }
1314
1315         // In order to use alt-up/down as a shortcut for moving the selected item
1316         // in the list, we need to override dispatchKeyEvent, not onKeyDown.
1317         // (onKeyDown never sees these events, since they are handled by the list)
1318         @Override
1319         public boolean dispatchKeyEvent(KeyEvent event) {
1320                 if (mPlaylist != null && event.getMetaState() != 0
1321                                 && event.getAction() == KeyEvent.ACTION_DOWN) {
1322                         switch (event.getKeyCode()) {
1323                         case KeyEvent.KEYCODE_DPAD_UP:
1324                                 moveItem(true);
1325                                 return true;
1326                         case KeyEvent.KEYCODE_DPAD_DOWN:
1327                                 moveItem(false);
1328                                 return true;
1329                         case KeyEvent.KEYCODE_DEL:
1330                                 removeItem();
1331                                 return true;
1332                         }
1333                 }
1334
1335                 return super.dispatchKeyEvent(event);
1336         }
1337
1338         private void removeItem() {
1339                 int curcount = mTrackCursor.getCount();
1340                 int curpos = mTrackList.getSelectedItemPosition();
1341                 if (curcount == 0 || curpos < 0) {
1342                         return;
1343                 }
1344
1345                 if ("nowplaying".equals(mPlaylist)) {
1346                         // remove track from queue
1347
1348                         // Work around bug 902971. To get quick visual feedback
1349                         // of the deletion of the item, hide the selected view.
1350                         try {
1351                                 if (curpos != MusicUtils.sService.getQueuePosition()) {
1352                                         mDeletedOneRow = true;
1353                                 }
1354                         } catch (RemoteException ex) {
1355                         }
1356                         View v = mTrackList.getSelectedView();
1357                         v.setVisibility(View.GONE);
1358                         mTrackList.invalidateViews();
1359                         ((NowPlayingCursor) mTrackCursor).removeItem(curpos);
1360                         v.setVisibility(View.VISIBLE);
1361                         mTrackList.invalidateViews();
1362                 } else {
1363                         // remove track from playlist
1364                         int colidx = mTrackCursor
1365                                         .getColumnIndexOrThrow(MediaStore.Audio.Playlists.Members._ID);
1366                         mTrackCursor.moveToPosition(curpos);
1367                         long id = mTrackCursor.getLong(colidx);
1368                         Uri uri = MediaStore.Audio.Playlists.Members.getContentUri(
1369                                         "external", Long.valueOf(mPlaylist));
1370                         getContentResolver().delete(ContentUris.withAppendedId(uri, id),
1371                                         null, null);
1372                         curcount--;
1373                         if (curcount == 0) {
1374                                 finish();
1375                         } else {
1376                                 mTrackList.setSelection(curpos < curcount ? curpos : curcount);
1377                         }
1378                 }
1379         }
1380
1381         private void moveItem(boolean up) {
1382                 int curcount = mTrackCursor.getCount();
1383                 int curpos = mTrackList.getSelectedItemPosition();
1384                 if ((up && curpos < 1) || (!up && curpos >= curcount - 1)) {
1385                         return;
1386                 }
1387
1388                 if (mTrackCursor instanceof NowPlayingCursor) {
1389                         NowPlayingCursor c = (NowPlayingCursor) mTrackCursor;
1390                         c.moveItem(curpos, up ? curpos - 1 : curpos + 1);
1391                         ((TrackListAdapter) getListAdapter()).notifyDataSetChanged();
1392                         getListView().invalidateViews();
1393                         mDeletedOneRow = true;
1394                         if (up) {
1395                                 mTrackList.setSelection(curpos - 1);
1396                         } else {
1397                                 mTrackList.setSelection(curpos + 1);
1398                         }
1399                 } else {
1400                         int colidx = mTrackCursor
1401                                         .getColumnIndexOrThrow(MediaStore.Audio.Playlists.Members.PLAY_ORDER);
1402                         mTrackCursor.moveToPosition(curpos);
1403                         int currentplayidx = mTrackCursor.getInt(colidx);
1404                         Uri baseUri = MediaStore.Audio.Playlists.Members.getContentUri(
1405                                         "external", Long.valueOf(mPlaylist));
1406                         ContentValues values = new ContentValues();
1407                         String where = MediaStore.Audio.Playlists.Members._ID + "=?";
1408                         String[] wherearg = new String[1];
1409                         ContentResolver res = getContentResolver();
1410                         if (up) {
1411                                 values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER,
1412                                                 currentplayidx - 1);
1413                                 wherearg[0] = mTrackCursor.getString(0);
1414                                 res.update(baseUri, values, where, wherearg);
1415                                 mTrackCursor.moveToPrevious();
1416                         } else {
1417                                 values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER,
1418                                                 currentplayidx + 1);
1419                                 wherearg[0] = mTrackCursor.getString(0);
1420                                 res.update(baseUri, values, where, wherearg);
1421                                 mTrackCursor.moveToNext();
1422                         }
1423                         values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER,
1424                                         currentplayidx);
1425                         wherearg[0] = mTrackCursor.getString(0);
1426                         res.update(baseUri, values, where, wherearg);
1427                 }
1428         }
1429
1430         @Override
1431         protected void onListItemClick(ListView l, View v, int position, long id) {
1432                 if (mTrackCursor.getCount() == 0) {
1433                         return;
1434                 }
1435                 // When selecting a track from the queue, just jump there instead of
1436                 // reloading the queue. This is both faster, and prevents accidentally
1437                 // dropping out of party shuffle.
1438                 if (mTrackCursor instanceof NowPlayingCursor) {
1439                         if (MusicUtils.sService != null) {
1440                                 try {
1441                                         MusicUtils.sService.setQueuePosition(position);
1442                                         return;
1443                                 } catch (RemoteException ex) {
1444                                 }
1445                         }
1446                 }
1447                 MusicUtils.playAll(this, mTrackCursor, position);
1448                 if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
1449                         setPauseButtonImage();
1450                 }
1451         }
1452
1453         @Override
1454         public boolean onCreateOptionsMenu(Menu menu) {
1455                 /*
1456                  * This activity is used for a number of different browsing modes, and
1457                  * the menu can be different for each of them: - all tracks, optionally
1458                  * restricted to an album, artist or playlist - the list of currently
1459                  * playing songs
1460                  */
1461                 super.onCreateOptionsMenu(menu);
1462                 if (mPlaylist == null) {
1463                         menu.add(0, PLAY_ALL, 0, R.string.play_all);
1464                 }
1465                 menu.add(0, PARTY_SHUFFLE, 0, R.string.party_shuffle);
1466                 menu.add(0, SHUFFLE_ALL, 0, R.string.shuffle_all);
1467                 menu.add(0, SETTINGS, 0, R.string.settings);
1468
1469                 if (mPlaylist != null) {
1470                         menu.add(0, SAVE_AS_PLAYLIST, 0, R.string.save_as_playlist)
1471                                         .setIcon(android.R.drawable.ic_menu_save);
1472                         if (mPlaylist.equals("nowplaying")) {
1473                                 menu.add(0, CLEAR_PLAYLIST, 0, R.string.clear_playlist);
1474                         }
1475                 }
1476                 return true;
1477         }
1478
1479         @Override
1480         public boolean onPrepareOptionsMenu(Menu menu) {
1481                 MusicUtils.setPartyShuffleMenuIcon(menu);
1482                 return super.onPrepareOptionsMenu(menu);
1483         }
1484
1485         @Override
1486         public boolean onOptionsItemSelected(MenuItem item) {
1487                 Intent intent;
1488                 Cursor cursor;
1489                 switch (item.getItemId()) {
1490                 case android.R.id.home:
1491                         super.onBackPressed();
1492                         return true;
1493                 case PLAY_ALL: {
1494                         MusicUtils.playAll(this, mTrackCursor);
1495                         return true;
1496                 }
1497
1498                 case PARTY_SHUFFLE:
1499                         MusicUtils.togglePartyShuffle();
1500                         break;
1501
1502                 case SHUFFLE_ALL:
1503                         // Should 'shuffle all' shuffle ALL, or only the tracks shown?
1504                         cursor = MusicUtils.query(this,
1505                                         MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
1506                                         new String[] { MediaStore.Audio.Media._ID },
1507                                         MediaStore.Audio.Media.IS_MUSIC + "=1", null,
1508                                         MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
1509                         if (cursor != null) {
1510                                 MusicUtils.shuffleAll(this, cursor);
1511                                 cursor.close();
1512                         }
1513                         return true;
1514
1515                 case SAVE_AS_PLAYLIST:
1516                         intent = new Intent();
1517                         intent.setClass(this, CreatePlaylist.class);
1518                         startActivityForResult(intent, SAVE_AS_PLAYLIST);
1519                         return true;
1520
1521                 case CLEAR_PLAYLIST:
1522                         // We only clear the current playlist
1523                         MusicUtils.clearQueue();
1524                         return true;
1525                 case SETTINGS:
1526                         intent = new Intent();
1527                         intent.setClass(this, MusicSettingsActivity.class);
1528                         startActivityForResult(intent, SETTINGS);
1529                         return true;
1530                 }
1531                 return super.onOptionsItemSelected(item);
1532         }
1533
1534         @Override
1535         protected void onActivityResult(int requestCode, int resultCode,
1536                         Intent intent) {
1537                 switch (requestCode) {
1538                 case SCAN_DONE:
1539                         if (resultCode == RESULT_CANCELED) {
1540                                 finish();
1541                         } else {
1542                                 getTrackCursor(mAdapter.getQueryHandler(), null, true);
1543                         }
1544                         break;
1545
1546                 case NEW_PLAYLIST:
1547                         if (resultCode == RESULT_OK) {
1548                                 Uri uri = intent.getData();
1549                                 if (uri != null) {
1550                                         long[] list = new long[] { mSelectedId };
1551                                         MusicUtils.addToPlaylist(this, list,
1552                                                         Integer.valueOf(uri.getLastPathSegment()));
1553                                 }
1554                         }
1555                         break;
1556
1557                 case SAVE_AS_PLAYLIST:
1558                         if (resultCode == RESULT_OK) {
1559                                 Uri uri = intent.getData();
1560                                 if (uri != null) {
1561                                         long[] list = MusicUtils.getSongListForCursor(mTrackCursor);
1562                                         int plid = Integer.parseInt(uri.getLastPathSegment());
1563                                         MusicUtils.addToPlaylist(this, list, plid);
1564                                 }
1565                         }
1566                         break;
1567                 }
1568         }
1569
1570         private Cursor getTrackCursor(
1571                         TrackListAdapter.TrackQueryHandler queryhandler, String filter,
1572                         boolean async) {
1573
1574                 if (queryhandler == null) {
1575                         throw new IllegalArgumentException();
1576                 }
1577
1578                 Cursor ret = null;
1579                 mSortOrder = MediaStore.Audio.Media.TITLE_KEY;
1580                 StringBuilder where = new StringBuilder();
1581                 where.append(MediaStore.Audio.Media.TITLE + " != ''");
1582
1583                 if (mGenre != null) {
1584                         Uri uri = MediaStore.Audio.Genres.Members.getContentUri("external",
1585                                         Integer.valueOf(mGenre));
1586                         if (!TextUtils.isEmpty(filter)) {
1587                                 uri = uri.buildUpon()
1588                                                 .appendQueryParameter("filter", Uri.encode(filter))
1589                                                 .build();
1590                         }
1591                         mSortOrder = MediaStore.Audio.Genres.Members.DEFAULT_SORT_ORDER;
1592                         ret = queryhandler.doQuery(uri, mCursorCols, where.toString(),
1593                                         null, mSortOrder, async);
1594                 } else if (mPlaylist != null) {
1595                         if (mPlaylist.equals("nowplaying")) {
1596                                 if (MusicUtils.sService != null) {
1597                                         ret = new NowPlayingCursor(MusicUtils.sService, mCursorCols);
1598                                         if (ret.getCount() == 0) {
1599                                                 finish();
1600                                         }
1601                                 } else {
1602                                         // Nothing is playing.
1603                                 }
1604                         } else if (mPlaylist.equals("podcasts")) {
1605                                 where.append(" AND " + MediaStore.Audio.Media.IS_PODCAST + "=1");
1606                                 Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
1607                                 if (!TextUtils.isEmpty(filter)) {
1608                                         uri = uri.buildUpon()
1609                                                         .appendQueryParameter("filter", Uri.encode(filter))
1610                                                         .build();
1611                                 }
1612                                 ret = queryhandler.doQuery(uri, mCursorCols, where.toString(),
1613                                                 null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER, async);
1614                         } else if (mPlaylist.equals("recentlyadded")) {
1615                                 // do a query for all songs added in the last X weeks
1616                                 Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
1617                                 if (!TextUtils.isEmpty(filter)) {
1618                                         uri = uri.buildUpon()
1619                                                         .appendQueryParameter("filter", Uri.encode(filter))
1620                                                         .build();
1621                                 }
1622                                 int X = MusicUtils.getIntPref(this, "numweeks", 2)
1623                                                 * (3600 * 24 * 7);
1624                                 where.append(" AND " + MediaStore.MediaColumns.DATE_ADDED + ">");
1625                                 where.append(System.currentTimeMillis() / 1000 - X);
1626                                 ret = queryhandler.doQuery(uri, mCursorCols, where.toString(),
1627                                                 null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER, async);
1628                         } else {
1629                                 Uri uri = MediaStore.Audio.Playlists.Members.getContentUri(
1630                                                 "external", Long.valueOf(mPlaylist));
1631                                 if (!TextUtils.isEmpty(filter)) {
1632                                         uri = uri.buildUpon()
1633                                                         .appendQueryParameter("filter", Uri.encode(filter))
1634                                                         .build();
1635                                 }
1636                                 mSortOrder = MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER;
1637                                 ret = queryhandler.doQuery(uri, mPlaylistMemberCols,
1638                                                 where.toString(), null, mSortOrder, async);
1639                         }
1640                 } else {
1641                         if (mAlbumId != null) {
1642                                 where.append(" AND " + MediaStore.Audio.Media.ALBUM_ID + "="
1643                                                 + mAlbumId);
1644                                 mSortOrder = MediaStore.Audio.Media.TRACK + ", " + mSortOrder;
1645                         }
1646                         if (mArtistId != null) {
1647                                 where.append(" AND " + MediaStore.Audio.Media.ARTIST_ID + "="
1648                                                 + mArtistId);
1649                         }
1650                         where.append(" AND " + MediaStore.Audio.Media.IS_MUSIC + "=1");
1651                         Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
1652                         if (!TextUtils.isEmpty(filter)) {
1653                                 uri = uri.buildUpon()
1654                                                 .appendQueryParameter("filter", Uri.encode(filter))
1655                                                 .build();
1656                         }
1657                         ret = queryhandler.doQuery(uri, mCursorCols, where.toString(),
1658                                         null, mSortOrder, async);
1659                 }
1660
1661                 // This special case is for the "nowplaying" cursor, which cannot be
1662                 // handled
1663                 // asynchronously using AsyncQueryHandler, so we do some extra
1664                 // initialization here.
1665                 if (ret != null && async) {
1666                         init(ret, false);
1667                         setTitle();
1668                 }
1669                 return ret;
1670         }
1671
1672         private class NowPlayingCursor extends AbstractCursor {
1673                 public NowPlayingCursor(IMediaPlaybackService service, String[] cols) {
1674                         mCols = cols;
1675                         mService = service;
1676                         makeNowPlayingCursor();
1677                 }
1678
1679                 private void makeNowPlayingCursor() {
1680                         mCurrentPlaylistCursor = null;
1681                         try {
1682                                 mNowPlaying = mService.getQueue();
1683                         } catch (RemoteException ex) {
1684                                 mNowPlaying = new long[0];
1685                         }
1686                         mSize = mNowPlaying.length;
1687                         if (mSize == 0) {
1688                                 return;
1689                         }
1690
1691                         StringBuilder where = new StringBuilder();
1692                         where.append(MediaStore.Audio.Media._ID + " IN (");
1693                         for (int i = 0; i < mSize; i++) {
1694                                 where.append(mNowPlaying[i]);
1695                                 if (i < mSize - 1) {
1696                                         where.append(",");
1697                                 }
1698                         }
1699                         where.append(")");
1700
1701                         mCurrentPlaylistCursor = MusicUtils.query(
1702                                         TrackBrowserActivity.this,
1703                                         MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, mCols,
1704                                         where.toString(), null, MediaStore.Audio.Media._ID);
1705
1706                         if (mCurrentPlaylistCursor == null) {
1707                                 mSize = 0;
1708                                 return;
1709                         }
1710
1711                         int size = mCurrentPlaylistCursor.getCount();
1712                         mCursorIdxs = new long[size];
1713                         mCurrentPlaylistCursor.moveToFirst();
1714                         int colidx = mCurrentPlaylistCursor
1715                                         .getColumnIndexOrThrow(MediaStore.Audio.Media._ID);
1716                         for (int i = 0; i < size; i++) {
1717                                 mCursorIdxs[i] = mCurrentPlaylistCursor.getLong(colidx);
1718                                 mCurrentPlaylistCursor.moveToNext();
1719                         }
1720                         mCurrentPlaylistCursor.moveToFirst();
1721                         mCurPos = -1;
1722
1723                         // At this point we can verify the 'now playing' list we got
1724                         // earlier to make sure that all the items in there still exist
1725                         // in the database, and remove those that aren't. This way we
1726                         // don't get any blank items in the list.
1727                         try {
1728                                 int removed = 0;
1729                                 for (int i = mNowPlaying.length - 1; i >= 0; i--) {
1730                                         long trackid = mNowPlaying[i];
1731                                         int crsridx = Arrays.binarySearch(mCursorIdxs, trackid);
1732                                         if (crsridx < 0) {
1733                                                 // Log.i("@@@@@", "item no longer exists in db: " +
1734                                                 // trackid);
1735                                                 removed += mService.removeTrack(trackid);
1736                                         }
1737                                 }
1738                                 if (removed > 0) {
1739                                         mNowPlaying = mService.getQueue();
1740                                         mSize = mNowPlaying.length;
1741                                         if (mSize == 0) {
1742                                                 mCursorIdxs = null;
1743                                                 return;
1744                                         }
1745                                 }
1746                         } catch (RemoteException ex) {
1747                                 mNowPlaying = new long[0];
1748                         }
1749                 }
1750
1751                 @Override
1752                 public int getCount() {
1753                         return mSize;
1754                 }
1755
1756                 @Override
1757                 public boolean onMove(int oldPosition, int newPosition) {
1758                         if (oldPosition == newPosition)
1759                                 return true;
1760
1761                         if (mNowPlaying == null || mCursorIdxs == null
1762                                         || newPosition >= mNowPlaying.length) {
1763                                 return false;
1764                         }
1765
1766                         // The cursor doesn't have any duplicates in it, and is not ordered
1767                         // in queue-order, so we need to figure out where in the cursor we
1768                         // should be.
1769
1770                         long newid = mNowPlaying[newPosition];
1771                         int crsridx = Arrays.binarySearch(mCursorIdxs, newid);
1772                         mCurrentPlaylistCursor.moveToPosition(crsridx);
1773                         mCurPos = newPosition;
1774
1775                         return true;
1776                 }
1777
1778                 public boolean removeItem(int which) {
1779                         try {
1780                                 if (mService.removeTracks(which, which) == 0) {
1781                                         return false; // delete failed
1782                                 }
1783                                 int i = (int) which;
1784                                 mSize--;
1785                                 while (i < mSize) {
1786                                         mNowPlaying[i] = mNowPlaying[i + 1];
1787                                         i++;
1788                                 }
1789                                 onMove(-1, (int) mCurPos);
1790                         } catch (RemoteException ex) {
1791                         }
1792                         return true;
1793                 }
1794
1795                 public void moveItem(int from, int to) {
1796                         try {
1797                                 mService.moveQueueItem(from, to);
1798                                 mNowPlaying = mService.getQueue();
1799                                 onMove(-1, mCurPos); // update the underlying cursor
1800                         } catch (RemoteException ex) {
1801                         }
1802                 }
1803
1804                 private void dump() {
1805                         String where = "(";
1806                         for (int i = 0; i < mSize; i++) {
1807                                 where += mNowPlaying[i];
1808                                 if (i < mSize - 1) {
1809                                         where += ",";
1810                                 }
1811                         }
1812                         where += ")";
1813                         Log.i("NowPlayingCursor: ", where);
1814                 }
1815
1816                 @Override
1817                 public String getString(int column) {
1818                         try {
1819                                 return mCurrentPlaylistCursor.getString(column);
1820                         } catch (Exception ex) {
1821                                 onChange(true);
1822                                 return "";
1823                         }
1824                 }
1825
1826                 @Override
1827                 public short getShort(int column) {
1828                         return mCurrentPlaylistCursor.getShort(column);
1829                 }
1830
1831                 @Override
1832                 public int getInt(int column) {
1833                         try {
1834                                 return mCurrentPlaylistCursor.getInt(column);
1835                         } catch (Exception ex) {
1836                                 onChange(true);
1837                                 return 0;
1838                         }
1839                 }
1840
1841                 @Override
1842                 public long getLong(int column) {
1843                         try {
1844                                 return mCurrentPlaylistCursor.getLong(column);
1845                         } catch (Exception ex) {
1846                                 onChange(true);
1847                                 return 0;
1848                         }
1849                 }
1850
1851                 @Override
1852                 public float getFloat(int column) {
1853                         return mCurrentPlaylistCursor.getFloat(column);
1854                 }
1855
1856                 @Override
1857                 public double getDouble(int column) {
1858                         return mCurrentPlaylistCursor.getDouble(column);
1859                 }
1860
1861                 @Override
1862                 public int getType(int column) {
1863                         return mCurrentPlaylistCursor.getType(column);
1864                 }
1865
1866                 @Override
1867                 public boolean isNull(int column) {
1868                         return mCurrentPlaylistCursor.isNull(column);
1869                 }
1870
1871                 @Override
1872                 public String[] getColumnNames() {
1873                         return mCols;
1874                 }
1875
1876                 @Override
1877                 public void deactivate() {
1878                         if (mCurrentPlaylistCursor != null)
1879                                 mCurrentPlaylistCursor.deactivate();
1880                 }
1881
1882                 @Override
1883                 public boolean requery() {
1884                         makeNowPlayingCursor();
1885                         return true;
1886                 }
1887
1888                 private String[] mCols;
1889                 private Cursor mCurrentPlaylistCursor; // updated in onMove
1890                 private int mSize; // size of the queue
1891                 private long[] mNowPlaying;
1892                 private long[] mCursorIdxs;
1893                 private int mCurPos;
1894                 private IMediaPlaybackService mService;
1895         }
1896
1897         static class TrackListAdapter extends SimpleCursorAdapter implements
1898                         SectionIndexer {
1899                 boolean mIsNowPlaying;
1900                 boolean mDisableNowPlayingIndicator;
1901
1902                 int mTitleIdx;
1903                 int mArtistIdx;
1904                 int mDurationIdx;
1905                 int mAudioIdIdx;
1906                 int mAlbumIdx;
1907
1908                 private final StringBuilder mBuilder = new StringBuilder();
1909                 private final String mUnknownArtist;
1910                 private final String mUnknownAlbum;
1911
1912                 private AlphabetIndexer mIndexer;
1913
1914                 private TrackBrowserActivity mActivity = null;
1915                 private TrackQueryHandler mQueryHandler;
1916                 private String mConstraint = null;
1917                 private boolean mConstraintIsValid = false;
1918
1919                 static class ViewHolder {
1920                         TextView line1;
1921                         TextView line2;
1922                         TextView duration;
1923                         ImageView play_indicator;
1924                         CharArrayBuffer buffer1;
1925                         char[] buffer2;
1926                         ImageView mCM;
1927                         public FrameLayout mContextMenu;
1928                 }
1929
1930                 class TrackQueryHandler extends AsyncQueryHandler {
1931
1932                         class QueryArgs {
1933                                 public Uri uri;
1934                                 public String[] projection;
1935                                 public String selection;
1936                                 public String[] selectionArgs;
1937                                 public String orderBy;
1938                         }
1939
1940                         TrackQueryHandler(ContentResolver res) {
1941                                 super(res);
1942                         }
1943
1944                         public Cursor doQuery(Uri uri, String[] projection,
1945                                         String selection, String[] selectionArgs, String orderBy,
1946                                         boolean async) {
1947                                 if (async) {
1948                                         // Get 100 results first, which is enough to allow the user
1949                                         // to start scrolling,
1950                                         // while still being very fast.
1951                                         Uri limituri = uri.buildUpon()
1952                                                         .appendQueryParameter("limit", "100").build();
1953                                         QueryArgs args = new QueryArgs();
1954                                         args.uri = uri;
1955                                         args.projection = projection;
1956                                         args.selection = selection;
1957                                         args.selectionArgs = selectionArgs;
1958                                         args.orderBy = orderBy;
1959
1960                                         startQuery(0, args, limituri, projection, selection,
1961                                                         selectionArgs, orderBy);
1962                                         return null;
1963                                 }
1964                                 return MusicUtils.query(mActivity, uri, projection, selection,
1965                                                 selectionArgs, orderBy);
1966                         }
1967
1968                         @Override
1969                         protected void onQueryComplete(int token, Object cookie,
1970                                         Cursor cursor) {
1971                                 // Log.i("@@@", "query complete: " + cursor.getCount() + "   " +
1972                                 // mActivity);
1973                                 mActivity.init(cursor, cookie != null);
1974                                 if (token == 0 && cookie != null && cursor != null
1975                                                 && cursor.getCount() >= 100) {
1976                                         QueryArgs args = (QueryArgs) cookie;
1977                                         startQuery(1, null, args.uri, args.projection,
1978                                                         args.selection, args.selectionArgs, args.orderBy);
1979                                 }
1980                         }
1981                 }
1982
1983                 TrackListAdapter(Context context, TrackBrowserActivity currentactivity,
1984                                 int layout, Cursor cursor, String[] from, int[] to,
1985                                 boolean isnowplaying, boolean disablenowplayingindicator) {
1986                         super(context, layout, cursor, from, to);
1987                         mActivity = currentactivity;
1988                         getColumnIndices(cursor);
1989                         mIsNowPlaying = isnowplaying;
1990                         mDisableNowPlayingIndicator = disablenowplayingindicator;
1991                         mUnknownArtist = context.getString(R.string.unknown_artist_name);
1992                         mUnknownAlbum = context.getString(R.string.unknown_album_name);
1993
1994                         mQueryHandler = new TrackQueryHandler(context.getContentResolver());
1995                 }
1996
1997                 public void setActivity(TrackBrowserActivity newactivity) {
1998                         mActivity = newactivity;
1999                 }
2000
2001                 public TrackQueryHandler getQueryHandler() {
2002                         return mQueryHandler;
2003                 }
2004
2005                 private void getColumnIndices(Cursor cursor) {
2006                         if (cursor != null) {
2007                                 mTitleIdx = cursor
2008                                                 .getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE);
2009                                 mArtistIdx = cursor
2010                                                 .getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST);
2011                                 mDurationIdx = cursor
2012                                                 .getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION);
2013                                 mAlbumIdx = cursor
2014                                                 .getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM);
2015
2016                                 try {
2017                                         mAudioIdIdx = cursor
2018                                                         .getColumnIndexOrThrow(MediaStore.Audio.Playlists.Members.AUDIO_ID);
2019                                 } catch (IllegalArgumentException ex) {
2020                                         mAudioIdIdx = cursor
2021                                                         .getColumnIndexOrThrow(MediaStore.Audio.Media._ID);
2022                                 }
2023
2024                                 if (mIndexer != null) {
2025                                         mIndexer.setCursor(cursor);
2026                                 } else if (!mActivity.mEditMode && mActivity.mAlbumId == null) {
2027                                         String alpha = mActivity
2028                                                         .getString(R.string.fast_scroll_alphabet);
2029
2030                                         mIndexer = new MusicAlphabetIndexer(cursor, mTitleIdx,
2031                                                         alpha);
2032                                 }
2033                         }
2034                 }
2035
2036                 private View.OnClickListener mCML = new View.OnClickListener() {
2037                         public void onClick(View v) {
2038                                 v.showContextMenu();
2039
2040                         }
2041                 };
2042
2043                 @Override
2044                 public View newView(Context context, Cursor cursor, ViewGroup parent) {
2045                         View v = super.newView(context, cursor, parent);
2046                         ImageView iv = (ImageView) v.findViewById(R.id.icon);
2047                         iv.setVisibility(View.GONE);
2048
2049                         ViewHolder vh = new ViewHolder();
2050                         vh.line1 = (TextView) v.findViewById(R.id.line1);
2051                         vh.line2 = (TextView) v.findViewById(R.id.line2);
2052                         vh.duration = (TextView) v.findViewById(R.id.duration);
2053                         vh.play_indicator = (ImageView) v.findViewById(R.id.play_indicator);
2054                         vh.buffer1 = new CharArrayBuffer(100);
2055                         vh.buffer2 = new char[200];
2056                         v.setTag(vh);
2057                         vh.mCM = (ImageView) v.findViewById(R.id.CM);
2058                         vh.mContextMenu = (FrameLayout) v
2059                                         .findViewById(R.id.second_column_icon);
2060                         vh.mContextMenu.setOnClickListener(mCML);
2061                         // ADW: Load the specified theme
2062                         String themePackage = MusicUtils.getThemePackageName(context,
2063                                         MusicSettingsActivity.THEME_DEFAULT);
2064                         PackageManager pm = context.getPackageManager();
2065                         Resources themeResources = null;
2066                         if (!themePackage.equals(MusicSettingsActivity.THEME_DEFAULT)) {
2067                                 try {
2068                                         themeResources = pm
2069                                                         .getResourcesForApplication(themePackage);
2070                                 } catch (NameNotFoundException e) {
2071                                         // ADW The saved theme was uninstalled so we save the
2072                                         // default one
2073                                         MusicUtils.setThemePackageName(context,
2074                                                         MusicSettingsActivity.THEME_DEFAULT);
2075                                 }
2076                         }
2077                         if (themeResources != null) {
2078                                 int line1 = themeResources.getIdentifier(
2079                                                 "song_tab_track_name_color", "color", themePackage);
2080                                 if (line1 != 0) {
2081                                         vh.line1.setTextColor(themeResources.getColor(line1));
2082                                 }
2083                                 int line2 = themeResources.getIdentifier(
2084                                                 "song_tab_album_name_color", "color", themePackage);
2085                                 if (line2 != 0) {
2086                                         vh.line2.setTextColor(themeResources.getColor(line2));
2087                                 }
2088                                 int duration = themeResources.getIdentifier(
2089                                                 "song_tab_duration_color", "color", themePackage);
2090                                 if (duration != 0) {
2091                                         vh.duration.setTextColor(themeResources.getColor(duration));
2092                                 }
2093                                 ArtistAlbumBrowserActivity.loadThemeResource(themeResources,
2094                                                 themePackage, "bt_context_menu", vh.mCM,
2095                                                 THEME_ITEM_FOREGROUND);
2096                         }
2097                         return v;
2098                 }
2099
2100                 @Override
2101                 public void bindView(View view, Context context, Cursor cursor) {
2102                         // ADW: Load the specified theme
2103                         String themePackage = MusicUtils.getThemePackageName(context,
2104                                         MusicSettingsActivity.THEME_DEFAULT);
2105                         PackageManager pm = context.getPackageManager();
2106                         Resources themeResources = null;
2107                         if (!themePackage.equals(MusicSettingsActivity.THEME_DEFAULT)) {
2108                                 try {
2109                                         themeResources = pm
2110                                                         .getResourcesForApplication(themePackage);
2111                                 } catch (NameNotFoundException e) {
2112                                         // ADW The saved theme was uninstalled so we save the
2113                                         // default one
2114                                         MusicUtils.setThemePackageName(context,
2115                                                         MusicSettingsActivity.THEME_DEFAULT);
2116                                 }
2117                         }
2118
2119                         ViewHolder vh = (ViewHolder) view.getTag();
2120
2121                         cursor.copyStringToBuffer(mTitleIdx, vh.buffer1);
2122                         vh.line1.setText(vh.buffer1.data, 0, vh.buffer1.sizeCopied);
2123
2124                         int secs = cursor.getInt(mDurationIdx) / 1000;
2125                         if (secs == 0) {
2126                                 vh.duration.setText("");
2127                         } else {
2128                                 vh.duration.setText(MusicUtils.makeTimeString(context, secs));
2129                         }
2130
2131                         final StringBuilder builder = mBuilder;
2132                         builder.delete(0, builder.length());
2133
2134                         String name = cursor.getString(mAlbumIdx);
2135                         if (name == null || name.equals(MediaStore.UNKNOWN_STRING)) {
2136                                 builder.append(mUnknownArtist);
2137                         } else {
2138                                 builder.append(name);
2139                         }
2140                         int len = builder.length();
2141                         if (vh.buffer2.length < len) {
2142                                 vh.buffer2 = new char[len];
2143                         }
2144                         builder.getChars(0, len, vh.buffer2, 0);
2145                         vh.line2.setText(vh.buffer2, 0, len);
2146
2147                         ImageView iv = vh.play_indicator;
2148                         long id = -1;
2149                         if (MusicUtils.sService != null) {
2150                                 // TODO: IPC call on each bind??
2151                                 try {
2152                                         if (mIsNowPlaying) {
2153                                                 id = MusicUtils.sService.getQueuePosition();
2154                                         } else {
2155                                                 id = MusicUtils.sService.getAudioId();
2156                                         }
2157                                 } catch (RemoteException ex) {
2158                                 }
2159                         }
2160
2161                         // Determining whether and where to show the "now playing indicator
2162                         // is tricky, because we don't actually keep track of where the
2163                         // songs
2164                         // in the current playlist came from after they've started playing.
2165                         //
2166                         // If the "current playlists" is shown, then we can simply match by
2167                         // position,
2168                         // otherwise, we need to match by id. Match-by-id gets a little
2169                         // weird if
2170                         // a song appears in a playlist more than once, and you're in
2171                         // edit-playlist
2172                         // mode. In that case, both items will have the "now playing"
2173                         // indicator.
2174                         // For this reason, we don't show the play indicator at all when in
2175                         // edit
2176                         // playlist mode (except when you're viewing the "current playlist",
2177                         // which is not really a playlist)
2178                         if ((mIsNowPlaying && cursor.getPosition() == id)
2179                                         || (!mIsNowPlaying && !mDisableNowPlayingIndicator && cursor
2180                                                         .getLong(mAudioIdIdx) == id)) {
2181                                 iv.setBackgroundResource(R.anim.peak_meter);
2182                                 AnimationDrawable frameAnimation = (AnimationDrawable) iv
2183                                                 .getBackground();
2184                                 if (themeResources != null) {
2185                                         int peak = themeResources.getIdentifier("peak_meter",
2186                                                         "anim", themePackage);
2187                                         if (peak != 0) {
2188                                                 iv.setBackgroundDrawable(themeResources
2189                                                                 .getDrawable(peak));
2190                                                 frameAnimation.start();
2191                                         }
2192                                 }
2193                                 // Start the animation (looped playback by default).
2194                                 frameAnimation.start();
2195                                 iv.setVisibility(View.VISIBLE);
2196                         } else {
2197                                 iv.setVisibility(View.GONE);
2198                         }
2199                 }
2200
2201                 @Override
2202                 public void changeCursor(Cursor cursor) {
2203                         if (mActivity.isFinishing() && cursor != null) {
2204                                 cursor.close();
2205                                 cursor = null;
2206                         }
2207                         if (cursor != mActivity.mTrackCursor) {
2208                                 mActivity.mTrackCursor = cursor;
2209                                 super.changeCursor(cursor);
2210                                 getColumnIndices(cursor);
2211                         }
2212                 }
2213
2214                 @Override
2215                 public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
2216                         String s = constraint.toString();
2217                         if (mConstraintIsValid
2218                                         && ((s == null && mConstraint == null) || (s != null && s
2219                                                         .equals(mConstraint)))) {
2220                                 return getCursor();
2221                         }
2222                         Cursor c = mActivity.getTrackCursor(mQueryHandler, s, false);
2223                         mConstraint = s;
2224                         mConstraintIsValid = true;
2225                         return c;
2226                 }
2227
2228                 // SectionIndexer methods
2229
2230                 public Object[] getSections() {
2231                         if (mIndexer != null) {
2232                                 return mIndexer.getSections();
2233                         } else {
2234                                 return new String[] { " " };
2235                         }
2236                 }
2237
2238                 public int getPositionForSection(int section) {
2239                         if (mIndexer != null) {
2240                                 return mIndexer.getPositionForSection(section);
2241                         }
2242                         return 0;
2243                 }
2244
2245                 public int getSectionForPosition(int position) {
2246                         return 0;
2247                 }
2248         }
2249
2250         // Methods for media control
2251         private void doPauseResume() {
2252                 try {
2253                         if (mService != null) {
2254                                 if (mService.isPlaying()) {
2255                                         mService.pause();
2256                                 } else {
2257                                         mService.play();
2258                                 }
2259                                 if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
2260                                         setPauseButtonImage();
2261                                 }
2262                         }
2263                 } catch (RemoteException ex) {
2264                 }
2265         }
2266
2267         private void setPauseButtonImage() {
2268                 // ADW: Load the specified theme
2269                 String themePackage = MusicUtils.getThemePackageName(this,
2270                                 MusicSettingsActivity.THEME_DEFAULT);
2271                 PackageManager pm = getPackageManager();
2272                 Resources themeResources = null;
2273                 if (!themePackage.equals(MusicSettingsActivity.THEME_DEFAULT)) {
2274                         try {
2275                                 themeResources = pm.getResourcesForApplication(themePackage);
2276                         } catch (NameNotFoundException e) {
2277                                 // ADW The saved theme was uninstalled so we save the
2278                                 // default one
2279                                 MusicUtils.setThemePackageName(this,
2280                                                 MusicSettingsActivity.THEME_DEFAULT);
2281                         }
2282                 }
2283                 try {
2284                         if (mService != null && mService.isPlaying()) {
2285                                 mPlay.setImageResource(R.drawable.ic_media_pause);
2286                                 ArtistAlbumBrowserActivity
2287                                                 .loadThemeResource(themeResources, themePackage,
2288                                                                 "snp_pause", mPlay, THEME_ITEM_FOREGROUND);
2289                         } else {
2290                                 mPlay.setImageResource(R.drawable.ic_appwidget_music_play);
2291                                 ArtistAlbumBrowserActivity.loadThemeResource(themeResources,
2292                                                 themePackage, "snp_play", mPlay, THEME_ITEM_FOREGROUND);
2293                         }
2294                 } catch (RemoteException ex) {
2295                 }
2296         }
2297
2298         private void refreshProgress() {
2299                 ProgressBar mProgress = (ProgressBar) findViewById(R.id.progress);
2300                 mProgress.setMax(1000);
2301                 try {
2302                         if ((MusicUtils.sService.position() >= 0)
2303                                         && (MusicUtils.sService.duration() > 0)) {
2304                                 mProgress.setProgress((int) (1000 * MusicUtils.sService
2305                                                 .position() / MusicUtils.sService.duration()));
2306                         } else {
2307                                 mProgress.setProgress(1000);
2308                         }
2309                 } catch (Exception e) {
2310                         // TODO Auto-generated catch block
2311                         e.printStackTrace();
2312                 }
2313
2314         }
2315
2316         private void doPrev() {
2317                 if (mService == null)
2318                         return;
2319                 try {
2320                         if (mService.position() < 2000) {
2321                                 mService.prev();
2322                         } else {
2323                                 mService.seek(0);
2324                                 mService.play();
2325                         }
2326                         setPauseButtonImage();
2327                 } catch (RemoteException ex) {
2328                 }
2329         }
2330
2331         private void doNext() {
2332                 if (mService == null)
2333                         return;
2334                 try {
2335                         mService.next();
2336                         setPauseButtonImage();
2337                 } catch (RemoteException ex) {
2338                 }
2339         }
2340
2341         private void playRecentlyAdded() {
2342                 // do a query for all songs added in the last X weeks
2343                 int X = MusicUtils.getIntPref(this, "numweeks", 2) * (3600 * 24 * 7);
2344                 final String[] ccols = new String[] { MediaStore.Audio.Media._ID };
2345                 String where = MediaStore.MediaColumns.DATE_ADDED + ">"
2346                                 + (System.currentTimeMillis() / 1000 - X);
2347                 Cursor cursor = MusicUtils.query(this,
2348                                 MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, ccols, where,
2349                                 null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
2350
2351                 if (cursor == null) {
2352                         // Todo: show a message
2353                         return;
2354                 }
2355                 try {
2356                         int len = cursor.getCount();
2357                         long[] list = new long[len];
2358                         for (int i = 0; i < len; i++) {
2359                                 cursor.moveToNext();
2360                                 list[i] = cursor.getLong(0);
2361                         }
2362                         MusicUtils.playAll(this, list, 0);
2363                 } catch (SQLiteException ex) {
2364                 } finally {
2365                         cursor.close();
2366                 }
2367         }
2368
2369         @Override
2370         public boolean onKeyLongPress(int keyCode, KeyEvent event) {
2371                 if (keyCode == KeyEvent.KEYCODE_BACK) {
2372                         back_button_db = mPreferences.getString("back_button_db", "0");
2373                         if (back_button_db.equals("0")) {
2374                                 MusicUtils.togglePartyShuffle();
2375                                 return true;
2376                         }
2377                         if (keyCode == KeyEvent.KEYCODE_BACK) {
2378                                 back_button_db = mPreferences.getString("back_button_db", "1");
2379                                 if (back_button_db.equals("1")) {
2380                                         playRecentlyAdded();
2381                                         return true;
2382                                 }
2383
2384                         }
2385                         if (keyCode == KeyEvent.KEYCODE_BACK) {
2386                                 back_button_db = mPreferences.getString("back_button_db", "2");
2387                                 if (back_button_db.equals("2")) {
2388                                         Cursor cursor;
2389                                         cursor = MusicUtils.query(this,
2390                                                         MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
2391                                                         new String[] { BaseColumns._ID },
2392                                                         AudioColumns.IS_MUSIC + "=1", null,
2393                                                         MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
2394                                         if (cursor != null) {
2395                                                 MusicUtils.shuffleAll(this, cursor);
2396                                                 cursor.close();
2397                                                 return true;
2398                                         }
2399                                 }
2400                         }
2401                 }
2402                 return super.onKeyLongPress(keyCode, event);
2403
2404         }
2405 }