5 package com.andrew.apollo.list.fragments;
\r
7 import android.content.BroadcastReceiver;
\r
8 import android.content.Context;
\r
9 import android.content.Intent;
\r
10 import android.content.IntentFilter;
\r
11 import android.database.Cursor;
\r
12 import android.net.Uri;
\r
13 import android.os.Bundle;
\r
14 import android.provider.BaseColumns;
\r
15 import android.provider.MediaStore.Audio;
\r
16 import android.provider.MediaStore.Audio.Albums;
\r
17 import android.provider.MediaStore.Audio.Artists;
\r
18 import android.provider.MediaStore.Audio.AudioColumns;
\r
19 import android.provider.MediaStore.Audio.Genres;
\r
20 import android.provider.MediaStore.Audio.Playlists;
\r
21 import android.provider.MediaStore.MediaColumns;
\r
22 import android.support.v4.app.Fragment;
\r
23 import android.support.v4.app.LoaderManager.LoaderCallbacks;
\r
24 import android.support.v4.content.CursorLoader;
\r
25 import android.support.v4.content.Loader;
\r
26 import android.view.ContextMenu;
\r
27 import android.view.ContextMenu.ContextMenuInfo;
\r
28 import android.view.LayoutInflater;
\r
29 import android.view.MenuItem;
\r
30 import android.view.View;
\r
31 import android.view.ViewGroup;
\r
32 import android.widget.AdapterView;
\r
33 import android.widget.AdapterView.AdapterContextMenuInfo;
\r
34 import android.widget.AdapterView.OnItemClickListener;
\r
35 import android.widget.LinearLayout;
\r
36 import android.widget.ListView;
\r
37 import android.widget.TextView;
\r
39 import com.andrew.apollo.Constants;
\r
40 import com.andrew.apollo.NowPlayingCursor;
\r
41 import com.andrew.apollo.R;
\r
42 import com.andrew.apollo.adapters.TrackAdapter;
\r
43 import com.andrew.apollo.service.ApolloService;
\r
44 import com.andrew.apollo.utils.ApolloUtils;
\r
45 import com.andrew.apollo.utils.MusicUtils;
\r
48 * @author Andrew Neal
\r
50 public class TracksFragment extends Fragment implements LoaderCallbacks<Cursor>,
\r
51 OnItemClickListener, Constants {
\r
54 private TrackAdapter mTrackAdapter;
\r
57 private ListView mListView;
\r
60 private Cursor mCursor;
\r
63 private long mPlaylistId = -1;
\r
65 // Selected position
\r
66 private int mSelectedPosition;
\r
68 // Used to set ringtone
\r
69 private long mSelectedId;
\r
72 private final int PLAY_SELECTION = 6;
\r
74 private final int USE_AS_RINGTONE = 7;
\r
76 private final int ADD_TO_PLAYLIST = 8;
\r
78 private final int SEARCH = 9;
\r
80 private final int REMOVE = 10;
\r
82 private boolean mEditMode = false;
\r
85 public static int mTitleIndex, mAlbumIndex, mArtistIndex, mMediaIdIndex;
\r
88 public TracksFragment() {
\r
91 public TracksFragment(Bundle args) {
\r
96 public void onActivityCreated(Bundle savedInstanceState) {
\r
97 super.onActivityCreated(savedInstanceState);
\r
102 mTrackAdapter = new TrackAdapter(getActivity(), R.layout.listview_items, null,
\r
103 new String[] {}, new int[] {}, 0);
\r
104 mListView.setOnCreateContextMenuListener(this);
\r
105 mListView.setOnItemClickListener(this);
\r
106 mListView.setAdapter(mTrackAdapter);
\r
109 getLoaderManager().initLoader(0, null, this);
\r
113 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
\r
114 View root = inflater.inflate(R.layout.listview, container, false);
\r
115 mListView = (ListView)root.findViewById(android.R.id.list);
\r
117 // Align the track list with the header, in other words,OCD.
\r
118 TextView mHeader = (TextView)root.findViewById(R.id.title);
\r
119 int eight = (int)getActivity().getResources().getDimension(
\r
120 R.dimen.list_separator_padding_left_right);
\r
121 mHeader.setPadding(eight, 0, 0, 0);
\r
123 // Set the header while in @TracksBrowser
\r
124 String header = getActivity().getResources().getString(R.string.track_header);
\r
125 int left = getActivity().getResources().getInteger(R.integer.listview_padding_left);
\r
126 int right = getActivity().getResources().getInteger(R.integer.listview_padding_right);
\r
127 ApolloUtils.listHeader(this, root, header);
\r
128 ApolloUtils.setListPadding(this, mListView, left, 0, right, 0);
\r
130 // Hide the extra spacing from the Bottom ActionBar in the queue
\r
131 // Fragment in @AudioPlayerHolder
\r
132 if (getArguments() != null) {
\r
133 mPlaylistId = getArguments().getLong(BaseColumns._ID);
\r
134 String mimeType = getArguments().getString(MIME_TYPE);
\r
135 if (Audio.Playlists.CONTENT_TYPE.equals(mimeType)) {
\r
136 switch ((int)mPlaylistId) {
\r
137 case (int)PLAYLIST_QUEUE:
\r
138 LinearLayout emptyness = (LinearLayout)root.findViewById(R.id.empty_view);
\r
139 emptyness.setVisibility(View.GONE);
\r
147 public Loader<Cursor> onCreateLoader(int id, Bundle args) {
\r
148 String[] projection = new String[] {
\r
149 BaseColumns._ID, MediaColumns.TITLE, AudioColumns.ALBUM, AudioColumns.ARTIST
\r
151 StringBuilder where = new StringBuilder();
\r
152 String sortOrder = Audio.Media.DEFAULT_SORT_ORDER;
\r
153 where.append(AudioColumns.IS_MUSIC + "=1").append(" AND " + MediaColumns.TITLE + " != ''");
\r
154 Uri uri = Audio.Media.EXTERNAL_CONTENT_URI;
\r
155 if (getArguments() != null) {
\r
156 mPlaylistId = getArguments().getLong(BaseColumns._ID);
\r
157 String mimeType = getArguments().getString(MIME_TYPE);
\r
158 if (Audio.Playlists.CONTENT_TYPE.equals(mimeType)) {
\r
159 where = new StringBuilder();
\r
160 where.append(AudioColumns.IS_MUSIC + "=1");
\r
161 where.append(" AND " + MediaColumns.TITLE + " != ''");
\r
162 switch ((int)mPlaylistId) {
\r
163 case (int)PLAYLIST_QUEUE:
\r
164 uri = Audio.Media.EXTERNAL_CONTENT_URI;
\r
165 long[] mNowPlaying = MusicUtils.getQueue();
\r
166 if (mNowPlaying.length == 0)
\r
168 where = new StringBuilder();
\r
169 where.append(BaseColumns._ID + " IN (");
\r
170 if (mNowPlaying == null || mNowPlaying.length <= 0)
\r
172 for (long queue_id : mNowPlaying) {
\r
173 where.append(queue_id + ",");
\r
175 where.deleteCharAt(where.length() - 1);
\r
178 case (int)PLAYLIST_FAVORITES:
\r
179 long favorites_id = MusicUtils.getFavoritesId(getActivity());
\r
180 projection = new String[] {
\r
181 Playlists.Members._ID, Playlists.Members.AUDIO_ID,
\r
182 MediaColumns.TITLE, AudioColumns.ALBUM, AudioColumns.ARTIST
\r
184 uri = Playlists.Members.getContentUri(EXTERNAL, favorites_id);
\r
185 sortOrder = Playlists.Members.DEFAULT_SORT_ORDER;
\r
190 projection = new String[] {
\r
191 Playlists.Members._ID, Playlists.Members.AUDIO_ID,
\r
192 MediaColumns.TITLE, AudioColumns.ALBUM, AudioColumns.ARTIST,
\r
193 AudioColumns.DURATION
\r
196 uri = Playlists.Members.getContentUri(EXTERNAL, mPlaylistId);
\r
197 sortOrder = Playlists.Members.DEFAULT_SORT_ORDER;
\r
200 } else if (Audio.Genres.CONTENT_TYPE.equals(mimeType)) {
\r
201 long genreId = getArguments().getLong(BaseColumns._ID);
\r
202 uri = Genres.Members.getContentUri(EXTERNAL, genreId);
\r
203 projection = new String[] {
\r
204 BaseColumns._ID, MediaColumns.TITLE, AudioColumns.ALBUM,
\r
205 AudioColumns.ARTIST
\r
207 where = new StringBuilder();
\r
208 where.append(AudioColumns.IS_MUSIC + "=1").append(
\r
209 " AND " + MediaColumns.TITLE + " != ''");
\r
210 sortOrder = Genres.Members.DEFAULT_SORT_ORDER;
\r
212 if (Audio.Albums.CONTENT_TYPE.equals(mimeType)) {
\r
213 long albumId = getArguments().getLong(BaseColumns._ID);
\r
214 where.append(" AND " + AudioColumns.ALBUM_ID + "=" + albumId);
\r
215 sortOrder = Audio.Media.TRACK + ", " + sortOrder;
\r
216 } else if (Audio.Artists.CONTENT_TYPE.equals(mimeType)) {
\r
217 sortOrder = MediaColumns.TITLE;
\r
218 long artist_id = getArguments().getLong(BaseColumns._ID);
\r
219 where.append(" AND " + AudioColumns.ARTIST_ID + "=" + artist_id);
\r
223 return new CursorLoader(getActivity(), uri, projection, where.toString(), null, sortOrder);
\r
227 public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
\r
228 // Check for database errors
\r
229 if (data == null) {
\r
233 if (getArguments() != null
\r
234 && Playlists.CONTENT_TYPE.equals(getArguments().getString(MIME_TYPE))
\r
235 && (getArguments().getLong(BaseColumns._ID) >= 0 || getArguments().getLong(
\r
236 BaseColumns._ID) == PLAYLIST_FAVORITES)) {
\r
237 mMediaIdIndex = data.getColumnIndexOrThrow(Playlists.Members.AUDIO_ID);
\r
238 mTitleIndex = data.getColumnIndexOrThrow(MediaColumns.TITLE);
\r
239 mAlbumIndex = data.getColumnIndexOrThrow(AudioColumns.ALBUM);
\r
242 // data.getColumnIndexOrThrow(Playlists.Members.ARTIST);
\r
243 } else if (getArguments() != null
\r
244 && Genres.CONTENT_TYPE.equals(getArguments().getString(MIME_TYPE))) {
\r
245 mMediaIdIndex = data.getColumnIndexOrThrow(BaseColumns._ID);
\r
246 mTitleIndex = data.getColumnIndexOrThrow(MediaColumns.TITLE);
\r
247 mArtistIndex = data.getColumnIndexOrThrow(AudioColumns.ARTIST);
\r
248 mAlbumIndex = data.getColumnIndexOrThrow(AudioColumns.ALBUM);
\r
249 } else if (getArguments() != null
\r
250 && Artists.CONTENT_TYPE.equals(getArguments().getString(MIME_TYPE))) {
\r
251 mTitleIndex = data.getColumnIndexOrThrow(MediaColumns.TITLE);
\r
252 // mArtistIndex is "line2" of the ListView
\r
253 mArtistIndex = data.getColumnIndexOrThrow(AudioColumns.ALBUM);
\r
254 } else if (getArguments() != null
\r
255 && Albums.CONTENT_TYPE.equals(getArguments().getString(MIME_TYPE))) {
\r
256 mMediaIdIndex = data.getColumnIndexOrThrow(BaseColumns._ID);
\r
257 mTitleIndex = data.getColumnIndexOrThrow(MediaColumns.TITLE);
\r
258 mArtistIndex = data.getColumnIndexOrThrow(AudioColumns.ARTIST);
\r
260 mMediaIdIndex = data.getColumnIndexOrThrow(BaseColumns._ID);
\r
261 mTitleIndex = data.getColumnIndexOrThrow(MediaColumns.TITLE);
\r
262 mArtistIndex = data.getColumnIndexOrThrow(AudioColumns.ARTIST);
\r
263 mAlbumIndex = data.getColumnIndexOrThrow(AudioColumns.ALBUM);
\r
265 mTrackAdapter.changeCursor(data);
\r
270 public void onLoaderReset(Loader<Cursor> loader) {
\r
271 if (mTrackAdapter != null)
\r
272 mTrackAdapter.changeCursor(null);
\r
276 public void onSaveInstanceState(Bundle outState) {
\r
277 outState.putAll(getArguments() != null ? getArguments() : new Bundle());
\r
278 super.onSaveInstanceState(outState);
\r
282 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
\r
283 menu.add(0, PLAY_SELECTION, 0, getResources().getString(R.string.play_all));
\r
284 menu.add(0, ADD_TO_PLAYLIST, 0, getResources().getString(R.string.add_to_playlist));
\r
285 menu.add(0, USE_AS_RINGTONE, 0, getResources().getString(R.string.use_as_ringtone));
\r
287 menu.add(0, REMOVE, 0, R.string.remove);
\r
289 menu.add(0, SEARCH, 0, getResources().getString(R.string.search));
\r
291 AdapterContextMenuInfo mi = (AdapterContextMenuInfo)menuInfo;
\r
292 mSelectedPosition = mi.position;
\r
293 mCursor.moveToPosition(mSelectedPosition);
\r
296 mSelectedId = mCursor.getLong(mMediaIdIndex);
\r
297 } catch (IllegalArgumentException ex) {
\r
298 mSelectedId = mi.id;
\r
301 String title = mCursor.getString(mTitleIndex);
\r
302 menu.setHeaderTitle(title);
\r
303 super.onCreateContextMenu(menu, v, menuInfo);
\r
307 public boolean onContextItemSelected(MenuItem item) {
\r
308 switch (item.getItemId()) {
\r
309 case PLAY_SELECTION:
\r
310 int position = mSelectedPosition;
\r
311 MusicUtils.playAll(getActivity(), mCursor, position);
\r
313 case ADD_TO_PLAYLIST: {
\r
314 Intent intent = new Intent(INTENT_ADD_TO_PLAYLIST);
\r
315 long[] list = new long[] {
\r
318 intent.putExtra(INTENT_PLAYLIST_LIST, list);
\r
319 getActivity().startActivity(intent);
\r
322 case USE_AS_RINGTONE:
\r
323 MusicUtils.setRingtone(getActivity(), mSelectedId);
\r
326 removePlaylistItem(mSelectedPosition);
\r
330 MusicUtils.doSearch(getActivity(), mCursor, mTitleIndex);
\r
336 return super.onContextItemSelected(item);
\r
340 public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
\r
341 if (mCursor instanceof NowPlayingCursor) {
\r
342 if (MusicUtils.mService != null) {
\r
343 MusicUtils.setQueuePosition(position);
\r
347 MusicUtils.playAll(getActivity(), mCursor, position);
\r
351 * Update the list as needed
\r
353 private final BroadcastReceiver mMediaStatusReceiver = new BroadcastReceiver() {
\r
356 public void onReceive(Context context, Intent intent) {
\r
357 if (mListView != null) {
\r
358 mTrackAdapter.notifyDataSetChanged();
\r
359 // Scroll to the currently playing track in the queue
\r
360 if (mPlaylistId == PLAYLIST_QUEUE)
\r
361 mListView.postDelayed(new Runnable() {
\r
363 public void run() {
\r
364 mListView.setSelection(MusicUtils.getQueuePosition());
\r
373 public void onStart() {
\r
376 IntentFilter filter = new IntentFilter();
\r
377 filter.addAction(ApolloService.META_CHANGED);
\r
378 filter.addAction(ApolloService.QUEUE_CHANGED);
\r
379 filter.addAction(ApolloService.PLAYSTATE_CHANGED);
\r
380 getActivity().registerReceiver(mMediaStatusReceiver, filter);
\r
384 public void onStop() {
\r
385 getActivity().unregisterReceiver(mMediaStatusReceiver);
\r
392 private void removePlaylistItem(int which) {
\r
394 mCursor.moveToPosition(which);
\r
395 long id = mCursor.getLong(mMediaIdIndex);
\r
396 if (mPlaylistId >= 0) {
\r
397 Uri uri = Playlists.Members.getContentUri(EXTERNAL, mPlaylistId);
\r
398 getActivity().getContentResolver().delete(uri, Playlists.Members.AUDIO_ID + "=" + id,
\r
400 } else if (mPlaylistId == PLAYLIST_QUEUE) {
\r
401 MusicUtils.removeTrack(id);
\r
402 reloadQueueCursor();
\r
403 } else if (mPlaylistId == PLAYLIST_FAVORITES) {
\r
404 MusicUtils.removeFromFavorites(getActivity(), id);
\r
406 mListView.invalidateViews();
\r
410 * Reload the queue after we remove a track
\r
412 private void reloadQueueCursor() {
\r
413 if (mPlaylistId == PLAYLIST_QUEUE) {
\r
414 String[] cols = new String[] {
\r
415 BaseColumns._ID, MediaColumns.TITLE, MediaColumns.DATA, AudioColumns.ALBUM,
\r
416 AudioColumns.ARTIST, AudioColumns.ARTIST_ID
\r
418 StringBuilder selection = new StringBuilder();
\r
419 selection.append(AudioColumns.IS_MUSIC + "=1");
\r
420 selection.append(" AND " + MediaColumns.TITLE + " != ''");
\r
421 Uri uri = Audio.Media.EXTERNAL_CONTENT_URI;
\r
422 long[] mNowPlaying = MusicUtils.getQueue();
\r
423 if (mNowPlaying.length == 0) {
\r
425 selection = new StringBuilder();
\r
426 selection.append(BaseColumns._ID + " IN (");
\r
427 for (int i = 0; i < mNowPlaying.length; i++) {
\r
428 selection.append(mNowPlaying[i]);
\r
429 if (i < mNowPlaying.length - 1) {
\r
430 selection.append(",");
\r
433 selection.append(")");
\r
434 mCursor = MusicUtils.query(getActivity(), uri, cols, selection.toString(), null, null);
\r
435 mTrackAdapter.changeCursor(mCursor);
\r
440 * Check if we're viewing the contents of a playlist
\r
442 public void isEditMode() {
\r
443 if (getArguments() != null) {
\r
444 String mimetype = getArguments().getString(MIME_TYPE);
\r
445 if (Audio.Playlists.CONTENT_TYPE.equals(mimetype)) {
\r
446 mPlaylistId = getArguments().getLong(BaseColumns._ID);
\r
447 switch ((int)mPlaylistId) {
\r
448 case (int)PLAYLIST_QUEUE:
\r
451 case (int)PLAYLIST_FAVORITES:
\r
455 if (mPlaylistId > 0) {
\r