Home | History | Annotate | Download | only in app
      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 
     17 package android.app;
     18 
     19 import android.database.Cursor;
     20 import android.os.Bundle;
     21 import java.util.List;
     22 import android.view.ContextMenu;
     23 import android.view.View;
     24 import android.view.ContextMenu.ContextMenuInfo;
     25 import android.view.View.OnCreateContextMenuListener;
     26 import android.widget.ExpandableListAdapter;
     27 import android.widget.ExpandableListView;
     28 import android.widget.SimpleCursorTreeAdapter;
     29 import android.widget.SimpleExpandableListAdapter;
     30 import android.widget.AdapterView.AdapterContextMenuInfo;
     31 
     32 import 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  * &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
     66  * &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     67  *         android:orientation=&quot;vertical&quot;
     68  *         android:layout_width=&quot;match_parent&quot;
     69  *         android:layout_height=&quot;match_parent&quot;
     70  *         android:paddingLeft=&quot;8dp&quot;
     71  *         android:paddingRight=&quot;8dp&quot;&gt;
     72  *
     73  *     &lt;ExpandableListView android:id=&quot;@id/android:list&quot;
     74  *               android:layout_width=&quot;match_parent&quot;
     75  *               android:layout_height=&quot;match_parent&quot;
     76  *               android:background=&quot;#00FF00&quot;
     77  *               android:layout_weight=&quot;1&quot;
     78  *               android:drawSelectorOnTop=&quot;false&quot;/&gt;
     79  *
     80  *     &lt;TextView android:id=&quot;@id/android:empty&quot;
     81  *               android:layout_width=&quot;match_parent&quot;
     82  *               android:layout_height=&quot;match_parent&quot;
     83  *               android:background=&quot;#FF0000&quot;
     84  *               android:text=&quot;No data&quot;/&gt;
     85  * &lt;/LinearLayout&gt;
     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  * &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
    116  * &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    117  *     android:layout_width=&quot;match_parent&quot;
    118  *     android:layout_height=&quot;wrap_content&quot;
    119  *     android:orientation=&quot;vertical&quot;&gt;
    120  *
    121  *     &lt;TextView android:id=&quot;@+id/text1&quot;
    122  *         android:textSize=&quot;16sp&quot;
    123  *         android:textStyle=&quot;bold&quot;
    124  *         android:layout_width=&quot;match_parent&quot;
    125  *         android:layout_height=&quot;wrap_content&quot;/&gt;
    126  *
    127  *     &lt;TextView android:id=&quot;@+id/text2&quot;
    128  *         android:textSize=&quot;16sp&quot;
    129  *         android:layout_width=&quot;match_parent&quot;
    130  *         android:layout_height=&quot;wrap_content&quot;/&gt;
    131  * &lt;/LinearLayout&gt;
    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  */
    155 public 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