1/* 2 * Copyright (C) 2006 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 android.app; 18 19import android.database.Cursor; 20import android.os.Bundle; 21import java.util.List; 22import android.view.ContextMenu; 23import android.view.View; 24import android.view.ContextMenu.ContextMenuInfo; 25import android.view.View.OnCreateContextMenuListener; 26import android.widget.ExpandableListAdapter; 27import android.widget.ExpandableListView; 28import android.widget.SimpleCursorTreeAdapter; 29import android.widget.SimpleExpandableListAdapter; 30 31import java.util.Map; 32 33/** 34 * An activity that displays an expandable list of items by binding to a data 35 * source implementing the ExpandableListAdapter, and exposes event handlers 36 * when the user selects an item. 37 * <p> 38 * ExpandableListActivity hosts a 39 * {@link android.widget.ExpandableListView ExpandableListView} object that can 40 * be bound to different data sources that provide a two-levels of data (the 41 * top-level is group, and below each group are children). Binding, screen 42 * layout, and row layout are discussed in the following sections. 43 * <p> 44 * <strong>Screen Layout</strong> 45 * </p> 46 * <p> 47 * ExpandableListActivity has a default layout that consists of a single, 48 * full-screen, centered expandable list. However, if you desire, you can 49 * customize the screen layout by setting your own view layout with 50 * setContentView() in onCreate(). To do this, your own view MUST contain an 51 * ExpandableListView object with the id "@android:id/list" (or 52 * {@link android.R.id#list} if it's in code) 53 * <p> 54 * Optionally, your custom view can contain another view object of any type to 55 * display when the list view is empty. This "empty list" notifier must have an 56 * id "android:empty". Note that when an empty view is present, the expandable 57 * list view will be hidden when there is no data to display. 58 * <p> 59 * The following code demonstrates an (ugly) custom screen layout. It has a list 60 * with a green background, and an alternate red "no data" message. 61 * </p> 62 * 63 * <pre> 64 * <?xml version="1.0" encoding="UTF-8"?> 65 * <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 66 * android:orientation="vertical" 67 * android:layout_width="match_parent" 68 * android:layout_height="match_parent" 69 * android:paddingLeft="8dp" 70 * android:paddingRight="8dp"> 71 * 72 * <ExpandableListView android:id="@id/android:list" 73 * android:layout_width="match_parent" 74 * android:layout_height="match_parent" 75 * android:background="#00FF00" 76 * android:layout_weight="1" 77 * android:drawSelectorOnTop="false"/> 78 * 79 * <TextView android:id="@id/android:empty" 80 * android:layout_width="match_parent" 81 * android:layout_height="match_parent" 82 * android:background="#FF0000" 83 * android:text="No data"/> 84 * </LinearLayout> 85 * </pre> 86 * 87 * <p> 88 * <strong>Row Layout</strong> 89 * </p> 90 * The {@link ExpandableListAdapter} set in the {@link ExpandableListActivity} 91 * via {@link #setListAdapter(ExpandableListAdapter)} provides the {@link View}s 92 * for each row. This adapter has separate methods for providing the group 93 * {@link View}s and child {@link View}s. There are a couple provided 94 * {@link ExpandableListAdapter}s that simplify use of adapters: 95 * {@link SimpleCursorTreeAdapter} and {@link SimpleExpandableListAdapter}. 96 * <p> 97 * With these, you can specify the layout of individual rows for groups and 98 * children in the list. These constructor takes a few parameters that specify 99 * layout resources for groups and children. It also has additional parameters 100 * that let you specify which data field to associate with which object in the 101 * row layout resource. The {@link SimpleCursorTreeAdapter} fetches data from 102 * {@link Cursor}s and the {@link SimpleExpandableListAdapter} fetches data 103 * from {@link List}s of {@link Map}s. 104 * </p> 105 * <p> 106 * Android provides some standard row layout resources. These are in the 107 * {@link android.R.layout} class, and have names such as simple_list_item_1, 108 * simple_list_item_2, and two_line_list_item. The following layout XML is the 109 * source for the resource two_line_list_item, which displays two data 110 * fields,one above the other, for each list row. 111 * </p> 112 * 113 * <pre> 114 * <?xml version="1.0" encoding="utf-8"?> 115 * <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 116 * android:layout_width="match_parent" 117 * android:layout_height="wrap_content" 118 * android:orientation="vertical"> 119 * 120 * <TextView android:id="@+id/text1" 121 * android:textSize="16sp" 122 * android:textStyle="bold" 123 * android:layout_width="match_parent" 124 * android:layout_height="wrap_content"/> 125 * 126 * <TextView android:id="@+id/text2" 127 * android:textSize="16sp" 128 * android:layout_width="match_parent" 129 * android:layout_height="wrap_content"/> 130 * </LinearLayout> 131 * </pre> 132 * 133 * <p> 134 * You must identify the data bound to each TextView object in this layout. The 135 * syntax for this is discussed in the next section. 136 * </p> 137 * <p> 138 * <strong>Binding to Data</strong> 139 * </p> 140 * <p> 141 * You bind the ExpandableListActivity's ExpandableListView object to data using 142 * a class that implements the 143 * {@link android.widget.ExpandableListAdapter ExpandableListAdapter} interface. 144 * Android provides two standard list adapters: 145 * {@link android.widget.SimpleExpandableListAdapter SimpleExpandableListAdapter} 146 * for static data (Maps), and 147 * {@link android.widget.SimpleCursorTreeAdapter SimpleCursorTreeAdapter} for 148 * Cursor query results. 149 * </p> 150 * 151 * @see #setListAdapter 152 * @see android.widget.ExpandableListView 153 */ 154public class ExpandableListActivity extends Activity implements 155 OnCreateContextMenuListener, 156 ExpandableListView.OnChildClickListener, ExpandableListView.OnGroupCollapseListener, 157 ExpandableListView.OnGroupExpandListener { 158 ExpandableListAdapter mAdapter; 159 ExpandableListView mList; 160 boolean mFinishedStart = false; 161 162 /** 163 * Override this to populate the context menu when an item is long pressed. menuInfo 164 * will contain an {@link android.widget.ExpandableListView.ExpandableListContextMenuInfo} 165 * whose packedPosition is a packed position 166 * that should be used with {@link ExpandableListView#getPackedPositionType(long)} and 167 * the other similar methods. 168 * <p> 169 * {@inheritDoc} 170 */ 171 @Override 172 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { 173 } 174 175 /** 176 * Override this for receiving callbacks when a child has been clicked. 177 * <p> 178 * {@inheritDoc} 179 */ 180 public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, 181 int childPosition, long id) { 182 return false; 183 } 184 185 /** 186 * Override this for receiving callbacks when a group has been collapsed. 187 */ 188 public void onGroupCollapse(int groupPosition) { 189 } 190 191 /** 192 * Override this for receiving callbacks when a group has been expanded. 193 */ 194 public void onGroupExpand(int groupPosition) { 195 } 196 197 /** 198 * Ensures the expandable list view has been created before Activity restores all 199 * of the view states. 200 * 201 *@see Activity#onRestoreInstanceState(Bundle) 202 */ 203 @Override 204 protected void onRestoreInstanceState(Bundle state) { 205 ensureList(); 206 super.onRestoreInstanceState(state); 207 } 208 209 /** 210 * Updates the screen state (current list and other views) when the 211 * content changes. 212 * 213 * @see Activity#onContentChanged() 214 */ 215 @Override 216 public void onContentChanged() { 217 super.onContentChanged(); 218 View emptyView = findViewById(com.android.internal.R.id.empty); 219 mList = (ExpandableListView)findViewById(com.android.internal.R.id.list); 220 if (mList == null) { 221 throw new RuntimeException( 222 "Your content must have a ExpandableListView whose id attribute is " + 223 "'android.R.id.list'"); 224 } 225 if (emptyView != null) { 226 mList.setEmptyView(emptyView); 227 } 228 mList.setOnChildClickListener(this); 229 mList.setOnGroupExpandListener(this); 230 mList.setOnGroupCollapseListener(this); 231 232 if (mFinishedStart) { 233 setListAdapter(mAdapter); 234 } 235 mFinishedStart = true; 236 } 237 238 /** 239 * Provide the adapter for the expandable list. 240 */ 241 public void setListAdapter(ExpandableListAdapter adapter) { 242 synchronized (this) { 243 ensureList(); 244 mAdapter = adapter; 245 mList.setAdapter(adapter); 246 } 247 } 248 249 /** 250 * Get the activity's expandable list view widget. This can be used to get the selection, 251 * set the selection, and many other useful functions. 252 * 253 * @see ExpandableListView 254 */ 255 public ExpandableListView getExpandableListView() { 256 ensureList(); 257 return mList; 258 } 259 260 /** 261 * Get the ExpandableListAdapter associated with this activity's 262 * ExpandableListView. 263 */ 264 public ExpandableListAdapter getExpandableListAdapter() { 265 return mAdapter; 266 } 267 268 private void ensureList() { 269 if (mList != null) { 270 return; 271 } 272 setContentView(com.android.internal.R.layout.expandable_list_content); 273 } 274 275 /** 276 * Gets the ID of the currently selected group or child. 277 * 278 * @return The ID of the currently selected group or child. 279 */ 280 public long getSelectedId() { 281 return mList.getSelectedId(); 282 } 283 284 /** 285 * Gets the position (in packed position representation) of the currently 286 * selected group or child. Use 287 * {@link ExpandableListView#getPackedPositionType}, 288 * {@link ExpandableListView#getPackedPositionGroup}, and 289 * {@link ExpandableListView#getPackedPositionChild} to unpack the returned 290 * packed position. 291 * 292 * @return A packed position representation containing the currently 293 * selected group or child's position and type. 294 */ 295 public long getSelectedPosition() { 296 return mList.getSelectedPosition(); 297 } 298 299 /** 300 * Sets the selection to the specified child. If the child is in a collapsed 301 * group, the group will only be expanded and child subsequently selected if 302 * shouldExpandGroup is set to true, otherwise the method will return false. 303 * 304 * @param groupPosition The position of the group that contains the child. 305 * @param childPosition The position of the child within the group. 306 * @param shouldExpandGroup Whether the child's group should be expanded if 307 * it is collapsed. 308 * @return Whether the selection was successfully set on the child. 309 */ 310 public boolean setSelectedChild(int groupPosition, int childPosition, boolean shouldExpandGroup) { 311 return mList.setSelectedChild(groupPosition, childPosition, shouldExpandGroup); 312 } 313 314 /** 315 * Sets the selection to the specified group. 316 * @param groupPosition The position of the group that should be selected. 317 */ 318 public void setSelectedGroup(int groupPosition) { 319 mList.setSelectedGroup(groupPosition); 320 } 321 322} 323 324