1 package com.xtremelabs.robolectric.shadows;
2 
3 import java.util.ArrayList;
4 import java.util.List;
5 
6 import android.util.SparseBooleanArray;
7 import android.view.View;
8 import android.widget.ListAdapter;
9 import android.widget.ListView;
10 
11 import com.xtremelabs.robolectric.internal.Implementation;
12 import com.xtremelabs.robolectric.internal.Implements;
13 import com.xtremelabs.robolectric.internal.RealObject;
14 
15 @SuppressWarnings({"UnusedDeclaration"})
16 @Implements(ListView.class)
17 public class ShadowListView extends ShadowAbsListView {
18     @RealObject private ListView realListView;
19 
20     private boolean itemsCanFocus;
21     private List<View> headerViews = new ArrayList<View>();
22     private List<View> footerViews = new ArrayList<View>();
23 
24     private int choiceMode;
25     private SparseBooleanArray checkedItemPositions = new SparseBooleanArray();
26 
27     @Implementation
28     @Override
findViewById(int id)29     public View findViewById(int id) {
30         View child = super.findViewById(id);
31         if (child == null) {
32             child = findView(headerViews, id);
33 
34             if (child == null) {
35                 child = findView(footerViews, id);
36             }
37         }
38         return child;
39     }
40 
findView(List<View> views, int viewId)41     private View findView(List<View> views, int viewId) {
42         View child = null;
43         for (View v : views) {
44             child = v.findViewById(viewId);
45             if (child != null) {
46                 break;
47             }
48         }
49         return child;
50     }
51 
52 
53     @Implementation
setItemsCanFocus(boolean itemsCanFocus)54     public void setItemsCanFocus(boolean itemsCanFocus) {
55         this.itemsCanFocus = itemsCanFocus;
56     }
57 
58     @Implementation
59     @Override
performItemClick(View view, int position, long id)60     public boolean performItemClick(View view, int position, long id) {
61         boolean handled = false;
62         if (choiceMode != ListView.CHOICE_MODE_NONE) {
63             handled = true;
64 
65             if (choiceMode == ListView.CHOICE_MODE_MULTIPLE) {
66                 boolean newValue = !checkedItemPositions.get(position, false);
67                 checkedItemPositions.put(position, newValue);
68             } else {
69                 boolean newValue = !checkedItemPositions.get(position, false);
70                 if (newValue) {
71                 	checkedItemPositions.clear();
72                 	checkedItemPositions.put(position, true);
73                 }
74             }
75         }
76 
77         handled |= super.performItemClick(view, position, id);
78         return handled;
79     }
80 
81     @Implementation
setAdapter(ListAdapter adapter)82     public void setAdapter(ListAdapter adapter) {
83         super.setAdapter(adapter);
84     }
85 
86     @Implementation
addHeaderView(View headerView)87     public void addHeaderView(View headerView) {
88         addHeaderView(headerView, null, true);
89     }
90 
91     @Implementation
addHeaderView(View headerView, Object data, boolean isSelectable)92     public void addHeaderView(View headerView, Object data, boolean isSelectable) {
93         ensureAdapterNotSet("header");
94         headerViews.add(headerView);
95         realListView.addView(headerView);
96     }
97 
98     @Implementation
getHeaderViewsCount()99     public int getHeaderViewsCount() {
100         return headerViews.size();
101     }
102 
103     @Implementation
getFooterViewsCount()104     public int getFooterViewsCount() {
105         return footerViews.size();
106     }
107 
108     @Implementation
addFooterView(View footerView, Object data, boolean isSelectable)109     public void addFooterView(View footerView, Object data, boolean isSelectable) {
110         ensureAdapterNotSet("footer");
111         footerViews.add(footerView);
112         realListView.addView(footerView);
113     }
114 
115     @Implementation
addFooterView(View footerView)116     public void addFooterView(View footerView) {
117         addFooterView(footerView, null, false);
118     }
119 
120     @Implementation
removeAllViews()121     public void removeAllViews() {
122         throw new UnsupportedOperationException();
123     }
124 
125     @Implementation
removeView(View view)126     public void removeView(View view) {
127         throw new UnsupportedOperationException();
128     }
129 
130     @Implementation
removeViewAt(int index)131     public void removeViewAt(int index) {
132         throw new UnsupportedOperationException();
133     }
134 
ensureAdapterNotSet(String view)135     private void ensureAdapterNotSet(String view) {
136         if (getAdapter() != null) {
137             throw new IllegalStateException("Cannot add " + view + " view to list -- setAdapter has already been called");
138         }
139     }
140 
isItemsCanFocus()141     public boolean isItemsCanFocus() {
142         return itemsCanFocus;
143     }
144 
getHeaderViews()145     public List<View> getHeaderViews() {
146         return headerViews;
147     }
148 
setHeaderViews(List<View> headerViews)149     public void setHeaderViews(List<View> headerViews) {
150         this.headerViews = headerViews;
151     }
152 
getFooterViews()153     public List<View> getFooterViews() {
154         return footerViews;
155     }
156 
setFooterViews(List<View> footerViews)157     public void setFooterViews(List<View> footerViews) {
158         this.footerViews = footerViews;
159     }
160 
161     @Override
addViews()162     protected void addViews() {
163         for (View headerView : headerViews) {
164             addView(headerView);
165         }
166 
167         super.addViews();
168 
169         for (View footerView : footerViews) {
170             addView(footerView);
171         }
172     }
173 
174     @Implementation
getChoiceMode()175     public int getChoiceMode() {
176         return choiceMode;
177     }
178 
179     @Implementation
setChoiceMode(int choiceMode)180     public void setChoiceMode(int choiceMode) {
181         this.choiceMode = choiceMode;
182     }
183 
184     @Implementation
setItemChecked(int position, boolean value)185     public void setItemChecked(int position, boolean value) {
186         if (choiceMode == ListView.CHOICE_MODE_SINGLE) {
187             checkedItemPositions.clear();
188             checkedItemPositions.put(position, value);
189         } else if (choiceMode == ListView.CHOICE_MODE_MULTIPLE) {
190             checkedItemPositions.put(position, value);
191         }
192     }
193 
194     @Implementation
getCheckedItemPosition()195     public int getCheckedItemPosition() {
196         if (choiceMode != ListView.CHOICE_MODE_SINGLE || checkedItemPositions.size() != 1)
197             return ListView.INVALID_POSITION;
198 
199         return checkedItemPositions.keyAt(0);
200     }
201 
202     @Implementation
getCheckedItemPositions()203     public SparseBooleanArray getCheckedItemPositions() {
204         if (choiceMode == ListView.CHOICE_MODE_NONE)
205             return null;
206 
207         return checkedItemPositions;
208     }
209 }
210