blob: 1b2eb159626d43beaf3f158bb718d3d83918e331 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.widget.cts.util;
import java.util.ArrayList;
import java.util.List;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.ListView;
import android.widget.TextView;
/**
* Utility base class for creating various Expandable List scenarios.
* <p>
* WARNING: A lot of the features are mixed between ListView's expected position
* (flat list position) and an ExpandableListView's expected position. You must add/change
* features as you need them.
*
* @see ListScenario
*/
public abstract class ExpandableListScenario extends ListScenario {
protected ExpandableListAdapter mAdapter;
protected List<MyGroup> mGroups;
@Override
protected ListView createListView() {
return new ExpandableListView(this);
}
@Override
protected Params createParams() {
return new ExpandableParams();
}
@Override
protected void setAdapter(ListView listView) {
((ExpandableListView) listView).setAdapter(mAdapter = createAdapter());
}
protected ExpandableListAdapter createAdapter() {
return new MyAdapter();
}
@Override
protected void readAndValidateParams(Params params) {
ExpandableParams expandableParams = (ExpandableParams) params;
int[] numChildren = expandableParams.mNumChildren;
mGroups = new ArrayList<MyGroup>(numChildren.length);
for (int i = 0; i < numChildren.length; i++) {
mGroups.add(new MyGroup(numChildren[i]));
}
expandableParams.superSetNumItems();
super.readAndValidateParams(params);
}
/**
* Get the ExpandableListView widget.
* @return The main widget.
*/
public ExpandableListView getExpandableListView() {
return (ExpandableListView) super.getListView();
}
public static class ExpandableParams extends Params {
private int[] mNumChildren;
/**
* Sets the number of children per group.
*
* @param numChildrenPerGroup The number of children per group.
*/
public ExpandableParams setNumChildren(int[] numChildren) {
mNumChildren = numChildren;
return this;
}
/**
* Sets the number of items on the superclass based on the number of
* groups and children per group.
*/
private ExpandableParams superSetNumItems() {
int numItems = 0;
if (mNumChildren != null) {
for (int i = mNumChildren.length - 1; i >= 0; i--) {
numItems += mNumChildren[i];
}
}
super.setNumItems(numItems);
return this;
}
@Override
public Params setNumItems(int numItems) {
throw new IllegalStateException("Use setNumGroups and setNumChildren instead.");
}
@Override
public ExpandableParams setFadingEdgeScreenSizeFactor(double fadingEdgeScreenSizeFactor) {
return (ExpandableParams) super.setFadingEdgeScreenSizeFactor(fadingEdgeScreenSizeFactor);
}
@Override
public ExpandableParams setItemScreenSizeFactor(double itemScreenSizeFactor) {
return (ExpandableParams) super.setItemScreenSizeFactor(itemScreenSizeFactor);
}
@Override
public ExpandableParams setItemsFocusable(boolean itemsFocusable) {
return (ExpandableParams) super.setItemsFocusable(itemsFocusable);
}
@Override
public ExpandableParams setMustFillScreen(boolean fillScreen) {
return (ExpandableParams) super.setMustFillScreen(fillScreen);
}
@Override
public ExpandableParams setPositionScreenSizeFactorOverride(int position, double itemScreenSizeFactor) {
return (ExpandableParams) super.setPositionScreenSizeFactorOverride(position, itemScreenSizeFactor);
}
@Override
public ExpandableParams setPositionUnselectable(int position) {
return (ExpandableParams) super.setPositionUnselectable(position);
}
@Override
public ExpandableParams setStackFromBottom(boolean stackFromBottom) {
return (ExpandableParams) super.setStackFromBottom(stackFromBottom);
}
@Override
public ExpandableParams setStartingSelectionPosition(int startingSelectionPosition) {
return (ExpandableParams) super.setStartingSelectionPosition(startingSelectionPosition);
}
@Override
public ExpandableParams setConnectAdapter(boolean connectAdapter) {
return (ExpandableParams) super.setConnectAdapter(connectAdapter);
}
}
/**
* Gets a string for the value of some item.
* @param packedPosition The position of the item.
* @return The string.
*/
public final String getValueAtPosition(long packedPosition) {
final int type = ExpandableListView.getPackedPositionType(packedPosition);
if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
return mGroups.get(ExpandableListView.getPackedPositionGroup(packedPosition))
.children.get(ExpandableListView.getPackedPositionChild(packedPosition))
.name;
} else if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
return mGroups.get(ExpandableListView.getPackedPositionGroup(packedPosition))
.name;
} else {
throw new IllegalStateException("packedPosition is not a valid position.");
}
}
/**
* Whether a particular position is out of bounds.
*
* @param packedPosition The packed position.
* @return Whether it's out of bounds.
*/
private boolean isOutOfBounds(long packedPosition) {
final int type = ExpandableListView.getPackedPositionType(packedPosition);
if (type == ExpandableListView.PACKED_POSITION_TYPE_NULL) {
throw new IllegalStateException("packedPosition is not a valid position.");
}
final int group = ExpandableListView.getPackedPositionGroup(packedPosition);
if (group >= mGroups.size() || group < 0) {
return true;
}
if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
final int child = ExpandableListView.getPackedPositionChild(packedPosition);
if (child >= mGroups.get(group).children.size() || child < 0) {
return true;
}
}
return false;
}
/**
* Gets a view for the packed position, possibly reusing the convertView.
*
* @param packedPosition The position to get a view for.
* @param convertView Optional view to convert.
* @param parent The future parent.
* @return A view.
*/
private View getView(long packedPosition, View convertView, ViewGroup parent) {
if (isOutOfBounds(packedPosition)) {
throw new IllegalStateException("position out of range for adapter!");
}
final ExpandableListView elv = getExpandableListView();
final int flPos = elv.getFlatListPosition(packedPosition);
if (convertView != null) {
((TextView) convertView).setText(getValueAtPosition(packedPosition));
convertView.setId(flPos);
return convertView;
}
int desiredHeight = getHeightForPosition(flPos);
return createView(packedPosition, flPos, parent, desiredHeight);
}
/**
* Create a view for a group or child position.
*
* @param packedPosition The packed position (has type, group pos, and optionally child pos).
* @param flPos The flat list position (the position that the ListView goes by).
* @param parent The parent view.
* @param desiredHeight The desired height.
* @return A view.
*/
protected View createView(long packedPosition, int flPos, ViewGroup parent, int desiredHeight) {
TextView result = new TextView(parent.getContext());
result.setHeight(desiredHeight);
result.setText(getValueAtPosition(packedPosition));
final ViewGroup.LayoutParams lp = new AbsListView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
result.setLayoutParams(lp);
result.setGravity(Gravity.CENTER_VERTICAL);
result.setPadding(36, 0, 0, 0);
result.setId(flPos);
return result;
}
/**
* Returns a group index containing either the number of children or at
* least one child.
*
* @param numChildren The group must have this amount, or -1 if using
* atLeastOneChild.
* @param atLeastOneChild The group must have at least one child, or false
* if using numChildren.
* @return A group index with the requirements.
*/
public int findGroupWithNumChildren(int numChildren, boolean atLeastOneChild) {
final ExpandableListAdapter adapter = mAdapter;
for (int i = adapter.getGroupCount() - 1; i >= 0; i--) {
final int curNumChildren = adapter.getChildrenCount(i);
if (numChildren == curNumChildren || atLeastOneChild && curNumChildren > 0) {
return i;
}
}
return -1;
}
public List<MyGroup> getGroups() {
return mGroups;
}
public ExpandableListAdapter getAdapter() {
return mAdapter;
}
/**
* Simple expandable list adapter.
*/
protected class MyAdapter extends BaseExpandableListAdapter {
public Object getChild(int groupPosition, int childPosition) {
return getValueAtPosition(ExpandableListView.getPackedPositionForChild(groupPosition,
childPosition));
}
public long getChildId(int groupPosition, int childPosition) {
return mGroups.get(groupPosition).children.get(childPosition).id;
}
public int getChildrenCount(int groupPosition) {
return mGroups.get(groupPosition).children.size();
}
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {
return getView(ExpandableListView.getPackedPositionForChild(groupPosition,
childPosition), convertView, parent);
}
public Object getGroup(int groupPosition) {
return getValueAtPosition(ExpandableListView.getPackedPositionForGroup(groupPosition));
}
public int getGroupCount() {
return mGroups.size();
}
public long getGroupId(int groupPosition) {
return mGroups.get(groupPosition).id;
}
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
ViewGroup parent) {
return getView(ExpandableListView.getPackedPositionForGroup(groupPosition),
convertView, parent);
}
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
public boolean hasStableIds() {
return true;
}
}
public static class MyGroup {
private static long mNextId = 1000;
String name;
long id = mNextId++;
List<MyChild> children;
public MyGroup(int numChildren) {
name = "Group " + id;
children = new ArrayList<MyChild>(numChildren);
for (int i = 0; i < numChildren; i++) {
children.add(new MyChild());
}
}
}
public static class MyChild {
private static long mNextId = 2000;
String name;
long id = mNextId++;
public MyChild() {
name = "Child " + id;
}
}
@Override
protected final void init(Params params) {
init((ExpandableParams) params);
}
/**
* @see ListScenario#init
*/
protected abstract void init(ExpandableParams params);
}