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 
31 import 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  * &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
65  * &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
66  *         android:orientation=&quot;vertical&quot;
67  *         android:layout_width=&quot;match_parent&quot;
68  *         android:layout_height=&quot;match_parent&quot;
69  *         android:paddingLeft=&quot;8dp&quot;
70  *         android:paddingRight=&quot;8dp&quot;&gt;
71  *
72  *     &lt;ExpandableListView android:id=&quot;@id/android:list&quot;
73  *               android:layout_width=&quot;match_parent&quot;
74  *               android:layout_height=&quot;match_parent&quot;
75  *               android:background=&quot;#00FF00&quot;
76  *               android:layout_weight=&quot;1&quot;
77  *               android:drawSelectorOnTop=&quot;false&quot;/&gt;
78  *
79  *     &lt;TextView android:id=&quot;@id/android:empty&quot;
80  *               android:layout_width=&quot;match_parent&quot;
81  *               android:layout_height=&quot;match_parent&quot;
82  *               android:background=&quot;#FF0000&quot;
83  *               android:text=&quot;No data&quot;/&gt;
84  * &lt;/LinearLayout&gt;
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  * &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
115  * &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
116  *     android:layout_width=&quot;match_parent&quot;
117  *     android:layout_height=&quot;wrap_content&quot;
118  *     android:orientation=&quot;vertical&quot;&gt;
119  *
120  *     &lt;TextView android:id=&quot;@+id/text1&quot;
121  *         android:textSize=&quot;16sp&quot;
122  *         android:textStyle=&quot;bold&quot;
123  *         android:layout_width=&quot;match_parent&quot;
124  *         android:layout_height=&quot;wrap_content&quot;/&gt;
125  *
126  *     &lt;TextView android:id=&quot;@+id/text2&quot;
127  *         android:textSize=&quot;16sp&quot;
128  *         android:layout_width=&quot;match_parent&quot;
129  *         android:layout_height=&quot;wrap_content&quot;/&gt;
130  * &lt;/LinearLayout&gt;
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  *
154  * @deprecated Use {@link androidx.recyclerview.widget.RecyclerView} or use
155  *   {@link android.widget.ExpandableListView} directly
156  */
157 @Deprecated
158 public class ExpandableListActivity extends Activity implements
159         OnCreateContextMenuListener,
160         ExpandableListView.OnChildClickListener, ExpandableListView.OnGroupCollapseListener,
161         ExpandableListView.OnGroupExpandListener {
162     ExpandableListAdapter mAdapter;
163     ExpandableListView mList;
164     boolean mFinishedStart = false;
165 
166     /**
167      * Override this to populate the context menu when an item is long pressed. menuInfo
168      * will contain an {@link android.widget.ExpandableListView.ExpandableListContextMenuInfo}
169      * whose packedPosition is a packed position
170      * that should be used with {@link ExpandableListView#getPackedPositionType(long)} and
171      * the other similar methods.
172      * <p>
173      * {@inheritDoc}
174      */
175     @Override
onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)176     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
177     }
178 
179     /**
180      * Override this for receiving callbacks when a child has been clicked.
181      * <p>
182      * {@inheritDoc}
183      */
onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id)184     public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
185             int childPosition, long id) {
186         return false;
187     }
188 
189     /**
190      * Override this for receiving callbacks when a group has been collapsed.
191      */
onGroupCollapse(int groupPosition)192     public void onGroupCollapse(int groupPosition) {
193     }
194 
195     /**
196      * Override this for receiving callbacks when a group has been expanded.
197      */
onGroupExpand(int groupPosition)198     public void onGroupExpand(int groupPosition) {
199     }
200 
201     /**
202      * Ensures the expandable list view has been created before Activity restores all
203      * of the view states.
204      *
205      *@see Activity#onRestoreInstanceState(Bundle)
206      */
207     @Override
onRestoreInstanceState(Bundle state)208     protected void onRestoreInstanceState(Bundle state) {
209         ensureList();
210         super.onRestoreInstanceState(state);
211     }
212 
213     /**
214      * Updates the screen state (current list and other views) when the
215      * content changes.
216      *
217      * @see Activity#onContentChanged()
218      */
219     @Override
onContentChanged()220     public void onContentChanged() {
221         super.onContentChanged();
222         View emptyView = findViewById(com.android.internal.R.id.empty);
223         mList = (ExpandableListView)findViewById(com.android.internal.R.id.list);
224         if (mList == null) {
225             throw new RuntimeException(
226                     "Your content must have a ExpandableListView whose id attribute is " +
227                     "'android.R.id.list'");
228         }
229         if (emptyView != null) {
230             mList.setEmptyView(emptyView);
231         }
232         mList.setOnChildClickListener(this);
233         mList.setOnGroupExpandListener(this);
234         mList.setOnGroupCollapseListener(this);
235 
236         if (mFinishedStart) {
237             setListAdapter(mAdapter);
238         }
239         mFinishedStart = true;
240     }
241 
242     /**
243      * Provide the adapter for the expandable list.
244      */
setListAdapter(ExpandableListAdapter adapter)245     public void setListAdapter(ExpandableListAdapter adapter) {
246         synchronized (this) {
247             ensureList();
248             mAdapter = adapter;
249             mList.setAdapter(adapter);
250         }
251     }
252 
253     /**
254      * Get the activity's expandable list view widget.  This can be used to get the selection,
255      * set the selection, and many other useful functions.
256      *
257      * @see ExpandableListView
258      */
getExpandableListView()259     public ExpandableListView getExpandableListView() {
260         ensureList();
261         return mList;
262     }
263 
264     /**
265      * Get the ExpandableListAdapter associated with this activity's
266      * ExpandableListView.
267      */
getExpandableListAdapter()268     public ExpandableListAdapter getExpandableListAdapter() {
269         return mAdapter;
270     }
271 
ensureList()272     private void ensureList() {
273         if (mList != null) {
274             return;
275         }
276         setContentView(com.android.internal.R.layout.expandable_list_content);
277     }
278 
279     /**
280      * Gets the ID of the currently selected group or child.
281      *
282      * @return The ID of the currently selected group or child.
283      */
getSelectedId()284     public long getSelectedId() {
285         return mList.getSelectedId();
286     }
287 
288     /**
289      * Gets the position (in packed position representation) of the currently
290      * selected group or child. Use
291      * {@link ExpandableListView#getPackedPositionType},
292      * {@link ExpandableListView#getPackedPositionGroup}, and
293      * {@link ExpandableListView#getPackedPositionChild} to unpack the returned
294      * packed position.
295      *
296      * @return A packed position representation containing the currently
297      *         selected group or child's position and type.
298      */
getSelectedPosition()299     public long getSelectedPosition() {
300         return mList.getSelectedPosition();
301     }
302 
303     /**
304      * Sets the selection to the specified child. If the child is in a collapsed
305      * group, the group will only be expanded and child subsequently selected if
306      * shouldExpandGroup is set to true, otherwise the method will return false.
307      *
308      * @param groupPosition The position of the group that contains the child.
309      * @param childPosition The position of the child within the group.
310      * @param shouldExpandGroup Whether the child's group should be expanded if
311      *            it is collapsed.
312      * @return Whether the selection was successfully set on the child.
313      */
setSelectedChild(int groupPosition, int childPosition, boolean shouldExpandGroup)314     public boolean setSelectedChild(int groupPosition, int childPosition, boolean shouldExpandGroup) {
315         return mList.setSelectedChild(groupPosition, childPosition, shouldExpandGroup);
316     }
317 
318     /**
319      * Sets the selection to the specified group.
320      * @param groupPosition The position of the group that should be selected.
321      */
setSelectedGroup(int groupPosition)322     public void setSelectedGroup(int groupPosition) {
323         mList.setSelectedGroup(groupPosition);
324     }
325 
326 }
327 
328