alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Android example source code file (MusicPicker.java)

This example Android source code file (MusicPicker.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Android by Example" TM.

Java - Android tags/keywords

album_menu, android, artist_menu, asc, content, cursor, dbg, object, override, photo, queryhandler, string, stringbuilder, textview, track_menu, ui, uri, view, viewholder, widget

The MusicPicker.java Android example source code

package com.example.android.rings_extended;

import android.app.ListActivity;
import android.content.AsyncQueryHandler;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.CharArrayBuffer;
import android.database.Cursor;
import android.media.AudioManager;
import android.media.MediaFile;
import android.media.MediaPlayer;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;

import java.io.IOException;
import java.text.Collator;
import java.util.Formatter;
import java.util.Locale;

/**
 * Activity allowing the user to select a music track on the device, and
 * return it to its caller.  The music picker user interface is fairly
 * extensive, providing information about each track like the music
 * application (title, author, album, duration), as well as the ability to
 * previous tracks and sort them in different orders.
 * 
 * <p>This class also illustrates how you can load data from a content
 * provider asynchronously, providing a good UI while doing so, perform
 * indexing of the content for use inside of a {@link FastScrollView}, and
 * perform filtering of the data as the user presses keys.
 */
public class MusicPicker extends ListActivity
        implements View.OnClickListener, MediaPlayer.OnCompletionListener {
    static final boolean DBG = false;
    static final String TAG = "MusicPicker";
    
    /** Holds the previous state of the list, to restore after the async
     * query has completed. */
    static final String LIST_STATE_KEY = "liststate";
    /** Remember whether the list last had focus for restoring its state. */
    static final String FOCUS_KEY = "focused";
    /** Remember the last ordering mode for restoring state. */
    static final String SORT_MODE_KEY = "sortMode";
    
    /** Arbitrary number, doesn't matter since we only do one query type. */
    final int MY_QUERY_TOKEN = 42;
    
    /** Menu item to sort the music list by track title. */
    static final int TRACK_MENU = Menu.FIRST;
    /** Menu item to sort the music list by album title. */
    static final int ALBUM_MENU = Menu.FIRST+1;
    /** Menu item to sort the music list by artist name. */
    static final int ARTIST_MENU = Menu.FIRST+2;
    
    /** These are the columns in the music cursor that we are interested in. */
    static final String[] CURSOR_COLS = new String[] {
            MediaStore.Audio.Media._ID,
            MediaStore.Audio.Media.TITLE,
            MediaStore.Audio.Media.TITLE_KEY,
            MediaStore.Audio.Media.DATA,
            MediaStore.Audio.Media.ALBUM,
            MediaStore.Audio.Media.ARTIST,
            MediaStore.Audio.Media.ARTIST_ID,
            MediaStore.Audio.Media.DURATION,
            MediaStore.Audio.Media.TRACK
    };
    
    /** Formatting optimization to avoid creating many temporary objects. */
    static StringBuilder sFormatBuilder = new StringBuilder();
    /** Formatting optimization to avoid creating many temporary objects. */
    static Formatter sFormatter = new Formatter(sFormatBuilder, Locale.getDefault());
    /** Formatting optimization to avoid creating many temporary objects. */
    static final Object[] sTimeArgs = new Object[5];

    /** Uri to the directory of all music being displayed. */
    Uri mBaseUri;
    
    /** This is the adapter used to display all of the tracks. */
    TrackListAdapter mAdapter;
    /** Our instance of QueryHandler used to perform async background queries. */
    QueryHandler mQueryHandler;
    
    /** Used to keep track of the last scroll state of the list. */
    Parcelable mListState = null;
    /** Used to keep track of whether the list last had focus. */
    boolean mListHasFocus;
    
    /** The current cursor on the music that is being displayed. */
    Cursor mCursor;
    /** The actual sort order the user has selected. */
    int mSortMode = -1;
    /** SQL order by string describing the currently selected sort order. */
    String mSortOrder;

    /** Container of the in-screen progress indicator, to be able to hide it
     * when done loading the initial cursor. */
    View mProgressContainer;
    /** Container of the list view hierarchy, to be able to show it when done
     * loading the initial cursor. */
    View mListContainer;
    /** Set to true when the list view has been shown for the first time. */
    boolean mListShown;
    
    /** View holding the okay button. */
    View mOkayButton;
    /** View holding the cancel button. */
    View mCancelButton;
    
    /** Which track row ID the user has last selected. */
    long mSelectedId = -1;
    /** Completel Uri that the user has last selected. */
    Uri mSelectedUri;
    
    /** If >= 0, we are currently playing a track for preview, and this is its
     * row ID. */
    long mPlayingId = -1;
    
    /** This is used for playing previews of the music files. */
    MediaPlayer mMediaPlayer;
    
    /**
     * A special implementation of SimpleCursorAdapter that knows how to bind
     * our cursor data to our list item structure, and takes care of other
     * advanced features such as indexing and filtering.
     */
    class TrackListAdapter extends SimpleCursorAdapter
            implements FastScrollView.SectionIndexer {
        final ListView mListView;
        
        private final StringBuilder mBuilder = new StringBuilder();
        private final String mUnknownArtist;
        private final String mUnknownAlbum;

        private int mIdIdx;
        private int mTitleIdx;
        private int mArtistIdx;
        private int mAlbumIdx;
        private int mDurationIdx;
        private int mAudioIdIdx;
        private int mTrackIdx;

        private boolean mLoading = true;
        private String [] mAlphabet;
        private int mIndexerSortMode;
        private boolean mIndexerOutOfDate;
        private AlphabetIndexer mIndexer;
        
        class ViewHolder {
            TextView line1;
            TextView line2;
            TextView duration;
            RadioButton radio;
            ImageView play_indicator;
            CharArrayBuffer buffer1;
            char [] buffer2;
        }
        
        TrackListAdapter(Context context, ListView listView, int layout,
                String[] from, int[] to) {
            super(context, layout, null, from, to);
            mListView = listView;
            mUnknownArtist = context.getString(R.string.unknownArtistName);
            mUnknownAlbum = context.getString(R.string.unknownAlbumName);
            getAlphabet(context);
        }

        /**
         * The mLoading flag is set while we are performing a background
         * query, to avoid displaying the "No music" empty view during
         * this time.
         */
        public void setLoading(boolean loading) {
            mLoading = loading;
        }

        @Override
        public boolean isEmpty() {
            if (mLoading) {
                // We don't want the empty state to show when loading.
                return false;
            } else {
                return super.isEmpty();
            }
        }
        
        @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {
            View v = super.newView(context, cursor, parent);
            ViewHolder vh = new ViewHolder();
            vh.line1 = (TextView) v.findViewById(R.id.line1);
            vh.line2 = (TextView) v.findViewById(R.id.line2);
            vh.duration = (TextView) v.findViewById(R.id.duration);
            vh.radio = (RadioButton) v.findViewById(R.id.radio);
            vh.play_indicator = (ImageView) v.findViewById(R.id.play_indicator);
            vh.buffer1 = new CharArrayBuffer(100);
            vh.buffer2 = new char[200];
            v.setTag(vh);
            return v;
        }

        @Override
        public void bindView(View view, Context context, Cursor cursor) {
            ViewHolder vh = (ViewHolder) view.getTag();
            
            cursor.copyStringToBuffer(mTitleIdx, vh.buffer1);
            vh.line1.setText(vh.buffer1.data, 0, vh.buffer1.sizeCopied);
            
            int secs = cursor.getInt(mDurationIdx) / 1000;
            if (secs == 0) {
                vh.duration.setText("");
            } else {
                vh.duration.setText(makeTimeString(context, secs));
            }
            
            final StringBuilder builder = mBuilder;
            builder.delete(0, builder.length());

            String name = cursor.getString(mAlbumIdx);
            if (name == null || name.equals(MediaFile.UNKNOWN_STRING)) {
                builder.append(mUnknownAlbum);
            } else {
                builder.append(name);
            }
            builder.append('\n');
            name = cursor.getString(mArtistIdx);
            if (name == null || name.equals(MediaFile.UNKNOWN_STRING)) {
                builder.append(mUnknownArtist);
            } else {
                builder.append(name);
            }
            int len = builder.length();
            if (vh.buffer2.length < len) {
                vh.buffer2 = new char[len];
            }
            builder.getChars(0, len, vh.buffer2, 0);
            vh.line2.setText(vh.buffer2, 0, len);

            // Update the checkbox of the item, based on which the user last
            // selected.  Note that doing it this way means we must have the
            // list view update all of its items when the selected item
            // changes.
            final long id = cursor.getLong(mIdIdx);
            vh.radio.setChecked(id == mSelectedId);
            if (DBG) Log.v(TAG, "Binding id=" + id + " sel=" + mSelectedId
                    + " playing=" + mPlayingId + " cursor=" + cursor);
            
            // Likewise, display the "now playing" icon if this item is
            // currently being previewed for the user.
            ImageView iv = vh.play_indicator;
            if (id == mPlayingId) {
                iv.setImageResource(R.drawable.now_playing);
                iv.setVisibility(View.VISIBLE);
            } else {
                iv.setVisibility(View.GONE);
            }
        }
        
        /**
         * This method is called whenever we receive a new cursor due to
         * an async query, and must take care of plugging the new one in
         * to the adapter.
         */
        @Override
        public void changeCursor(Cursor cursor) {
            super.changeCursor(cursor);
            if (DBG) Log.v(TAG, "Setting cursor to: " + cursor
                    + " from: " + MusicPicker.this.mCursor);
            
            MusicPicker.this.mCursor = cursor;
            
            if (cursor != null) {
                // Retrieve indices of the various columns we are interested in.
                mIdIdx = cursor.getColumnIndex(MediaStore.Audio.Media._ID);
                mTitleIdx = cursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
                mArtistIdx = cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST);
                mAlbumIdx = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM);
                mDurationIdx = cursor.getColumnIndex(MediaStore.Audio.Media.DURATION);
                int audioIdIdx = cursor.getColumnIndex(MediaStore.Audio.Playlists.Members.AUDIO_ID);
                if (audioIdIdx < 0) {
                    audioIdIdx = cursor.getColumnIndex(MediaStore.Audio.Media._ID);
                }
                mAudioIdIdx = audioIdIdx;
                mTrackIdx = cursor.getColumnIndex(MediaStore.Audio.Media.TRACK);
            }
            
            // The next time the indexer is needed, we will need to rebind it
            // to this cursor.
            mIndexerOutOfDate = true;
            
            // Ensure that the list is shown (and initial progress indicator
            // hidden) in case this is the first cursor we have gotten.
            makeListShown();
        }
        
        /**
         * This method is called from a background thread by the list view
         * when the user has typed a letter that should result in a filtering
         * of the displayed items.  It returns a Cursor, when will then be
         * handed to changeCursor.
         */
        @Override
        public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
            if (DBG) Log.v(TAG, "Getting new cursor...");
            return doQuery(true, constraint.toString());
        }
        
        /**
         * Build a list of alphabetic characters appropriate for the
         * current locale.
         */
        private void getAlphabet(Context context) {
            String alphabetString = context.getResources().getString(R.string.alphabet);
            mAlphabet = new String[alphabetString.length()];
            for (int i = 0; i < mAlphabet.length; i++) {
                mAlphabet[i] = String.valueOf(alphabetString.charAt(i));
            }
        }
        
        public int getPositionForSection(int section) {
            Cursor cursor = getCursor();
            if (cursor == null) {
                // No cursor, the section doesn't exist so just return 0
                return 0;
            }
            
            // If the sort mode has changed, or we haven't yet created an
            // indexer one, then create a new one that is indexing the
            // appropriate column based on the sort mode.
            if (mIndexerSortMode != mSortMode || mIndexer == null) {
                mIndexerSortMode = mSortMode;
                int idx = mTitleIdx;
                switch (mIndexerSortMode) {
                    case ARTIST_MENU:
                        idx = mArtistIdx;
                        break;
                    case ALBUM_MENU:
                        idx = mAlbumIdx;
                        break;
                }
                mIndexer = new AlphabetIndexer(cursor, idx, mAlphabet);
                
            // If we have a valid indexer, but the cursor has changed since
            // its last use, then point it to the current cursor.
            } else if (mIndexerOutOfDate) {
                mIndexer.setCursor(cursor);
            }
            
            mIndexerOutOfDate = false;
            
            return mIndexer.indexOf(section);
        }

        public int getSectionForPosition(int position) {
            return 0;
        }

        public Object[] getSections() {
            return mAlphabet;
        }
    }

    /**
     * This is our specialization of AsyncQueryHandler applies new cursors
     * to our state as they become available.
     */
    private final class QueryHandler extends AsyncQueryHandler {
        public QueryHandler(Context context) {
            super(context.getContentResolver());
        }

        @Override
        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
            if (!isFinishing()) {
                // Update the adapter: we are no longer loading, and have
                // a new cursor for it.
                mAdapter.setLoading(false);
                mAdapter.changeCursor(cursor);
                setProgressBarIndeterminateVisibility(false);
    
                // Now that the cursor is populated again, it's possible to restore the list state
                if (mListState != null) {
                    getListView().onRestoreInstanceState(mListState);
                    if (mListHasFocus) {
                        getListView().requestFocus();
                    }
                    mListHasFocus = false;
                    mListState = null;
                }
            } else {
                cursor.close();
            }
        }
    }

    public static String makeTimeString(Context context, long secs) {
        String durationformat = context.getString(R.string.durationformat);
        
        /* Provide multiple arguments so the format can be changed easily
         * by modifying the xml.
         */
        sFormatBuilder.setLength(0);

        final Object[] timeArgs = sTimeArgs;
        timeArgs[0] = secs / 3600;
        timeArgs[1] = secs / 60;
        timeArgs[2] = (secs / 60) % 60;
        timeArgs[3] = secs;
        timeArgs[4] = secs % 60;

        return sFormatter.format(durationformat, timeArgs).toString();
    }
    
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        
        setTitle(R.string.musicPickerTitle);
        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
        
        int sortMode = TRACK_MENU;
        if (icicle == null) {
            mSelectedUri = getIntent().getParcelableExtra(
                    RingtoneManager.EXTRA_RINGTONE_EXISTING_URI);
        } else {
            mSelectedUri = (Uri)icicle.getParcelable(
                    RingtoneManager.EXTRA_RINGTONE_EXISTING_URI);
            // Retrieve list state. This will be applied after the
            // QueryHandler has run
            mListState = icicle.getParcelable(LIST_STATE_KEY);
            mListHasFocus = icicle.getBoolean(FOCUS_KEY);
            sortMode = icicle.getInt(SORT_MODE_KEY, sortMode);
        }
        if (Intent.ACTION_GET_CONTENT.equals(getIntent().getAction())) {
            mBaseUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        } else {
            mBaseUri = getIntent().getData();
            if (mBaseUri == null) {
                Log.w("MusicPicker", "No data URI given to PICK action");
                finish();
                return;
            }
        }
        
        setContentView(R.layout.music_picker);

        mSortOrder = MediaStore.Audio.Media.TITLE_KEY;

        final ListView listView = getListView();

        listView.setItemsCanFocus(false);
        
        mAdapter = new TrackListAdapter(this, listView,
                R.layout.track_list_item, new String[] {},
                new int[] {});

        setListAdapter(mAdapter);
        
        listView.setTextFilterEnabled(true);
        
        // We manually save/restore the listview state
        listView.setSaveEnabled(false);

        mQueryHandler = new QueryHandler(this);
        
        mProgressContainer = findViewById(R.id.progressContainer);
        mListContainer = findViewById(R.id.listContainer);
        
        mOkayButton = findViewById(R.id.okayButton);
        mOkayButton.setOnClickListener(this);
        mCancelButton = findViewById(R.id.cancelButton);
        mCancelButton.setOnClickListener(this);
        
        // If there is a currently selected Uri, then try to determine who
        // it is.
        if (mSelectedUri != null) {
            Uri.Builder builder = mSelectedUri.buildUpon();
            String path = mSelectedUri.getEncodedPath();
            int idx = path.lastIndexOf('/');
            if (idx >= 0) {
                path = path.substring(0, idx);
            }
            builder.encodedPath(path);
            Uri baseSelectedUri = builder.build();
            if (DBG) Log.v(TAG, "Selected Uri: " + mSelectedUri);
            if (DBG) Log.v(TAG, "Selected base Uri: " + baseSelectedUri);
            if (DBG) Log.v(TAG, "Base Uri: " + mBaseUri);
            if (baseSelectedUri.equals(mBaseUri)) {
                // If the base Uri of the selected Uri is the same as our
                // content's base Uri, then use the selection!
                mSelectedId = ContentUris.parseId(mSelectedUri);
            }
        }
        
        setSortMode(sortMode);
    }

    @Override public void onRestart() {
        super.onRestart();
        doQuery(false, null);
    }
    
    @Override public boolean onOptionsItemSelected(MenuItem item) {
        if (setSortMode(item.getItemId())) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        menu.add(Menu.NONE, TRACK_MENU, Menu.NONE, R.string.sortByTrack);
        menu.add(Menu.NONE, ALBUM_MENU, Menu.NONE, R.string.sortByAlbum);
        menu.add(Menu.NONE, ARTIST_MENU, Menu.NONE, R.string.sortByArtist);
        return true;
    }

    @Override protected void onSaveInstanceState(Bundle icicle) {
        super.onSaveInstanceState(icicle);
        // Save list state in the bundle so we can restore it after the
        // QueryHandler has run
        icicle.putParcelable(LIST_STATE_KEY, getListView().onSaveInstanceState());
        icicle.putBoolean(FOCUS_KEY, getListView().hasFocus());
        icicle.putInt(SORT_MODE_KEY, mSortMode);
    }
    
    @Override public void onPause() {
        super.onPause();
        stopMediaPlayer();
    }
    
    @Override public void onStop() {
        super.onStop();
        
        // We don't want the list to display the empty state, since when we
        // resume it will still be there and show up while the new query is
        // happening. After the async query finishes in response to onResume()
        // setLoading(false) will be called.
        mAdapter.setLoading(true);
        mAdapter.changeCursor(null);
    }
    
    /**
     * Changes the current sort order, building the appropriate query string
     * for the selected order.
     */
    boolean setSortMode(int sortMode) {
        if (sortMode != mSortMode) {
            switch (sortMode) {
                case TRACK_MENU:
                    mSortMode = sortMode;
                    mSortOrder = MediaStore.Audio.Media.TITLE_KEY;
                    doQuery(false, null);
                    return true;
                case ALBUM_MENU:
                    mSortMode = sortMode;
                    mSortOrder = MediaStore.Audio.Media.ALBUM_KEY + " ASC, "
                            + MediaStore.Audio.Media.TRACK + " ASC, "
                            + MediaStore.Audio.Media.TITLE_KEY + " ASC";
                    doQuery(false, null);
                    return true;
                case ARTIST_MENU:
                    mSortMode = sortMode;
                    mSortOrder = MediaStore.Audio.Media.ARTIST_KEY + " ASC, "
                            + MediaStore.Audio.Media.ALBUM_KEY + " ASC, "
                            + MediaStore.Audio.Media.TRACK + " ASC, "
                            + MediaStore.Audio.Media.TITLE_KEY + " ASC";
                    doQuery(false, null);
                    return true;
            }
            
        }
        return false;
    }
    
    /**
     * The first time this is called, we hide the large progress indicator
     * and show the list view, doing fade animations between them.
     */
    void makeListShown() {
        if (!mListShown) {
            mListShown = true;
            mProgressContainer.startAnimation(AnimationUtils.loadAnimation(
                    this, android.R.anim.fade_out));
            mProgressContainer.setVisibility(View.GONE);
            mListContainer.startAnimation(AnimationUtils.loadAnimation(
                    this, android.R.anim.fade_in));
            mListContainer.setVisibility(View.VISIBLE);
        }
    }
    
    /**
     * Common method for performing a query of the music database, called for
     * both top-level queries and filtering.
     * 
     * @param sync If true, this query should be done synchronously and the
     * resulting cursor returned.  If false, it will be done asynchronously and
     * null returned.
     * @param filterstring If non-null, this is a filter to apply to the query.
     */
    Cursor doQuery(boolean sync, String filterstring) {
        // Cancel any pending queries
        mQueryHandler.cancelOperation(MY_QUERY_TOKEN);
        
        StringBuilder where = new StringBuilder();
        where.append(MediaStore.Audio.Media.TITLE + " != ''");
        
        // Add in the filtering constraints
        String [] keywords = null;
        if (filterstring != null) {
            String [] searchWords = filterstring.split(" ");
            keywords = new String[searchWords.length];
            Collator col = Collator.getInstance();
            col.setStrength(Collator.PRIMARY);
            for (int i = 0; i < searchWords.length; i++) {
                keywords[i] = '%' + MediaStore.Audio.keyFor(searchWords[i]) + '%';
            }
            for (int i = 0; i < searchWords.length; i++) {
                where.append(" AND ");
                where.append(MediaStore.Audio.Media.ARTIST_KEY + "||");
                where.append(MediaStore.Audio.Media.ALBUM_KEY + "||");
                where.append(MediaStore.Audio.Media.TITLE_KEY + " LIKE ?");
            }
        }
        
        // We want to show all audio files, even recordings.  Enforcing the
        // following condition would hide recordings.
        //where.append(" AND " + MediaStore.Audio.Media.IS_MUSIC + "=1");
        
        if (sync) {
            try {
                return getContentResolver().query(mBaseUri, CURSOR_COLS,
                        where.toString(), keywords, mSortOrder);
            } catch (UnsupportedOperationException ex) {
            }
        } else {
            mAdapter.setLoading(true);
            setProgressBarIndeterminateVisibility(true);
            mQueryHandler.startQuery(MY_QUERY_TOKEN, null, mBaseUri, CURSOR_COLS,
                    where.toString(), keywords, mSortOrder);
        }
        return null;
    }
    
    @Override protected void onListItemClick(ListView l, View v, int position,
            long id) {
        mCursor.moveToPosition(position);
        if (DBG) Log.v(TAG, "Click on " + position + " (id=" + id
                + ", cursid="
                + mCursor.getLong(mCursor.getColumnIndex(MediaStore.Audio.Media._ID))
                + ") in cursor " + mCursor
                + " adapter=" + l.getAdapter());
        setSelected(mCursor);
    }
    
    void setSelected(Cursor c) {
        Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        long newId = mCursor.getLong(mCursor.getColumnIndex(MediaStore.Audio.Media._ID));
        mSelectedUri = ContentUris.withAppendedId(uri, newId);
        
        mSelectedId = newId;
        if (newId != mPlayingId || mMediaPlayer == null) {
            stopMediaPlayer();
            mMediaPlayer = new MediaPlayer();
            try {
                mMediaPlayer.setDataSource(this, mSelectedUri);
                mMediaPlayer.setOnCompletionListener(this);
                mMediaPlayer.setAudioStreamType(AudioManager.STREAM_RING);
                mMediaPlayer.prepare();
                mMediaPlayer.start();
                mPlayingId = newId;
                getListView().invalidateViews();
            } catch (IOException e) {
                Log.w("MusicPicker", "Unable to play track", e);
            }
        } else if (mMediaPlayer != null) {
            stopMediaPlayer();
            getListView().invalidateViews();
        }
    }
    
    public void onCompletion(MediaPlayer mp) {
        if (mMediaPlayer == mp) {
            mp.stop();
            mp.release();
            mMediaPlayer = null;
            mPlayingId = -1;
            getListView().invalidateViews();
        }
    }
    
    void stopMediaPlayer() {
        if (mMediaPlayer != null) {
            mMediaPlayer.stop();
            mMediaPlayer.release();
            mMediaPlayer = null;
            mPlayingId = -1;
        }
    }
    
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.okayButton:
                if (mSelectedId >= 0) {
                    setResult(RESULT_OK, new Intent().setData(mSelectedUri));
                    finish();
                }
                break;

            case R.id.cancelButton:
                finish();
                break;
        }
    }
}

Other Android examples (source code examples)

Here is a short list of links related to this Android MusicPicker.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.