1792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project/*
2792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *
4792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * you may not use this file except in compliance with the License.
6792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * You may obtain a copy of the License at
7792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *
8792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *
10792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * See the License for the specific language governing permissions and
14792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * limitations under the License.
15792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */
16792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
17792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectpackage com.android.music;
18792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
19792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.app.ListActivity;
20792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.AsyncQueryHandler;
21792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.ContentUris;
22792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.Context;
23792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.Intent;
24792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.database.CharArrayBuffer;
25792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.database.Cursor;
26792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.media.AudioManager;
27792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.media.MediaPlayer;
28792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.media.RingtoneManager;
29792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.net.Uri;
30792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.Bundle;
31792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.Parcelable;
32792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.provider.MediaStore;
3389f6c66505717689d9ea3f3d8e81709616b3e588Marco Nelissenimport android.text.TextUtils;
34792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.util.Log;
35792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.view.Menu;
36792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.view.MenuItem;
37792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.view.View;
38792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.view.ViewGroup;
39792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.view.Window;
40792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.view.animation.AnimationUtils;
41792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.widget.ImageView;
42792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.widget.ListView;
43792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.widget.RadioButton;
44792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.widget.SectionIndexer;
45792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.widget.SimpleCursorAdapter;
46792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.widget.TextView;
47792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
48792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport java.io.IOException;
49792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport java.text.Collator;
50792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport java.util.Formatter;
51792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport java.util.Locale;
52792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
53792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project/**
54792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Activity allowing the user to select a music track on the device, and
55792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * return it to its caller.  The music picker user interface is fairly
56792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * extensive, providing information about each track like the music
57792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * application (title, author, album, duration), as well as the ability to
58792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * previous tracks and sort them in different orders.
59792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *
60792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * <p>This class also illustrates how you can load data from a content
61792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * provider asynchronously, providing a good UI while doing so, perform
62792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * indexing of the content for use inside of a {@link FastScrollView}, and
63792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * perform filtering of the data as the user presses keys.
64792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */
65792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectpublic class MusicPicker extends ListActivity
66792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        implements View.OnClickListener, MediaPlayer.OnCompletionListener,
67792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        MusicUtils.Defs {
68792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    static final boolean DBG = false;
69792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    static final String TAG = "MusicPicker";
70792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
71792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Holds the previous state of the list, to restore after the async
72792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * query has completed. */
73792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    static final String LIST_STATE_KEY = "liststate";
74792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Remember whether the list last had focus for restoring its state. */
75792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    static final String FOCUS_KEY = "focused";
76792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Remember the last ordering mode for restoring state. */
77792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    static final String SORT_MODE_KEY = "sortMode";
78792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
79792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Arbitrary number, doesn't matter since we only do one query type. */
80756c3f57f11a7bb3bf1cf1333ee8ffbc51039748Marco Nelissen    static final int MY_QUERY_TOKEN = 42;
81792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
82792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Menu item to sort the music list by track title. */
83792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    static final int TRACK_MENU = Menu.FIRST;
84792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Menu item to sort the music list by album title. */
85792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    static final int ALBUM_MENU = Menu.FIRST+1;
86792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Menu item to sort the music list by artist name. */
87792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    static final int ARTIST_MENU = Menu.FIRST+2;
88792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
89792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** These are the columns in the music cursor that we are interested in. */
90792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    static final String[] CURSOR_COLS = new String[] {
91792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media._ID,
92792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.TITLE,
93792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.TITLE_KEY,
94792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.DATA,
95792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ALBUM,
96792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ARTIST,
97792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ARTIST_ID,
98792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.DURATION,
99792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.TRACK
100792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
101792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
102792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Formatting optimization to avoid creating many temporary objects. */
103792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    static StringBuilder sFormatBuilder = new StringBuilder();
104792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Formatting optimization to avoid creating many temporary objects. */
105792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    static Formatter sFormatter = new Formatter(sFormatBuilder, Locale.getDefault());
106792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Formatting optimization to avoid creating many temporary objects. */
107792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    static final Object[] sTimeArgs = new Object[5];
108792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
109792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Uri to the directory of all music being displayed. */
110792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    Uri mBaseUri;
111792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
112792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** This is the adapter used to display all of the tracks. */
113792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    TrackListAdapter mAdapter;
114792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Our instance of QueryHandler used to perform async background queries. */
115792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    QueryHandler mQueryHandler;
116792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
117792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Used to keep track of the last scroll state of the list. */
118792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    Parcelable mListState = null;
119792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Used to keep track of whether the list last had focus. */
120792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    boolean mListHasFocus;
121792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
122792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** The current cursor on the music that is being displayed. */
123792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    Cursor mCursor;
124792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** The actual sort order the user has selected. */
125792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    int mSortMode = -1;
126792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** SQL order by string describing the currently selected sort order. */
127792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    String mSortOrder;
128792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
129792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Container of the in-screen progress indicator, to be able to hide it
130792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * when done loading the initial cursor. */
131792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    View mProgressContainer;
132792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Container of the list view hierarchy, to be able to show it when done
133792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * loading the initial cursor. */
134792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    View mListContainer;
135792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Set to true when the list view has been shown for the first time. */
136792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    boolean mListShown;
137792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
138792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** View holding the okay button. */
139792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    View mOkayButton;
140792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** View holding the cancel button. */
141792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    View mCancelButton;
142792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
143792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Which track row ID the user has last selected. */
144792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    long mSelectedId = -1;
145792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Completel Uri that the user has last selected. */
146792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    Uri mSelectedUri;
147792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
148792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** If >= 0, we are currently playing a track for preview, and this is its
149792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * row ID. */
150792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    long mPlayingId = -1;
151792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
152792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** This is used for playing previews of the music files. */
153792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    MediaPlayer mMediaPlayer;
154792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
155792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
156792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * A special implementation of SimpleCursorAdapter that knows how to bind
157792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * our cursor data to our list item structure, and takes care of other
158792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * advanced features such as indexing and filtering.
159792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
160792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    class TrackListAdapter extends SimpleCursorAdapter
161792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            implements SectionIndexer {
162792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        final ListView mListView;
163792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
164792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private final StringBuilder mBuilder = new StringBuilder();
165792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private final String mUnknownArtist;
166792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private final String mUnknownAlbum;
167792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
168792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private int mIdIdx;
169792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private int mTitleIdx;
170792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private int mArtistIdx;
171792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private int mAlbumIdx;
172792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private int mDurationIdx;
173792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
174792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private boolean mLoading = true;
175792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private int mIndexerSortMode;
176792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private MusicAlphabetIndexer mIndexer;
177792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
178792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        class ViewHolder {
179792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            TextView line1;
180792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            TextView line2;
181792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            TextView duration;
182792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            RadioButton radio;
183792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ImageView play_indicator;
184792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            CharArrayBuffer buffer1;
185792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            char [] buffer2;
186792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
187792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
188792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        TrackListAdapter(Context context, ListView listView, int layout,
189792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String[] from, int[] to) {
190792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            super(context, layout, null, from, to);
191792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mListView = listView;
192792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mUnknownArtist = context.getString(R.string.unknown_artist_name);
193792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mUnknownAlbum = context.getString(R.string.unknown_album_name);
194792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
195792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
196792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        /**
197792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         * The mLoading flag is set while we are performing a background
198792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         * query, to avoid displaying the "No music" empty view during
199792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         * this time.
200792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         */
201792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setLoading(boolean loading) {
202792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mLoading = loading;
203792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
204792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
205792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
206792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public boolean isEmpty() {
207792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mLoading) {
208792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // We don't want the empty state to show when loading.
209792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return false;
210792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
211792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return super.isEmpty();
212792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
213792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
214792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
215792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
216792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public View newView(Context context, Cursor cursor, ViewGroup parent) {
217792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            View v = super.newView(context, cursor, parent);
218792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ViewHolder vh = new ViewHolder();
219792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            vh.line1 = (TextView) v.findViewById(R.id.line1);
220792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            vh.line2 = (TextView) v.findViewById(R.id.line2);
221792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            vh.duration = (TextView) v.findViewById(R.id.duration);
222792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            vh.radio = (RadioButton) v.findViewById(R.id.radio);
223792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            vh.play_indicator = (ImageView) v.findViewById(R.id.play_indicator);
224792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            vh.buffer1 = new CharArrayBuffer(100);
225792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            vh.buffer2 = new char[200];
226792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            v.setTag(vh);
227792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return v;
228792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
229792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
230792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
231792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void bindView(View view, Context context, Cursor cursor) {
232792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ViewHolder vh = (ViewHolder) view.getTag();
233792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
234792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            cursor.copyStringToBuffer(mTitleIdx, vh.buffer1);
235792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            vh.line1.setText(vh.buffer1.data, 0, vh.buffer1.sizeCopied);
236792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
237792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int secs = cursor.getInt(mDurationIdx) / 1000;
238792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (secs == 0) {
239792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                vh.duration.setText("");
240792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
2411e5a567390e41045cba6abac1d2c94eb8f59fc30Marco Nelissen                vh.duration.setText(MusicUtils.makeTimeString(context, secs));
242792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
243792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
244792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            final StringBuilder builder = mBuilder;
245792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            builder.delete(0, builder.length());
246792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
247792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String name = cursor.getString(mAlbumIdx);
248792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (name == null || name.equals("<unknown>")) {
249792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                builder.append(mUnknownAlbum);
250792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
251792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                builder.append(name);
252792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
253792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            builder.append('\n');
254792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            name = cursor.getString(mArtistIdx);
255792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (name == null || name.equals("<unknown>")) {
256792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                builder.append(mUnknownArtist);
257792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
258792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                builder.append(name);
259792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
260792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int len = builder.length();
261792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (vh.buffer2.length < len) {
262792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                vh.buffer2 = new char[len];
263792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
264792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            builder.getChars(0, len, vh.buffer2, 0);
265792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            vh.line2.setText(vh.buffer2, 0, len);
266792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
267792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Update the checkbox of the item, based on which the user last
268792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // selected.  Note that doing it this way means we must have the
269792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // list view update all of its items when the selected item
270792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // changes.
271792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            final long id = cursor.getLong(mIdIdx);
272792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            vh.radio.setChecked(id == mSelectedId);
273792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (DBG) Log.v(TAG, "Binding id=" + id + " sel=" + mSelectedId
274792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    + " playing=" + mPlayingId + " cursor=" + cursor);
275792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
276792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Likewise, display the "now playing" icon if this item is
277792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // currently being previewed for the user.
278792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ImageView iv = vh.play_indicator;
279792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (id == mPlayingId) {
280792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                iv.setImageResource(R.drawable.indicator_ic_mp_playing_list);
281792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                iv.setVisibility(View.VISIBLE);
282792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
283792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                iv.setVisibility(View.GONE);
284792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
285792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
286792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
287792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        /**
288792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         * This method is called whenever we receive a new cursor due to
289792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         * an async query, and must take care of plugging the new one in
290792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         * to the adapter.
291792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         */
292792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
293792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void changeCursor(Cursor cursor) {
294792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            super.changeCursor(cursor);
295792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (DBG) Log.v(TAG, "Setting cursor to: " + cursor
296792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    + " from: " + MusicPicker.this.mCursor);
297792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
298792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MusicPicker.this.mCursor = cursor;
299792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
300792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (cursor != null) {
301792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // Retrieve indices of the various columns we are interested in.
302792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mIdIdx = cursor.getColumnIndex(MediaStore.Audio.Media._ID);
303792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mTitleIdx = cursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
304792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mArtistIdx = cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST);
305792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mAlbumIdx = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM);
306792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mDurationIdx = cursor.getColumnIndex(MediaStore.Audio.Media.DURATION);
3074c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen
3084c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                // If the sort mode has changed, or we haven't yet created an
3094c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                // indexer one, then create a new one that is indexing the
3104c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                // appropriate column based on the sort mode.
3114c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                if (mIndexerSortMode != mSortMode || mIndexer == null) {
3124c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                    mIndexerSortMode = mSortMode;
3134c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                    int idx = mTitleIdx;
3144c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                    switch (mIndexerSortMode) {
3154c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                        case ARTIST_MENU:
3164c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                            idx = mArtistIdx;
3174c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                            break;
3184c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                        case ALBUM_MENU:
3194c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                            idx = mAlbumIdx;
3204c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                            break;
3214c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                    }
3224c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                    mIndexer = new MusicAlphabetIndexer(cursor, idx,
3233d4b2625018856a506a203e046550afd2d9d8a92Marco Nelissen                            getResources().getString(R.string.fast_scroll_alphabet));
3244c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen
3254c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                // If we have a valid indexer, but the cursor has changed since
3264c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                // its last use, then point it to the current cursor.
3274c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                } else {
3284c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                    mIndexer.setCursor(cursor);
3294c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                }
330792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
331792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
332792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Ensure that the list is shown (and initial progress indicator
333792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // hidden) in case this is the first cursor we have gotten.
334792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            makeListShown();
335792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
336792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
337792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        /**
338792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         * This method is called from a background thread by the list view
339792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         * when the user has typed a letter that should result in a filtering
340792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         * of the displayed items.  It returns a Cursor, when will then be
341792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         * handed to changeCursor.
342792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project         */
343792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
344792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
345792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (DBG) Log.v(TAG, "Getting new cursor...");
346792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return doQuery(true, constraint.toString());
347792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
348792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
349792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getPositionForSection(int section) {
350792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Cursor cursor = getCursor();
351792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (cursor == null) {
352792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // No cursor, the section doesn't exist so just return 0
353792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return 0;
354792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
355792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
356792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mIndexer.getPositionForSection(section);
357792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
358792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
359792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getSectionForPosition(int position) {
360792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return 0;
361792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
362792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
363792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public Object[] getSections() {
3644c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen            if (mIndexer != null) {
3654c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen                return mIndexer.getSections();
3664c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen            }
3674c7fcfad7fd8000d6cc4d99026e895d06b6b5624Marco Nelissen            return null;
368792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
369792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
370792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
371792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
372792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * This is our specialization of AsyncQueryHandler applies new cursors
373792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * to our state as they become available.
374792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
375792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final class QueryHandler extends AsyncQueryHandler {
376792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public QueryHandler(Context context) {
377792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            super(context.getContentResolver());
378792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
379792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
380792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
381792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
382792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (!isFinishing()) {
383792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // Update the adapter: we are no longer loading, and have
384792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // a new cursor for it.
385792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mAdapter.setLoading(false);
386792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mAdapter.changeCursor(cursor);
387792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                setProgressBarIndeterminateVisibility(false);
388792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
389792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // Now that the cursor is populated again, it's possible to restore the list state
390792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mListState != null) {
391792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    getListView().onRestoreInstanceState(mListState);
392792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (mListHasFocus) {
393792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        getListView().requestFocus();
394792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
395792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mListHasFocus = false;
396792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mListState = null;
397792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
398792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
399792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                cursor.close();
400792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
401792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
402792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
403792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
404792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** Called when the activity is first created. */
405792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
406792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void onCreate(Bundle icicle) {
407792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        super.onCreate(icicle);
408792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
409792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
410792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
411792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int sortMode = TRACK_MENU;
412792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (icicle == null) {
413792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mSelectedUri = getIntent().getParcelableExtra(
414792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    RingtoneManager.EXTRA_RINGTONE_EXISTING_URI);
415792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else {
416792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mSelectedUri = (Uri)icicle.getParcelable(
417792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    RingtoneManager.EXTRA_RINGTONE_EXISTING_URI);
418792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Retrieve list state. This will be applied after the
419792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // QueryHandler has run
420792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mListState = icicle.getParcelable(LIST_STATE_KEY);
421792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mListHasFocus = icicle.getBoolean(FOCUS_KEY);
422792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            sortMode = icicle.getInt(SORT_MODE_KEY, sortMode);
423792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
424792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (Intent.ACTION_GET_CONTENT.equals(getIntent().getAction())) {
425792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mBaseUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
426792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else {
427792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mBaseUri = getIntent().getData();
428792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mBaseUri == null) {
429792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                Log.w("MusicPicker", "No data URI given to PICK action");
430792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                finish();
431792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
432792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
433792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
434792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
435792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        setContentView(R.layout.music_picker);
436792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
437792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mSortOrder = MediaStore.Audio.Media.TITLE_KEY;
438792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
439792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        final ListView listView = getListView();
440792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
441792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        listView.setItemsCanFocus(false);
442792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
443792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mAdapter = new TrackListAdapter(this, listView,
444792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                R.layout.music_picker_item, new String[] {},
445792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                new int[] {});
446792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
447792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        setListAdapter(mAdapter);
448792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
449792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        listView.setTextFilterEnabled(true);
450792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
451792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // We manually save/restore the listview state
452792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        listView.setSaveEnabled(false);
453792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
454792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mQueryHandler = new QueryHandler(this);
455792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
456792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mProgressContainer = findViewById(R.id.progressContainer);
457792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mListContainer = findViewById(R.id.listContainer);
458792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
459792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mOkayButton = findViewById(R.id.okayButton);
460792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mOkayButton.setOnClickListener(this);
461792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mCancelButton = findViewById(R.id.cancelButton);
462792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mCancelButton.setOnClickListener(this);
463792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
464792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // If there is a currently selected Uri, then try to determine who
465792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // it is.
466792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mSelectedUri != null) {
467792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Uri.Builder builder = mSelectedUri.buildUpon();
468792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String path = mSelectedUri.getEncodedPath();
469792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int idx = path.lastIndexOf('/');
470792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (idx >= 0) {
471792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                path = path.substring(0, idx);
472792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
473792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            builder.encodedPath(path);
474792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Uri baseSelectedUri = builder.build();
475792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (DBG) Log.v(TAG, "Selected Uri: " + mSelectedUri);
476792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (DBG) Log.v(TAG, "Selected base Uri: " + baseSelectedUri);
477792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (DBG) Log.v(TAG, "Base Uri: " + mBaseUri);
478792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (baseSelectedUri.equals(mBaseUri)) {
479792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // If the base Uri of the selected Uri is the same as our
480792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // content's base Uri, then use the selection!
481792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mSelectedId = ContentUris.parseId(mSelectedUri);
482792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
483792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
484792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
485792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        setSortMode(sortMode);
486792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
487792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
488792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override public void onRestart() {
489792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        super.onRestart();
490792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        doQuery(false, null);
491792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
492792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
493792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override public boolean onOptionsItemSelected(MenuItem item) {
494792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (setSortMode(item.getItemId())) {
495792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return true;
496792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
497792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return super.onOptionsItemSelected(item);
498792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
499792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
500792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override public boolean onCreateOptionsMenu(Menu menu) {
501792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        super.onCreateOptionsMenu(menu);
502792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        menu.add(Menu.NONE, TRACK_MENU, Menu.NONE, R.string.sort_by_track);
503792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        menu.add(Menu.NONE, ALBUM_MENU, Menu.NONE, R.string.sort_by_album);
504792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        menu.add(Menu.NONE, ARTIST_MENU, Menu.NONE, R.string.sort_by_artist);
505792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return true;
506792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
507792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
508792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override protected void onSaveInstanceState(Bundle icicle) {
509792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        super.onSaveInstanceState(icicle);
510792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Save list state in the bundle so we can restore it after the
511792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // QueryHandler has run
512792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        icicle.putParcelable(LIST_STATE_KEY, getListView().onSaveInstanceState());
513792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        icicle.putBoolean(FOCUS_KEY, getListView().hasFocus());
514792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        icicle.putInt(SORT_MODE_KEY, mSortMode);
515792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
516792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
517792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override public void onPause() {
518792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        super.onPause();
519792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        stopMediaPlayer();
520792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
521792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
522792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override public void onStop() {
523792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        super.onStop();
524792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
525792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // We don't want the list to display the empty state, since when we
526792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // resume it will still be there and show up while the new query is
527792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // happening. After the async query finishes in response to onResume()
528792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // setLoading(false) will be called.
529792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mAdapter.setLoading(true);
530792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mAdapter.changeCursor(null);
531792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
532792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
533792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
534792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Changes the current sort order, building the appropriate query string
535792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * for the selected order.
536792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
537792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    boolean setSortMode(int sortMode) {
538792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (sortMode != mSortMode) {
539792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            switch (sortMode) {
540792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case TRACK_MENU:
541792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mSortMode = sortMode;
542792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mSortOrder = MediaStore.Audio.Media.TITLE_KEY;
543792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    doQuery(false, null);
544792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return true;
545792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case ALBUM_MENU:
546792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mSortMode = sortMode;
547792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mSortOrder = MediaStore.Audio.Media.ALBUM_KEY + " ASC, "
548792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            + MediaStore.Audio.Media.TRACK + " ASC, "
549792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            + MediaStore.Audio.Media.TITLE_KEY + " ASC";
550792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    doQuery(false, null);
551792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return true;
552792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case ARTIST_MENU:
553792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mSortMode = sortMode;
554792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mSortOrder = MediaStore.Audio.Media.ARTIST_KEY + " ASC, "
555792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            + MediaStore.Audio.Media.ALBUM_KEY + " ASC, "
556792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            + MediaStore.Audio.Media.TRACK + " ASC, "
557792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            + MediaStore.Audio.Media.TITLE_KEY + " ASC";
558792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    doQuery(false, null);
559792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return true;
560792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
561792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
562792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
563792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return false;
564792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
565792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
566792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
567792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * The first time this is called, we hide the large progress indicator
568792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * and show the list view, doing fade animations between them.
569792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
570792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    void makeListShown() {
571792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (!mListShown) {
572792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mListShown = true;
573792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mProgressContainer.startAnimation(AnimationUtils.loadAnimation(
574792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    this, android.R.anim.fade_out));
575792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mProgressContainer.setVisibility(View.GONE);
576792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mListContainer.startAnimation(AnimationUtils.loadAnimation(
577792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    this, android.R.anim.fade_in));
578792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mListContainer.setVisibility(View.VISIBLE);
579792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
580792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
581792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
582792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
583792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Common method for performing a query of the music database, called for
584792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * both top-level queries and filtering.
585792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
586792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param sync If true, this query should be done synchronously and the
587792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * resulting cursor returned.  If false, it will be done asynchronously and
588792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * null returned.
589792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param filterstring If non-null, this is a filter to apply to the query.
590792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
591792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    Cursor doQuery(boolean sync, String filterstring) {
592792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Cancel any pending queries
593792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mQueryHandler.cancelOperation(MY_QUERY_TOKEN);
594792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
595792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        StringBuilder where = new StringBuilder();
596792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        where.append(MediaStore.Audio.Media.TITLE + " != ''");
597792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
598792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // We want to show all audio files, even recordings.  Enforcing the
599792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // following condition would hide recordings.
600792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        //where.append(" AND " + MediaStore.Audio.Media.IS_MUSIC + "=1");
60189f6c66505717689d9ea3f3d8e81709616b3e588Marco Nelissen
60289f6c66505717689d9ea3f3d8e81709616b3e588Marco Nelissen        Uri uri = mBaseUri;
60389f6c66505717689d9ea3f3d8e81709616b3e588Marco Nelissen        if (!TextUtils.isEmpty(filterstring)) {
60489f6c66505717689d9ea3f3d8e81709616b3e588Marco Nelissen            uri = uri.buildUpon().appendQueryParameter("filter", Uri.encode(filterstring)).build();
60589f6c66505717689d9ea3f3d8e81709616b3e588Marco Nelissen        }
60689f6c66505717689d9ea3f3d8e81709616b3e588Marco Nelissen
607792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (sync) {
608792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            try {
60989f6c66505717689d9ea3f3d8e81709616b3e588Marco Nelissen                return getContentResolver().query(uri, CURSOR_COLS,
61089f6c66505717689d9ea3f3d8e81709616b3e588Marco Nelissen                        where.toString(), null, mSortOrder);
611792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (UnsupportedOperationException ex) {
612792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
613792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else {
614792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mAdapter.setLoading(true);
615792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            setProgressBarIndeterminateVisibility(true);
61689f6c66505717689d9ea3f3d8e81709616b3e588Marco Nelissen            mQueryHandler.startQuery(MY_QUERY_TOKEN, null, uri, CURSOR_COLS,
61789f6c66505717689d9ea3f3d8e81709616b3e588Marco Nelissen                    where.toString(), null, mSortOrder);
618792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
619792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return null;
620792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
621792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
622792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override protected void onListItemClick(ListView l, View v, int position,
623792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            long id) {
624792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mCursor.moveToPosition(position);
625792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (DBG) Log.v(TAG, "Click on " + position + " (id=" + id
626792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                + ", cursid="
627792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                + mCursor.getLong(mCursor.getColumnIndex(MediaStore.Audio.Media._ID))
628792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                + ") in cursor " + mCursor
629792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                + " adapter=" + l.getAdapter());
630792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        setSelected(mCursor);
631792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
632792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
633792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    void setSelected(Cursor c) {
634792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
635792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        long newId = mCursor.getLong(mCursor.getColumnIndex(MediaStore.Audio.Media._ID));
636792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mSelectedUri = ContentUris.withAppendedId(uri, newId);
637792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
638792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mSelectedId = newId;
639792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (newId != mPlayingId || mMediaPlayer == null) {
640792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stopMediaPlayer();
641792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer = new MediaPlayer();
642792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            try {
643792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.setDataSource(this, mSelectedUri);
644792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.setOnCompletionListener(this);
645792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.setAudioStreamType(AudioManager.STREAM_RING);
646792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.prepare();
647792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.start();
648792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayingId = newId;
649792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                getListView().invalidateViews();
650792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (IOException e) {
651792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                Log.w("MusicPicker", "Unable to play track", e);
652792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
653792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else if (mMediaPlayer != null) {
654792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stopMediaPlayer();
655792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            getListView().invalidateViews();
656792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
657792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
658792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
659792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void onCompletion(MediaPlayer mp) {
660792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mMediaPlayer == mp) {
661792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mp.stop();
662792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mp.release();
663792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer = null;
664792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayingId = -1;
665792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            getListView().invalidateViews();
666792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
667792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
668792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
669792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    void stopMediaPlayer() {
670792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mMediaPlayer != null) {
671792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.stop();
672792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.release();
673792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer = null;
674792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayingId = -1;
675792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
676792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
677792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
678792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void onClick(View v) {
679792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        switch (v.getId()) {
680792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            case R.id.okayButton:
681792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mSelectedId >= 0) {
682792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    setResult(RESULT_OK, new Intent().setData(mSelectedUri));
683792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    finish();
684792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
685792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                break;
686792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
687792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            case R.id.cancelButton:
688792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                finish();
689792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                break;
690792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
691792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
692792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project}
693