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