19fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn/*
29fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * Copyright (C) 2010 The Android Open Source Project
39fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn *
49fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License");
59fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * you may not use this file except in compliance with the License.
69fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * You may obtain a copy of the License at
79fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn *
89fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn *      http://www.apache.org/licenses/LICENSE-2.0
99fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn *
109fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * Unless required by applicable law or agreed to in writing, software
119fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS,
129fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * See the License for the specific language governing permissions and
149fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn * limitations under the License.
159fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn */
169fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
1710c33528e033643099783a5bc4eedb4b8a1e9a0eDianne Hackbornpackage com.example.android.supportv4.app;
189fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
199fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.support.v4.app.FragmentActivity;
209fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.support.v4.app.FragmentManager;
219fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.support.v4.app.ListFragment;
229fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.support.v4.app.LoaderManager;
239fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.support.v4.content.CursorLoader;
249fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.support.v4.content.Loader;
25a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganovimport android.support.v4.view.MenuItemCompat;
26a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganovimport android.support.v4.widget.SearchViewCompat;
27a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganovimport android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat;
289fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.support.v4.widget.SimpleCursorAdapter;
299fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
309fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.database.Cursor;
319fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.net.Uri;
329fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.os.Bundle;
33a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganovimport android.provider.BaseColumns;
34a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganovimport android.provider.Contacts.People;
359fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.text.TextUtils;
369fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.util.Log;
379fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.view.Menu;
389fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.view.MenuInflater;
39a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganovimport android.view.MenuItem;
409fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.view.View;
419fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackbornimport android.widget.ListView;
429fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
439fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn/**
44d9012d1bfa132969fb8fed737e2f9f19eefbc0b5Dianne Hackborn * Demonstration of the use of a CursorLoader to load and display contacts
45d9012d1bfa132969fb8fed737e2f9f19eefbc0b5Dianne Hackborn * data in a fragment.
469fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn */
47a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov@SuppressWarnings("all")
48d9012d1bfa132969fb8fed737e2f9f19eefbc0b5Dianne Hackbornpublic class LoaderCursorSupport extends FragmentActivity {
499fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
509fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn    @Override
519fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn    protected void onCreate(Bundle savedInstanceState) {
529fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        super.onCreate(savedInstanceState);
539fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
549fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        FragmentManager fm = getSupportFragmentManager();
559fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
569fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        // Create the list fragment and add it as our sole content.
579fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        if (fm.findFragmentById(android.R.id.content) == null) {
589fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            CursorLoaderListFragment list = new CursorLoaderListFragment();
599fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            fm.beginTransaction().add(android.R.id.content, list).commit();
609fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        }
619fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn    }
629fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
639fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn//BEGIN_INCLUDE(fragment_cursor)
649fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn    public static class CursorLoaderListFragment extends ListFragment
659fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            implements LoaderManager.LoaderCallbacks<Cursor> {
669fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
679fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        // This is the Adapter being used to display the list's data.
689fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        SimpleCursorAdapter mAdapter;
699fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
709fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        // If non-null, this is the current filter the user has provided.
719fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        String mCurFilter;
729fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
739fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        @Override public void onActivityCreated(Bundle savedInstanceState) {
749fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            super.onActivityCreated(savedInstanceState);
759fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
769fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            // Give some text to display if there is no data.  In a real
779fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            // application this would come from a resource.
789fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            setEmptyText("No phone numbers");
799fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
809fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            // We have a menu item to show in action bar.
819fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            setHasOptionsMenu(true);
829fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
839fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            // Create an empty adapter we will use to display the loaded data.
849fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            mAdapter = new SimpleCursorAdapter(getActivity(),
85a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov                    android.R.layout.simple_list_item_1, null,
86a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov                    new String[] { People.DISPLAY_NAME },
87a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov                    new int[] { android.R.id.text1}, 0);
889fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            setListAdapter(mAdapter);
899fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
90be6b6b494f094eea0abcd83eb8770bc4b9f7e34eDianne Hackborn            // Start out with a progress indicator.
91be6b6b494f094eea0abcd83eb8770bc4b9f7e34eDianne Hackborn            setListShown(false);
92be6b6b494f094eea0abcd83eb8770bc4b9f7e34eDianne Hackborn
939fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            // Prepare the loader.  Either re-connect with an existing one,
949fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            // or start a new one.
959fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            getLoaderManager().initLoader(0, null, this);
969fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        }
979fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
989fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
999fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            // Place an action bar item for searching.
100a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov            MenuItem item = menu.add("Search");
101a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov            item.setIcon(android.R.drawable.ic_menu_search);
10280df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn            MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS
10380df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn                    | MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
104a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov            View searchView = SearchViewCompat.newSearchView(getActivity());
105a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov            if (searchView != null) {
106a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov                SearchViewCompat.setOnQueryTextListener(searchView,
107a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov                        new OnQueryTextListenerCompat() {
108a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov                    @Override
109a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov                    public boolean onQueryTextChange(String newText) {
110a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov                        // Called when the action bar search text has changed.  Update
111a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov                        // the search filter, and restart the loader to do a new query
112a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov                        // with this filter.
11380df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn                        String newFilter = !TextUtils.isEmpty(newText) ? newText : null;
11480df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn                        // Don't do anything if the filter hasn't actually changed.
11580df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn                        // Prevents restarting the loader when restoring state.
11680df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn                        if (mCurFilter == null && newFilter == null) {
11780df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn                            return true;
11880df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn                        }
11980df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn                        if (mCurFilter != null && mCurFilter.equals(newFilter)) {
12080df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn                            return true;
12180df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn                        }
12280df91c7f2ac155c1cf4c3337f8db5a4bf5426b5Dianne Hackborn                        mCurFilter = newFilter;
123a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov                        getLoaderManager().restartLoader(0, null, CursorLoaderListFragment.this);
124a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov                        return true;
125a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov                    }
126a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov                });
127a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov                MenuItemCompat.setActionView(item, searchView);
128a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov            }
1299fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        }
1309fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
1319fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        @Override public void onListItemClick(ListView l, View v, int position, long id) {
1329fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            // Insert desired behavior here.
1339fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            Log.i("FragmentComplexList", "Item clicked: " + id);
1349fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        }
1359fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
1369fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        // These are the Contacts rows that we will retrieve.
1379fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
138a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov            People._ID,
139a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov            People.DISPLAY_NAME,
1409fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        };
1419fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
1429fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
1439fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            // This is called when a new Loader needs to be created.  This
1449fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            // sample only has one Loader, so we don't care about the ID.
1459fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            // First, pick the base URI to use depending on whether we are
1469fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            // currently filtering.
1479fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            Uri baseUri;
1489fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            if (mCurFilter != null) {
149a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov                baseUri = Uri.withAppendedPath(People.CONTENT_FILTER_URI, Uri.encode(mCurFilter));
1509fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            } else {
151a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov                baseUri = People.CONTENT_URI;
1529fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            }
1539fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
1549fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            // Now create and return a CursorLoader that will take care of
1559fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            // creating a Cursor for the data being displayed.
156a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov            String select = "((" + People.DISPLAY_NAME + " NOTNULL) AND ("
157a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov                    + People.DISPLAY_NAME + " != '' ))";
1589fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            return new CursorLoader(getActivity(), baseUri,
1599fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn                    CONTACTS_SUMMARY_PROJECTION, select, null,
160a09e21a223dd1db2f3d16c1250f6607b712155dcSvetoslav Ganov                    People.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
1619fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        }
1629fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
1639fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
1649fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            // Swap the new cursor in.  (The framework will take care of closing the
1659fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            // old cursor once we return.)
1669fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            mAdapter.swapCursor(data);
167be6b6b494f094eea0abcd83eb8770bc4b9f7e34eDianne Hackborn
168be6b6b494f094eea0abcd83eb8770bc4b9f7e34eDianne Hackborn            // The list should now be shown.
169be6b6b494f094eea0abcd83eb8770bc4b9f7e34eDianne Hackborn            if (isResumed()) {
170be6b6b494f094eea0abcd83eb8770bc4b9f7e34eDianne Hackborn                setListShown(true);
171be6b6b494f094eea0abcd83eb8770bc4b9f7e34eDianne Hackborn            } else {
172be6b6b494f094eea0abcd83eb8770bc4b9f7e34eDianne Hackborn                setListShownNoAnimation(true);
173be6b6b494f094eea0abcd83eb8770bc4b9f7e34eDianne Hackborn            }
1749fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        }
1759fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn
1769fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        public void onLoaderReset(Loader<Cursor> loader) {
1779fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            // This is called when the last Cursor provided to onLoadFinished()
1789fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            // above is about to be closed.  We need to make sure we are no
1799fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            // longer using it.
1809fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn            mAdapter.swapCursor(null);
1819fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn        }
1829fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn    }
1839fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn//END_INCLUDE(fragment_cursor)
1849fd3b6e9933096ad992dcc2212fdce99ce80b597Dianne Hackborn}
185