OSDN Git Service

auto import from //branches/cupcake/...@125939
[android-x86/packages-apps-Music.git] / src / com / android / music / QueryBrowserActivity.java
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.android.music;
18
19 import android.app.ListActivity;
20 import android.app.SearchManager;
21 import android.content.AsyncQueryHandler;
22 import android.content.BroadcastReceiver;
23 import android.content.ContentResolver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27
28 import android.database.Cursor;
29 import android.database.DatabaseUtils;
30 import android.media.AudioManager;
31 import android.media.MediaFile;
32 import android.net.Uri;
33 import android.os.Bundle;
34 import android.os.Handler;
35 import android.os.Message;
36 import android.provider.MediaStore;
37 import android.text.TextUtils;
38 import android.util.Log;
39 import android.view.KeyEvent;
40 import android.view.MenuItem;
41 import android.view.View;
42 import android.view.ViewGroup;
43 import android.view.Window;
44 import android.view.ViewGroup.OnHierarchyChangeListener;
45 import android.widget.ImageView;
46 import android.widget.ListView;
47 import android.widget.SimpleCursorAdapter;
48 import android.widget.TextView;
49
50 import java.util.ArrayList;
51
52 public class QueryBrowserActivity extends ListActivity implements MusicUtils.Defs
53 {
54     private final static int PLAY_NOW = 0;
55     private final static int ADD_TO_QUEUE = 1;
56     private final static int PLAY_NEXT = 2;
57     private final static int PLAY_ARTIST = 3;
58     private final static int EXPLORE_ARTIST = 4;
59     private final static int PLAY_ALBUM = 5;
60     private final static int EXPLORE_ALBUM = 6;
61     private final static int REQUERY = 3;
62     private QueryListAdapter mAdapter;
63     private boolean mAdapterSent;
64     private String mFilterString = "";
65
66     public QueryBrowserActivity()
67     {
68     }
69
70     /** Called when the activity is first created. */
71     @Override
72     public void onCreate(Bundle icicle)
73     {
74         super.onCreate(icicle);
75         setVolumeControlStream(AudioManager.STREAM_MUSIC);
76         MusicUtils.bindToService(this);
77         
78         if (icicle == null) {
79             Intent intent = getIntent();
80             mFilterString = intent.getStringExtra(SearchManager.QUERY);
81         }
82
83         IntentFilter f = new IntentFilter();
84         f.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
85         f.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
86         f.addDataScheme("file");
87         registerReceiver(mScanListener, f);
88
89         setContentView(R.layout.query_activity);
90         mTrackList = getListView();
91         mTrackList.setTextFilterEnabled(true);
92         mAdapter = (QueryListAdapter) getLastNonConfigurationInstance();
93         if (mAdapter == null) {
94             mAdapter = new QueryListAdapter(
95                     getApplication(),
96                     this,
97                     R.layout.track_list_item,
98                     null, // cursor
99                     new String[] {},
100                     new int[] {});
101             setListAdapter(mAdapter);
102             getQueryCursor(mAdapter.getQueryHandler(), mFilterString);
103         } else {
104             mAdapter.setActivity(this);
105             setListAdapter(mAdapter);
106             mQueryCursor = mAdapter.getCursor();
107             if (mQueryCursor != null) {
108                 init(mQueryCursor);
109             } else {
110                 getQueryCursor(mAdapter.getQueryHandler(), mFilterString);
111             }
112         }
113     }
114     
115     @Override
116     public Object onRetainNonConfigurationInstance() {
117         mAdapterSent = true;
118         return mAdapter;
119     }
120     
121     @Override
122     public void onPause() {
123         mReScanHandler.removeCallbacksAndMessages(null);
124         super.onPause();
125     }
126
127     @Override
128     public void onDestroy() {
129         MusicUtils.unbindFromService(this);
130         unregisterReceiver(mScanListener);
131         super.onDestroy();
132         if (!mAdapterSent) {
133             Cursor c = mAdapter.getCursor();
134             if (c != null) {
135                 c.close();
136             }
137         }
138     }
139     
140     /*
141      * This listener gets called when the media scanner starts up, and when the
142      * sd card is unmounted.
143      */
144     private BroadcastReceiver mScanListener = new BroadcastReceiver() {
145         @Override
146         public void onReceive(Context context, Intent intent) {
147             MusicUtils.setSpinnerState(QueryBrowserActivity.this);
148             mReScanHandler.sendEmptyMessage(0);
149         }
150     };
151     
152     private Handler mReScanHandler = new Handler() {
153         @Override
154         public void handleMessage(Message msg) {
155             getQueryCursor(mAdapter.getQueryHandler(), null);
156             // if the query results in a null cursor, onQueryComplete() will
157             // call init(), which will post a delayed message to this handler
158             // in order to try again.
159         }
160     };
161
162     @Override
163     protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
164         switch (requestCode) {
165             case SCAN_DONE:
166                 if (resultCode == RESULT_CANCELED) {
167                     finish();
168                 } else {
169                     getQueryCursor(mAdapter.getQueryHandler(), null);
170                 }
171                 break;
172         }
173     }
174     
175     public void init(Cursor c) {
176         
177         mAdapter.changeCursor(c);
178
179         if (mQueryCursor == null) {
180             MusicUtils.displayDatabaseError(this);
181             setListAdapter(null);
182             mReScanHandler.sendEmptyMessageDelayed(0, 1000);
183             return;
184         }
185         MusicUtils.hideDatabaseError(this);
186
187         if (!TextUtils.isEmpty(mFilterString)) {
188             mTrackList.setFilterText(mFilterString);
189             mFilterString = null;
190         }
191     }
192     
193     @Override
194     protected void onListItemClick(ListView l, View v, int position, long id)
195     {
196         // Dialog doesn't allow us to wait for a result, so we need to store
197         // the info we need for when the dialog posts its result
198         mQueryCursor.moveToPosition(position);
199         if (mQueryCursor.isBeforeFirst() || mQueryCursor.isAfterLast()) {
200             return;
201         }
202         String selectedType = mQueryCursor.getString(mQueryCursor.getColumnIndexOrThrow(
203                 MediaStore.Audio.Media.MIME_TYPE));
204         
205         if ("artist".equals(selectedType)) {
206             Intent intent = new Intent(Intent.ACTION_PICK);
207             intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/album");
208             intent.putExtra("artist", Long.valueOf(id).toString());
209             startActivity(intent);
210         } else if ("album".equals(selectedType)) {
211             Intent intent = new Intent(Intent.ACTION_PICK);
212             intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track");
213             intent.putExtra("album", Long.valueOf(id).toString());
214             startActivity(intent);
215         } else if (position >= 0 && id >= 0){
216             int [] list = new int[] { (int) id };
217             MusicUtils.playAll(this, list, 0);
218         } else {
219             Log.e("QueryBrowser", "invalid position/id: " + position + "/" + id);
220         }
221     }
222
223     @Override
224     public boolean onOptionsItemSelected(MenuItem item) {
225         switch (item.getItemId()) {
226             case USE_AS_RINGTONE: {
227                 // Set the system setting to make this the current ringtone
228                 MusicUtils.setRingtone(this, mTrackList.getSelectedItemId());
229                 return true;
230             }
231
232         }
233         return super.onOptionsItemSelected(item);
234     }
235
236     private Cursor getQueryCursor(AsyncQueryHandler async, String filter) {
237         if (filter == null) {
238             filter = "";
239         }
240         String[] ccols = new String[] {
241                 "_id",   // this will be the artist, album or track ID
242                 MediaStore.Audio.Media.MIME_TYPE, // mimetype of audio file, or "artist" or "album"
243                 SearchManager.SUGGEST_COLUMN_TEXT_1,
244                 "data1",
245                 "data2"
246         };
247
248         Uri search = Uri.parse("content://media/external/audio/" + 
249                 SearchManager.SUGGEST_URI_PATH_QUERY + "/" + Uri.encode(filter));
250         
251         Cursor ret = null;
252         if (async != null) {
253             async.startQuery(0, null, search, ccols, null, null, null);
254         } else {
255             ret = MusicUtils.query(this, search, ccols, null, null, null);
256         }
257         return ret;
258     }
259     
260     static class QueryListAdapter extends SimpleCursorAdapter {
261         private QueryBrowserActivity mActivity = null;
262         private AsyncQueryHandler mQueryHandler;
263
264         class QueryHandler extends AsyncQueryHandler {
265             QueryHandler(ContentResolver res) {
266                 super(res);
267             }
268             
269             @Override
270             protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
271                 mActivity.init(cursor);
272             }
273         }
274
275         QueryListAdapter(Context context, QueryBrowserActivity currentactivity,
276                 int layout, Cursor cursor, String[] from, int[] to) {
277             super(context, layout, cursor, from, to);
278             mActivity = currentactivity;
279             mQueryHandler = new QueryHandler(context.getContentResolver());
280         }
281
282         public void setActivity(QueryBrowserActivity newactivity) {
283             mActivity = newactivity;
284         }
285         
286         public AsyncQueryHandler getQueryHandler() {
287             return mQueryHandler;
288         }
289
290         @Override
291         public void bindView(View view, Context context, Cursor cursor) {
292             
293             TextView tv1 = (TextView) view.findViewById(R.id.line1);
294             TextView tv2 = (TextView) view.findViewById(R.id.line2);
295             ImageView iv = (ImageView) view.findViewById(R.id.icon);
296             ViewGroup.LayoutParams p = iv.getLayoutParams();
297             if (p == null) {
298                 // seen this happen, not sure why
299                 DatabaseUtils.dumpCursor(cursor);
300                 return;
301             }
302             p.width = ViewGroup.LayoutParams.WRAP_CONTENT;
303             p.height = ViewGroup.LayoutParams.WRAP_CONTENT;
304             
305             String mimetype = cursor.getString(cursor.getColumnIndexOrThrow(
306                     MediaStore.Audio.Media.MIME_TYPE));
307             
308             if (mimetype == null) {
309                 mimetype = "audio/";
310             }
311             if (mimetype.equals("artist")) {
312                 iv.setImageResource(R.drawable.ic_search_category_music_artist);
313                 String name = cursor.getString(cursor.getColumnIndexOrThrow(
314                         SearchManager.SUGGEST_COLUMN_TEXT_1));
315                 String displayname = name;
316                 if (name.equals(MediaFile.UNKNOWN_STRING)) {
317                     displayname = context.getString(R.string.unknown_artist_name);
318                 }
319                 tv1.setText(displayname);
320
321                 int numalbums = cursor.getInt(cursor.getColumnIndexOrThrow("data1"));
322                 int numsongs = cursor.getInt(cursor.getColumnIndexOrThrow("data2"));
323                 
324                 String songs_albums = MusicUtils.makeAlbumsSongsLabel(context,
325                         numalbums, numsongs, name.equals(MediaFile.UNKNOWN_STRING));
326                 
327                 tv2.setText(songs_albums);
328             
329             } else if (mimetype.equals("album")) {
330                 iv.setImageResource(R.drawable.ic_search_category_music_album);
331                 String name = cursor.getString(cursor.getColumnIndexOrThrow(
332                         SearchManager.SUGGEST_COLUMN_TEXT_1));
333                 String displayname = name;
334                 if (name.equals(MediaFile.UNKNOWN_STRING)) {
335                     displayname = context.getString(R.string.unknown_album_name);
336                 }
337                 tv1.setText(displayname);
338                 
339                 name = cursor.getString(cursor.getColumnIndexOrThrow("data1"));
340                 displayname = name;
341                 if (name.equals(MediaFile.UNKNOWN_STRING)) {
342                     displayname = context.getString(R.string.unknown_artist_name);
343                 }
344                 tv2.setText(displayname);
345                 
346             } else if(mimetype.startsWith("audio/") ||
347                     mimetype.equals("application/ogg") ||
348                     mimetype.equals("application/x-ogg")) {
349                 iv.setImageResource(R.drawable.ic_search_category_music_song);
350                 String name = cursor.getString(cursor.getColumnIndexOrThrow(
351                         SearchManager.SUGGEST_COLUMN_TEXT_1));
352                 tv1.setText(name);
353
354                 String displayname = cursor.getString(cursor.getColumnIndexOrThrow("data1"));
355                 if (name.equals(MediaFile.UNKNOWN_STRING)) {
356                     displayname = context.getString(R.string.unknown_artist_name);
357                 }
358                 name = cursor.getString(cursor.getColumnIndexOrThrow("data2"));
359                 if (name.equals(MediaFile.UNKNOWN_STRING)) {
360                     name = context.getString(R.string.unknown_artist_name);
361                 }
362                 tv2.setText(displayname + " - " + name);
363             }
364         }
365         @Override
366         public void changeCursor(Cursor cursor) {
367             if (cursor != mActivity.mQueryCursor) {
368                 mActivity.mQueryCursor = cursor;
369                 super.changeCursor(cursor);
370             }
371         }
372         @Override
373         public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
374             return mActivity.getQueryCursor(null, constraint.toString());
375         }
376     }
377
378     private ListView mTrackList;
379     private Cursor mQueryCursor;
380 }
381