QueryBrowserActivity.java revision a857e7ab7608a85c8d66e971e5807051bdb6daba
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 17package com.android.music; 18 19import android.app.ListActivity; 20import android.app.SearchManager; 21import android.content.AsyncQueryHandler; 22import android.content.ContentResolver; 23import android.content.Context; 24import android.content.Intent; 25import com.android.internal.database.ArrayListCursor; 26import com.android.music.TrackBrowserActivity.MyQueryHandler; 27 28import android.database.Cursor; 29import android.database.DatabaseUtils; 30import android.media.AudioManager; 31import android.media.MediaFile; 32import android.net.Uri; 33import android.os.Bundle; 34import android.provider.MediaStore; 35import android.util.Log; 36import android.view.KeyEvent; 37import android.view.MenuItem; 38import android.view.View; 39import android.view.ViewGroup; 40import android.view.Window; 41import android.view.ViewGroup.OnHierarchyChangeListener; 42import android.widget.ImageView; 43import android.widget.ListView; 44import android.widget.SimpleCursorAdapter; 45import android.widget.TextView; 46 47import java.util.ArrayList; 48 49public class QueryBrowserActivity extends ListActivity implements MusicUtils.Defs 50{ 51 private final static int PLAY_NOW = 0; 52 private final static int ADD_TO_QUEUE = 1; 53 private final static int PLAY_NEXT = 2; 54 private final static int PLAY_ARTIST = 3; 55 private final static int EXPLORE_ARTIST = 4; 56 private final static int PLAY_ALBUM = 5; 57 private final static int EXPLORE_ALBUM = 6; 58 private final static int REQUERY = 3; 59 private MyQueryHandler mQueryHandler; 60 private String mFilterString = ""; 61 62 public QueryBrowserActivity() 63 { 64 } 65 66 /** Called when the activity is first created. */ 67 @Override 68 public void onCreate(Bundle icicle) 69 { 70 super.onCreate(icicle); 71 setVolumeControlStream(AudioManager.STREAM_MUSIC); 72 MusicUtils.bindToService(this); 73 74 if (icicle == null) { 75 Intent intent = getIntent(); 76 mFilterString = intent.getStringExtra(SearchManager.QUERY); 77 } 78 if (mFilterString == null) { 79 mFilterString = ""; 80 } 81 82 setContentView(R.layout.query_activity); 83 mTrackList = (ListView) findViewById(android.R.id.list); 84 85 mQueryHandler = new MyQueryHandler(getContentResolver()); 86 mQueryCursor = (Cursor) getLastNonConfigurationInstance(); 87 if (mQueryCursor == null) { 88 //Log.i("@@@", "starting query"); 89 setTitle(R.string.working_songs); 90 getQueryCursor(mQueryHandler); 91 } else { 92 init(mQueryCursor); 93 } 94 } 95 96 @Override 97 public Object onRetainNonConfigurationInstance() { 98 Cursor c = mQueryCursor; 99 mQueryCursor = null; 100 return c; 101 } 102 103 class MyQueryHandler extends AsyncQueryHandler { 104 MyQueryHandler(ContentResolver res) { 105 super(res); 106 } 107 108 @Override 109 protected void onQueryComplete(int token, Object cookie, Cursor cursor) { 110 Log.i("@@@", "query complete"); 111 init(cursor); 112 } 113 } 114 115 @Override 116 public void onDestroy() { 117 MusicUtils.unbindFromService(this); 118 super.onDestroy(); 119 if (mQueryCursor != null) { 120 mQueryCursor.close(); 121 } 122 } 123 124 public void init(Cursor c) { 125 126 mQueryCursor = c; 127 128 ListView lv = getListView(); 129 lv.setTextFilterEnabled(true); 130 131 if (mQueryCursor == null) { 132 MusicUtils.displayDatabaseError(this); 133 setListAdapter(null); 134 lv.setFocusable(false); 135 return; 136 } 137 138 // Map Cursor columns to views defined in media_list_item.xml 139 QueryListAdapter adapter = new QueryListAdapter( 140 this, 141 R.layout.track_list_item, 142 mQueryCursor, 143 new String[] {}, 144 new int[] {}); 145 146 setListAdapter(adapter); 147 148 if (mFilterString.length() != 0) { 149 // Hack. Can be removed once ListView supports starting filtering with a given string 150 lv.setOnHierarchyChangeListener(mHierarchyListener); 151 } 152 } 153 154 OnHierarchyChangeListener mHierarchyListener = new OnHierarchyChangeListener() { 155 public void onChildViewAdded(View parent, View child) { 156 ((ListView)parent).setOnHierarchyChangeListener(null); 157 // need to do this here to be sure all the views have been initialized 158 startFilteringWithString(mFilterString); 159 } 160 161 public void onChildViewRemoved(View parent, View child) { 162 } 163 }; 164 165 private KeyEvent eventForChar(char c) { 166 int code = -1; 167 if (c >= 'a' && c <= 'z') { 168 code = KeyEvent.KEYCODE_A + (c - 'a'); 169 } else if (c >= 'A' && c <= 'Z') { 170 code = KeyEvent.KEYCODE_A + (c - 'A'); 171 } else if (c >= '0' && c <= '9') { 172 code = KeyEvent.KEYCODE_0 + (c - '0'); 173 } 174 if (code != -1) { 175 return new KeyEvent(KeyEvent.ACTION_DOWN, code); 176 } 177 return null; 178 } 179 private void startFilteringWithString(String filterstring) { 180 ListView lv = getListView(); 181 for (int i = 0; i < filterstring.length(); i++) { 182 KeyEvent event = eventForChar(filterstring.charAt(i)); 183 if (event != null) { 184 lv.onKeyDown(event.getKeyCode(), event); 185 } 186 } 187 } 188 189 @Override 190 protected void onListItemClick(ListView l, View v, int position, long id) 191 { 192 // Dialog doesn't allow us to wait for a result, so we need to store 193 // the info we need for when the dialog posts its result 194 mQueryCursor.moveToPosition(position); 195 if (mQueryCursor.isBeforeFirst() || mQueryCursor.isAfterLast()) { 196 return; 197 } 198 String selectedType = mQueryCursor.getString(mQueryCursor.getColumnIndexOrThrow( 199 MediaStore.Audio.Media.MIME_TYPE)); 200 201 if ("artist".equals(selectedType)) { 202 Intent intent = new Intent(Intent.ACTION_PICK); 203 intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/album"); 204 intent.putExtra("artist", Long.valueOf(id).toString()); 205 startActivity(intent); 206 } else if ("album".equals(selectedType)) { 207 Intent intent = new Intent(Intent.ACTION_PICK); 208 intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track"); 209 intent.putExtra("album", Long.valueOf(id).toString()); 210 startActivity(intent); 211 } else if (position >= 0 && id >= 0){ 212 int [] list = new int[] { (int) id }; 213 MusicUtils.playAll(this, list, 0); 214 } else { 215 Log.e("QueryBrowser", "invalid position/id: " + position + "/" + id); 216 } 217 } 218 219 @Override 220 public boolean onOptionsItemSelected(MenuItem item) { 221 switch (item.getItemId()) { 222 case USE_AS_RINGTONE: { 223 // Set the system setting to make this the current ringtone 224 MusicUtils.setRingtone(this, mTrackList.getSelectedItemId()); 225 return true; 226 } 227 228 } 229 return super.onOptionsItemSelected(item); 230 } 231 232 private Cursor getQueryCursor(AsyncQueryHandler async) { 233 String[] ccols = new String[] { 234 "_id", // this will be the artist, album or track ID 235 MediaStore.Audio.Media.MIME_TYPE, // mimetype of audio file, or "artist" or "album" 236 SearchManager.SUGGEST_COLUMN_TEXT_1, 237 "data1", 238 "data2" 239 }; 240 241 Uri search = Uri.parse("content://media/external/audio/" + 242 SearchManager.SUGGEST_URI_PATH_QUERY + "/" + Uri.encode(mFilterString)); 243 244 Cursor ret = null; 245 if (async != null) { 246 async.startQuery(0, null, search, ccols, null, null, null); 247 } else { 248 ret = MusicUtils.query(this, search, ccols, null, null, null); 249 } 250 return ret; 251 } 252 253 class QueryListAdapter extends SimpleCursorAdapter { 254 QueryListAdapter(Context context, int layout, Cursor cursor, String[] from, int[] to) { 255 super(context, layout, cursor, from, to); 256 } 257 258 @Override 259 public void bindView(View view, Context context, Cursor cursor) { 260 261 TextView tv1 = (TextView) view.findViewById(R.id.line1); 262 TextView tv2 = (TextView) view.findViewById(R.id.line2); 263 ImageView iv = (ImageView) view.findViewById(R.id.icon); 264 ViewGroup.LayoutParams p = iv.getLayoutParams(); 265 if (p == null) { 266 // seen this happen, not sure why 267 DatabaseUtils.dumpCursor(cursor); 268 return; 269 } 270 p.width = ViewGroup.LayoutParams.WRAP_CONTENT; 271 p.height = ViewGroup.LayoutParams.WRAP_CONTENT; 272 273 String mimetype = cursor.getString(cursor.getColumnIndexOrThrow( 274 MediaStore.Audio.Media.MIME_TYPE)); 275 276 if (mimetype == null) { 277 mimetype = "audio/"; 278 } 279 if (mimetype.equals("artist")) { 280 iv.setImageResource(R.drawable.ic_search_category_music_artist); 281 String name = cursor.getString(cursor.getColumnIndexOrThrow( 282 SearchManager.SUGGEST_COLUMN_TEXT_1)); 283 String displayname = name; 284 if (name.equals(MediaFile.UNKNOWN_STRING)) { 285 displayname = context.getString(R.string.unknown_artist_name); 286 } 287 tv1.setText(displayname); 288 289 int numalbums = cursor.getInt(cursor.getColumnIndexOrThrow("data1")); 290 int numsongs = cursor.getInt(cursor.getColumnIndexOrThrow("data2")); 291 292 String songs_albums = MusicUtils.makeAlbumsSongsLabel(context, 293 numalbums, numsongs, name.equals(MediaFile.UNKNOWN_STRING)); 294 295 tv2.setText(songs_albums); 296 297 } else if (mimetype.equals("album")) { 298 iv.setImageResource(R.drawable.ic_search_category_music_album); 299 String name = cursor.getString(cursor.getColumnIndexOrThrow( 300 SearchManager.SUGGEST_COLUMN_TEXT_1)); 301 String displayname = name; 302 if (name.equals(MediaFile.UNKNOWN_STRING)) { 303 displayname = context.getString(R.string.unknown_album_name); 304 } 305 tv1.setText(displayname); 306 307 name = cursor.getString(cursor.getColumnIndexOrThrow("data1")); 308 displayname = name; 309 if (name.equals(MediaFile.UNKNOWN_STRING)) { 310 displayname = context.getString(R.string.unknown_artist_name); 311 } 312 tv2.setText(displayname); 313 314 } else if(mimetype.startsWith("audio/") || 315 mimetype.equals("application/ogg") || 316 mimetype.equals("application/x-ogg")) { 317 iv.setImageResource(R.drawable.ic_search_category_music_song); 318 String name = cursor.getString(cursor.getColumnIndexOrThrow( 319 SearchManager.SUGGEST_COLUMN_TEXT_1)); 320 tv1.setText(name); 321 322 String displayname = cursor.getString(cursor.getColumnIndexOrThrow("data1")); 323 if (name.equals(MediaFile.UNKNOWN_STRING)) { 324 displayname = context.getString(R.string.unknown_artist_name); 325 } 326 name = cursor.getString(cursor.getColumnIndexOrThrow("data2")); 327 if (name.equals(MediaFile.UNKNOWN_STRING)) { 328 name = context.getString(R.string.unknown_artist_name); 329 } 330 tv2.setText(displayname + " - " + name); 331 } 332 } 333 @Override 334 public void changeCursor(Cursor cursor) { 335 super.changeCursor(cursor); 336 mQueryCursor = cursor; 337 } 338 @Override 339 public Cursor runQueryOnBackgroundThread(CharSequence constraint) { 340 mFilterString = constraint.toString(); 341 return getQueryCursor(null); 342 } 343 } 344 345 private ListView mTrackList; 346 private Cursor mQueryCursor; 347} 348 349