12a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn/*
22a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn * Copyright (C) 2011 The Android Open Source Project
32a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn *
42a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License");
52a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn * you may not use this file except in compliance with the License.
62a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn * You may obtain a copy of the License at
72a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn *
82a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn *      http://www.apache.org/licenses/LICENSE-2.0
92a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn *
102a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn * Unless required by applicable law or agreed to in writing, software
112a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS,
122a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn * See the License for the specific language governing permissions and
142a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn * limitations under the License.
152a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn */
162a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
172a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackbornpackage com.example.android.supportv13.app;
182a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
192a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackbornimport android.app.ListFragment;
202a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackbornimport android.app.LoaderManager;
212a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackbornimport android.content.CursorLoader;
222a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackbornimport android.content.Loader;
232a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackbornimport android.database.Cursor;
242a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackbornimport android.net.Uri;
252a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackbornimport android.os.Bundle;
262a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackbornimport android.provider.ContactsContract.Contacts;
272a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackbornimport android.text.TextUtils;
282a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackbornimport android.util.Log;
292a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackbornimport android.view.Menu;
302a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackbornimport android.view.MenuInflater;
312a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackbornimport android.view.MenuItem;
322a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackbornimport android.view.View;
332a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackbornimport android.widget.ListView;
342a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackbornimport android.widget.SearchView;
352a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackbornimport android.widget.SearchView.OnQueryTextListener;
36def582a5836579a3fadabfdbe4413cb1652bf098Aurimas Liutikasimport android.widget.SimpleCursorAdapter;
372a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
382a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
392a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackbornpublic class CursorFragment extends ListFragment
402a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> {
412a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
422a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    // This is the Adapter being used to display the list's data.
432a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    SimpleCursorAdapter mAdapter;
442a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
452a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    // If non-null, this is the current filter the user has provided.
462a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    String mCurFilter;
472a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
482a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    @Override public void onActivityCreated(Bundle savedInstanceState) {
492a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        super.onActivityCreated(savedInstanceState);
502a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
512a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // Give some text to display if there is no data.  In a real
522a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // application this would come from a resource.
532a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        setEmptyText("No phone numbers");
542a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
552a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // We have a menu item to show in action bar.
562a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        setHasOptionsMenu(true);
572a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
582a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // Create an empty adapter we will use to display the loaded data.
592a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        mAdapter = new SimpleCursorAdapter(getActivity(),
602a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn                android.R.layout.simple_list_item_2, null,
612a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn                new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS },
622a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn                new int[] { android.R.id.text1, android.R.id.text2 }, 0);
632a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        setListAdapter(mAdapter);
642a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
652a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // Start out with a progress indicator.
662a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        setListShown(false);
672a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
682a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // Prepare the loader.  Either re-connect with an existing one,
692a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // or start a new one.
702a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        getLoaderManager().initLoader(0, null, this);
712a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    }
722a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
732a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
742a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // Place an action bar item for searching.
752a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        MenuItem item = menu.add("Search");
762a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        item.setIcon(android.R.drawable.ic_menu_search);
779399add0ae12999002418744b3827a0593a7e812Dianne Hackborn        item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM
789399add0ae12999002418744b3827a0593a7e812Dianne Hackborn                | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
792a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        SearchView sv = new SearchView(getActivity());
802a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        sv.setOnQueryTextListener(this);
812a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        item.setActionView(sv);
822a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    }
832a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
84e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas    @Override
852a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    public boolean onQueryTextChange(String newText) {
862a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // Called when the action bar search text has changed.  Update
872a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // the search filter, and restart the loader to do a new query
882a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // with this filter.
892a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
902a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        getLoaderManager().restartLoader(0, null, this);
912a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        return true;
922a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    }
932a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
942a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    @Override public boolean onQueryTextSubmit(String query) {
952a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // Don't care about this.
962a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        return true;
972a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    }
982a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
992a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    @Override public void onListItemClick(ListView l, View v, int position, long id) {
1002a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // Insert desired behavior here.
1012a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        Log.i("FragmentComplexList", "Item clicked: " + id);
1022a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    }
1032a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
1042a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    // These are the Contacts rows that we will retrieve.
1052a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
1062a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        Contacts._ID,
1072a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        Contacts.DISPLAY_NAME,
1082a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        Contacts.CONTACT_STATUS,
1092a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        Contacts.CONTACT_PRESENCE,
1102a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        Contacts.PHOTO_ID,
1112a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        Contacts.LOOKUP_KEY,
1122a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    };
1132a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
114e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas    @Override
1152a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
1162a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // This is called when a new Loader needs to be created.  This
1172a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // sample only has one Loader, so we don't care about the ID.
1182a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // First, pick the base URI to use depending on whether we are
1192a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // currently filtering.
1202a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        Uri baseUri;
1212a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        if (mCurFilter != null) {
1222a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn            baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
1232a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn                    Uri.encode(mCurFilter));
1242a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        } else {
1252a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn            baseUri = Contacts.CONTENT_URI;
1262a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        }
1272a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
1282a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // Now create and return a CursorLoader that will take care of
1292a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // creating a Cursor for the data being displayed.
1302a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("
1312a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn                + Contacts.HAS_PHONE_NUMBER + "=1) AND ("
1322a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn                + Contacts.DISPLAY_NAME + " != '' ))";
1332a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        return new CursorLoader(getActivity(), baseUri,
1342a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn                CONTACTS_SUMMARY_PROJECTION, select, null,
1352a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn                Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
1362a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    }
1372a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
138e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas    @Override
1392a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
1402a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // Swap the new cursor in.  (The framework will take care of closing the
1412a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // old cursor once we return.)
1422a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        mAdapter.swapCursor(data);
1432a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
1442a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // The list should now be shown.
1452a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        if (isResumed()) {
1462a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn            setListShown(true);
1472a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        } else {
1482a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn            setListShownNoAnimation(true);
1492a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        }
1502a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    }
1512a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn
152e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas    @Override
1532a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    public void onLoaderReset(Loader<Cursor> loader) {
1542a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // This is called when the last Cursor provided to onLoadFinished()
1552a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // above is about to be closed.  We need to make sure we are no
1562a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        // longer using it.
1572a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn        mAdapter.swapCursor(null);
1582a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn    }
1592a5ea7ee95eba09f0824eda66efd4c9a2f8ad5e8Dianne Hackborn}
160