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