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