1 /*
2  * Copyright (C) 2008 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.widget.cts;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertSame;
23 import static org.junit.Assert.assertTrue;
24 import static org.junit.Assert.fail;
25 
26 import android.app.Activity;
27 import android.content.Context;
28 import android.util.AttributeSet;
29 import android.util.Xml;
30 import android.view.Gravity;
31 import android.view.View;
32 import android.view.ViewGroup;
33 import android.view.ViewGroup.OnHierarchyChangeListener;
34 import android.view.accessibility.AccessibilityNodeInfo;
35 import android.widget.LinearLayout;
36 import android.widget.RadioButton;
37 import android.widget.RadioGroup;
38 import android.widget.RadioGroup.LayoutParams;
39 import android.widget.RadioGroup.OnCheckedChangeListener;
40 import android.widget.RelativeLayout;
41 
42 import androidx.test.annotation.UiThreadTest;
43 import androidx.test.filters.SmallTest;
44 import androidx.test.rule.ActivityTestRule;
45 import androidx.test.runner.AndroidJUnit4;
46 
47 import org.junit.Before;
48 import org.junit.Rule;
49 import org.junit.Test;
50 import org.junit.runner.RunWith;
51 import org.xmlpull.v1.XmlPullParser;
52 import org.xmlpull.v1.XmlPullParserException;
53 
54 import java.io.IOException;
55 import java.util.Vector;
56 
57 /**
58  * Test {@link RadioGroup}.
59  */
60 @SmallTest
61 @RunWith(AndroidJUnit4.class)
62 public class RadioGroupTest {
63     private Activity mActivity;
64     private RadioGroup mRadioGroup;
65 
66     @Rule
67     public ActivityTestRule<RadioGroupCtsActivity> mActivityRule =
68             new ActivityTestRule<>(RadioGroupCtsActivity.class);
69 
70     @Before
setup()71     public void setup() {
72         mActivity = mActivityRule.getActivity();
73         mRadioGroup = (RadioGroup) mActivity.findViewById(R.id.radio_group);
74     }
75 
76     @Test
testConstructors()77     public void testConstructors() {
78         new RadioGroup(mActivity);
79 
80         AttributeSet attrs = getAttributeSet(R.layout.radiogroup_1);
81         new RadioGroup(mActivity, attrs);
82         new RadioGroup(mActivity, null);
83     }
84 
85     @UiThreadTest
86     @Test
testSetOnHierarchyChangeListener()87     public void testSetOnHierarchyChangeListener() {
88         MockOnHierarchyChangeListener listener = new MockOnHierarchyChangeListener();
89         mRadioGroup.setOnHierarchyChangeListener(listener);
90 
91         View button3 = mRadioGroup.findViewById(R.id.radio_button_3);
92         listener.reset();
93         mRadioGroup.removeView(button3);
94         assertSame(mRadioGroup, listener.getOnChildViewRemovedParentParam());
95         assertSame(button3, listener.getOnChildViewRemovedChildParam());
96 
97         listener.reset();
98         mRadioGroup.addView(button3);
99         assertSame(mRadioGroup, listener.getOnChildViewAddedParentParam());
100         assertSame(button3, listener.getOnChildViewAddedChildParam());
101 
102         // Set listener to null
103         mRadioGroup.setOnHierarchyChangeListener(null);
104         // and no exceptions thrown in the following method calls
105         mRadioGroup.removeView(button3);
106         mRadioGroup.addView(button3);
107     }
108 
109     @UiThreadTest
110     @Test
testInternalPassThroughHierarchyChangeListener()111     public void testInternalPassThroughHierarchyChangeListener() {
112         RadioButton newButton = new RadioButton(mActivity);
113 
114         assertEquals(View.NO_ID, newButton.getId());
115         mRadioGroup.addView(newButton, new RadioGroup.LayoutParams(
116                 RadioGroup.LayoutParams.WRAP_CONTENT, RadioGroup.LayoutParams.WRAP_CONTENT));
117         // aapt-generated IDs have a nonzero high byte; check that the ID generated by
118         // RadioGroup falls within a range that will not collide with aapt IDs.
119         assertEquals(0, newButton.getId() & 0xFF000000);
120     }
121 
122     @UiThreadTest
123     @Test
testInternalCheckedStateTracker()124     public void testInternalCheckedStateTracker() {
125         RadioButton newButton = new RadioButton(mActivity);
126         // inject the tracker to the button when the button is added by
127         // CompoundButton#setOnCheckedChangeWidgetListener(OnCheckedChangeListener)
128         mRadioGroup.addView(newButton, new RadioGroup.LayoutParams(
129                 RadioGroup.LayoutParams.WRAP_CONTENT, RadioGroup.LayoutParams.WRAP_CONTENT));
130         MockOnCheckedChangeListener listener = new MockOnCheckedChangeListener();
131         mRadioGroup.setOnCheckedChangeListener(listener);
132 
133         listener.reset();
134         newButton.setChecked(true);
135         // the tracker informs the checked state change of the button to the group
136         assertHasCalledOnCheckedChanged(listener);
137 
138         listener.reset();
139         // the tracker informs the checked state change of the button to the group
140         newButton.setChecked(false);
141         assertHasCalledOnCheckedChanged(listener);
142 
143         // remove the tracker from the button when the button is removed
144         mRadioGroup.removeView(newButton);
145         listener.reset();
146         newButton.setChecked(true);
147         assertHaveNotCalledOnCheckedChanged(listener);
148 
149         listener.reset();
150         newButton.setChecked(false);
151         assertHaveNotCalledOnCheckedChanged(listener);
152     }
153 
154     @UiThreadTest
155     @Test
testGetCheckedRadioButtonId()156     public void testGetCheckedRadioButtonId() {
157         assertEquals(-1, mRadioGroup.getCheckedRadioButtonId());
158 
159         mRadioGroup.check(R.id.radio_button_0);
160         assertEquals(R.id.radio_button_0, mRadioGroup.getCheckedRadioButtonId());
161 
162         mRadioGroup.check(R.id.radio_button_3);
163         assertEquals(R.id.radio_button_3, mRadioGroup.getCheckedRadioButtonId());
164 
165         // None of the buttons inside the group has of of the following IDs
166         mRadioGroup.check(4);
167         assertEquals(4, mRadioGroup.getCheckedRadioButtonId());
168 
169         mRadioGroup.check(-1);
170         assertEquals(-1, mRadioGroup.getCheckedRadioButtonId());
171 
172         mRadioGroup.check(-3);
173         assertEquals(-3, mRadioGroup.getCheckedRadioButtonId());
174     }
175 
176     @UiThreadTest
177     @Test
testClearCheck()178     public void testClearCheck() {
179         MockOnCheckedChangeListener listener = new MockOnCheckedChangeListener();
180         mRadioGroup.setOnCheckedChangeListener(listener);
181 
182         mRadioGroup.check(R.id.radio_button_3);
183         assertEquals(R.id.radio_button_3, mRadioGroup.getCheckedRadioButtonId());
184 
185         listener.reset();
186         mRadioGroup.clearCheck();
187         assertEquals(-1, mRadioGroup.getCheckedRadioButtonId());
188         assertHasCalledOnCheckedChanged(listener);
189         // uncheck the original button
190         assertOnCheckedChangedParams(listener, 0, mRadioGroup, R.id.radio_button_3);
191 
192         // None of the buttons inside the group has of of the following IDs
193         mRadioGroup.check(4);
194         assertEquals(4, mRadioGroup.getCheckedRadioButtonId());
195 
196         listener.reset();
197         mRadioGroup.clearCheck();
198         assertEquals(-1, mRadioGroup.getCheckedRadioButtonId());
199         // why the method is called while none of the button is checked or unchecked?
200         assertHasCalledOnCheckedChanged(listener);
201         assertOnCheckedChangedParams(listener, 0, mRadioGroup, -1);
202 
203         mRadioGroup.check(-1);
204         assertEquals(-1, mRadioGroup.getCheckedRadioButtonId());
205 
206         listener.reset();
207         mRadioGroup.clearCheck();
208         assertEquals(-1, mRadioGroup.getCheckedRadioButtonId());
209         // why the method is called while none of the button is checked or unchecked?
210         assertHasCalledOnCheckedChanged(listener);
211         assertOnCheckedChangedParams(listener, 0, mRadioGroup, -1);
212     }
213 
214     @UiThreadTest
215     @Test
testCheck()216     public void testCheck() {
217         MockOnCheckedChangeListener listener = new MockOnCheckedChangeListener();
218         mRadioGroup.setOnCheckedChangeListener(listener);
219         assertEquals(-1, mRadioGroup.getCheckedRadioButtonId());
220 
221         listener.reset();
222         mRadioGroup.check(R.id.radio_button_0);
223         assertHasCalledOnCheckedChanged(listener);
224         assertOnCheckedChangedParams(listener, 0, mRadioGroup, R.id.radio_button_0);
225 
226         listener.reset();
227         mRadioGroup.check(R.id.radio_button_1);
228         assertHasCalledOnCheckedChanged(listener);
229         // uncheck the original button
230         assertOnCheckedChangedParams(listener, 0, mRadioGroup, R.id.radio_button_0);
231         // check the new button
232         assertOnCheckedChangedParams(listener, 1, mRadioGroup, R.id.radio_button_1);
233 
234         listener.reset();
235         mRadioGroup.check(-1);
236         assertHasCalledOnCheckedChanged(listener);
237         // uncheck the original button
238         assertOnCheckedChangedParams(listener, 0, mRadioGroup, R.id.radio_button_1);
239         assertOnCheckedChangedParams(listener, 1, mRadioGroup, -1);
240 
241         // None of the buttons inside the group has of of the following IDs
242         listener.reset();
243         mRadioGroup.check(-1);
244         // why the method is called while none of the inside buttons has been changed
245         assertHasCalledOnCheckedChanged(listener);
246         assertOnCheckedChangedParams(listener, 0, mRadioGroup, -1);
247 
248         listener.reset();
249         mRadioGroup.check(4);
250         // why the method is called while none of the inside buttons has been changed
251         assertHasCalledOnCheckedChanged(listener);
252         assertOnCheckedChangedParams(listener, 0, mRadioGroup, 4);
253 
254         // Set listener to null
255         mRadioGroup.setOnCheckedChangeListener(null);
256         // no exceptions thrown during the following method
257         mRadioGroup.check(0);
258     }
259 
260     @UiThreadTest
261     @Test
testSetOnCheckedChangeListener()262     public void testSetOnCheckedChangeListener() {
263         MockOnCheckedChangeListener listener = new MockOnCheckedChangeListener();
264         mRadioGroup.setOnCheckedChangeListener(listener);
265 
266         listener.reset();
267         mRadioGroup.check(R.id.radio_button_0);
268         assertHasCalledOnCheckedChanged(listener);
269 
270         // does not call the method if the button the id is already checked
271         listener.reset();
272         mRadioGroup.check(R.id.radio_button_0);
273         assertHaveNotCalledOnCheckedChanged(listener);
274 
275         // call the method if none of the buttons inside the group has the id
276         listener.reset();
277         mRadioGroup.check(-3);
278         assertHasCalledOnCheckedChanged(listener);
279 
280         // does not call the method if the button the id is already checked
281         // and none of the buttons inside the group has the id
282         listener.reset();
283         mRadioGroup.check(-3);
284         assertHaveNotCalledOnCheckedChanged(listener);
285 
286         // always call the method if the checked id is -1
287         listener.reset();
288         mRadioGroup.clearCheck();
289         assertHasCalledOnCheckedChanged(listener);
290 
291         listener.reset();
292         mRadioGroup.check(-1);
293         assertHasCalledOnCheckedChanged(listener);
294 
295         // Set listener to null
296         mRadioGroup.setOnCheckedChangeListener(null);
297         // no exceptions thrown during the following method
298         mRadioGroup.check(0);
299     }
300 
301     @Test
testGenerateLayoutParams()302     public void testGenerateLayoutParams() {
303         RadioGroup.LayoutParams layoutParams =
304             mRadioGroup.generateLayoutParams((AttributeSet) null);
305         assertNotNull(layoutParams);
306         // default values
307         assertEquals(0.0, layoutParams.weight, 0);
308         assertEquals(-1, layoutParams.gravity);
309         assertEquals(0, layoutParams.leftMargin);
310         assertEquals(0, layoutParams.topMargin);
311         assertEquals(0, layoutParams.rightMargin);
312         assertEquals(0, layoutParams.bottomMargin);
313         assertEquals(LayoutParams.WRAP_CONTENT, layoutParams.width);
314         assertEquals(LayoutParams.WRAP_CONTENT, layoutParams.height);
315 
316         AttributeSet attrs = getAttributeSet(R.layout.radiogroup_1);
317         layoutParams = mRadioGroup.generateLayoutParams(attrs);
318         // values from layout
319         assertNotNull(layoutParams);
320         assertEquals(0.5, layoutParams.weight, 0);
321         assertEquals(Gravity.BOTTOM, layoutParams.gravity);
322         assertEquals(5, layoutParams.leftMargin);
323         assertEquals(5, layoutParams.topMargin);
324         assertEquals(5, layoutParams.rightMargin);
325         assertEquals(5, layoutParams.bottomMargin);
326         assertEquals(LayoutParams.MATCH_PARENT, layoutParams.width);
327         assertEquals(LayoutParams.MATCH_PARENT, layoutParams.height);
328     }
329 
330     @Test
testCheckLayoutParams()331     public void testCheckLayoutParams() {
332         MockRadioGroup mRadioGroupWrapper = new MockRadioGroup(mActivity);
333 
334         assertFalse(mRadioGroupWrapper.checkLayoutParams(null));
335 
336         RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(
337                 RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
338         assertFalse(mRadioGroupWrapper.checkLayoutParams(relativeParams));
339 
340         LinearLayout.LayoutParams linearParams = new LinearLayout.LayoutParams(
341                 LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
342         assertFalse(mRadioGroupWrapper.checkLayoutParams(linearParams));
343 
344         RadioGroup.LayoutParams radioParams = new RadioGroup.LayoutParams(
345                 RadioGroup.LayoutParams.MATCH_PARENT, RadioGroup.LayoutParams.MATCH_PARENT);
346         assertTrue(mRadioGroupWrapper.checkLayoutParams(radioParams));
347     }
348 
349     @Test
testGenerateDefaultLayoutParams()350     public void testGenerateDefaultLayoutParams() {
351         MockRadioGroup radioGroupWrapper = new MockRadioGroup(mActivity);
352         LinearLayout.LayoutParams p = radioGroupWrapper.generateDefaultLayoutParams();
353 
354         assertTrue(p instanceof RadioGroup.LayoutParams);
355         assertEquals(RadioGroup.LayoutParams.WRAP_CONTENT, p.width);
356         assertEquals(RadioGroup.LayoutParams.WRAP_CONTENT, p.height);
357     }
358 
359     @UiThreadTest
360     @Test
testOnFinishInflate()361     public void testOnFinishInflate() {
362         MockRadioGroup radioGroup = new MockRadioGroup(mActivity);
363         int checkId = 100;
364         radioGroup.check(checkId);
365         // the button is added after the check(int)method
366         // and it not checked though it has exactly the checkId
367         RadioButton button = new RadioButton(mActivity);
368         button.setId(checkId);
369         radioGroup.addView(button, new LinearLayout.LayoutParams(
370                 LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
371         MockOnCheckedChangeListener listener = new MockOnCheckedChangeListener();
372         radioGroup.setOnCheckedChangeListener(listener);
373 
374         // check the button which id is CheckedRadioButtonId
375         listener.reset();
376         assertFalse(button.isChecked());
377         radioGroup.onFinishInflate();
378         assertTrue(button.isChecked());
379         assertHasCalledOnCheckedChanged(listener);
380         assertEquals(checkId, radioGroup.getCheckedRadioButtonId());
381 
382         radioGroup = new MockRadioGroup(mActivity);
383         button = new RadioButton(mActivity);
384         radioGroup.addView(button, new LinearLayout.LayoutParams(
385                 LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
386         listener = new MockOnCheckedChangeListener();
387         radioGroup.setOnCheckedChangeListener(listener);
388 
389         // nothing happens if checkedRadioButtonId is -1
390         assertEquals(-1, radioGroup.getCheckedRadioButtonId());
391         assertFalse(button.isChecked());
392         listener.reset();
393         radioGroup.onFinishInflate();
394         assertHaveNotCalledOnCheckedChanged(listener);
395         assertEquals(-1, radioGroup.getCheckedRadioButtonId());
396         assertFalse(button.isChecked());
397     }
398 
399     @UiThreadTest
400     @Test
testAddView()401     public void testAddView() {
402         mRadioGroup.check(R.id.radio_button_0);
403         assertEquals(R.id.radio_button_0, mRadioGroup.getCheckedRadioButtonId());
404         assertEquals(4, mRadioGroup.getChildCount());
405 
406         int id = R.id.radio_button_3 + 10;
407         RadioButton choice4 = new RadioButton(mActivity);
408         choice4.setText("choice4");
409         choice4.setId(id);
410         choice4.setChecked(true);
411         mRadioGroup.addView(choice4, 4, new ViewGroup.LayoutParams(100, 200));
412         assertEquals(id, mRadioGroup.getCheckedRadioButtonId());
413         assertEquals(5, mRadioGroup.getChildCount());
414     }
415 
416     @UiThreadTest
417     @Test
testOnInitializeAccessibilityNodeInfo_populatesCollectionInfo()418     public void testOnInitializeAccessibilityNodeInfo_populatesCollectionInfo() {
419         AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
420         mRadioGroup.onInitializeAccessibilityNodeInfo(info);
421 
422         AccessibilityNodeInfo.CollectionInfo colInfo = info.getCollectionInfo();
423         assertNotNull(colInfo);
424         assertEquals(colInfo.getRowCount(), mRadioGroup.getChildCount());
425     }
426 
427     @UiThreadTest
428     @Test
testOnInitializeAccessibilityNodeInfo_populatesCollectionItemInfo()429     public void testOnInitializeAccessibilityNodeInfo_populatesCollectionItemInfo() {
430         RadioButton child = (RadioButton) mRadioGroup.getChildAt(1);
431         child.setChecked(true);
432 
433         AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
434         child.onInitializeAccessibilityNodeInfo(info);
435 
436         AccessibilityNodeInfo.CollectionItemInfo colItemInfo = info.getCollectionItemInfo();
437         assertEquals(colItemInfo.getRowIndex(), 1);
438         assertEquals(colItemInfo.isSelected(), true);
439     }
440 
441     @UiThreadTest
442     @Test
testOnInitializeAccessibilityNodeInfo_populatesColInfoWithInvalidCount()443     public void testOnInitializeAccessibilityNodeInfo_populatesColInfoWithInvalidCount() {
444         for (int i = 0; i < mRadioGroup.getChildCount(); i++) {
445             ((RadioButton) mRadioGroup.getChildAt(i)).setText("");
446         }
447         AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
448         mRadioGroup.onInitializeAccessibilityNodeInfo(info);
449 
450         AccessibilityNodeInfo.CollectionInfo colInfo = info.getCollectionInfo();
451         assertNotNull(colInfo);
452         assertEquals(colInfo.getRowCount(), 0);
453     }
454 
getAttributeSet(int resId)455     private AttributeSet getAttributeSet(int resId) {
456         XmlPullParser parser = mActivity.getResources().getLayout(resId);
457         assertNotNull(parser);
458         int type = 0;
459         try {
460             while ((type = parser.next()) != XmlPullParser.START_TAG
461                     && type != XmlPullParser.END_DOCUMENT) {
462                 // Empty
463             }
464         } catch (XmlPullParserException e) {
465             fail(e.getMessage());
466         } catch (IOException e) {
467             fail(e.getMessage());
468         }
469 
470         assertEquals("No RadioGroup element found", XmlPullParser.START_TAG, type);
471         assertEquals("The first element is not RadioGroup", "RadioGroup", parser.getName());
472         return Xml.asAttributeSet(parser);
473     }
474 
assertHaveNotCalledOnCheckedChanged(MockOnCheckedChangeListener listener)475     private void assertHaveNotCalledOnCheckedChanged(MockOnCheckedChangeListener listener) {
476         assertEquals(0, listener.getOnCheckedChangedGroupParams().size());
477         assertEquals(0, listener.getOnCheckedChangedCheckedIdParams().size());
478     }
479 
assertHasCalledOnCheckedChanged(MockOnCheckedChangeListener listener)480     private void assertHasCalledOnCheckedChanged(MockOnCheckedChangeListener listener) {
481         assertTrue(listener.getOnCheckedChangedGroupParams().size() > 0);
482         assertTrue(listener.getOnCheckedChangedCheckedIdParams().size() > 0);
483     }
484 
assertOnCheckedChangedParams(MockOnCheckedChangeListener listener, int time, RadioGroup paramGroup, int paramCheckedId)485     private void assertOnCheckedChangedParams(MockOnCheckedChangeListener listener, int time,
486             RadioGroup paramGroup, int paramCheckedId) {
487         assertSame(paramGroup,
488                 listener.getOnCheckedChangedGroupParams().get(time));
489         assertEquals(paramCheckedId, listener
490                 .getOnCheckedChangedCheckedIdParams().get(time).intValue());
491     }
492 
493     private class MockOnCheckedChangeListener implements OnCheckedChangeListener {
494         private Vector<RadioGroup> mOnCheckedChangedGroupParams = new Vector<RadioGroup>();
495 
496         private Vector<Integer> mOnCheckedChangedCheckedIdParams = new Vector<Integer>();
497 
getOnCheckedChangedGroupParams()498         public Vector<RadioGroup> getOnCheckedChangedGroupParams() {
499             return mOnCheckedChangedGroupParams;
500         }
501 
getOnCheckedChangedCheckedIdParams()502         public Vector<Integer> getOnCheckedChangedCheckedIdParams() {
503             return mOnCheckedChangedCheckedIdParams;
504         }
505 
reset()506         public void reset() {
507             mOnCheckedChangedGroupParams.clear();
508             mOnCheckedChangedCheckedIdParams.clear();
509         }
510 
onCheckedChanged(RadioGroup group, int checkedId)511         public void onCheckedChanged(RadioGroup group, int checkedId) {
512             mOnCheckedChangedGroupParams.add(group);
513             mOnCheckedChangedCheckedIdParams.add(checkedId);
514         }
515     }
516 
517     private class MockOnHierarchyChangeListener implements OnHierarchyChangeListener {
518         private View mOnChildViewAddedParentParam;
519 
520         private View mOnChildViewAddedChildParam;
521 
522         private View mOnChildViewRemovedParentParam;
523 
524         private View mOnChildViewRemovedChildParam;
525 
getOnChildViewAddedParentParam()526         public View getOnChildViewAddedParentParam() {
527             return mOnChildViewAddedParentParam;
528         }
529 
getOnChildViewAddedChildParam()530         public View getOnChildViewAddedChildParam() {
531             return mOnChildViewAddedChildParam;
532         }
533 
getOnChildViewRemovedParentParam()534         public View getOnChildViewRemovedParentParam() {
535             return mOnChildViewRemovedParentParam;
536         }
537 
getOnChildViewRemovedChildParam()538         public View getOnChildViewRemovedChildParam() {
539             return mOnChildViewRemovedChildParam;
540         }
541 
reset()542         public void reset() {
543             mOnChildViewAddedParentParam = null;
544             mOnChildViewAddedChildParam = null;
545             mOnChildViewRemovedParentParam = null;
546             mOnChildViewRemovedChildParam = null;
547         }
548 
onChildViewAdded(View parent, View child)549         public void onChildViewAdded(View parent, View child) {
550             mOnChildViewAddedParentParam = parent;
551             mOnChildViewAddedChildParam = child;
552         }
553 
onChildViewRemoved(View parent, View child)554         public void onChildViewRemoved(View parent, View child) {
555             mOnChildViewRemovedParentParam = parent;
556             mOnChildViewRemovedChildParam = child;
557         }
558     }
559 
560     public static class MockRadioGroup extends RadioGroup {
MockRadioGroup(Context context)561         public MockRadioGroup(Context context) {
562             super(context);
563         }
564 
565         @Override
checkLayoutParams(ViewGroup.LayoutParams p)566         protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
567             return super.checkLayoutParams(p);
568         }
569 
570         @Override
generateDefaultLayoutParams()571         protected android.widget.LinearLayout.LayoutParams generateDefaultLayoutParams() {
572             return super.generateDefaultLayoutParams();
573         }
574 
575         @Override
onFinishInflate()576         protected void onFinishInflate() {
577             super.onFinishInflate();
578         }
579     }
580 }
581