Java tutorial
/* * YAMMP - Yet Another Multi Media Player for android * Copyright (C) 2011-2012 Mariotaku Lee <mariotaku.lee@gmail.com> * * This file is part of YAMMP. * * YAMMP is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * YAMMP is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with YAMMP. If not, see <http://www.gnu.org/licenses/>. */ package org.yammp.fragment; import java.io.File; import org.yammp.Constants; import org.yammp.R; import org.yammp.YAMMPApplication; import org.yammp.app.TrackBrowserActivity; import org.yammp.dialog.DeleteDialogFragment; import org.yammp.util.LazyImageLoader; import org.yammp.util.MediaUtils; import android.app.SearchManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import android.provider.MediaStore.Audio; import android.support.v4.app.FragmentTransaction; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v4.widget.SimpleCursorAdapter; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; import android.view.View.OnCreateContextMenuListener; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ExpandableListView; import android.widget.ExpandableListView.ExpandableListContextMenuInfo; import android.widget.ExpandableListView.OnGroupExpandListener; import android.widget.GridView; import android.widget.ImageView; import android.widget.SimpleCursorTreeAdapter; import android.widget.TextView; import com.actionbarsherlock.app.SherlockFragment; public class ArtistFragment extends SherlockFragment implements LoaderManager.LoaderCallbacks<Cursor>, Constants, OnGroupExpandListener, OnItemSelectedListener { private ArtistsAdapter mArtistsAdapter; private ExpandableListView mListView; private int mSelectedGroupPosition; private long mSelectedGroupId, mSelectedChildId; private Cursor mGroupCursor; private String mCurrentGroupArtistName, mCurrentChildArtistNameForAlbum, mCurrentChildAlbumName; private boolean mGroupSelected, mChildSelected = false; private LazyImageLoader mImageLoader; private int mGroupArtistIdIdx, mGroupArtistIdx, mGroupAlbumIdx, mGroupSongIdx; private BroadcastReceiver mMediaStatusReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { mListView.invalidateViews(); } }; private MediaUtils mUtils; public ArtistFragment() { } public ArtistFragment(Bundle args) { setArguments(args); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mUtils = ((YAMMPApplication) getSherlockActivity().getApplication()).getMediaUtils(); setHasOptionsMenu(true); mImageLoader = ((YAMMPApplication) getSherlockActivity().getApplication()).getLazyImageLoader(); mArtistsAdapter = new ArtistsAdapter(getSherlockActivity(), null, R.layout.artist_list_item_group, new String[] {}, new int[] {}, R.layout.artist_list_item_child, new String[] {}, new int[] {}); mListView = (ExpandableListView) getView().findViewById(R.id.artist_expandable_list); mListView.setAdapter(mArtistsAdapter); mListView.setOnGroupExpandListener(this); mListView.setOnCreateContextMenuListener(this); mListView.setOnItemSelectedListener(this); registerForContextMenu(mListView); getLoaderManager().initLoader(0, null, this); } @Override public boolean onContextItemSelected(MenuItem item) { if (item.getGroupId() == hashCode()) { switch (item.getItemId()) { case PLAY_SELECTION: if (mGroupSelected && !mChildSelected) { long[] list = mUtils.getSongListForArtist(mSelectedGroupId); mUtils.playAll(list, 0); } else if (mChildSelected && !mGroupSelected) { long[] list = mUtils.getSongListForAlbum(mSelectedChildId); mUtils.playAll(list, 0); } return true; case DELETE_ITEMS: if (mGroupSelected && !mChildSelected) { DeleteDialogFragment.getInstance(false, mSelectedGroupId, DeleteDialogFragment.ARTIST) .show(getFragmentManager(), "dialog"); } else if (mChildSelected && !mGroupSelected) { DeleteDialogFragment.getInstance(false, mSelectedChildId, DeleteDialogFragment.ARTIST) .show(getFragmentManager(), "dialog"); } return true; case DELETE_LYRICS: if (mGroupSelected && !mChildSelected) { DeleteDialogFragment.getInstance(true, mSelectedGroupId, DeleteDialogFragment.ARTIST) .show(getFragmentManager(), "dialog"); } else if (mChildSelected && !mGroupSelected) { DeleteDialogFragment.getInstance(true, mSelectedChildId, DeleteDialogFragment.ARTIST) .show(getFragmentManager(), "dialog"); } return true; case SEARCH: if (mGroupSelected && !mChildSelected) { doSearch(mCurrentGroupArtistName, null); } else if (mChildSelected && !mGroupSelected) { doSearch(mCurrentChildArtistNameForAlbum, mCurrentChildAlbumName); } return true; } } return super.onContextItemSelected(item); } @Override public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) { ExpandableListContextMenuInfo mi = (ExpandableListContextMenuInfo) info; int itemtype = ExpandableListView.getPackedPositionType(mi.packedPosition); mSelectedGroupPosition = ExpandableListView.getPackedPositionGroup(mi.packedPosition); int gpos = mSelectedGroupPosition; if (itemtype == ExpandableListView.PACKED_POSITION_TYPE_GROUP) { mGroupSelected = true; mChildSelected = false; mGroupCursor.moveToPosition(gpos); menu.add(hashCode(), PLAY_SELECTION, 0, R.string.play_selection); menu.add(hashCode(), DELETE_ITEMS, 0, R.string.delete_music); menu.add(hashCode(), DELETE_LYRICS, 0, R.string.delete_lyrics); if (gpos == -1) { // this shouldn't happen Log.d("Artist/Album", "no group"); return; } mCurrentGroupArtistName = mGroupCursor.getString(mGroupArtistIdx); mSelectedGroupId = mGroupCursor.getLong(mGroupArtistIdIdx); if (mCurrentGroupArtistName != null && !MediaStore.UNKNOWN_STRING.equals(mCurrentGroupArtistName)) { menu.setHeaderTitle(mCurrentGroupArtistName); menu.add(hashCode(), SEARCH, 0, android.R.string.search_go); } else { menu.setHeaderTitle(getString(R.string.unknown_artist)); } } } @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { String[] cols = new String[] { Audio.Artists._ID, Audio.Artists.ARTIST, Audio.Artists.NUMBER_OF_ALBUMS, Audio.Artists.NUMBER_OF_TRACKS }; Uri uri = Audio.Artists.EXTERNAL_CONTENT_URI; return new CursorLoader(getSherlockActivity(), uri, cols, null, null, Audio.Artists.DEFAULT_SORT_ORDER); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.artist_album_browser, container, false); return view; } @Override public void onGroupExpand(int position) { long id = mArtistsAdapter.getGroupId(position); showGroupDetails(position, id); } @Override public void onItemSelected(AdapterView<?> adapter, View view, int position, long id) { if (view.getTag() != null && view.getTag() instanceof ViewHolderChild) { mListView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); ((ViewHolderChild) view.getTag()).gridview.requestFocus(); } else { mListView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS); mListView.requestFocus(); } } @Override public void onLoaderReset(Loader<Cursor> loader) { mArtistsAdapter.setGroupCursor(null); } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { if (data == null) { getSherlockActivity().finish(); return; } mGroupCursor = data; mGroupArtistIdIdx = data.getColumnIndexOrThrow(Audio.Artists._ID); mGroupArtistIdx = data.getColumnIndexOrThrow(Audio.Artists.ARTIST); mGroupAlbumIdx = data.getColumnIndexOrThrow(Audio.Artists.NUMBER_OF_ALBUMS); mGroupSongIdx = data.getColumnIndexOrThrow(Audio.Artists.NUMBER_OF_TRACKS); mArtistsAdapter.changeCursor(data); } @Override public void onNothingSelected(AdapterView<?> arg0) { if (!mListView.isFocused()) { mListView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS); mListView.requestFocus(); } } @Override public void onSaveInstanceState(Bundle outState) { outState.putAll(getArguments() != null ? getArguments() : new Bundle()); super.onSaveInstanceState(outState); } @Override public void onStart() { super.onStart(); IntentFilter filter = new IntentFilter(); filter.addAction(BROADCAST_META_CHANGED); filter.addAction(BROADCAST_QUEUE_CHANGED); getSherlockActivity().registerReceiver(mMediaStatusReceiver, filter); } @Override public void onStop() { getSherlockActivity().unregisterReceiver(mMediaStatusReceiver); super.onStop(); } private void doSearch(String artist, String album) { CharSequence title = null; String query = null; boolean isUnknownArtist = artist == null || MediaStore.UNKNOWN_STRING.equals(artist); boolean isUnknownAlbum = album == null || MediaStore.UNKNOWN_STRING.equals(album); if (isUnknownArtist && isUnknownAlbum) return; Intent i = new Intent(); i.setAction(MediaStore.INTENT_ACTION_MEDIA_SEARCH); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); title = album != null ? album : artist; query = album != null ? album : artist; if (!isUnknownArtist) { i.putExtra(MediaStore.EXTRA_MEDIA_ARTIST, artist); } if (!isUnknownAlbum) { i.putExtra(MediaStore.EXTRA_MEDIA_ALBUM, album); } i.putExtra(MediaStore.EXTRA_MEDIA_FOCUS, "audio/*"); title = getString(R.string.mediasearch, title); i.putExtra(SearchManager.QUERY, query); startActivity(Intent.createChooser(i, title)); } private void showGroupDetails(int groupPosition, long id) { View detailsFrame = getSherlockActivity().findViewById(R.id.frame_details); boolean mDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE; if (mDualPane) { mListView.setSelectedGroup(groupPosition); TrackFragment fragment = new TrackFragment(); Bundle args = new Bundle(); args.putString(INTENT_KEY_TYPE, MediaStore.Audio.Artists.CONTENT_TYPE); args.putLong(Audio.Artists._ID, id); fragment.setArguments(args); FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.replace(R.id.frame_details, fragment); ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); ft.commit(); } } private class AlbumChildAdapter extends SimpleCursorAdapter implements OnCreateContextMenuListener { private int mAlbumIndex; private int mArtistIndex; private int mAlbumArtIndex; private AlbumChildAdapter(Context context, int layout, Cursor cursor, String[] from, int[] to, int flags) { super(context, layout, cursor, from, to, flags); getColumnIndices(cursor); } @Override public void bindView(View view, Context context, Cursor cursor) { view.setOnCreateContextMenuListener(this); ViewHolderItem viewholder = (ViewHolderItem) view.getTag(); if (viewholder == null) return; String album_name = cursor.getString(mAlbumIndex); boolean unknown = album_name == null || album_name.equals(MediaStore.UNKNOWN_STRING); if (unknown) { album_name = context.getString(R.string.unknown_album); } viewholder.album_name.setText(album_name); String artist_name = cursor.getString(mArtistIndex); if (artist_name == null || artist_name.equals(MediaStore.UNKNOWN_STRING)) { artist_name = context.getString(R.string.unknown_artist); } viewholder.artist_name.setText(artist_name); long aid = cursor.getLong(0); long currentalbumid = mUtils.getCurrentAlbumId(); if (currentalbumid == aid) { viewholder.album_name.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_indicator_nowplaying_small, 0); } else { viewholder.album_name.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); } String art = cursor.getString(mAlbumArtIndex); if (art != null && art.toString().length() > 0) { mImageLoader.displayImage(new File(art), viewholder.album_art); } else { viewholder.album_art.setImageResource(R.drawable.ic_mp_albumart_unknown); } viewholder.album_id = aid; viewholder.album_name_string = album_name; viewholder.artist_name_string = artist_name; } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { View view = super.newView(context, cursor, parent); ViewHolderItem mViewHolder = new ViewHolderItem(view); view.setTag(mViewHolder); return view; } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo info) { mGroupSelected = false; mChildSelected = true; getSherlockActivity().getMenuInflater().inflate(R.menu.music_browser_item, menu); if (v.getTag() == null) return; ViewHolderItem viewholder = (ViewHolderItem) v.getTag(); mCurrentChildArtistNameForAlbum = viewholder.artist_name_string; mCurrentChildAlbumName = viewholder.album_name_string; mSelectedChildId = viewholder.album_id; if (mCurrentChildAlbumName == null || MediaStore.UNKNOWN_STRING.equals(mCurrentChildAlbumName)) { menu.setHeaderTitle(getString(R.string.unknown_artist)); menu.findItem(R.id.search).setEnabled(false); menu.findItem(R.id.search).setVisible(false); } else { menu.setHeaderTitle(mCurrentChildAlbumName); } } private void getColumnIndices(Cursor cursor) { if (cursor != null) { mAlbumIndex = cursor.getColumnIndexOrThrow(Audio.Albums.ALBUM); mArtistIndex = cursor.getColumnIndexOrThrow(Audio.Albums.ARTIST); mAlbumArtIndex = cursor.getColumnIndexOrThrow(Audio.Albums.ALBUM_ART); } } private class ViewHolderItem { TextView album_name; TextView artist_name; ImageView album_art; long album_id; String album_name_string; String artist_name_string; public ViewHolderItem(View view) { album_name = (TextView) view.findViewById(R.id.album_name); artist_name = (TextView) view.findViewById(R.id.artist_name); album_art = (ImageView) view.findViewById(R.id.album_art); } } } private class ArtistsAdapter extends SimpleCursorTreeAdapter implements OnItemClickListener { public ArtistsAdapter(Context context, Cursor cursor, int glayout, String[] gfrom, int[] gto, int clayout, String[] cfrom, int[] cto) { super(context, cursor, glayout, gfrom, gto, clayout, cfrom, cto); } @Override public void bindChildView(View view, Context context, Cursor cursor, boolean isLastChild) { ViewHolderChild viewholder = (ViewHolderChild) view.getTag(); viewholder.gridview.setAdapter(new AlbumChildAdapter(context, R.layout.album_grid_item, cursor, new String[] {}, new int[] {}, 0)); viewholder.gridview.setOnItemClickListener(this); int item_width = getResources().getDimensionPixelOffset(R.dimen.gridview_item_width); int item_height = getResources().getDimensionPixelOffset(R.dimen.gridview_item_height); int parent_width = mListView.getWidth(); int albums_count = cursor.getCount(); int gridview_columns = (int) (Math.floor(parent_width / item_width) > 0 ? Math.floor(parent_width / item_width) : 1); int gridview_rows = (int) Math.ceil((float) albums_count / gridview_columns); int default_padding = getResources().getDimensionPixelOffset(R.dimen.default_element_spacing); int paddings_sum = default_padding * (gridview_rows + 1); viewholder.gridview.getLayoutParams().height = item_height * gridview_rows + paddings_sum; } @Override public void bindGroupView(View view, Context context, Cursor cursor, boolean isexpanded) { ViewHolderGroup viewholder = (ViewHolderGroup) view.getTag(); String artist = cursor.getString(mGroupArtistIdx); boolean unknown = artist == null || MediaStore.UNKNOWN_STRING.equals(artist); if (unknown) { viewholder.artist_name.setText(R.string.unknown_artist); } else { viewholder.artist_name.setText(artist); } int numalbums = cursor.getInt(mGroupAlbumIdx); int numsongs = cursor.getInt(mGroupSongIdx); String songs_albums = mUtils.makeAlbumsLabel(numalbums, numsongs, unknown); viewholder.album_track_count.setText(songs_albums); long currentartistid = mUtils.getCurrentArtistId(); long aid = cursor.getLong(mGroupArtistIdIdx); if (currentartistid == aid) { viewholder.artist_name.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_indicator_nowplaying_small, 0); } else { viewholder.artist_name.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); } } @Override public int getChildrenCount(int groupPosition) { return 1; } @Override public View newChildView(Context context, Cursor cursor, boolean isLastChild, ViewGroup parent) { View view = super.newChildView(context, cursor, isLastChild, parent); ViewHolderChild viewholder = new ViewHolderChild(view); view.setTag(viewholder); return view; } @Override public View newGroupView(Context context, Cursor cursor, boolean isExpanded, ViewGroup parent) { View view = super.newGroupView(context, cursor, isExpanded, parent); ViewHolderGroup viewholder = new ViewHolderGroup(view); view.setTag(viewholder); return view; } @Override public void onItemClick(AdapterView<?> adapter, View view, int position, long id) { showDetails(position, id); } private void showDetails(int childPosition, long id) { View detailsFrame = getSherlockActivity().findViewById(R.id.frame_details); boolean mDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE; Bundle bundle = new Bundle(); bundle.putString(INTENT_KEY_TYPE, MediaStore.Audio.Albums.CONTENT_TYPE); bundle.putLong(MediaStore.Audio.Albums._ID, id); if (mDualPane) { TrackFragment fragment = new TrackFragment(); fragment.setArguments(bundle); FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.replace(R.id.frame_details, fragment); ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); ft.commit(); } else { Intent intent = new Intent(getSherlockActivity(), TrackBrowserActivity.class); intent.putExtras(bundle); startActivity(intent); } } @Override protected Cursor getChildrenCursor(Cursor groupCursor) { long id = groupCursor.getLong(groupCursor.getColumnIndexOrThrow(Audio.Artists._ID)); String[] cols = new String[] { Audio.Albums._ID, Audio.Albums.ALBUM, Audio.Albums.ARTIST, Audio.Albums.NUMBER_OF_SONGS, Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST, Audio.Albums.ALBUM_ART }; Uri uri = Audio.Artists.Albums.getContentUri(EXTERNAL_VOLUME, id); Cursor c = getSherlockActivity().getContentResolver().query(uri, cols, null, null, Audio.Albums.DEFAULT_SORT_ORDER); return c; } } private class ViewHolderChild { GridView gridview; public ViewHolderChild(View view) { gridview = (GridView) view.findViewById(R.id.artist_child_grid_view); } } private class ViewHolderGroup { TextView artist_name; TextView album_track_count; public ViewHolderGroup(View view) { artist_name = (TextView) view.findViewById(R.id.name); album_track_count = (TextView) view.findViewById(R.id.summary); } } }