OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / frameworks / base / core / tests / coretests / src / android / util / ExpandableListScenario.java
1 /*
2  * Copyright (C) 2007 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.util;
18
19 import java.util.ArrayList;
20 import java.util.List;
21
22 import android.view.Gravity;
23 import android.view.View;
24 import android.view.ViewGroup;
25 import android.widget.AbsListView;
26 import android.widget.BaseExpandableListAdapter;
27 import android.widget.ExpandableListAdapter;
28 import android.widget.ExpandableListView;
29 import android.widget.ListView;
30 import android.widget.TextView;
31
32 /**
33  * Utility base class for creating various Expandable List scenarios.
34  * <p>
35  * WARNING: A lot of the features are mixed between ListView's expected position
36  * (flat list position) and an ExpandableListView's expected position.  You must add/change
37  * features as you need them.
38  * 
39  * @see ListScenario
40  */
41 public abstract class ExpandableListScenario extends ListScenario {
42     protected ExpandableListAdapter mAdapter; 
43     protected List<MyGroup> mGroups;
44     
45     @Override
46     protected ListView createListView() {
47         return new ExpandableListView(this);
48     }
49
50     @Override
51     protected Params createParams() {
52         return new ExpandableParams();
53     }
54
55     @Override
56     protected void setAdapter(ListView listView) {
57         ((ExpandableListView) listView).setAdapter(mAdapter = createAdapter());
58     }
59     
60     protected ExpandableListAdapter createAdapter() {
61         return new MyAdapter();
62     }
63     
64     @Override
65     protected void readAndValidateParams(Params params) {
66         ExpandableParams expandableParams = (ExpandableParams) params;
67         
68         int[] numChildren = expandableParams.mNumChildren;
69         
70         mGroups = new ArrayList<MyGroup>(numChildren.length);
71         for (int i = 0; i < numChildren.length; i++) {
72             mGroups.add(new MyGroup(numChildren[i]));
73         }
74         
75         expandableParams.superSetNumItems();
76         
77         super.readAndValidateParams(params);
78     }
79
80     /**
81      * Get the ExpandableListView widget.
82      * @return The main widget.
83      */
84     public ExpandableListView getExpandableListView() {
85         return (ExpandableListView) super.getListView();
86     }
87
88     public static class ExpandableParams extends Params {
89         private int[] mNumChildren;
90         
91         /**
92          * Sets the number of children per group.
93          *  
94          * @param numChildrenPerGroup The number of children per group.
95          */
96         public ExpandableParams setNumChildren(int[] numChildren) {
97             mNumChildren = numChildren;
98             return this;
99         }
100
101         /**
102          * Sets the number of items on the superclass based on the number of
103          * groups and children per group.
104          */
105         private ExpandableParams superSetNumItems() {
106             int numItems = 0;
107             
108             if (mNumChildren != null) {
109                 for (int i = mNumChildren.length - 1; i >= 0; i--) {
110                     numItems += mNumChildren[i];
111                 }
112             }
113             
114             super.setNumItems(numItems);
115             
116             return this;
117         }
118         
119         @Override
120         public Params setNumItems(int numItems) {
121             throw new IllegalStateException("Use setNumGroups and setNumChildren instead.");
122         }
123
124         @Override
125         public ExpandableParams setFadingEdgeScreenSizeFactor(double fadingEdgeScreenSizeFactor) {
126             return (ExpandableParams) super.setFadingEdgeScreenSizeFactor(fadingEdgeScreenSizeFactor);
127         }
128
129         @Override
130         public ExpandableParams setItemScreenSizeFactor(double itemScreenSizeFactor) {
131             return (ExpandableParams) super.setItemScreenSizeFactor(itemScreenSizeFactor);
132         }
133
134         @Override
135         public ExpandableParams setItemsFocusable(boolean itemsFocusable) {
136             return (ExpandableParams) super.setItemsFocusable(itemsFocusable);
137         }
138
139         @Override
140         public ExpandableParams setMustFillScreen(boolean fillScreen) {
141             return (ExpandableParams) super.setMustFillScreen(fillScreen);
142         }
143
144         @Override
145         public ExpandableParams setPositionScreenSizeFactorOverride(int position, double itemScreenSizeFactor) {
146             return (ExpandableParams) super.setPositionScreenSizeFactorOverride(position, itemScreenSizeFactor);
147         }
148
149         @Override
150         public ExpandableParams setPositionUnselectable(int position) {
151             return (ExpandableParams) super.setPositionUnselectable(position);
152         }
153
154         @Override
155         public ExpandableParams setStackFromBottom(boolean stackFromBottom) {
156             return (ExpandableParams) super.setStackFromBottom(stackFromBottom);
157         }
158
159         @Override
160         public ExpandableParams setStartingSelectionPosition(int startingSelectionPosition) {
161             return (ExpandableParams) super.setStartingSelectionPosition(startingSelectionPosition);
162         }
163
164         @Override
165         public ExpandableParams setConnectAdapter(boolean connectAdapter) {
166             return (ExpandableParams) super.setConnectAdapter(connectAdapter);
167         }
168     }
169
170     /**
171      * Gets a string for the value of some item.
172      * @param packedPosition The position of the item.
173      * @return The string.
174      */
175     public final String getValueAtPosition(long packedPosition) {
176         final int type = ExpandableListView.getPackedPositionType(packedPosition);
177         
178         if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
179             return mGroups.get(ExpandableListView.getPackedPositionGroup(packedPosition))
180                     .children.get(ExpandableListView.getPackedPositionChild(packedPosition))
181                     .name;
182         } else if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
183             return mGroups.get(ExpandableListView.getPackedPositionGroup(packedPosition))
184                     .name;
185         } else {
186             throw new IllegalStateException("packedPosition is not a valid position.");
187         }
188     }
189
190     /**
191      * Whether a particular position is out of bounds.
192      * 
193      * @param packedPosition The packed position.
194      * @return Whether it's out of bounds.
195      */
196     private boolean isOutOfBounds(long packedPosition) {
197         final int type = ExpandableListView.getPackedPositionType(packedPosition);
198         
199         if (type == ExpandableListView.PACKED_POSITION_TYPE_NULL) {
200             throw new IllegalStateException("packedPosition is not a valid position.");
201         }
202
203         final int group = ExpandableListView.getPackedPositionGroup(packedPosition); 
204         if (group >= mGroups.size() || group < 0) {
205             return true;
206         }
207         
208         if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
209             final int child = ExpandableListView.getPackedPositionChild(packedPosition); 
210             if (child >= mGroups.get(group).children.size() || child < 0) {
211                 return true;
212             }
213         }
214         
215         return false;
216     }
217     
218     /**
219      * Gets a view for the packed position, possibly reusing the convertView.
220      * 
221      * @param packedPosition The position to get a view for.
222      * @param convertView Optional view to convert.
223      * @param parent The future parent.
224      * @return A view.
225      */
226     private View getView(long packedPosition, View convertView, ViewGroup parent) {
227         if (isOutOfBounds(packedPosition)) {
228             throw new IllegalStateException("position out of range for adapter!");
229         }
230         
231         final ExpandableListView elv = getExpandableListView();
232         final int flPos = elv.getFlatListPosition(packedPosition); 
233         
234         if (convertView != null) {
235             ((TextView) convertView).setText(getValueAtPosition(packedPosition));
236             convertView.setId(flPos);
237             return convertView;
238         }
239
240         int desiredHeight = getHeightForPosition(flPos);
241         return createView(packedPosition, flPos, parent, desiredHeight);
242     }
243     
244     /**
245      * Create a view for a group or child position.
246      * 
247      * @param packedPosition The packed position (has type, group pos, and optionally child pos).
248      * @param flPos The flat list position (the position that the ListView goes by).
249      * @param parent The parent view.
250      * @param desiredHeight The desired height.
251      * @return A view.
252      */
253     protected View createView(long packedPosition, int flPos, ViewGroup parent, int desiredHeight) {
254         TextView result = new TextView(parent.getContext());
255         result.setHeight(desiredHeight);
256         result.setText(getValueAtPosition(packedPosition));
257         final ViewGroup.LayoutParams lp = new AbsListView.LayoutParams(
258                 ViewGroup.LayoutParams.MATCH_PARENT,
259                 ViewGroup.LayoutParams.WRAP_CONTENT);
260         result.setLayoutParams(lp);
261         result.setGravity(Gravity.CENTER_VERTICAL);
262         result.setPadding(36, 0, 0, 0);
263         result.setId(flPos);
264         return result;
265     }
266     
267     /**
268      * Returns a group index containing either the number of children or at
269      * least one child.
270      * 
271      * @param numChildren The group must have this amount, or -1 if using
272      *            atLeastOneChild.
273      * @param atLeastOneChild The group must have at least one child, or false
274      *            if using numChildren.
275      * @return A group index with the requirements.
276      */
277     public int findGroupWithNumChildren(int numChildren, boolean atLeastOneChild) {
278         final ExpandableListAdapter adapter = mAdapter;
279         
280         for (int i = adapter.getGroupCount() - 1; i >= 0; i--) {
281             final int curNumChildren = adapter.getChildrenCount(i);
282             
283             if (numChildren == curNumChildren || atLeastOneChild && curNumChildren > 0) {
284                 return i;
285             }
286         }
287         
288         return -1;
289     }
290     
291     public List<MyGroup> getGroups() {
292         return mGroups;
293     }
294     
295     public ExpandableListAdapter getAdapter() {
296         return mAdapter;
297     }
298
299     /**
300      * Simple expandable list adapter.
301      */
302     protected class MyAdapter extends BaseExpandableListAdapter {
303         public Object getChild(int groupPosition, int childPosition) {
304             return getValueAtPosition(ExpandableListView.getPackedPositionForChild(groupPosition,
305                     childPosition));
306         }
307
308         public long getChildId(int groupPosition, int childPosition) {
309             return mGroups.get(groupPosition).children.get(childPosition).id;
310         }
311
312         public int getChildrenCount(int groupPosition) {
313             return mGroups.get(groupPosition).children.size();
314         }
315
316         public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
317                 View convertView, ViewGroup parent) {
318             return getView(ExpandableListView.getPackedPositionForChild(groupPosition,
319                     childPosition), convertView, parent);
320         }
321
322         public Object getGroup(int groupPosition) {
323             return getValueAtPosition(ExpandableListView.getPackedPositionForGroup(groupPosition));
324         }
325
326         public int getGroupCount() {
327             return mGroups.size();
328         }
329
330         public long getGroupId(int groupPosition) {
331             return mGroups.get(groupPosition).id;
332         }
333
334         public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
335                 ViewGroup parent) {
336             return getView(ExpandableListView.getPackedPositionForGroup(groupPosition),
337                     convertView, parent);
338         }
339
340         public boolean isChildSelectable(int groupPosition, int childPosition) {
341             return true;
342         }
343
344         public boolean hasStableIds() {
345             return true;
346         }
347         
348     }
349
350     public static class MyGroup {
351         private static long mNextId = 1000;
352         
353         String name;
354         long id = mNextId++;
355         List<MyChild> children;
356         
357         public MyGroup(int numChildren) {
358             name = "Group " + id;
359             children = new ArrayList<MyChild>(numChildren);
360             for (int i = 0; i < numChildren; i++) {
361                 children.add(new MyChild());
362             }
363         }
364     }
365     
366     public static class MyChild {
367         private static long mNextId = 2000;
368         
369         String name;
370         long id = mNextId++;
371         
372         public MyChild() {
373             name = "Child " + id;
374         }
375     }
376     
377     @Override
378     protected final void init(Params params) {
379         init((ExpandableParams) params);
380     }
381
382     /**
383      * @see ListScenario#init
384      */
385     protected abstract void init(ExpandableParams params);
386 }