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.assertNull; 23 import static org.junit.Assert.assertSame; 24 import static org.junit.Assert.assertTrue; 25 import static org.mockito.Matchers.any; 26 import static org.mockito.Mockito.never; 27 import static org.mockito.Mockito.reset; 28 import static org.mockito.Mockito.spy; 29 import static org.mockito.Mockito.times; 30 import static org.mockito.Mockito.verify; 31 32 import android.app.Activity; 33 import android.app.Instrumentation; 34 import android.content.Context; 35 import android.content.res.ColorStateList; 36 import android.graphics.Color; 37 import android.graphics.PorterDuff; 38 import android.graphics.Rect; 39 import android.graphics.Region; 40 import android.graphics.drawable.BitmapDrawable; 41 import android.graphics.drawable.ColorDrawable; 42 import android.graphics.drawable.Drawable; 43 import android.util.AttributeSet; 44 import android.util.Xml; 45 import android.view.Gravity; 46 import android.view.View; 47 import android.view.ViewGroup; 48 import android.widget.Button; 49 import android.widget.FrameLayout; 50 import android.widget.FrameLayout.LayoutParams; 51 import android.widget.LinearLayout; 52 import android.widget.TextView; 53 54 import androidx.test.InstrumentationRegistry; 55 import androidx.test.annotation.UiThreadTest; 56 import androidx.test.filters.SmallTest; 57 import androidx.test.rule.ActivityTestRule; 58 import androidx.test.runner.AndroidJUnit4; 59 60 import com.android.compatibility.common.util.PollingCheck; 61 import com.android.compatibility.common.util.WidgetTestUtils; 62 63 import org.junit.Before; 64 import org.junit.Rule; 65 import org.junit.Test; 66 import org.junit.runner.RunWith; 67 import org.mockito.ArgumentCaptor; 68 import org.xmlpull.v1.XmlPullParser; 69 import org.xmlpull.v1.XmlPullParserException; 70 71 import java.io.IOException; 72 73 @SmallTest 74 @RunWith(AndroidJUnit4.class) 75 public class FrameLayoutTest { 76 private Instrumentation mInstrumentation; 77 private Activity mActivity; 78 private FrameLayout mFrameLayout; 79 80 @Rule 81 public ActivityTestRule<FrameLayoutCtsActivity> mActivityRule = 82 new ActivityTestRule<>(FrameLayoutCtsActivity.class); 83 84 @Before setup()85 public void setup() { 86 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 87 mActivity = mActivityRule.getActivity(); 88 mFrameLayout = (FrameLayout) mActivity.findViewById(R.id.framelayout); 89 } 90 91 @Test testConstructor()92 public void testConstructor() throws XmlPullParserException, IOException { 93 AttributeSet attrs = getAttributeSet(); 94 95 new FrameLayout(mActivity); 96 new FrameLayout(mActivity, attrs); 97 new FrameLayout(mActivity, attrs, 0); 98 } 99 100 @Test testSetForegroundGravity()101 public void testSetForegroundGravity() throws Throwable { 102 final BitmapDrawable foreground 103 = (BitmapDrawable) mActivity.getResources().getDrawable(R.drawable.size_48x48); 104 WidgetTestUtils.assertScaledPixels(48, foreground.getIntrinsicHeight(), mActivity); 105 WidgetTestUtils.assertScaledPixels(48, foreground.getIntrinsicWidth(), mActivity); 106 assertTrue(mFrameLayout.getHeight() > foreground.getIntrinsicHeight()); 107 assertTrue(mFrameLayout.getWidth() > foreground.getIntrinsicWidth()); 108 assertNull(mFrameLayout.getForeground()); 109 110 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mFrameLayout, 111 () -> mFrameLayout.setForeground(foreground)); 112 assertSame(foreground, mFrameLayout.getForeground()); 113 // check the default gravity FILL, it completely fills its container 114 assertTrue(foreground.isVisible()); 115 final Rect rect = foreground.getBounds(); 116 // foreground has been stretched 117 PollingCheck.waitFor(() -> mFrameLayout.getHeight() == rect.bottom - rect.top); 118 assertEquals(mFrameLayout.getWidth(), rect.right - rect.left); 119 120 // should get a new foreground again, because former foreground has been stretched 121 final BitmapDrawable newForeground = 122 (BitmapDrawable) mActivity.getDrawable(R.drawable.size_48x48); 123 WidgetTestUtils.assertScaledPixels(48, newForeground.getIntrinsicHeight(), mActivity); 124 WidgetTestUtils.assertScaledPixels(48, newForeground.getIntrinsicWidth(), mActivity); 125 assertTrue(mFrameLayout.getHeight() > newForeground.getIntrinsicHeight()); 126 assertTrue(mFrameLayout.getWidth() > foreground.getIntrinsicWidth()); 127 128 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mFrameLayout, () -> { 129 mFrameLayout.setForeground(newForeground); 130 mFrameLayout.setForegroundGravity(Gravity.CENTER); 131 }); 132 assertSame(newForeground, mFrameLayout.getForeground()); 133 assertTrue(newForeground.isVisible()); 134 Rect rect2 = newForeground.getBounds(); 135 // not changing its size 136 assertEquals(foreground.getIntrinsicHeight(), rect2.bottom - rect2.top); 137 assertEquals(foreground.getIntrinsicWidth(), rect2.right - rect2.left); 138 assertCenterAligned(mFrameLayout, newForeground); 139 } 140 141 @Test testGatherTransparentRegion()142 public void testGatherTransparentRegion() throws Throwable { 143 final LinearLayout container = 144 (LinearLayout) mActivity.findViewById(R.id.framelayout_container); 145 final Drawable foreground = mActivity.getResources().getDrawable(R.drawable.size_48x48); 146 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mFrameLayout, () -> { 147 mFrameLayout.setForeground(foreground); 148 mFrameLayout.setForegroundGravity(Gravity.CENTER); 149 }); 150 Region region = new Region(foreground.getBounds()); 151 assertTrue(mFrameLayout.gatherTransparentRegion(region)); 152 153 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, mFrameLayout, 154 () -> container.requestTransparentRegion(mFrameLayout)); 155 region = new Region(foreground.getBounds()); 156 assertTrue(mFrameLayout.gatherTransparentRegion(region)); 157 } 158 159 @Test testAccessMeasureAllChildren()160 public void testAccessMeasureAllChildren() throws Throwable { 161 final FrameLayout frameLayout 162 = (FrameLayout) mActivity.findViewById(R.id.framelayout_measureall); 163 assertFalse(frameLayout.getConsiderGoneChildrenWhenMeasuring()); 164 165 // text view and button are VISIBLE, they should be measured 166 final TextView textView = (TextView) frameLayout.findViewById(R.id.framelayout_textview); 167 WidgetTestUtils.assertScaledPixels(30, textView.getMeasuredHeight(), mActivity); 168 WidgetTestUtils.assertScaledPixels(60, textView.getMeasuredWidth(), mActivity); 169 assertEquals(textView.getMeasuredHeight(), frameLayout.getMeasuredHeight()); 170 assertEquals(textView.getMeasuredWidth(), frameLayout.getMeasuredWidth()); 171 172 // measureAll is false and text view is GONE, text view will NOT be measured 173 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, frameLayout, () -> { 174 textView.setVisibility(View.GONE); 175 frameLayout.requestLayout(); 176 }); 177 assertFalse(frameLayout.getConsiderGoneChildrenWhenMeasuring()); 178 Button button = (Button) frameLayout.findViewById(R.id.framelayout_button); 179 WidgetTestUtils.assertScaledPixels(15, button.getMeasuredHeight(), mActivity); 180 WidgetTestUtils.assertScaledPixels(50, button.getMeasuredWidth(), mActivity); 181 assertEquals(button.getMeasuredHeight(), frameLayout.getMeasuredHeight()); 182 assertEquals(button.getMeasuredWidth(), frameLayout.getMeasuredWidth()); 183 184 // measureAll is true and text view is GONE, text view will be measured 185 WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, frameLayout, () -> { 186 frameLayout.setMeasureAllChildren(true); 187 frameLayout.requestLayout(); 188 }); 189 assertTrue(frameLayout.getMeasureAllChildren()); 190 assertTrue(frameLayout.getConsiderGoneChildrenWhenMeasuring()); 191 assertEquals(textView.getMeasuredHeight(), frameLayout.getMeasuredHeight()); 192 assertEquals(textView.getMeasuredWidth(), frameLayout.getMeasuredWidth()); 193 } 194 195 @Test testGenerateLayoutParams1()196 public void testGenerateLayoutParams1() { 197 MyFrameLayout myFrameLayout = new MyFrameLayout(mActivity); 198 ViewGroup.LayoutParams p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 199 ViewGroup.LayoutParams.WRAP_CONTENT); 200 201 ViewGroup.LayoutParams params = myFrameLayout.generateLayoutParams(p); 202 assertNotNull(params); 203 assertTrue(params instanceof FrameLayout.LayoutParams); 204 assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, params.width); 205 assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, params.height); 206 } 207 208 @Test testGenerateLayoutParams2()209 public void testGenerateLayoutParams2() throws XmlPullParserException, IOException { 210 AttributeSet attrs = getAttributeSet(); 211 212 FrameLayout.LayoutParams params = mFrameLayout.generateLayoutParams(attrs); 213 assertNotNull(params); 214 assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, params.width); 215 assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, params.height); 216 assertEquals(Gravity.BOTTOM, params.gravity); 217 } 218 219 @Test testCheckLayoutParams()220 public void testCheckLayoutParams() { 221 MyFrameLayout myFrameLayout = new MyFrameLayout(mActivity); 222 assertFalse(myFrameLayout.checkLayoutParams(null)); 223 224 int width = 120; 225 int height = 80; 226 ViewGroup.LayoutParams params1 = new ViewGroup.LayoutParams(width, height); 227 assertFalse(myFrameLayout.checkLayoutParams(params1)); 228 229 FrameLayout.LayoutParams params2 = new FrameLayout.LayoutParams(width, height); 230 assertTrue(myFrameLayout.checkLayoutParams(params2)); 231 } 232 233 @Test testGenerateLayoutParamsFromMarginParams()234 public void testGenerateLayoutParamsFromMarginParams() { 235 MyFrameLayout myFrameLayout = new MyFrameLayout(mActivity); 236 ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(3, 5); 237 lp.leftMargin = 1; 238 lp.topMargin = 2; 239 lp.rightMargin = 3; 240 lp.bottomMargin = 4; 241 LayoutParams generated = (LayoutParams) myFrameLayout.generateLayoutParams(lp); 242 assertNotNull(generated); 243 assertEquals(3, generated.width); 244 assertEquals(5, generated.height); 245 246 assertEquals(1, generated.leftMargin); 247 assertEquals(2, generated.topMargin); 248 assertEquals(3, generated.rightMargin); 249 assertEquals(4, generated.bottomMargin); 250 } 251 252 @Test testGenerateDefaultLayoutParams()253 public void testGenerateDefaultLayoutParams() { 254 MyFrameLayout frameLayout = new MyFrameLayout(mActivity); 255 FrameLayout.LayoutParams params = frameLayout.generateDefaultLayoutParams(); 256 257 assertNotNull(params); 258 assertEquals(LayoutParams.MATCH_PARENT, params.width); 259 assertEquals(LayoutParams.MATCH_PARENT, params.height); 260 } 261 262 @Test testVerifyDrawable()263 public void testVerifyDrawable() { 264 MyFrameLayout myFrameLayout = new MyFrameLayout(mActivity); 265 266 Drawable drawable = mActivity.getResources().getDrawable(R.drawable.scenery); 267 myFrameLayout.setForeground(drawable); 268 assertTrue(myFrameLayout.verifyDrawable(drawable)); 269 270 drawable = mActivity.getResources().getDrawable(R.drawable.black); 271 assertFalse(myFrameLayout.verifyDrawable(drawable)); 272 273 assertTrue(myFrameLayout.verifyDrawable(null)); 274 } 275 276 @UiThreadTest 277 @Test testForegroundTint()278 public void testForegroundTint() { 279 FrameLayout inflatedView = (FrameLayout) mActivity.findViewById(R.id.foreground_tint); 280 281 assertEquals("Foreground tint inflated correctly", 282 Color.WHITE, inflatedView.getForegroundTintList().getDefaultColor()); 283 assertEquals("Foreground tint mode inflated correctly", 284 PorterDuff.Mode.SRC_OVER, inflatedView.getForegroundTintMode()); 285 286 final Drawable foreground = spy(new ColorDrawable()); 287 FrameLayout view = new FrameLayout(mActivity); 288 289 view.setForeground(foreground); 290 verify(foreground, never()).setTintList(any(ColorStateList.class)); 291 292 view.setForegroundTintList(ColorStateList.valueOf(Color.RED)); 293 final ArgumentCaptor<ColorStateList> colorStateListCaptor = 294 ArgumentCaptor.forClass(ColorStateList.class); 295 verify(foreground, times(1)).setTintList(colorStateListCaptor.capture()); 296 assertEquals(1, colorStateListCaptor.getValue().getStates().length); 297 int[] emptyState = new int[0]; 298 assertEquals(Color.RED, 299 colorStateListCaptor.getValue().getColorForState(emptyState, Color.BLUE)); 300 301 reset(foreground); 302 view.setForeground(null); 303 view.setForeground(foreground); 304 verify(foreground, times(1)).setTintList(colorStateListCaptor.capture()); 305 assertEquals(1, colorStateListCaptor.getValue().getStates().length); 306 assertEquals(Color.RED, 307 colorStateListCaptor.getValue().getColorForState(emptyState, Color.BLUE)); 308 } 309 assertCenterAligned(View container, Drawable drawable)310 private static void assertCenterAligned(View container, Drawable drawable) { 311 Rect rect = drawable.getBounds(); 312 int leftDelta = rect.left - container.getLeft(); 313 int rightDelta = container.getRight() - rect.right; 314 int topDelta = rect.top - container.getTop(); 315 int bottomDelta = container.getBottom() - rect.bottom; 316 317 assertTrue(Math.abs(leftDelta - rightDelta) <= 1); 318 assertTrue(Math.abs(topDelta - bottomDelta) <= 1); 319 } 320 getAttributeSet()321 private AttributeSet getAttributeSet() throws XmlPullParserException, IOException { 322 XmlPullParser parser = mActivity.getResources().getLayout(R.layout.framelayout_layout); 323 WidgetTestUtils.beginDocument(parser, "LinearLayout"); 324 return Xml.asAttributeSet(parser); 325 } 326 327 private static class MyFrameLayout extends FrameLayout { MyFrameLayout(Context context)328 public MyFrameLayout(Context context) { 329 super(context); 330 } 331 332 @Override checkLayoutParams(ViewGroup.LayoutParams p)333 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 334 return super.checkLayoutParams(p); 335 } 336 337 @Override drawableStateChanged()338 protected void drawableStateChanged() { 339 super.drawableStateChanged(); 340 } 341 342 @Override generateDefaultLayoutParams()343 protected LayoutParams generateDefaultLayoutParams() { 344 return super.generateDefaultLayoutParams(); 345 } 346 347 @Override verifyDrawable(Drawable who)348 protected boolean verifyDrawable(Drawable who) { 349 return super.verifyDrawable(who); 350 } 351 352 @Override generateLayoutParams(ViewGroup.LayoutParams p)353 protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 354 return super.generateLayoutParams(p); 355 } 356 } 357 } 358