1/*
2 * Copyright (C) 2010 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.example.android.supportv4.app;
18
19import android.support.v4.app.FragmentActivity;
20import android.support.v4.app.FragmentManager;
21import android.support.v4.app.ListFragment;
22import android.support.v4.app.LoaderManager;
23import android.support.v4.content.CursorLoader;
24import android.support.v4.content.Loader;
25import android.support.v4.view.MenuItemCompat;
26import android.support.v4.widget.SearchViewCompat;
27import android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat;
28import android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat;
29import android.support.v4.widget.SimpleCursorAdapter;
30
31import android.database.Cursor;
32import android.net.Uri;
33import android.os.Bundle;
34import android.provider.BaseColumns;
35import android.provider.Contacts.People;
36import android.text.TextUtils;
37import android.util.Log;
38import android.view.Menu;
39import android.view.MenuInflater;
40import android.view.MenuItem;
41import android.view.View;
42import android.widget.ListView;
43
44/**
45 * Demonstration of the use of a CursorLoader to load and display contacts
46 * data in a fragment.
47 */
48@SuppressWarnings("all")
49public class LoaderCursorSupport extends FragmentActivity {
50
51    @Override
52    protected void onCreate(Bundle savedInstanceState) {
53        super.onCreate(savedInstanceState);
54
55        FragmentManager fm = getSupportFragmentManager();
56
57        // Create the list fragment and add it as our sole content.
58        if (fm.findFragmentById(android.R.id.content) == null) {
59            CursorLoaderListFragment list = new CursorLoaderListFragment();
60            fm.beginTransaction().add(android.R.id.content, list).commit();
61        }
62    }
63
64//BEGIN_INCLUDE(fragment_cursor)
65    public static class CursorLoaderListFragment extends ListFragment
66            implements LoaderManager.LoaderCallbacks<Cursor> {
67
68        // This is the Adapter being used to display the list's data.
69        SimpleCursorAdapter mAdapter;
70
71        // If non-null, this is the current filter the user has provided.
72        String mCurFilter;
73
74        @Override public void onActivityCreated(Bundle savedInstanceState) {
75            super.onActivityCreated(savedInstanceState);
76
77            // Give some text to display if there is no data.  In a real
78            // application this would come from a resource.
79            setEmptyText("No phone numbers");
80
81            // We have a menu item to show in action bar.
82            setHasOptionsMenu(true);
83
84            // Create an empty adapter we will use to display the loaded data.
85            mAdapter = new SimpleCursorAdapter(getActivity(),
86                    android.R.layout.simple_list_item_1, null,
87                    new String[] { People.DISPLAY_NAME },
88                    new int[] { android.R.id.text1}, 0);
89            setListAdapter(mAdapter);
90
91            // Start out with a progress indicator.
92            setListShown(false);
93
94            // Prepare the loader.  Either re-connect with an existing one,
95            // or start a new one.
96            getLoaderManager().initLoader(0, null, this);
97        }
98
99        @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
100            // Place an action bar item for searching.
101            MenuItem item = menu.add("Search");
102            item.setIcon(android.R.drawable.ic_menu_search);
103            MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS
104                    | MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
105            final View searchView = SearchViewCompat.newSearchView(getActivity());
106            if (searchView != null) {
107                SearchViewCompat.setOnQueryTextListener(searchView,
108                        new OnQueryTextListenerCompat() {
109                    @Override
110                    public boolean onQueryTextChange(String newText) {
111                        // Called when the action bar search text has changed.  Update
112                        // the search filter, and restart the loader to do a new query
113                        // with this filter.
114                        String newFilter = !TextUtils.isEmpty(newText) ? newText : null;
115                        // Don't do anything if the filter hasn't actually changed.
116                        // Prevents restarting the loader when restoring state.
117                        if (mCurFilter == null && newFilter == null) {
118                            return true;
119                        }
120                        if (mCurFilter != null && mCurFilter.equals(newFilter)) {
121                            return true;
122                        }
123                        mCurFilter = newFilter;
124                        getLoaderManager().restartLoader(0, null, CursorLoaderListFragment.this);
125                        return true;
126                    }
127                });
128                SearchViewCompat.setOnCloseListener(searchView,
129                        new OnCloseListenerCompat() {
130                            @Override
131                            public boolean onClose() {
132                                if (!TextUtils.isEmpty(SearchViewCompat.getQuery(searchView))) {
133                                    SearchViewCompat.setQuery(searchView, null, true);
134                                }
135                                return true;
136                            }
137
138                });
139                MenuItemCompat.setActionView(item, searchView);
140            }
141        }
142
143        @Override public void onListItemClick(ListView l, View v, int position, long id) {
144            // Insert desired behavior here.
145            Log.i("FragmentComplexList", "Item clicked: " + id);
146        }
147
148        // These are the Contacts rows that we will retrieve.
149        static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
150            People._ID,
151            People.DISPLAY_NAME,
152        };
153
154        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
155            // This is called when a new Loader needs to be created.  This
156            // sample only has one Loader, so we don't care about the ID.
157            // First, pick the base URI to use depending on whether we are
158            // currently filtering.
159            Uri baseUri;
160            if (mCurFilter != null) {
161                baseUri = Uri.withAppendedPath(People.CONTENT_FILTER_URI, Uri.encode(mCurFilter));
162            } else {
163                baseUri = People.CONTENT_URI;
164            }
165
166            // Now create and return a CursorLoader that will take care of
167            // creating a Cursor for the data being displayed.
168            String select = "((" + People.DISPLAY_NAME + " NOTNULL) AND ("
169                    + People.DISPLAY_NAME + " != '' ))";
170            return new CursorLoader(getActivity(), baseUri,
171                    CONTACTS_SUMMARY_PROJECTION, select, null,
172                    People.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
173        }
174
175        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
176            // Swap the new cursor in.  (The framework will take care of closing the
177            // old cursor once we return.)
178            mAdapter.swapCursor(data);
179
180            // The list should now be shown.
181            if (isResumed()) {
182                setListShown(true);
183            } else {
184                setListShownNoAnimation(true);
185            }
186        }
187
188        public void onLoaderReset(Loader<Cursor> loader) {
189            // This is called when the last Cursor provided to onLoadFinished()
190            // above is about to be closed.  We need to make sure we are no
191            // longer using it.
192            mAdapter.swapCursor(null);
193        }
194    }
195//END_INCLUDE(fragment_cursor)
196}
197