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.os.Bundle;
20 import android.os.Handler;
21 import android.view.View;
22 import android.widget.AdapterView;
23 import android.widget.ListAdapter;
24 import android.widget.ListView;
25 
26 /**
27  * An activity that displays a list of items by binding to a data source such as
28  * an array or Cursor, and exposes event handlers when the user selects an item.
29  * <p>
30  * ListActivity hosts a {@link android.widget.ListView ListView} object that can
31  * be bound to different data sources, typically either an array or a Cursor
32  * holding query results. Binding, screen layout, and row layout are discussed
33  * in the following sections.
34  * <p>
35  * <strong>Screen Layout</strong>
36  * </p>
37  * <p>
38  * ListActivity has a default layout that consists of a single, full-screen list
39  * in the center of the screen. However, if you desire, you can customize the
40  * screen layout by setting your own view layout with setContentView() in
41  * onCreate(). To do this, your own view MUST contain a ListView object with the
42  * id "@android:id/list" (or {@link android.R.id#list} if it's in code)
43  * <p>
44  * Optionally, your custom view can contain another view object of any type to
45  * display when the list view is empty. This "empty list" notifier must have an
46  * id "android:id/empty". Note that when an empty view is present, the list view
47  * will be hidden when there is no data to display.
48  * <p>
49  * The following code demonstrates an (ugly) custom screen layout. It has a list
50  * with a green background, and an alternate red "no data" message.
51  * </p>
52  *
53  * <pre>
54  * &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
55  * &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
56  *         android:orientation=&quot;vertical&quot;
57  *         android:layout_width=&quot;match_parent&quot;
58  *         android:layout_height=&quot;match_parent&quot;
59  *         android:paddingLeft=&quot;8dp&quot;
60  *         android:paddingRight=&quot;8dp&quot;&gt;
61  *
62  *     &lt;ListView android:id=&quot;@android:id/list&quot;
63  *               android:layout_width=&quot;match_parent&quot;
64  *               android:layout_height=&quot;match_parent&quot;
65  *               android:background=&quot;#00FF00&quot;
66  *               android:layout_weight=&quot;1&quot;
67  *               android:drawSelectorOnTop=&quot;false&quot;/&gt;
68  *
69  *     &lt;TextView android:id=&quot;@android:id/empty&quot;
70  *               android:layout_width=&quot;match_parent&quot;
71  *               android:layout_height=&quot;match_parent&quot;
72  *               android:background=&quot;#FF0000&quot;
73  *               android:text=&quot;No data&quot;/&gt;
74  * &lt;/LinearLayout&gt;
75  * </pre>
76  *
77  * <p>
78  * <strong>Row Layout</strong>
79  * </p>
80  * <p>
81  * You can specify the layout of individual rows in the list. You do this by
82  * specifying a layout resource in the ListAdapter object hosted by the activity
83  * (the ListAdapter binds the ListView to the data; more on this later).
84  * <p>
85  * A ListAdapter constructor takes a parameter that specifies a layout resource
86  * for each row. It also has two additional parameters that let you specify
87  * which data field to associate with which object in the row layout resource.
88  * These two parameters are typically parallel arrays.
89  * </p>
90  * <p>
91  * Android provides some standard row layout resources. These are in the
92  * {@link android.R.layout} class, and have names such as simple_list_item_1,
93  * simple_list_item_2, and two_line_list_item. The following layout XML is the
94  * source for the resource two_line_list_item, which displays two data
95  * fields,one above the other, for each list row.
96  * </p>
97  *
98  * <pre>
99  * &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
100  * &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
101  *     android:layout_width=&quot;match_parent&quot;
102  *     android:layout_height=&quot;wrap_content&quot;
103  *     android:orientation=&quot;vertical&quot;&gt;
104  *
105  *     &lt;TextView android:id=&quot;@+id/text1&quot;
106  *         android:textSize=&quot;16sp&quot;
107  *         android:textStyle=&quot;bold&quot;
108  *         android:layout_width=&quot;match_parent&quot;
109  *         android:layout_height=&quot;wrap_content&quot;/&gt;
110  *
111  *     &lt;TextView android:id=&quot;@+id/text2&quot;
112  *         android:textSize=&quot;16sp&quot;
113  *         android:layout_width=&quot;match_parent&quot;
114  *         android:layout_height=&quot;wrap_content&quot;/&gt;
115  * &lt;/LinearLayout&gt;
116  * </pre>
117  *
118  * <p>
119  * You must identify the data bound to each TextView object in this layout. The
120  * syntax for this is discussed in the next section.
121  * </p>
122  * <p>
123  * <strong>Binding to Data</strong>
124  * </p>
125  * <p>
126  * You bind the ListActivity's ListView object to data using a class that
127  * implements the {@link android.widget.ListAdapter ListAdapter} interface.
128  * Android provides two standard list adapters:
129  * {@link android.widget.SimpleAdapter SimpleAdapter} for static data (Maps),
130  * and {@link android.widget.SimpleCursorAdapter SimpleCursorAdapter} for Cursor
131  * query results.
132  * </p>
133  * <p>
134  * The following code from a custom ListActivity demonstrates querying the
135  * Contacts provider for all contacts, then binding the Name and Company fields
136  * to a two line row layout in the activity's ListView.
137  * </p>
138  *
139  * <pre>
140  * public class MyListAdapter extends ListActivity {
141  *
142  *     &#064;Override
143  *     protected void onCreate(Bundle savedInstanceState){
144  *         super.onCreate(savedInstanceState);
145  *
146  *         // We'll define a custom screen layout here (the one shown above), but
147  *         // typically, you could just use the standard ListActivity layout.
148  *         setContentView(R.layout.custom_list_activity_view);
149  *
150  *         // Query for all people contacts using the {@link android.provider.Contacts.People} convenience class.
151  *         // Put a managed wrapper around the retrieved cursor so we don't have to worry about
152  *         // requerying or closing it as the activity changes state.
153  *         mCursor = this.getContentResolver().query(People.CONTENT_URI, null, null, null, null);
154  *         startManagingCursor(mCursor);
155  *
156  *         // Now create a new list adapter bound to the cursor.
157  *         // SimpleListAdapter is designed for binding to a Cursor.
158  *         ListAdapter adapter = new SimpleCursorAdapter(
159  *                 this, // Context.
160  *                 android.R.layout.two_line_list_item,  // Specify the row template to use (here, two columns bound to the two retrieved cursor
161  * rows).
162  *                 mCursor,                                              // Pass in the cursor to bind to.
163  *                 new String[] {People.NAME, People.COMPANY},           // Array of cursor columns to bind to.
164  *                 new int[] {android.R.id.text1, android.R.id.text2});  // Parallel array of which template objects to bind to those columns.
165  *
166  *         // Bind to our new adapter.
167  *         setListAdapter(adapter);
168  *     }
169  * }
170  * </pre>
171  *
172  * @see #setListAdapter
173  * @see android.widget.ListView
174  *
175  * @deprecated Use {@link androidx.fragment.app.ListFragment} or
176  *   {@link androidx.recyclerview.widget.RecyclerView} to implement your Activity instead.
177  */
178 @Deprecated
179 public class ListActivity extends Activity {
180     /**
181      * This field should be made private, so it is hidden from the SDK.
182      * {@hide}
183      */
184     protected ListAdapter mAdapter;
185     /**
186      * This field should be made private, so it is hidden from the SDK.
187      * {@hide}
188      */
189     protected ListView mList;
190 
191     private Handler mHandler = new Handler();
192     private boolean mFinishedStart = false;
193 
194     private Runnable mRequestFocus = new Runnable() {
195         public void run() {
196             mList.focusableViewAvailable(mList);
197         }
198     };
199 
200     /**
201      * This method will be called when an item in the list is selected.
202      * Subclasses should override. Subclasses can call
203      * getListView().getItemAtPosition(position) if they need to access the
204      * data associated with the selected item.
205      *
206      * @param l The ListView where the click happened
207      * @param v The view that was clicked within the ListView
208      * @param position The position of the view in the list
209      * @param id The row id of the item that was clicked
210      */
onListItemClick(ListView l, View v, int position, long id)211     protected void onListItemClick(ListView l, View v, int position, long id) {
212     }
213 
214     /**
215      * Ensures the list view has been created before Activity restores all
216      * of the view states.
217      *
218      *@see Activity#onRestoreInstanceState(Bundle)
219      */
220     @Override
onRestoreInstanceState(Bundle state)221     protected void onRestoreInstanceState(Bundle state) {
222         ensureList();
223         super.onRestoreInstanceState(state);
224     }
225 
226     /**
227      * @see Activity#onDestroy()
228      */
229     @Override
onDestroy()230     protected void onDestroy() {
231         mHandler.removeCallbacks(mRequestFocus);
232         super.onDestroy();
233     }
234 
235     /**
236      * Updates the screen state (current list and other views) when the
237      * content changes.
238      *
239      * @see Activity#onContentChanged()
240      */
241     @Override
onContentChanged()242     public void onContentChanged() {
243         super.onContentChanged();
244         View emptyView = findViewById(com.android.internal.R.id.empty);
245         mList = (ListView)findViewById(com.android.internal.R.id.list);
246         if (mList == null) {
247             throw new RuntimeException(
248                     "Your content must have a ListView whose id attribute is " +
249                     "'android.R.id.list'");
250         }
251         if (emptyView != null) {
252             mList.setEmptyView(emptyView);
253         }
254         mList.setOnItemClickListener(mOnClickListener);
255         if (mFinishedStart) {
256             setListAdapter(mAdapter);
257         }
258         mHandler.post(mRequestFocus);
259         mFinishedStart = true;
260     }
261 
262     /**
263      * Provide the cursor for the list view.
264      */
setListAdapter(ListAdapter adapter)265     public void setListAdapter(ListAdapter adapter) {
266         synchronized (this) {
267             ensureList();
268             mAdapter = adapter;
269             mList.setAdapter(adapter);
270         }
271     }
272 
273     /**
274      * Set the currently selected list item to the specified
275      * position with the adapter's data
276      *
277      * @param position
278      */
setSelection(int position)279     public void setSelection(int position) {
280         mList.setSelection(position);
281     }
282 
283     /**
284      * Get the position of the currently selected list item.
285      */
getSelectedItemPosition()286     public int getSelectedItemPosition() {
287         return mList.getSelectedItemPosition();
288     }
289 
290     /**
291      * Get the cursor row ID of the currently selected list item.
292      */
getSelectedItemId()293     public long getSelectedItemId() {
294         return mList.getSelectedItemId();
295     }
296 
297     /**
298      * Get the activity's list view widget.
299      */
getListView()300     public ListView getListView() {
301         ensureList();
302         return mList;
303     }
304 
305     /**
306      * Get the ListAdapter associated with this activity's ListView.
307      */
getListAdapter()308     public ListAdapter getListAdapter() {
309         return mAdapter;
310     }
311 
ensureList()312     private void ensureList() {
313         if (mList != null) {
314             return;
315         }
316         setContentView(com.android.internal.R.layout.list_content_simple);
317 
318     }
319 
320     private AdapterView.OnItemClickListener mOnClickListener = new AdapterView.OnItemClickListener() {
321         public void onItemClick(AdapterView<?> parent, View v, int position, long id)
322         {
323             onListItemClick((ListView)parent, v, position, id);
324         }
325     };
326 }
327