1 /* 2 * Copyright (C) 2012 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 package com.example.android.basiccontactables; 17 18 import android.app.Activity; 19 import android.app.LoaderManager; 20 import android.content.Context; 21 import android.content.CursorLoader; 22 import android.content.Loader; 23 import android.database.Cursor; 24 import android.net.Uri; 25 import android.os.Bundle; 26 import android.provider.ContactsContract.CommonDataKinds; 27 import android.util.Log; 28 import android.widget.TextView; 29 30 /** 31 * Helper class to handle all the callbacks that occur when interacting with loaders. Most of the 32 * interesting code in this sample app will be in this file. 33 */ 34 public class ContactablesLoaderCallbacks implements LoaderManager.LoaderCallbacks<Cursor> { 35 36 Context mContext; 37 38 public static final String QUERY_KEY = "query"; 39 40 public static final String TAG = "ContactablesLoaderCallbacks"; 41 ContactablesLoaderCallbacks(Context context)42 public ContactablesLoaderCallbacks(Context context) { 43 mContext = context; 44 } 45 46 @Override onCreateLoader(int loaderIndex, Bundle args)47 public Loader<Cursor> onCreateLoader(int loaderIndex, Bundle args) { 48 // Where the Contactables table excels is matching text queries, 49 // not just data dumps from Contacts db. One search term is used to query 50 // display name, email address and phone number. In this case, the query was extracted 51 // from an incoming intent in the handleIntent() method, via the 52 // intent.getStringExtra() method. 53 54 // BEGIN_INCLUDE(uri_with_query) 55 String query = args.getString(QUERY_KEY); 56 Uri uri = Uri.withAppendedPath( 57 CommonDataKinds.Contactables.CONTENT_FILTER_URI, query); 58 // END_INCLUDE(uri_with_query) 59 60 61 // BEGIN_INCLUDE(cursor_loader) 62 // Easy way to limit the query to contacts with phone numbers. 63 String selection = 64 CommonDataKinds.Contactables.HAS_PHONE_NUMBER + " = " + 1; 65 66 // Sort results such that rows for the same contact stay together. 67 String sortBy = CommonDataKinds.Contactables.LOOKUP_KEY; 68 69 return new CursorLoader( 70 mContext, // Context 71 uri, // URI representing the table/resource to be queried 72 null, // projection - the list of columns to return. Null means "all" 73 selection, // selection - Which rows to return (condition rows must match) 74 null, // selection args - can be provided separately and subbed into selection. 75 sortBy); // string specifying sort order 76 // END_INCLUDE(cursor_loader) 77 } 78 79 @Override onLoadFinished(Loader<Cursor> arg0, Cursor cursor)80 public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor) { 81 TextView tv = (TextView) ((Activity)mContext).findViewById(R.id.sample_output); 82 if(tv == null) { 83 Log.e(TAG, "TextView is null?!"); 84 } else if (mContext == null) { 85 Log.e(TAG, "Context is null?"); 86 } else { 87 Log.e(TAG, "Nothing is null?!"); 88 } 89 90 // Reset text in case of a previous query 91 tv.setText(mContext.getText(R.string.intro_message) + "\n\n"); 92 93 if (cursor.getCount() == 0) { 94 return; 95 } 96 97 // Pulling the relevant value from the cursor requires knowing the column index to pull 98 // it from. 99 // BEGIN_INCLUDE(get_columns) 100 int phoneColumnIndex = cursor.getColumnIndex(CommonDataKinds.Phone.NUMBER); 101 int emailColumnIndex = cursor.getColumnIndex(CommonDataKinds.Email.ADDRESS); 102 int nameColumnIndex = cursor.getColumnIndex(CommonDataKinds.Contactables.DISPLAY_NAME); 103 int lookupColumnIndex = cursor.getColumnIndex(CommonDataKinds.Contactables.LOOKUP_KEY); 104 int typeColumnIndex = cursor.getColumnIndex(CommonDataKinds.Contactables.MIMETYPE); 105 // END_INCLUDE(get_columns) 106 107 cursor.moveToFirst(); 108 // Lookup key is the easiest way to verify a row of data is for the same 109 // contact as the previous row. 110 String lookupKey = ""; 111 do { 112 // BEGIN_INCLUDE(lookup_key) 113 String currentLookupKey = cursor.getString(lookupColumnIndex); 114 if (!lookupKey.equals(currentLookupKey)) { 115 String displayName = cursor.getString(nameColumnIndex); 116 tv.append(displayName + "\n"); 117 lookupKey = currentLookupKey; 118 } 119 // END_INCLUDE(lookup_key) 120 121 // BEGIN_INCLUDE(retrieve_data) 122 // The data type can be determined using the mime type column. 123 String mimeType = cursor.getString(typeColumnIndex); 124 if (mimeType.equals(CommonDataKinds.Phone.CONTENT_ITEM_TYPE)) { 125 tv.append("\tPhone Number: " + cursor.getString(phoneColumnIndex) + "\n"); 126 } else if (mimeType.equals(CommonDataKinds.Email.CONTENT_ITEM_TYPE)) { 127 tv.append("\tEmail Address: " + cursor.getString(emailColumnIndex) + "\n"); 128 } 129 // END_INCLUDE(retrieve_data) 130 131 // Look at DDMS to see all the columns returned by a query to Contactables. 132 // Behold, the firehose! 133 for(String column : cursor.getColumnNames()) { 134 Log.d(TAG, column + column + ": " + 135 cursor.getString(cursor.getColumnIndex(column)) + "\n"); 136 } 137 } while (cursor.moveToNext()); 138 } 139 140 @Override onLoaderReset(Loader<Cursor> cursorLoader)141 public void onLoaderReset(Loader<Cursor> cursorLoader) { 142 } 143 } 144