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