1 /* 2 * Copyright (C) 2007 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 17 package com.example.android.apis.view; 18 19 import android.app.ExpandableListActivity; 20 import android.content.AsyncQueryHandler; 21 import android.content.ContentUris; 22 import android.content.Context; 23 import android.database.Cursor; 24 import android.net.Uri; 25 import android.os.Bundle; 26 import android.provider.ContactsContract.CommonDataKinds.Phone; 27 import android.provider.ContactsContract.Contacts; 28 import android.widget.CursorTreeAdapter; 29 import android.widget.SimpleCursorTreeAdapter; 30 31 /** 32 * Demonstrates expandable lists backed by Cursors 33 */ 34 public class ExpandableList2 extends ExpandableListActivity { 35 36 private static final String[] CONTACTS_PROJECTION = new String[] { 37 Contacts._ID, 38 Contacts.DISPLAY_NAME 39 }; 40 private static final int GROUP_ID_COLUMN_INDEX = 0; 41 42 private static final String[] PHONE_NUMBER_PROJECTION = new String[] { 43 Phone._ID, 44 Phone.NUMBER 45 }; 46 47 private static final int TOKEN_GROUP = 0; 48 private static final int TOKEN_CHILD = 1; 49 50 private static final class QueryHandler extends AsyncQueryHandler { 51 private CursorTreeAdapter mAdapter; 52 53 public QueryHandler(Context context, CursorTreeAdapter adapter) { 54 super(context.getContentResolver()); 55 this.mAdapter = adapter; 56 } 57 58 @Override 59 protected void onQueryComplete(int token, Object cookie, Cursor cursor) { 60 switch (token) { 61 case TOKEN_GROUP: 62 mAdapter.setGroupCursor(cursor); 63 break; 64 65 case TOKEN_CHILD: 66 int groupPosition = (Integer) cookie; 67 mAdapter.setChildrenCursor(groupPosition, cursor); 68 break; 69 } 70 } 71 } 72 73 public class MyExpandableListAdapter extends SimpleCursorTreeAdapter { 74 75 // Note that the constructor does not take a Cursor. This is done to avoid querying the 76 // database on the main thread. 77 public MyExpandableListAdapter(Context context, int groupLayout, 78 int childLayout, String[] groupFrom, int[] groupTo, String[] childrenFrom, 79 int[] childrenTo) { 80 81 super(context, null, groupLayout, groupFrom, groupTo, childLayout, childrenFrom, 82 childrenTo); 83 } 84 85 @Override 86 protected Cursor getChildrenCursor(Cursor groupCursor) { 87 // Given the group, we return a cursor for all the children within that group 88 89 // Return a cursor that points to this contact's phone numbers 90 Uri.Builder builder = Contacts.CONTENT_URI.buildUpon(); 91 ContentUris.appendId(builder, groupCursor.getLong(GROUP_ID_COLUMN_INDEX)); 92 builder.appendEncodedPath(Contacts.Data.CONTENT_DIRECTORY); 93 Uri phoneNumbersUri = builder.build(); 94 95 mQueryHandler.startQuery(TOKEN_CHILD, groupCursor.getPosition(), phoneNumbersUri, 96 PHONE_NUMBER_PROJECTION, Phone.MIMETYPE + "=?", 97 new String[] { Phone.CONTENT_ITEM_TYPE }, null); 98 99 return null; 100 } 101 } 102 103 private QueryHandler mQueryHandler; 104 private CursorTreeAdapter mAdapter; 105 106 @Override 107 public void onCreate(Bundle savedInstanceState) { 108 super.onCreate(savedInstanceState); 109 110 // Set up our adapter 111 mAdapter = new MyExpandableListAdapter( 112 this, 113 android.R.layout.simple_expandable_list_item_1, 114 android.R.layout.simple_expandable_list_item_1, 115 new String[] { Contacts.DISPLAY_NAME }, // Name for group layouts 116 new int[] { android.R.id.text1 }, 117 new String[] { Phone.NUMBER }, // Number for child layouts 118 new int[] { android.R.id.text1 }); 119 120 setListAdapter(mAdapter); 121 122 mQueryHandler = new QueryHandler(this, mAdapter); 123 124 // Query for people 125 mQueryHandler.startQuery(TOKEN_GROUP, null, Contacts.CONTENT_URI, CONTACTS_PROJECTION, 126 Contacts.HAS_PHONE_NUMBER + "=1", null, null); 127 } 128 129 @Override 130 protected void onDestroy() { 131 super.onDestroy(); 132 133 // Null out the group cursor. This will cause the group cursor and all of the child cursors 134 // to be closed. 135 mAdapter.changeCursor(null); 136 mAdapter = null; 137 } 138 } 139