Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2009 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.view.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.assertNull;
     23 import static org.junit.Assert.assertSame;
     24 import static org.junit.Assert.assertTrue;
     25 import static org.junit.Assert.fail;
     26 
     27 import android.content.ComponentName;
     28 import android.content.Context;
     29 import android.content.pm.ActivityInfo;
     30 import android.content.pm.PackageManager;
     31 import android.content.res.Resources;
     32 import android.content.res.Resources.Theme;
     33 import android.content.res.XmlResourceParser;
     34 import android.support.test.InstrumentationRegistry;
     35 import android.support.test.filters.SmallTest;
     36 import android.support.test.runner.AndroidJUnit4;
     37 import android.util.AttributeSet;
     38 import android.util.TypedValue;
     39 import android.util.Xml;
     40 import android.view.ContextThemeWrapper;
     41 import android.view.Gravity;
     42 import android.view.InflateException;
     43 import android.view.LayoutInflater;
     44 import android.view.LayoutInflater.Factory;
     45 import android.view.LayoutInflater.Filter;
     46 import android.view.View;
     47 import android.view.ViewGroup;
     48 import android.view.cts.util.XmlUtils;
     49 import android.widget.LinearLayout;
     50 
     51 import org.junit.Before;
     52 import org.junit.Test;
     53 import org.junit.runner.RunWith;
     54 import org.xmlpull.v1.XmlPullParser;
     55 
     56 @SmallTest
     57 @RunWith(AndroidJUnit4.class)
     58 public class LayoutInflaterTest {
     59     private LayoutInflater mLayoutInflater;
     60 
     61     private Context mContext;
     62 
     63     private final Factory mFactory = (String name, Context context, AttributeSet attrs) -> null;
     64 
     65     private boolean isOnLoadClass;
     66 
     67     private final Filter mFilter = (Class clazz) -> {
     68         isOnLoadClass = true;
     69         return true;
     70     };
     71 
     72     @Before
     73     public void setup() {
     74         mContext = InstrumentationRegistry.getTargetContext();
     75         mLayoutInflater = (LayoutInflater) mContext.getSystemService(
     76                 Context.LAYOUT_INFLATER_SERVICE);
     77     }
     78 
     79     @Test
     80     public void testFrom() {
     81         mLayoutInflater = null;
     82         mLayoutInflater = LayoutInflater.from(mContext);
     83         assertNotNull(mLayoutInflater);
     84         mLayoutInflater = null;
     85         mLayoutInflater = new MockLayoutInflater(mContext);
     86         assertNotNull(mLayoutInflater);
     87 
     88         LayoutInflater layoutInflater = new MockLayoutInflater(mLayoutInflater,
     89                 mContext);
     90         assertNotNull(layoutInflater);
     91     }
     92 
     93     @Test
     94     public void testAccessLayoutInflaterProperties() {
     95         mLayoutInflater.setFilter(mFilter);
     96         assertSame(mFilter, mLayoutInflater.getFilter());
     97         mLayoutInflater.setFactory(mFactory);
     98         assertSame(mFactory, mLayoutInflater.getFactory());
     99         mLayoutInflater = new MockLayoutInflater(mContext);
    100         assertSame(mContext, mLayoutInflater.getContext());
    101     }
    102 
    103     private AttributeSet getAttrs() {
    104         XmlResourceParser parser = null;
    105         AttributeSet attrs = null;
    106         ActivityInfo ai = null;
    107         ComponentName mComponentName = new ComponentName(mContext,
    108                 MockActivity.class);
    109         try {
    110             ai = mContext.getPackageManager().getActivityInfo(mComponentName,
    111                     PackageManager.GET_META_DATA);
    112             parser = ai.loadXmlMetaData(mContext.getPackageManager(),
    113                     "android.widget.layout");
    114             int type;
    115             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
    116                     && type != XmlPullParser.START_TAG) {
    117             }
    118             String nodeName = parser.getName();
    119             if (!"alias".equals(nodeName)) {
    120                 throw new InflateException();
    121             }
    122             int outerDepth = parser.getDepth();
    123             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
    124                     && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
    125                 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
    126                     continue;
    127                 }
    128                 nodeName = parser.getName();
    129                 if ("AbsoluteLayout".equals(nodeName)) {
    130                     attrs = Xml.asAttributeSet(parser);
    131                 } else {
    132                     XmlUtils.skipCurrentTag(parser);
    133                 }
    134             }
    135         } catch (Exception e) {
    136         }
    137         return attrs;
    138     }
    139 
    140     @Test
    141     public void testCreateView() {
    142         AttributeSet attrs = getAttrs();
    143         isOnLoadClass = false;
    144         View view = null;
    145         try {
    146             view = mLayoutInflater.createView("testthrow", "com.android", attrs);
    147             fail("should throw exception");
    148         } catch (InflateException e) {
    149         } catch (ClassNotFoundException e) {
    150         }
    151         assertFalse(isOnLoadClass);
    152         assertNull(view);
    153         mLayoutInflater = null;
    154         mLayoutInflater = LayoutInflater.from(mContext);
    155         isOnLoadClass = false;
    156         mLayoutInflater.setFilter((Class clazz) -> {
    157             isOnLoadClass = true;
    158             return false;
    159         });
    160         try {
    161             view = mLayoutInflater.createView("MockActivity",
    162                     "com.android.app.", attrs);
    163             fail("should throw exception");
    164         } catch (InflateException e) {
    165         } catch (ClassNotFoundException e) {
    166         }
    167         assertFalse(isOnLoadClass);
    168         assertNull(view);
    169 
    170         isOnLoadClass = false;
    171         // allowedState is false
    172         try {
    173             view = mLayoutInflater.createView(MockActivity.class.getName(),
    174                     MockActivity.class.getPackage().toString(), attrs);
    175             fail("should throw exception");
    176         } catch (InflateException e) {
    177         } catch (ClassNotFoundException e) {
    178         }
    179         assertFalse(isOnLoadClass);
    180         assertNull(view);
    181         mLayoutInflater = null;
    182         mLayoutInflater = LayoutInflater.from(mContext);
    183         try {
    184             mLayoutInflater.setFilter(null);
    185             view = mLayoutInflater.createView("com.android.app.MockActivity",
    186                     null, attrs);
    187             assertNotNull(view);
    188             assertFalse(isOnLoadClass);
    189             mLayoutInflater = null;
    190             mLayoutInflater = LayoutInflater.from(mContext);
    191             mLayoutInflater.setFilter(null);
    192 
    193             view = mLayoutInflater.createView(MockActivity.class.getName(),
    194                     MockActivity.class.getPackage().toString(), attrs);
    195             assertNotNull(view);
    196             assertFalse(isOnLoadClass);
    197             mLayoutInflater.setFilter(mFilter);
    198             view = mLayoutInflater.createView(MockActivity.class.getName(),
    199                     MockActivity.class.getPackage().toString(), attrs);
    200             assertNotNull(view);
    201             assertTrue(isOnLoadClass);
    202             // allowedState!=null
    203             view = mLayoutInflater.createView(MockActivity.class.getName(),
    204                     MockActivity.class.getPackage().toString(), attrs);
    205             assertNotNull(view);
    206             assertTrue(isOnLoadClass);
    207         } catch (InflateException e) {
    208         } catch (ClassNotFoundException e) {
    209         }
    210     }
    211 
    212     @Test(expected=Resources.NotFoundException.class)
    213     public void testInflateInvalidId() {
    214         mLayoutInflater.inflate(-1, null);
    215     }
    216 
    217     @Test
    218     public void testInflate() {
    219         View view = mLayoutInflater.inflate(
    220                 android.view.cts.R.layout.inflater_layout, null);
    221         assertNotNull(view);
    222 
    223         LinearLayout linearLayout = new LinearLayout(mContext);
    224         linearLayout.setOrientation(LinearLayout.VERTICAL);
    225         linearLayout.setHorizontalGravity(Gravity.LEFT);
    226         linearLayout.setLayoutParams(new ViewGroup.LayoutParams(
    227                 ViewGroup.LayoutParams.MATCH_PARENT,
    228                 ViewGroup.LayoutParams.MATCH_PARENT));
    229         assertEquals(0, linearLayout.getChildCount());
    230         view = mLayoutInflater.inflate(R.layout.inflater_layout,
    231                 linearLayout);
    232         assertNotNull(view);
    233         assertEquals(1, linearLayout.getChildCount());
    234     }
    235 
    236     @Test(expected=Resources.NotFoundException.class)
    237     public void testInflateAttachToRootInvalidId() {
    238         mLayoutInflater.inflate(-1, null, false);
    239     }
    240 
    241     @Test
    242     public void testInflateAttachToRoot() {
    243         View view = mLayoutInflater.inflate(
    244                 R.layout.inflater_layout, null, false);
    245         assertNotNull(view);
    246 
    247         LinearLayout linearLayout = new LinearLayout(mContext);
    248         linearLayout.setOrientation(LinearLayout.VERTICAL);
    249         linearLayout.setHorizontalGravity(Gravity.LEFT);
    250         linearLayout.setLayoutParams(new ViewGroup.LayoutParams(
    251                 ViewGroup.LayoutParams.MATCH_PARENT,
    252                 ViewGroup.LayoutParams.MATCH_PARENT));
    253         assertEquals(0, linearLayout.getChildCount());
    254         view = mLayoutInflater.inflate(R.layout.inflater_layout,
    255                 linearLayout, false);
    256         assertNotNull(view);
    257         assertEquals(0, linearLayout.getChildCount());
    258 
    259         view = mLayoutInflater.inflate(R.layout.inflater_layout,
    260                 linearLayout, true);
    261         assertNotNull(view);
    262         assertEquals(1, linearLayout.getChildCount());
    263     }
    264 
    265     @Test(expected=NullPointerException.class)
    266     public void testInflateParserNullParser() {
    267         mLayoutInflater.inflate(null, null);
    268     }
    269 
    270     @Test
    271     public void testInflateParser() {
    272         XmlResourceParser parser = mContext.getResources().getLayout(R.layout.inflater_layout);
    273         View view = mLayoutInflater.inflate(parser, null);
    274         assertNotNull(view);
    275 
    276         LinearLayout linearLayout = new LinearLayout(mContext);
    277         linearLayout.setOrientation(LinearLayout.VERTICAL);
    278         linearLayout.setHorizontalGravity(Gravity.LEFT);
    279         linearLayout.setLayoutParams(new ViewGroup.LayoutParams(
    280                 ViewGroup.LayoutParams.MATCH_PARENT,
    281                 ViewGroup.LayoutParams.MATCH_PARENT));
    282         assertEquals(0, linearLayout.getChildCount());
    283 
    284         try {
    285             mLayoutInflater.inflate(parser, linearLayout);
    286             fail("should throw exception");
    287         } catch (NullPointerException e) {
    288         }
    289 
    290         parser = mContext.getResources().getLayout(R.layout.inflater_layout);
    291         view = mLayoutInflater.inflate(parser, linearLayout);
    292         assertNotNull(view);
    293         assertEquals(1, linearLayout.getChildCount());
    294         parser = mContext.getResources().getLayout(R.layout.inflater_layout);
    295         view = mLayoutInflater.inflate(parser, linearLayout);
    296         assertNotNull(view);
    297         assertEquals(2, linearLayout.getChildCount());
    298 
    299         parser = getParser();
    300         view = mLayoutInflater.inflate(parser, linearLayout);
    301         assertNotNull(view);
    302         assertEquals(3, linearLayout.getChildCount());
    303     }
    304 
    305     @Test(expected=NullPointerException.class)
    306     public void testInflateParserAttachToRootNullParser() {
    307         mLayoutInflater.inflate(null, null, false);
    308     }
    309 
    310     @Test
    311     public void testInflateParserAttachToRoot() {
    312         XmlResourceParser parser = mContext.getResources().getLayout(R.layout.inflater_layout);
    313         View view = mLayoutInflater.inflate(parser, null, false);
    314         assertNotNull(view);
    315 
    316         LinearLayout linearLayout = new LinearLayout(mContext);
    317         linearLayout.setOrientation(LinearLayout.VERTICAL);
    318         linearLayout.setHorizontalGravity(Gravity.LEFT);
    319         linearLayout.setLayoutParams(new ViewGroup.LayoutParams(
    320                 ViewGroup.LayoutParams.MATCH_PARENT,
    321                 ViewGroup.LayoutParams.MATCH_PARENT));
    322         assertEquals(0, linearLayout.getChildCount());
    323 
    324         try {
    325             mLayoutInflater.inflate(parser, linearLayout, false);
    326             fail("should throw exception");
    327         } catch (NullPointerException e) {
    328         }
    329 
    330         parser = mContext.getResources().getLayout(R.layout.inflater_layout);
    331         view = mLayoutInflater.inflate(parser, linearLayout, false);
    332         assertNull(view.getParent());
    333         assertNotNull(view);
    334         assertEquals(0, linearLayout.getChildCount());
    335         parser = mContext.getResources().getLayout(R.layout.inflater_layout);
    336         assertEquals(0, linearLayout.getChildCount());
    337         view = mLayoutInflater.inflate(parser, linearLayout, true);
    338         assertNotNull(view);
    339         assertNull(view.getParent());
    340         assertEquals(1, linearLayout.getChildCount());
    341 
    342         parser = getParser();
    343         try {
    344             mLayoutInflater.inflate(parser, linearLayout, false);
    345             fail("should throw exception");
    346         } catch (InflateException e) {
    347         }
    348 
    349         parser = getParser();
    350 
    351         view = mLayoutInflater.inflate(parser, linearLayout, true);
    352         assertNotNull(view);
    353         assertEquals(2, linearLayout.getChildCount());
    354     }
    355 
    356     @Test
    357     public void testOverrideTheme() {
    358         View container = mLayoutInflater.inflate(R.layout.inflater_override_theme_layout, null);
    359         verifyThemeType(container, "view_outer", R.id.view_outer, 1);
    360         verifyThemeType(container, "view_inner", R.id.view_inner, 2);
    361         verifyThemeType(container, "view_attr", R.id.view_attr, 3);
    362         verifyThemeType(container, "view_include", R.id.view_include, 4);
    363         verifyThemeType(container, "view_include_notheme", R.id.view_include_notheme, 5);
    364     }
    365 
    366     private void verifyThemeType(View container, String tag, int id, int type) {
    367         TypedValue outValue = new TypedValue();
    368         View view = container.findViewById(id);
    369         assertNotNull("Found " + tag, view);
    370         Theme theme = view.getContext().getTheme();
    371         boolean resolved = theme.resolveAttribute(R.attr.themeType, outValue, true);
    372         assertTrue("Resolved themeType for " + tag, resolved);
    373         assertEquals(tag + " has themeType " + type, type, outValue.data);
    374     }
    375 
    376     @Test
    377     public void testInflateTags() {
    378         final View view = mLayoutInflater.inflate(
    379                 android.view.cts.R.layout.inflater_layout_tags, null);
    380         assertNotNull(view);
    381 
    382         checkViewTag(view, R.id.viewlayout_root, R.id.tag_viewlayout_root, R.string.tag1);
    383         checkViewTag(view, R.id.mock_view, R.id.tag_mock_view, R.string.tag2);
    384     }
    385 
    386     private void checkViewTag(View parent, int viewId, int tagId, int valueResId) {
    387         final View target = parent.findViewById(viewId);
    388         assertNotNull("Found target view for " + viewId, target);
    389 
    390         final Object tag = target.getTag(tagId);
    391         assertNotNull("Tag is set", tag);
    392         assertTrue("Tag is a character sequence", tag instanceof CharSequence);
    393 
    394         final Context targetContext = target.getContext();
    395         final CharSequence expectedValue = targetContext.getString(valueResId);
    396         assertEquals(tagId + " has tag " + expectedValue, expectedValue, tag);
    397     }
    398 
    399     @Test
    400     public void testInclude() {
    401         final Context themedContext = new ContextThemeWrapper(mContext, R.style.Test_Theme);
    402         final LayoutInflater inflater = LayoutInflater.from(themedContext);
    403 
    404         final View container = inflater.inflate(R.layout.inflater_layout_include, null);
    405         assertNotNull(container.findViewById(R.id.include_layout_explicit));
    406         assertNotNull(container.findViewById(R.id.include_layout_from_attr));
    407     }
    408 
    409     @Test(expected = InflateException.class)
    410     public void testIncludeMissingAttr() {
    411         final View container = mLayoutInflater.inflate(R.layout.inflater_layout_include, null);
    412         assertNotNull(container.findViewById(R.id.include_layout_from_attr));
    413     }
    414 
    415     static class MockLayoutInflater extends LayoutInflater {
    416 
    417         public MockLayoutInflater(Context c) {
    418             super(c);
    419         }
    420 
    421         public MockLayoutInflater(LayoutInflater original, Context newContext) {
    422             super(original, newContext);
    423         }
    424 
    425         @Override
    426         public View onCreateView(String name, AttributeSet attrs)
    427                 throws ClassNotFoundException {
    428             return super.onCreateView(name, attrs);
    429         }
    430 
    431         @Override
    432         public LayoutInflater cloneInContext(Context newContext) {
    433             return null;
    434         }
    435     }
    436 
    437     private XmlResourceParser getParser() {
    438         XmlResourceParser parser = null;
    439         ActivityInfo ai = null;
    440         ComponentName mComponentName = new ComponentName(mContext,
    441                 MockActivity.class);
    442         try {
    443             ai = mContext.getPackageManager().getActivityInfo(mComponentName,
    444                     PackageManager.GET_META_DATA);
    445             parser = ai.loadXmlMetaData(mContext.getPackageManager(),
    446                     "android.view.merge");
    447         } catch (Exception e) {
    448         }
    449         return parser;
    450     }
    451 }
    452