1c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn/* 2c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn * Copyright (C) 2010 The Android Open Source Project 3c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn * 4c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License"); 5c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn * you may not use this file except in compliance with the License. 6c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn * You may obtain a copy of the License at 7c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn * 8c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn * http://www.apache.org/licenses/LICENSE-2.0 9c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn * 10c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn * Unless required by applicable law or agreed to in writing, software 11c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS, 12c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn * See the License for the specific language governing permissions and 14c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn * limitations under the License. 15c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn */ 16c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 17c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackbornpackage com.example.android.supportv4.app; 18c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 19c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackbornimport android.support.v4.app.FragmentActivity; 20c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackbornimport android.support.v4.app.FragmentManager; 21c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackbornimport android.support.v4.app.ListFragment; 22c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackbornimport android.support.v4.app.LoaderManager; 23c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackbornimport android.support.v4.content.CursorLoader; 24c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackbornimport android.support.v4.content.Loader; 25109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport android.support.v4.view.MenuItemCompat; 26109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport android.support.v4.widget.SearchViewCompat; 279243026743939a62a1db9e759e471c16ecb5c51dDianne Hackbornimport android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat; 28109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat; 29c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackbornimport android.support.v4.widget.SimpleCursorAdapter; 30c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 31c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackbornimport android.database.Cursor; 32c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackbornimport android.net.Uri; 33c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackbornimport android.os.Bundle; 34109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport android.provider.BaseColumns; 35109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport android.provider.Contacts.People; 36c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackbornimport android.text.TextUtils; 37c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackbornimport android.util.Log; 38c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackbornimport android.view.Menu; 39c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackbornimport android.view.MenuInflater; 40109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganovimport android.view.MenuItem; 41c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackbornimport android.view.View; 42c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackbornimport android.widget.ListView; 43c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 44c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn/** 45c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn * Demonstration of the use of a CursorLoader to load and display contacts 46c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn * data in a fragment. 47c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn */ 48109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov@SuppressWarnings("all") 49c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackbornpublic class LoaderCursorSupport extends FragmentActivity { 50c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 51c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn @Override 52c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn protected void onCreate(Bundle savedInstanceState) { 53c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn super.onCreate(savedInstanceState); 54c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 55c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn FragmentManager fm = getSupportFragmentManager(); 56c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 57c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // Create the list fragment and add it as our sole content. 58c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn if (fm.findFragmentById(android.R.id.content) == null) { 59c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn CursorLoaderListFragment list = new CursorLoaderListFragment(); 60c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn fm.beginTransaction().add(android.R.id.content, list).commit(); 61c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn } 62c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn } 63c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 64c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn//BEGIN_INCLUDE(fragment_cursor) 65c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn public static class CursorLoaderListFragment extends ListFragment 66c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn implements LoaderManager.LoaderCallbacks<Cursor> { 67c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 68c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // This is the Adapter being used to display the list's data. 69c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn SimpleCursorAdapter mAdapter; 70c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 71c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // If non-null, this is the current filter the user has provided. 72c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn String mCurFilter; 73c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 74c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn @Override public void onActivityCreated(Bundle savedInstanceState) { 75c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn super.onActivityCreated(savedInstanceState); 76c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 77c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // Give some text to display if there is no data. In a real 78c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // application this would come from a resource. 79c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn setEmptyText("No phone numbers"); 80c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 81c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // We have a menu item to show in action bar. 82c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn setHasOptionsMenu(true); 83c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 84c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // Create an empty adapter we will use to display the loaded data. 85c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn mAdapter = new SimpleCursorAdapter(getActivity(), 86109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov android.R.layout.simple_list_item_1, null, 87109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov new String[] { People.DISPLAY_NAME }, 88109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov new int[] { android.R.id.text1}, 0); 89c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn setListAdapter(mAdapter); 90c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 91aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // Start out with a progress indicator. 92aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn setListShown(false); 93aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 94c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // Prepare the loader. Either re-connect with an existing one, 95c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // or start a new one. 96c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn getLoaderManager().initLoader(0, null, this); 97c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn } 98c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 99c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 100c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // Place an action bar item for searching. 101109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov MenuItem item = menu.add("Search"); 102109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov item.setIcon(android.R.drawable.ic_menu_search); 1036a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS 1046a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn | MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW); 1059243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn final View searchView = SearchViewCompat.newSearchView(getActivity()); 106109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov if (searchView != null) { 107109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov SearchViewCompat.setOnQueryTextListener(searchView, 108109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov new OnQueryTextListenerCompat() { 109109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov @Override 110109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov public boolean onQueryTextChange(String newText) { 111109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov // Called when the action bar search text has changed. Update 112109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov // the search filter, and restart the loader to do a new query 113109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov // with this filter. 1146a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn String newFilter = !TextUtils.isEmpty(newText) ? newText : null; 1156a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // Don't do anything if the filter hasn't actually changed. 1166a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn // Prevents restarting the loader when restoring state. 1176a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn if (mCurFilter == null && newFilter == null) { 1186a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn return true; 1196a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn } 1206a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn if (mCurFilter != null && mCurFilter.equals(newFilter)) { 1216a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn return true; 1226a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn } 1236a8875b9abd9914c20d28ccd8eb483da4ff9e4a5Dianne Hackborn mCurFilter = newFilter; 124109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov getLoaderManager().restartLoader(0, null, CursorLoaderListFragment.this); 125109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov return true; 126109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov } 127109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov }); 1289243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn SearchViewCompat.setOnCloseListener(searchView, 1299243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn new OnCloseListenerCompat() { 1309243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn @Override 1319243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn public boolean onClose() { 1329243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn if (!TextUtils.isEmpty(SearchViewCompat.getQuery(searchView))) { 1339243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn SearchViewCompat.setQuery(searchView, null, true); 1349243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn } 1359243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn return true; 1369243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn } 1379243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn 1389243026743939a62a1db9e759e471c16ecb5c51dDianne Hackborn }); 139109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov MenuItemCompat.setActionView(item, searchView); 140109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov } 141c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn } 142c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 143c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn @Override public void onListItemClick(ListView l, View v, int position, long id) { 144c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // Insert desired behavior here. 145c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn Log.i("FragmentComplexList", "Item clicked: " + id); 146c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn } 147c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 148c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // These are the Contacts rows that we will retrieve. 149c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { 150109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov People._ID, 151109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov People.DISPLAY_NAME, 152c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn }; 153c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 154c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn public Loader<Cursor> onCreateLoader(int id, Bundle args) { 155c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // This is called when a new Loader needs to be created. This 156c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // sample only has one Loader, so we don't care about the ID. 157c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // First, pick the base URI to use depending on whether we are 158c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // currently filtering. 159c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn Uri baseUri; 160c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn if (mCurFilter != null) { 161109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov baseUri = Uri.withAppendedPath(People.CONTENT_FILTER_URI, Uri.encode(mCurFilter)); 162c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn } else { 163109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov baseUri = People.CONTENT_URI; 164c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn } 165c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 166c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // Now create and return a CursorLoader that will take care of 167c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // creating a Cursor for the data being displayed. 168109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov String select = "((" + People.DISPLAY_NAME + " NOTNULL) AND (" 169109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov + People.DISPLAY_NAME + " != '' ))"; 170c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn return new CursorLoader(getActivity(), baseUri, 171c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn CONTACTS_SUMMARY_PROJECTION, select, null, 172109979ea9794aa98665d125ebe6a90448ff65f1fSvetoslav Ganov People.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); 173c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn } 174c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 175c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 176c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // Swap the new cursor in. (The framework will take care of closing the 177c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // old cursor once we return.) 178c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn mAdapter.swapCursor(data); 179aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn 180aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn // The list should now be shown. 181aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn if (isResumed()) { 182aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn setListShown(true); 183aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } else { 184aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn setListShownNoAnimation(true); 185aefd2819f5d9f972a6c6dc33a3c66d6d2891d4e8Dianne Hackborn } 186c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn } 187c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn 188c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn public void onLoaderReset(Loader<Cursor> loader) { 189c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // This is called when the last Cursor provided to onLoadFinished() 190c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // above is about to be closed. We need to make sure we are no 191c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn // longer using it. 192c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn mAdapter.swapCursor(null); 193c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn } 194c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn } 195c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn//END_INCLUDE(fragment_cursor) 196c644c91b91b83a6b400a57b02671f4ef7b7a810bDianne Hackborn} 197