1 /* 2 * Copyright (C) 2014 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 com.android.layoutlib.bridge.intensive; 18 19 import com.android.ide.common.rendering.api.RenderSession; 20 import com.android.ide.common.rendering.api.ResourceNamespace; 21 import com.android.ide.common.rendering.api.ResourceReference; 22 import com.android.ide.common.rendering.api.ResourceValueImpl; 23 import com.android.ide.common.rendering.api.SessionParams; 24 import com.android.ide.common.rendering.api.SessionParams.RenderingMode; 25 import com.android.ide.common.rendering.api.ViewInfo; 26 import com.android.ide.common.rendering.api.XmlParserFactory; 27 import com.android.internal.R; 28 import com.android.layoutlib.bridge.android.BridgeContext; 29 import com.android.layoutlib.bridge.android.RenderParamsFlags; 30 import com.android.layoutlib.bridge.impl.ParserFactory; 31 import com.android.layoutlib.bridge.impl.RenderAction; 32 import com.android.layoutlib.bridge.impl.RenderActionTestUtil; 33 import com.android.layoutlib.bridge.impl.ResourceHelper; 34 import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator; 35 import com.android.layoutlib.bridge.intensive.setup.LayoutLibTestCallback; 36 import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser; 37 import com.android.resources.Density; 38 import com.android.resources.Navigation; 39 import com.android.resources.ResourceType; 40 41 import org.junit.After; 42 import org.junit.Test; 43 import org.kxml2.io.KXmlParser; 44 import org.xmlpull.v1.XmlPullParser; 45 46 import android.R.attr; 47 import android.annotation.NonNull; 48 import android.annotation.Nullable; 49 import android.content.res.AssetManager; 50 import android.content.res.ColorStateList; 51 import android.content.res.Configuration; 52 import android.content.res.Resources; 53 import android.content.res.Resources_Delegate; 54 import android.graphics.Color; 55 import android.util.DisplayMetrics; 56 import android.util.StateSet; 57 import android.util.TypedValue; 58 59 import java.awt.BasicStroke; 60 import java.awt.Graphics2D; 61 import java.awt.image.BufferedImage; 62 import java.io.File; 63 import java.io.FileNotFoundException; 64 import java.io.FileOutputStream; 65 import java.io.PrintWriter; 66 import java.lang.reflect.Field; 67 import java.util.concurrent.TimeUnit; 68 69 import static org.junit.Assert.assertArrayEquals; 70 import static org.junit.Assert.assertEquals; 71 import static org.junit.Assert.assertFalse; 72 import static org.junit.Assert.assertNotEquals; 73 import static org.junit.Assert.assertNotNull; 74 import static org.junit.Assert.assertTrue; 75 76 /** 77 * Set of render tests 78 */ 79 public class RenderTests extends RenderTestBase { 80 81 @After afterTestCase()82 public void afterTestCase() { 83 com.android.layoutlib.bridge.test.widgets.HookWidget.reset(); 84 } 85 86 @Test testActivity()87 public void testActivity() throws ClassNotFoundException, FileNotFoundException { 88 renderAndVerify("activity.xml", "activity.png", true); 89 } 90 91 @Test testActivityOnOldTheme()92 public void testActivityOnOldTheme() throws ClassNotFoundException, FileNotFoundException { 93 LayoutLibTestCallback layoutLibCallback = 94 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 95 layoutLibCallback.initResources(); 96 97 LayoutPullParser parser = LayoutPullParser.createFromString( 98 "<RelativeLayout xmlns:android=\"http://schemas" + 99 ".android.com/apk/res/android\"\n" + 100 " android:layout_width=\"match_parent\"\n" + 101 " android:layout_height=\"match_parent\"\n" + 102 " android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n" + 103 " android:paddingRight=\"@dimen/activity_horizontal_margin\"\n" + 104 " android:paddingTop=\"@dimen/activity_vertical_margin\"\n" + 105 " android:paddingBottom=\"@dimen/activity_vertical_margin\">\n" + 106 " <TextView\n" + 107 " android:text=\"@string/hello_world\"\n" + 108 " android:layout_width=\"wrap_content\"\n" + 109 " android:layout_height=\"200dp\"\n" + 110 " android:background=\"#FF0000\"\n" + 111 " android:id=\"@+id/text1\"/>\n" + 112 "</RelativeLayout>"); 113 SessionParams params = getSessionParamsBuilder() 114 .setParser(parser) 115 .setCallback(layoutLibCallback) 116 .setTheme("Theme.NoTitleBar", false) 117 .build(); 118 119 renderAndVerify(params, "simple_activity-old-theme.png"); 120 } 121 122 @Test testTranslucentBars()123 public void testTranslucentBars() throws ClassNotFoundException, FileNotFoundException { 124 LayoutLibTestCallback layoutLibCallback = 125 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 126 layoutLibCallback.initResources(); 127 128 LayoutPullParser parser = createParserFromPath("four_corners.xml"); 129 SessionParams params = getSessionParamsBuilder() 130 .setParser(parser) 131 .setCallback(layoutLibCallback) 132 .setTheme("Theme.Material.Light.NoActionBar.TranslucentDecor", false) 133 .build(); 134 renderAndVerify(params, "four_corners_translucent.png"); 135 136 parser = createParserFromPath("four_corners.xml"); 137 params = getSessionParamsBuilder() 138 .setConfigGenerator(ConfigGenerator.NEXUS_5_LAND) 139 .setParser(parser) 140 .setCallback(layoutLibCallback) 141 .setTheme("Theme.Material.Light.NoActionBar.TranslucentDecor", false) 142 .build(); 143 renderAndVerify(params, "four_corners_translucent_land.png"); 144 145 parser = createParserFromPath("four_corners.xml"); 146 params = getSessionParamsBuilder() 147 .setParser(parser) 148 .setCallback(layoutLibCallback) 149 .setTheme("Theme.Material.Light.NoActionBar", false) 150 .build(); 151 renderAndVerify(params, "four_corners.png"); 152 } 153 154 @Test testAllWidgets()155 public void testAllWidgets() throws ClassNotFoundException, FileNotFoundException { 156 LayoutPullParser parser = createParserFromPath("allwidgets.xml"); 157 LayoutLibTestCallback layoutLibCallback = 158 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 159 layoutLibCallback.initResources(); 160 SessionParams params = getSessionParamsBuilder() 161 .setParser(parser) 162 .setConfigGenerator(ConfigGenerator.NEXUS_5) 163 .setCallback(layoutLibCallback) 164 .disableShadows() 165 .build(); 166 167 renderAndVerify(params, "allwidgets.png"); 168 169 // We expect fidelity warnings for Path.isConvex. Fail for anything else. 170 sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported.")); 171 } 172 173 @Test testArrayCheck()174 public void testArrayCheck() throws ClassNotFoundException, FileNotFoundException { 175 renderAndVerify("array_check.xml", "array_check.png", false); 176 177 // We expect fidelity warnings for Path.isConvex. Fail for anything else. 178 sRenderMessages.removeIf( 179 message -> message.equals("Font$Builder.nAddAxis is not supported.")); 180 } 181 182 @Test testAllWidgetsTablet()183 public void testAllWidgetsTablet() throws ClassNotFoundException, FileNotFoundException { 184 LayoutPullParser parser = createParserFromPath("allwidgets.xml"); 185 LayoutLibTestCallback layoutLibCallback = 186 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 187 layoutLibCallback.initResources(); 188 SessionParams params = getSessionParamsBuilder() 189 .setParser(parser) 190 .setConfigGenerator(ConfigGenerator.NEXUS_7_2012) 191 .setCallback(layoutLibCallback) 192 .disableShadows() 193 .build(); 194 renderAndVerify(params, "allwidgets_tab.png"); 195 196 // We expect fidelity warnings for Path.isConvex. Fail for anything else. 197 sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported.")); 198 sRenderMessages.removeIf(message -> message.equals("Font$Builder.nAddAxis is not supported.")); 199 } 200 201 @Test testActivityActionBar()202 public void testActivityActionBar() throws ClassNotFoundException { 203 String simpleActivity = 204 "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 205 " android:layout_width=\"match_parent\"\n" + 206 " android:layout_height=\"match_parent\"\n" + 207 " android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n" + 208 " android:paddingRight=\"@dimen/activity_horizontal_margin\"\n" + 209 " android:paddingTop=\"@dimen/activity_vertical_margin\"\n" + 210 " android:paddingBottom=\"@dimen/activity_vertical_margin\">\n" + 211 " <TextView\n" + 212 " android:text=\"@string/hello_world\"\n" + 213 " android:layout_width=\"wrap_content\"\n" + 214 " android:layout_height=\"200dp\"\n" + 215 " android:background=\"#FF0000\"\n" + 216 " android:id=\"@+id/text1\"/>\n" + 217 "</RelativeLayout>"; 218 219 LayoutPullParser parser = LayoutPullParser.createFromString(simpleActivity); 220 LayoutLibTestCallback layoutLibCallback = 221 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 222 layoutLibCallback.initResources(); 223 224 SessionParams params = getSessionParamsBuilder() 225 .setParser(parser) 226 .setCallback(layoutLibCallback) 227 .setTheme("Theme.Material.Light.NoActionBar", false) 228 .setRenderingMode(RenderingMode.V_SCROLL) 229 .build(); 230 231 renderAndVerify(params, "simple_activity_noactionbar.png"); 232 233 parser = LayoutPullParser.createFromString(simpleActivity); 234 params = getSessionParamsBuilder() 235 .setParser(parser) 236 .setCallback(layoutLibCallback) 237 .setTheme("Theme.Material.Light", false) 238 .setRenderingMode(RenderingMode.V_SCROLL) 239 .build(); 240 241 renderAndVerify(params, "simple_activity.png"); 242 243 // This also tests that a theme with "NoActionBar" DOES HAVE an action bar when we are 244 // displaying menus. 245 parser = LayoutPullParser.createFromString(simpleActivity); 246 params = getSessionParamsBuilder() 247 .setParser(parser) 248 .setCallback(layoutLibCallback) 249 .setTheme("Theme.Material.Light.NoActionBar", false) 250 .setRenderingMode(RenderingMode.V_SCROLL) 251 .build(); 252 params.setFlag(RenderParamsFlags.FLAG_KEY_ROOT_TAG, "menu"); 253 renderAndVerify(params, "simple_activity.png"); 254 } 255 256 @Test testOnApplyInsetsCall()257 public void testOnApplyInsetsCall() 258 throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { 259 // We get the widget via reflection to avoid IntelliJ complaining about the class being 260 // located in the wrong package. (From the Bridge tests point of view, it is) 261 Class insetsWidgetClass = Class.forName("com.android.layoutlib.test.myapplication.widgets" + 262 ".InsetsWidget"); 263 Field field = insetsWidgetClass.getDeclaredField("sApplyInsetsCalled"); 264 assertFalse((Boolean)field.get(null)); 265 266 LayoutPullParser parser = LayoutPullParser.createFromString( 267 "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 268 " android:padding=\"16dp\"\n" + 269 " android:orientation=\"horizontal\"\n" + 270 " android:layout_width=\"wrap_content\"\n" + 271 " android:layout_height=\"wrap_content\">\n" + "\n" + 272 " <com.android.layoutlib.test.myapplication.widgets.InsetsWidget\n" + 273 " android:text=\"Hello world\"\n" + 274 " android:layout_width=\"wrap_content\"\n" + 275 " android:layout_height=\"wrap_content\"\n" + 276 " android:id=\"@+id/text1\"/>\n" + "</LinearLayout>\n"); 277 LayoutLibTestCallback layoutLibCallback = 278 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 279 layoutLibCallback.initResources(); 280 SessionParams params = getSessionParamsBuilder() 281 .setParser(parser) 282 .setCallback(layoutLibCallback) 283 .setTheme("Theme.Material.Light.NoActionBar", false) 284 .build(); 285 286 render(sBridge, params, -1); 287 288 assertTrue((Boolean)field.get(null)); 289 field.set(null, false); 290 } 291 292 /** Test expand_layout.xml */ 293 @Test testExpand()294 public void testExpand() throws ClassNotFoundException, FileNotFoundException { 295 // Create the layout pull parser. 296 LayoutPullParser parser = createParserFromPath("expand_vert_layout.xml"); 297 // Create LayoutLibCallback. 298 LayoutLibTestCallback layoutLibCallback = 299 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 300 layoutLibCallback.initResources(); 301 302 ConfigGenerator customConfigGenerator = new ConfigGenerator() 303 .setScreenWidth(300) 304 .setScreenHeight(20) 305 .setDensity(Density.XHIGH) 306 .setNavigation(Navigation.NONAV); 307 308 SessionParams params = getSessionParamsBuilder() 309 .setParser(parser) 310 .setConfigGenerator(customConfigGenerator) 311 .setCallback(layoutLibCallback) 312 .setTheme("Theme.Material.Light.NoActionBar.Fullscreen", false) 313 .setRenderingMode(RenderingMode.V_SCROLL) 314 .build(); 315 316 renderAndVerify(params, "expand_vert_layout.png"); 317 318 customConfigGenerator = new ConfigGenerator() 319 .setScreenWidth(20) 320 .setScreenHeight(300) 321 .setDensity(Density.XHIGH) 322 .setNavigation(Navigation.NONAV); 323 parser = createParserFromPath("expand_horz_layout.xml"); 324 params = getSessionParamsBuilder() 325 .setParser(parser) 326 .setConfigGenerator(customConfigGenerator) 327 .setCallback(layoutLibCallback) 328 .setTheme("Theme.Material.Light.NoActionBar.Fullscreen", false) 329 .setRenderingMode(RenderingMode.H_SCROLL) 330 .build(); 331 332 renderAndVerify(params, "expand_horz_layout.png"); 333 } 334 335 @Test testShrink()336 public void testShrink() throws ClassNotFoundException, FileNotFoundException { 337 // Create the layout pull parser. 338 LayoutPullParser parser = createParserFromPath("expand_vert_layout.xml"); 339 // Create LayoutLibCallback. 340 LayoutLibTestCallback layoutLibCallback = 341 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 342 layoutLibCallback.initResources(); 343 // Normal mode 344 ConfigGenerator customConfigGenerator = new ConfigGenerator() 345 .setScreenWidth(600) 346 .setScreenHeight(3000) 347 .setDensity(Density.XHIGH) 348 .setNavigation(Navigation.NONAV); 349 SessionParams params = getSessionParamsBuilder() 350 .setParser(parser) 351 .setConfigGenerator(customConfigGenerator) 352 .setCallback(layoutLibCallback) 353 .setTheme("Theme.Material.Light.NoActionBar.Fullscreen", false) 354 .setRenderingMode(RenderingMode.NORMAL) 355 .disableDecoration() 356 .build(); 357 358 renderAndVerify(params, "normal_layout.png"); 359 360 // Shrink mode 361 customConfigGenerator = new ConfigGenerator() 362 .setScreenWidth(600) 363 .setScreenHeight(3000) 364 .setDensity(Density.XHIGH) 365 .setNavigation(Navigation.NONAV); 366 parser = createParserFromPath("expand_vert_layout.xml"); 367 params = getSessionParamsBuilder() 368 .setParser(parser) 369 .setConfigGenerator(customConfigGenerator) 370 .setCallback(layoutLibCallback) 371 .setTheme("Theme.Material.Light.NoActionBar.Fullscreen", false) 372 .setRenderingMode(RenderingMode.SHRINK) 373 .disableDecoration() 374 .build(); 375 376 renderAndVerify(params, "shrunk_layout.png"); 377 } 378 379 /** Test indeterminate_progressbar.xml */ 380 @Test testVectorAnimation()381 public void testVectorAnimation() throws ClassNotFoundException { 382 String layout = "\n" + 383 "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 384 " android:padding=\"16dp\"\n" + 385 " android:orientation=\"horizontal\"\n" + 386 " android:layout_width=\"fill_parent\"\n" + 387 " android:layout_height=\"fill_parent\">\n" + "\n" + 388 " <ProgressBar\n" + " android:layout_height=\"fill_parent\"\n" + 389 " android:layout_width=\"fill_parent\" />\n" + "\n" + 390 "</LinearLayout>\n"; 391 392 // Create the layout pull parser. 393 LayoutPullParser parser = LayoutPullParser.createFromString(layout); 394 // Create LayoutLibCallback. 395 LayoutLibTestCallback layoutLibCallback = 396 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 397 layoutLibCallback.initResources(); 398 399 SessionParams params = getSessionParamsBuilder() 400 .setParser(parser) 401 .setCallback(layoutLibCallback) 402 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 403 .setRenderingMode(RenderingMode.V_SCROLL) 404 .build(); 405 406 renderAndVerify(params, "animated_vector.png", TimeUnit.SECONDS.toNanos(2)); 407 408 parser = LayoutPullParser.createFromString(layout); 409 params = getSessionParamsBuilder() 410 .setParser(parser) 411 .setCallback(layoutLibCallback) 412 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 413 .setRenderingMode(RenderingMode.V_SCROLL) 414 .build(); 415 renderAndVerify(params, "animated_vector_1.png", TimeUnit.SECONDS.toNanos(3)); 416 } 417 418 /** 419 * Test a vector drawable that uses trimStart and trimEnd. It also tests all the primitives 420 * for vector drawables (lines, moves and cubic and quadratic curves). 421 */ 422 @Test testVectorDrawable()423 public void testVectorDrawable() throws ClassNotFoundException { 424 // Create the layout pull parser. 425 LayoutPullParser parser = LayoutPullParser.createFromString( 426 "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 427 " android:padding=\"16dp\"\n" + 428 " android:orientation=\"horizontal\"\n" + 429 " android:layout_width=\"fill_parent\"\n" + 430 " android:layout_height=\"fill_parent\">\n" + 431 " <ImageView\n" + 432 " android:layout_height=\"fill_parent\"\n" + 433 " android:layout_width=\"fill_parent\"\n" + 434 " android:src=\"@drawable/multi_path\" />\n" + "\n" + 435 "</LinearLayout>"); 436 // Create LayoutLibCallback. 437 LayoutLibTestCallback layoutLibCallback = 438 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 439 layoutLibCallback.initResources(); 440 441 SessionParams params = getSessionParamsBuilder() 442 .setParser(parser) 443 .setCallback(layoutLibCallback) 444 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 445 .disableDecoration() 446 .setRenderingMode(RenderingMode.V_SCROLL) 447 .build(); 448 449 renderAndVerify(params, "vector_drawable.png", TimeUnit.SECONDS.toNanos(2)); 450 } 451 452 /** 453 * Regression test for http://b.android.com/91383 and http://b.android.com/203797 454 */ 455 @Test testVectorDrawable91383()456 public void testVectorDrawable91383() throws ClassNotFoundException { 457 // Create the layout pull parser. 458 LayoutPullParser parser = LayoutPullParser.createFromString( 459 "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 460 " android:padding=\"16dp\"\n" + 461 " android:orientation=\"vertical\"\n" + 462 " android:layout_width=\"fill_parent\"\n" + 463 " android:layout_height=\"fill_parent\">\n" + 464 " <ImageView\n" + 465 " android:layout_height=\"wrap_content\"\n" + 466 " android:layout_width=\"wrap_content\"\n" + 467 " android:src=\"@drawable/android\"/>\n" + 468 " <ImageView\n" + 469 " android:layout_height=\"wrap_content\"\n" + 470 " android:layout_width=\"wrap_content\"\n" + 471 " android:src=\"@drawable/headset\"/>\n" + 472 " <ImageView\n" + 473 " android:layout_height=\"wrap_content\"\n" + 474 " android:layout_width=\"wrap_content\"\n" + 475 " android:src=\"@drawable/clipped_even_odd\"/>\n" + 476 "</LinearLayout>"); 477 // Create LayoutLibCallback. 478 LayoutLibTestCallback layoutLibCallback = 479 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 480 layoutLibCallback.initResources(); 481 482 SessionParams params = getSessionParamsBuilder() 483 .setParser(parser) 484 .setCallback(layoutLibCallback) 485 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 486 .setRenderingMode(RenderingMode.V_SCROLL) 487 .build(); 488 489 renderAndVerify(params, "vector_drawable_91383.png", TimeUnit.SECONDS.toNanos(2)); 490 } 491 492 /** 493 * Test a ImageView which has a vector drawable as its src and tint attribute. 494 */ 495 @Test testVectorDrawableWithTintInImageView()496 public void testVectorDrawableWithTintInImageView() throws ClassNotFoundException { 497 // Create the layout pull parser. 498 LayoutPullParser parser = LayoutPullParser.createFromString( 499 "<ImageView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 500 " android:layout_height=\"match_parent\"\n" + 501 " android:layout_width=\"match_parent\"\n" + 502 " android:src=\"@drawable/vector_drawable_without_tint\"\n" + 503 " android:tint=\"#FF00FF00\" />"); 504 // Create LayoutLibCallback. 505 LayoutLibTestCallback layoutLibCallback = 506 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 507 layoutLibCallback.initResources(); 508 509 SessionParams params = getSessionParamsBuilder() 510 .setParser(parser) 511 .setCallback(layoutLibCallback) 512 .setTheme("Theme.Material.Light.NoActionBar.Fullscreen", false) 513 .setRenderingMode(RenderingMode.V_SCROLL) 514 .build(); 515 516 renderAndVerify(params, "vector_drawable_with_tint_in_image_view.png", 517 TimeUnit.SECONDS.toNanos(2)); 518 } 519 520 /** 521 * Test a vector drawable which has tint attribute. 522 */ 523 @Test testVectorDrawableWithTintInItself()524 public void testVectorDrawableWithTintInItself() throws ClassNotFoundException { 525 // Create the layout pull parser. 526 LayoutPullParser parser = LayoutPullParser.createFromString( 527 "<ImageView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 528 " android:layout_height=\"match_parent\"\n" + 529 " android:layout_width=\"match_parent\"\n" + 530 " android:src=\"@drawable/vector_drawable_with_tint\" />"); 531 // Create LayoutLibCallback. 532 LayoutLibTestCallback layoutLibCallback = 533 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 534 layoutLibCallback.initResources(); 535 536 SessionParams params = getSessionParamsBuilder() 537 .setParser(parser) 538 .setCallback(layoutLibCallback) 539 .setTheme("Theme.Material.Light.NoActionBar.Fullscreen", false) 540 .setRenderingMode(RenderingMode.V_SCROLL) 541 .build(); 542 543 renderAndVerify(params, "vector_drawable_with_tint_itself.png", 544 TimeUnit.SECONDS.toNanos(2)); 545 } 546 547 /** 548 * Test a vector drawable that uses trimStart and trimEnd. It also tests all the primitives 549 * for vector drawables (lines, moves and cubic and quadratic curves). 550 */ 551 @Test testVectorDrawableHasMultipleLineInPathData()552 public void testVectorDrawableHasMultipleLineInPathData() throws ClassNotFoundException { 553 // Create the layout pull parser. 554 LayoutPullParser parser = LayoutPullParser.createFromString( 555 "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 556 " android:padding=\"16dp\"\n" + 557 " android:orientation=\"horizontal\"\n" + 558 " android:layout_width=\"match_parent\"\n" + 559 " android:layout_height=\"match_parent\">\n" + 560 " <ImageView\n" + 561 " android:layout_height=\"match_parent\"\n" + 562 " android:layout_width=\"match_parent\"\n" + 563 " android:src=\"@drawable/multi_line_of_path_data\" />\n\n" + 564 "</LinearLayout>"); 565 // Create LayoutLibCallback. 566 LayoutLibTestCallback layoutLibCallback = 567 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 568 layoutLibCallback.initResources(); 569 570 SessionParams params = getSessionParamsBuilder() 571 .setParser(parser) 572 .setCallback(layoutLibCallback) 573 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 574 .setRenderingMode(RenderingMode.V_SCROLL) 575 .build(); 576 577 renderAndVerify(params, "vector_drawable_multi_line_of_path_data.png", 578 TimeUnit.SECONDS.toNanos(2)); 579 } 580 581 /** 582 * Tests that the gradients are correctly transformed using the viewport of the vector drawable. 583 * <p/> 584 * If a vector drawable is 50x50 and the gradient has startX=25 and startY=25, the gradient 585 * will start in the middle of the box. 586 * <p/> 587 * http://b/65495452 588 */ 589 @Test testVectorDrawableGradient()590 public void testVectorDrawableGradient() throws ClassNotFoundException { 591 // Create the layout pull parser. 592 LayoutPullParser parser = LayoutPullParser.createFromString( 593 "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 594 " android:padding=\"16dp\"\n" + 595 " android:orientation=\"horizontal\"\n" + 596 " android:layout_width=\"match_parent\"\n" + 597 " android:layout_height=\"match_parent\">\n" + 598 " <ImageView\n" + 599 " android:layout_height=\"match_parent\"\n" + 600 " android:layout_width=\"match_parent\"\n" + 601 " android:src=\"@drawable/shadow\" />\n\n" + 602 "</LinearLayout>"); 603 // Create LayoutLibCallback. 604 LayoutLibTestCallback layoutLibCallback = 605 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 606 layoutLibCallback.initResources(); 607 608 SessionParams params = getSessionParamsBuilder() 609 .setParser(parser) 610 .setCallback(layoutLibCallback) 611 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 612 .setRenderingMode(RenderingMode.V_SCROLL) 613 .build(); 614 615 renderAndVerify(params, "vector_drawable_gradient.png", 616 TimeUnit.SECONDS.toNanos(2)); 617 } 618 619 /** 620 * Tests that the radial gradients are correctly transformed using the viewport of the vector 621 * drawable. 622 * <p/> 623 * http://b/66168608 624 */ 625 @Test testVectorDrawableRadialGradient()626 public void testVectorDrawableRadialGradient() throws ClassNotFoundException { 627 // Create the layout pull parser. 628 LayoutPullParser parser = LayoutPullParser.createFromString( 629 "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 630 " android:padding=\"16dp\"\n" + 631 " android:orientation=\"horizontal\"\n" + 632 " android:layout_width=\"match_parent\"\n" + 633 " android:layout_height=\"match_parent\">\n" + 634 " <ImageView\n" + 635 " android:layout_height=\"match_parent\"\n" + 636 " android:layout_width=\"match_parent\"\n" + 637 " android:src=\"@drawable/radial_gradient\" />\n\n" + 638 "</LinearLayout>"); 639 // Create LayoutLibCallback. 640 LayoutLibTestCallback layoutLibCallback = 641 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 642 layoutLibCallback.initResources(); 643 644 SessionParams params = getSessionParamsBuilder() 645 .setParser(parser) 646 .setCallback(layoutLibCallback) 647 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 648 .setRenderingMode(RenderingMode.V_SCROLL) 649 .build(); 650 651 renderAndVerify(params, "vector_drawable_radial_gradient.png", 652 TimeUnit.SECONDS.toNanos(2)); 653 } 654 655 /** 656 * Tests that the gradients are correctly displayed when using transparent colors 657 * and a wide range of offset values. 658 * <p/> 659 * http://b/112759140 660 */ 661 @Test testGradientColors()662 public void testGradientColors() throws ClassNotFoundException { 663 // Create the layout pull parser. 664 LayoutPullParser parser = LayoutPullParser.createFromString( 665 "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 666 " android:padding=\"16dp\"\n" + 667 " android:orientation=\"horizontal\"\n" + 668 " android:layout_width=\"match_parent\"\n" + 669 " android:layout_height=\"match_parent\">\n" + 670 " <ImageView\n" + 671 " android:layout_height=\"match_parent\"\n" + 672 " android:layout_width=\"match_parent\"\n" + 673 " android:src=\"@drawable/gradient\" />\n\n" + 674 "</LinearLayout>"); 675 // Create LayoutLibCallback. 676 LayoutLibTestCallback layoutLibCallback = 677 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 678 layoutLibCallback.initResources(); 679 680 SessionParams params = getSessionParamsBuilder() 681 .setParser(parser) 682 .setCallback(layoutLibCallback) 683 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 684 .setRenderingMode(RenderingMode.V_SCROLL) 685 .disableDecoration() 686 .build(); 687 688 renderAndVerify(params, "gradient_colors.png", 689 TimeUnit.SECONDS.toNanos(2)); 690 } 691 692 /** 693 * Tests that the gradients are correctly combined with alpha values. 694 * <p/> 695 * http://b/122260583 696 */ 697 @Test testGradientAlphaDrawable()698 public void testGradientAlphaDrawable() throws ClassNotFoundException { 699 // Create the layout pull parser. 700 LayoutPullParser parser = LayoutPullParser.createFromString( 701 "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 702 " android:padding=\"16dp\"\n" + 703 " android:orientation=\"horizontal\"\n" + 704 " android:layout_width=\"match_parent\"\n" + 705 " android:layout_height=\"match_parent\">\n" + 706 " <ImageView\n" + 707 " android:layout_height=\"match_parent\"\n" + 708 " android:layout_width=\"match_parent\"\n" + 709 " android:src=\"@drawable/vector_gradient_alpha\" />\n\n" + 710 "</LinearLayout>"); 711 // Create LayoutLibCallback. 712 LayoutLibTestCallback layoutLibCallback = 713 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 714 layoutLibCallback.initResources(); 715 716 SessionParams params = getSessionParamsBuilder() 717 .setParser(parser) 718 .setCallback(layoutLibCallback) 719 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 720 .setRenderingMode(RenderingMode.V_SCROLL) 721 .disableDecoration() 722 .build(); 723 724 renderAndVerify(params, "gradient_alpha_drawable.png", 725 TimeUnit.SECONDS.toNanos(2)); 726 } 727 728 /** Test activity.xml */ 729 @Test testScrollingAndMeasure()730 public void testScrollingAndMeasure() throws ClassNotFoundException, FileNotFoundException { 731 // Create the layout pull parser. 732 LayoutPullParser parser = createParserFromPath("scrolled.xml"); 733 // Create LayoutLibCallback. 734 LayoutLibTestCallback layoutLibCallback = 735 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 736 layoutLibCallback.initResources(); 737 738 SessionParams params = getSessionParamsBuilder() 739 .setParser(parser) 740 .setCallback(layoutLibCallback) 741 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 742 .setRenderingMode(RenderingMode.V_SCROLL) 743 .disableDecoration() 744 .build(); 745 params.setExtendedViewInfoMode(true); 746 747 // Do an only-measure pass 748 RenderSession session = sBridge.createSession(params); 749 session.measure(); 750 RenderResult result = RenderResult.getFromSession(session); 751 assertNotNull(result); 752 assertNotNull(result.getResult()); 753 assertTrue(result.getResult().isSuccess()); 754 755 ViewInfo rootLayout = result.getRootViews().get(0); 756 // Check the first box in the main LinearLayout 757 assertEquals(-90, rootLayout.getChildren().get(0).getTop()); 758 assertEquals(-30, rootLayout.getChildren().get(0).getLeft()); 759 assertEquals(90, rootLayout.getChildren().get(0).getBottom()); 760 assertEquals(150, rootLayout.getChildren().get(0).getRight()); 761 762 // Check the first box within the nested LinearLayout 763 assertEquals(-450, rootLayout.getChildren().get(5).getChildren().get(0).getTop()); 764 assertEquals(90, rootLayout.getChildren().get(5).getChildren().get(0).getLeft()); 765 assertEquals(-270, rootLayout.getChildren().get(5).getChildren().get(0).getBottom()); 766 assertEquals(690, rootLayout.getChildren().get(5).getChildren().get(0).getRight()); 767 768 // Do a full render pass 769 parser = createParserFromPath("scrolled.xml"); 770 771 params = getSessionParamsBuilder() 772 .setParser(parser) 773 .setCallback(layoutLibCallback) 774 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 775 .setRenderingMode(RenderingMode.V_SCROLL) 776 .disableDecoration() 777 .build(); 778 params.setExtendedViewInfoMode(true); 779 780 result = renderAndVerify(params, "scrolled.png"); 781 assertNotNull(result); 782 assertNotNull(result.getResult()); 783 assertTrue(result.getResult().isSuccess()); 784 } 785 786 @Test testGetResourceNameVariants()787 public void testGetResourceNameVariants() throws Exception { 788 // Setup 789 // Create the layout pull parser for our resources (empty.xml can not be part of the test 790 // app as it won't compile). 791 LayoutPullParser parser = LayoutPullParser.createFromPath("/empty.xml"); 792 // Create LayoutLibCallback. 793 LayoutLibTestCallback layoutLibCallback = 794 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 795 layoutLibCallback.initResources(); 796 SessionParams params = getSessionParamsBuilder() 797 .setParser(parser) 798 .setConfigGenerator(ConfigGenerator.NEXUS_4) 799 .setCallback(layoutLibCallback) 800 .build(); 801 AssetManager assetManager = AssetManager.getSystem(); 802 DisplayMetrics metrics = new DisplayMetrics(); 803 Configuration configuration = RenderAction.getConfiguration(params); 804 BridgeContext context = new BridgeContext(params.getProjectKey(), metrics, params.getResources(), 805 params.getAssets(), params.getLayoutlibCallback(), configuration, 806 params.getTargetSdkVersion(), params.isRtlSupported(), true, true); 807 Resources resources = Resources_Delegate.initSystem(context, assetManager, metrics, 808 configuration, params.getLayoutlibCallback()); 809 // Test 810 assertEquals("android:style/ButtonBar", 811 resources.getResourceName(android.R.style.ButtonBar)); 812 assertEquals("android", resources.getResourcePackageName(android.R.style.ButtonBar)); 813 assertEquals("ButtonBar", resources.getResourceEntryName(android.R.style.ButtonBar)); 814 assertEquals("style", resources.getResourceTypeName(android.R.style.ButtonBar)); 815 Integer id = Resources_Delegate.getLayoutlibCallback(resources).getOrGenerateResourceId( 816 new ResourceReference(ResourceNamespace.RES_AUTO, ResourceType.STRING, "app_name")); 817 assertNotNull(id); 818 assertEquals("com.android.layoutlib.test.myapplication:string/app_name", 819 resources.getResourceName(id)); 820 assertEquals("com.android.layoutlib.test.myapplication", 821 resources.getResourcePackageName(id)); 822 assertEquals("string", resources.getResourceTypeName(id)); 823 assertEquals("app_name", resources.getResourceEntryName(id)); 824 825 context.disposeResources(); 826 } 827 828 @Test testStringEscaping()829 public void testStringEscaping() throws Exception { 830 // Setup 831 // Create the layout pull parser for our resources (empty.xml can not be part of the test 832 // app as it won't compile). 833 LayoutPullParser parser = LayoutPullParser.createFromPath("/empty.xml"); 834 // Create LayoutLibCallback. 835 LayoutLibTestCallback layoutLibCallback = 836 new LayoutLibTestCallback(RenderTestBase.getLogger(), mDefaultClassLoader); 837 layoutLibCallback.initResources(); 838 SessionParams params = getSessionParamsBuilder() 839 .setConfigGenerator(ConfigGenerator.NEXUS_4) 840 .setParser(parser) 841 .setCallback(layoutLibCallback) 842 .build(); 843 AssetManager assetManager = AssetManager.getSystem(); 844 DisplayMetrics metrics = new DisplayMetrics(); 845 Configuration configuration = RenderAction.getConfiguration(params); 846 BridgeContext context = new BridgeContext(params.getProjectKey(), metrics, params.getResources(), 847 params.getAssets(), params.getLayoutlibCallback(), configuration, 848 params.getTargetSdkVersion(), params.isRtlSupported(), true, true); 849 Resources resources = Resources_Delegate.initSystem(context, assetManager, metrics, 850 configuration, params.getLayoutlibCallback()); 851 852 Integer id = 853 Resources_Delegate.getLayoutlibCallback(resources) 854 .getOrGenerateResourceId( 855 new ResourceReference( 856 ResourceNamespace.RES_AUTO, 857 ResourceType.ARRAY, 858 "string_array")); 859 assertNotNull(id); 860 String[] strings = resources.getStringArray(id); 861 assertArrayEquals( 862 new String[]{"mystring", "Hello world!", "candidates", "Unknown", "?EC"}, 863 strings); 864 assertTrue(sRenderMessages.isEmpty()); 865 866 context.disposeResources(); 867 } 868 869 @Test testFonts()870 public void testFonts() throws ClassNotFoundException, FileNotFoundException { 871 // TODO: styles seem to be broken in TextView 872 renderAndVerify("fonts_test.xml", "font_test.png", false); 873 sRenderMessages.removeIf( 874 message -> message.equals("Font$Builder.nAddAxis is not supported.")); 875 } 876 877 @Test testAdaptiveIcon()878 public void testAdaptiveIcon() throws ClassNotFoundException, FileNotFoundException { 879 // Create the layout pull parser. 880 String layout = 881 "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 882 " android:padding=\"16dp\"\n" + 883 " android:orientation=\"horizontal\"\n" + 884 " android:layout_width=\"fill_parent\"\n" + 885 " android:layout_height=\"fill_parent\">\n" + 886 " <ImageView\n" + 887 " android:layout_height=\"wrap_content\"\n" + 888 " android:layout_width=\"wrap_content\"\n" + 889 " android:src=\"@drawable/adaptive\" />\n" + 890 "</LinearLayout>\n"; 891 LayoutPullParser parser = LayoutPullParser.createFromString(layout); 892 // Create LayoutLibCallback. 893 LayoutLibTestCallback layoutLibCallback = 894 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 895 layoutLibCallback.initResources(); 896 897 layoutLibCallback.setAdaptiveIconMaskPath("M50,0L100,0 100,100 0,100 0,0z"); 898 SessionParams params = getSessionParamsBuilder() 899 .setParser(parser) 900 .setCallback(layoutLibCallback) 901 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 902 .setRenderingMode(RenderingMode.V_SCROLL) 903 .build(); 904 905 renderAndVerify(params, "adaptive_icon.png"); 906 907 layoutLibCallback.setAdaptiveIconMaskPath( 908 "M50 0C77.6 0 100 22.4 100 50C100 77.6 77.6 100 50 100C22.4 100 0 77.6 0 50C0 " + 909 "22.4 22.4 0 50 0Z"); 910 params = getSessionParamsBuilder() 911 .setParser(LayoutPullParser.createFromString(layout)) 912 .setCallback(layoutLibCallback) 913 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 914 .setRenderingMode(RenderingMode.V_SCROLL) 915 .build(); 916 renderAndVerify(params, "adaptive_icon_circle.png"); 917 918 layoutLibCallback.setAdaptiveIconMaskPath( 919 "M50,0L92,0C96.42,0 100,4.58 100 8L100,92C100, 96.42 96.42 100 92 100L8 100C4.58," + 920 " 100 0 96.42 0 92L0 8 C 0 4.42 4.42 0 8 0L50 0Z"); 921 params = getSessionParamsBuilder() 922 .setParser(LayoutPullParser.createFromString(layout)) 923 .setCallback(layoutLibCallback) 924 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 925 .setRenderingMode(RenderingMode.V_SCROLL) 926 .build(); 927 renderAndVerify(params, "adaptive_icon_rounded_corners.png"); 928 929 layoutLibCallback.setAdaptiveIconMaskPath( 930 "M50,0 C10,0 0,10 0,50 0,90 10,100 50,100 90,100 100,90 100,50 100,10 90,0 50,0 Z"); 931 params = getSessionParamsBuilder() 932 .setParser(LayoutPullParser.createFromString(layout)) 933 .setCallback(layoutLibCallback) 934 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 935 .setRenderingMode(RenderingMode.V_SCROLL) 936 .build(); 937 renderAndVerify(params, "adaptive_icon_squircle.png"); 938 } 939 940 @Test testTypedValue()941 public void testTypedValue() throws Exception { 942 // Setup 943 // Create the layout pull parser for our resources (empty.xml can not be part of the test 944 // app as it won't compile). 945 LayoutPullParser parser = LayoutPullParser.createFromPath("/empty.xml"); 946 // Create LayoutLibCallback. 947 LayoutLibTestCallback layoutLibCallback = 948 new LayoutLibTestCallback(RenderTestBase.getLogger(), mDefaultClassLoader); 949 layoutLibCallback.initResources(); 950 SessionParams params = getSessionParamsBuilder() 951 .setConfigGenerator(ConfigGenerator.NEXUS_4) 952 .setParser(parser) 953 .setCallback(layoutLibCallback) 954 .build(); 955 DisplayMetrics metrics = new DisplayMetrics(); 956 Configuration configuration = RenderAction.getConfiguration(params); 957 958 BridgeContext mContext = 959 new BridgeContext(params.getProjectKey(), metrics, params.getResources(), 960 params.getAssets(), params.getLayoutlibCallback(), configuration, 961 params.getTargetSdkVersion(), params.isRtlSupported(), true, true); 962 963 TypedValue outValue = new TypedValue(); 964 mContext.resolveThemeAttribute(android.R.attr.colorPrimary, outValue, true); 965 assertEquals(TypedValue.TYPE_INT_COLOR_ARGB8, outValue.type); 966 assertNotEquals(0, outValue.data); 967 968 outValue = new TypedValue(); 969 mContext.resolveThemeAttribute(android.R.attr.colorError, outValue, true); 970 assertEquals(TypedValue.TYPE_INT_COLOR_RGB4, outValue.type); 971 assertEquals(-65536, outValue.data); 972 973 outValue = new TypedValue(); 974 mContext.resolveThemeAttribute(attr.colorActivatedHighlight, outValue, true); 975 assertEquals(TypedValue.TYPE_INT_COLOR_ARGB4, outValue.type); 976 assertEquals(-872349952, outValue.data); 977 978 outValue = new TypedValue(); 979 mContext.resolveThemeAttribute(android.R.attr.isLightTheme, outValue, true); 980 assertEquals(TypedValue.TYPE_INT_BOOLEAN, outValue.type); 981 assertEquals(1, outValue.data); 982 assertTrue(sRenderMessages.isEmpty()); 983 } 984 985 @Test testColorStateList()986 public void testColorStateList() throws Exception { 987 final String STATE_LIST = "<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n" + 988 " <item android:state_pressed=\"true\"\n" + 989 " android:color=\"?android:attr/colorForeground\"/> \n" + 990 " <item android:state_focused=\"true\"\n" + 991 " android:color=\"?android:attr/colorBackground\"/> \n" + 992 " <item android:color=\"#a000\"/> <!-- default -->\n" + "</selector>"; 993 994 File tmpColorList = File.createTempFile("statelist", "xml"); 995 try(PrintWriter output = new PrintWriter(new FileOutputStream(tmpColorList))) { 996 output.println(STATE_LIST); 997 } 998 999 // Setup 1000 // Create the layout pull parser for our resources (empty.xml can not be part of the test 1001 // app as it won't compile). 1002 ParserFactory.setParserFactory(new XmlParserFactory() { 1003 @Override 1004 @Nullable 1005 public XmlPullParser createXmlParserForPsiFile(@NonNull String fileName) { 1006 return null; 1007 } 1008 1009 @Override 1010 @Nullable 1011 public XmlPullParser createXmlParserForFile(@NonNull String fileName) { 1012 return null; 1013 } 1014 1015 @Override 1016 @NonNull 1017 public XmlPullParser createXmlParser() { 1018 return new KXmlParser(); 1019 } 1020 }); 1021 1022 LayoutPullParser parser = LayoutPullParser.createFromPath("/empty.xml"); 1023 // Create LayoutLibCallback. 1024 LayoutLibTestCallback layoutLibCallback = 1025 new LayoutLibTestCallback(RenderTestBase.getLogger(), mDefaultClassLoader); 1026 layoutLibCallback.initResources(); 1027 SessionParams params = getSessionParamsBuilder() 1028 .setConfigGenerator(ConfigGenerator.NEXUS_4) 1029 .setParser(parser) 1030 .setCallback(layoutLibCallback) 1031 .setTheme("Theme.Material", false) 1032 .build(); 1033 DisplayMetrics metrics = new DisplayMetrics(); 1034 Configuration configuration = RenderAction.getConfiguration(params); 1035 1036 BridgeContext mContext = 1037 new BridgeContext(params.getProjectKey(), metrics, params.getResources(), 1038 params.getAssets(), params.getLayoutlibCallback(), configuration, 1039 params.getTargetSdkVersion(), params.isRtlSupported(), true, true); 1040 mContext.initResources(); 1041 BridgeContext oldContext = RenderActionTestUtil.setBridgeContext(mContext); 1042 1043 try { 1044 ColorStateList stateList = ResourceHelper.getColorStateList( 1045 new ResourceValueImpl( 1046 ResourceNamespace.RES_AUTO, 1047 ResourceType.COLOR, 1048 "test_list", 1049 tmpColorList.getAbsolutePath()), 1050 mContext, 1051 null); 1052 assertNotNull(stateList); 1053 assertEquals(Color.parseColor("#ffffffff"), stateList.getColorForState( 1054 StateSet.get(StateSet.VIEW_STATE_PRESSED), 1055 0 1056 )); 1057 assertEquals(Color.parseColor("#ff303030"), stateList.getColorForState( 1058 StateSet.get(StateSet.VIEW_STATE_FOCUSED), 1059 0 1060 )); 1061 assertEquals(Color.parseColor("#AA000000"), stateList.getDefaultColor()); 1062 1063 // Now apply theme overlay and check the colors changed 1064 Resources.Theme theme = mContext.getResources().newTheme(); 1065 theme.applyStyle(R.style.ThemeOverlay_Material_Light, true); 1066 stateList = ResourceHelper.getColorStateList( 1067 new ResourceValueImpl( 1068 ResourceNamespace.RES_AUTO, 1069 ResourceType.COLOR, 1070 "test_list", 1071 tmpColorList.getAbsolutePath()), 1072 mContext, 1073 theme); 1074 assertNotNull(stateList); 1075 assertEquals(Color.parseColor("#ff000000"), stateList.getColorForState( 1076 StateSet.get(StateSet.VIEW_STATE_PRESSED), 1077 0 1078 )); 1079 assertEquals(Color.parseColor("#fffafafa"), stateList.getColorForState( 1080 StateSet.get(StateSet.VIEW_STATE_FOCUSED), 1081 0 1082 )); 1083 assertEquals(Color.parseColor("#AA000000"), stateList.getDefaultColor()); 1084 } finally { 1085 RenderActionTestUtil.setBridgeContext(oldContext); 1086 } 1087 mContext.disposeResources(); 1088 } 1089 1090 @Test testShadowFlagsNoShadows()1091 public void testShadowFlagsNoShadows() throws Exception { 1092 LayoutPullParser parser = createParserFromPath("shadows_test.xml"); 1093 LayoutLibTestCallback layoutLibCallback = 1094 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 1095 layoutLibCallback.initResources(); 1096 SessionParams params = getSessionParamsBuilder() 1097 .setParser(parser) 1098 .setConfigGenerator(ConfigGenerator.NEXUS_5) 1099 .setCallback(layoutLibCallback) 1100 .disableDecoration() 1101 .disableShadows() 1102 .build(); 1103 1104 renderAndVerify(params, "shadows_test_no_shadow.png"); 1105 // We expect fidelity warnings for Path.isConvex. Fail for anything else. 1106 sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported.")); 1107 } 1108 1109 @Test testRectangleShadow()1110 public void testRectangleShadow() throws Exception { 1111 LayoutPullParser parser = createParserFromPath("shadows_test.xml"); 1112 LayoutLibTestCallback layoutLibCallback = 1113 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 1114 layoutLibCallback.initResources(); 1115 SessionParams params = getSessionParamsBuilder() 1116 .setParser(parser) 1117 .setConfigGenerator(ConfigGenerator.NEXUS_5) 1118 .setCallback(layoutLibCallback) 1119 .disableDecoration() 1120 .disableHighQualityShadows() 1121 .build(); 1122 1123 renderAndVerify(params, "shadows_test.png"); 1124 // We expect fidelity warnings for Path.isConvex. Fail for anything else. 1125 sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported.")); 1126 } 1127 1128 @Test testResourcesGetIdentifier()1129 public void testResourcesGetIdentifier() throws Exception { 1130 // Setup 1131 // Create the layout pull parser for our resources (empty.xml can not be part of the test 1132 // app as it won't compile). 1133 LayoutPullParser parser = LayoutPullParser.createFromPath("/empty.xml"); 1134 // Create LayoutLibCallback. 1135 LayoutLibTestCallback layoutLibCallback = 1136 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 1137 layoutLibCallback.initResources(); 1138 SessionParams params = getSessionParamsBuilder() 1139 .setConfigGenerator(ConfigGenerator.NEXUS_4) 1140 .setParser(parser) 1141 .setCallback(layoutLibCallback) 1142 .build(); 1143 AssetManager assetManager = AssetManager.getSystem(); 1144 DisplayMetrics metrics = new DisplayMetrics(); 1145 Configuration configuration = RenderAction.getConfiguration(params); 1146 BridgeContext context = new BridgeContext(params.getProjectKey(), metrics, params.getResources(), 1147 params.getAssets(), params.getLayoutlibCallback(), configuration, 1148 params.getTargetSdkVersion(), params.isRtlSupported(), true, true); 1149 Resources resources = Resources_Delegate.initSystem(context, assetManager, metrics, 1150 configuration, params.getLayoutlibCallback()); 1151 Integer id = 1152 Resources_Delegate.getLayoutlibCallback(resources) 1153 .getOrGenerateResourceId( 1154 new ResourceReference( 1155 ResourceNamespace.RES_AUTO, 1156 ResourceType.STRING, 1157 "app_name")); 1158 assertNotNull(id); 1159 assertEquals(id.intValue(), 1160 resources.getIdentifier("com.android.layoutlib.test.myapplication:string/app_name", 1161 null, null)); 1162 assertEquals(id.intValue(), resources.getIdentifier("app_name", "string", 1163 "com.android.layoutlib.test.myapplication")); 1164 assertEquals(0, resources.getIdentifier("string/app_name", null, null)); 1165 assertEquals(0, resources.getIdentifier("string/app_name", null, "com.foo.bar")); 1166 assertEquals(0, resources.getIdentifier("string/does_not_exist", null, 1167 "com.android.layoutlib.test.myapplication")); 1168 assertEquals(R.string.accept, resources.getIdentifier("android:string/accept", null, 1169 null)); 1170 assertEquals(R.string.accept, resources.getIdentifier("string/accept", null, 1171 "android")); 1172 assertEquals(R.id.message, resources.getIdentifier("id/message", null, 1173 "android")); 1174 assertEquals(R.string.accept, resources.getIdentifier("accept", "string", 1175 "android")); 1176 1177 context.disposeResources(); 1178 } 1179 1180 /** 1181 * If a 9patch image was in the nodpi or anydpi folder, the density of the image was 0 resulting 1182 * in a float division by 0 and thus an infinite padding 1183 * when layoutlib tries to scale the padding of the 9patch. 1184 * 1185 * http://b/37136109 1186 */ 1187 @Test test9PatchNoDPIBackground()1188 public void test9PatchNoDPIBackground() throws Exception { 1189 String layout = 1190 "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 1191 " android:layout_width=\"match_parent\"\n" + 1192 " android:layout_height=\"match_parent\"\n" + 1193 " android:background=\"@drawable/ninepatch\"\n" + 1194 " android:layout_margin=\"20dp\"\n" + 1195 " android:orientation=\"vertical\">\n\n" + 1196 " <Button\n" + 1197 " android:layout_width=\"wrap_content\"\n" + 1198 " android:layout_height=\"wrap_content\"\n" + 1199 " android:text=\"Button\" />\n\n" + 1200 " <Button\n" + 1201 " android:layout_width=\"wrap_content\"\n" + 1202 " android:layout_height=\"wrap_content\"\n" + 1203 " android:text=\"Button\" />\n" 1204 + "</LinearLayout>"; 1205 1206 LayoutPullParser parser = LayoutPullParser.createFromString(layout); 1207 // Create LayoutLibCallback. 1208 LayoutLibTestCallback layoutLibCallback = 1209 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 1210 layoutLibCallback.initResources(); 1211 1212 SessionParams params = getSessionParamsBuilder() 1213 .setParser(parser) 1214 .setCallback(layoutLibCallback) 1215 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 1216 .setRenderingMode(RenderingMode.V_SCROLL) 1217 .build(); 1218 1219 renderAndVerify(params, "ninepatch_background.png"); 1220 } 1221 1222 @Test testAssetManager()1223 public void testAssetManager() throws Exception { 1224 String layout = 1225 "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 1226 " android:padding=\"16dp\"\n" + 1227 " android:orientation=\"horizontal\"\n" + 1228 " android:layout_width=\"fill_parent\"\n" + 1229 " android:layout_height=\"fill_parent\">\n" + 1230 " <com.android.layoutlib.test.myapplication.widgets.AssetView\n" + 1231 " android:layout_height=\"wrap_content\"\n" + 1232 " android:layout_width=\"wrap_content\" />\n" + 1233 "</LinearLayout>\n"; 1234 LayoutPullParser parser = LayoutPullParser.createFromString(layout); 1235 // Create LayoutLibCallback. 1236 LayoutLibTestCallback layoutLibCallback = 1237 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 1238 layoutLibCallback.initResources(); 1239 1240 SessionParams params = getSessionParamsBuilder() 1241 .setParser(parser) 1242 .setCallback(layoutLibCallback) 1243 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 1244 .setRenderingMode(RenderingMode.V_SCROLL) 1245 .build(); 1246 1247 renderAndVerify(params, "asset.png"); 1248 } 1249 1250 /** 1251 * Tests that calling setTheme in a ContextThemeWrapper actually applies the theme 1252 * 1253 * http://b/66902070 1254 */ 1255 @Test testContextThemeWrapper()1256 public void testContextThemeWrapper() throws ClassNotFoundException { 1257 // Create the layout pull parser. 1258 LayoutPullParser parser = LayoutPullParser.createFromString( 1259 "<com.android.layoutlib.test.myapplication.ThemableWidget " + 1260 "xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 1261 " android:layout_width=\"wrap_content\"\n" + 1262 " android:layout_height=\"wrap_content\" />\n"); 1263 // Create LayoutLibCallback. 1264 LayoutLibTestCallback layoutLibCallback = 1265 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 1266 layoutLibCallback.initResources(); 1267 1268 SessionParams params = getSessionParamsBuilder() 1269 .setParser(parser) 1270 .setCallback(layoutLibCallback) 1271 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 1272 .setRenderingMode(RenderingMode.V_SCROLL) 1273 .build(); 1274 1275 renderAndVerify(params, "context_theme_wrapper.png", TimeUnit.SECONDS.toNanos(2)); 1276 } 1277 1278 /** 1279 * Tests that a crashing view does not prevent others from working. This is meant to prevent 1280 * crashes in framework views since custom views are already handled by Android Studio by 1281 * rewriting the byte code. 1282 */ 1283 @Test testCrashes()1284 public void testCrashes() throws ClassNotFoundException { 1285 final String layout = 1286 "<LinearLayout " + 1287 "xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 1288 " android:layout_width=\"match_parent\"\n" + 1289 " android:layout_height=\"match_parent\">\n" + 1290 "<com.android.layoutlib.bridge.test.widgets.HookWidget " + 1291 " android:layout_width=\"100dp\"\n" + 1292 " android:layout_height=\"200dp\" />\n" + 1293 "<LinearLayout " + 1294 " android:background=\"#CBBAF0\"\n" + 1295 " android:layout_width=\"100dp\"\n" + 1296 " android:layout_height=\"200dp\" />\n" + 1297 "</LinearLayout>"; 1298 { 1299 com.android.layoutlib.bridge.test.widgets.HookWidget.setOnPreDrawHook(() -> { 1300 throw new NullPointerException(); 1301 }); 1302 1303 // Create the layout pull parser. 1304 LayoutPullParser parser = LayoutPullParser.createFromString(layout); 1305 // Create LayoutLibCallback. 1306 LayoutLibTestCallback layoutLibCallback = 1307 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 1308 layoutLibCallback.initResources(); 1309 1310 SessionParams params = getSessionParamsBuilder() 1311 .setParser(parser) 1312 .setCallback(layoutLibCallback) 1313 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 1314 .setRenderingMode(RenderingMode.V_SCROLL) 1315 .build(); 1316 1317 renderAndVerify(params, "ondraw_crash.png", TimeUnit.SECONDS.toNanos(2)); 1318 } 1319 1320 com.android.layoutlib.bridge.test.widgets.HookWidget.reset(); 1321 1322 { 1323 com.android.layoutlib.bridge.test.widgets.HookWidget.setOnPreMeasure(() -> { 1324 throw new NullPointerException(); 1325 }); 1326 1327 LayoutPullParser parser = LayoutPullParser.createFromString(layout); 1328 LayoutLibTestCallback layoutLibCallback = 1329 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 1330 layoutLibCallback.initResources(); 1331 1332 SessionParams params = getSessionParamsBuilder() 1333 .setParser(parser) 1334 .setCallback(layoutLibCallback) 1335 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 1336 .setRenderingMode(RenderingMode.V_SCROLL) 1337 .build(); 1338 1339 renderAndVerify(params, "onmeasure_crash.png", TimeUnit.SECONDS.toNanos(2)); 1340 } 1341 1342 // We expect the view error messages. Fail for anything else. 1343 sRenderMessages.removeIf(message -> message.equals("View draw failed")); 1344 sRenderMessages.removeIf(message -> message.equals("View measure failed")); 1345 } 1346 1347 /** 1348 * Paints the borders of the given {@link ViewInfo} and its children to the passed 1349 * {@link Graphics2D} context. 1350 * The method will used the given parentLeft and parentTop as the given vInfo coordinates. 1351 * The depth is used to calculate different colors for the borders depending on the hierarchy 1352 * depth. 1353 */ paintBorders(@onNull Graphics2D g, int parentLeft, int parentTop, int depth, @NonNull ViewInfo vInfo)1354 private void paintBorders(@NonNull Graphics2D g, int parentLeft, int parentTop, int depth, 1355 @NonNull ViewInfo vInfo) { 1356 int leftMargin = Math.max(0, vInfo.getLeftMargin()); 1357 int topMargin = Math.max(0, vInfo.getTopMargin()); 1358 int x = parentLeft + vInfo.getLeft() + leftMargin; 1359 int y = parentTop + vInfo.getTop() + topMargin; 1360 int w = vInfo.getRight() - vInfo.getLeft(); 1361 int h = vInfo.getBottom() - vInfo.getTop(); 1362 g.setXORMode(java.awt.Color.decode(Integer.toString(depth * 50000))); 1363 g.drawRect(x, y, w, h); 1364 1365 for (ViewInfo child : vInfo.getChildren()) { 1366 paintBorders(g, x, y, depth + 1, child); 1367 } 1368 } 1369 1370 @Test testViewBoundariesReporting()1371 public void testViewBoundariesReporting() throws Exception { 1372 String layout = 1373 "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 1374 " android:layout_width=\"match_parent\"\n" + 1375 " android:layout_height=\"match_parent\"\n" + 1376 " android:background=\"@drawable/ninepatch\"\n" + 1377 " android:layout_margin=\"20dp\"\n" + 1378 " android:orientation=\"vertical\">\n" + "\n" + 1379 " <TextView\n" + 1380 " android:layout_width=\"150dp\"\n" + 1381 " android:layout_height=\"50dp\"\n" + 1382 " android:background=\"#FF0\"/>\n" + 1383 " <TextView\n" + 1384 " android:layout_width=\"150dp\"\n" + 1385 " android:layout_height=\"50dp\"\n" + 1386 " android:background=\"#F00\"/>\n" + 1387 " <LinearLayout\n" + 1388 " android:layout_width=\"wrap_content\"\n" + 1389 " android:layout_height=\"wrap_content\"\n" + 1390 " android:paddingLeft=\"10dp\">\n" + 1391 " <TextView\n" + 1392 " android:layout_width=\"150dp\"\n" + 1393 " android:layout_height=\"50dp\"\n" + 1394 " android:background=\"#00F\"/>\n" + 1395 " </LinearLayout>\n" + 1396 " <LinearLayout\n" + 1397 " android:layout_width=\"wrap_content\"\n" + 1398 " android:layout_height=\"wrap_content\"\n" + 1399 " android:layout_marginLeft=\"30dp\"\n" + 1400 " android:layout_marginTop=\"15dp\">\n" + 1401 " <TextView\n" + 1402 " android:layout_width=\"150dp\"\n" + 1403 " android:layout_height=\"50dp\"\n" + 1404 " android:background=\"#F0F\"/>\n" + 1405 " </LinearLayout>\n" + 1406 "</LinearLayout>"; 1407 1408 LayoutPullParser parser = LayoutPullParser.createFromString(layout); 1409 // Create LayoutLibCallback. 1410 LayoutLibTestCallback layoutLibCallback = 1411 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 1412 layoutLibCallback.initResources(); 1413 1414 SessionParams params = getSessionParamsBuilder() 1415 .setParser(parser) 1416 .setCallback(layoutLibCallback) 1417 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 1418 .setRenderingMode(RenderingMode.V_SCROLL) 1419 .disableDecoration() 1420 .build(); 1421 1422 RenderResult result = RenderTestBase.render(sBridge, params, -1); 1423 BufferedImage image = result.getImage(); 1424 assertNotNull(image); 1425 Graphics2D g = (Graphics2D) image.getGraphics(); 1426 g.setStroke(new BasicStroke(8)); 1427 for (ViewInfo vInfo : result.getSystemViews()) { 1428 paintBorders(g, 0, 0, 0, vInfo); 1429 } 1430 1431 RenderTestBase.verify("view_boundaries.png", image); 1432 } 1433 1434 /** 1435 * Test rendering of strings that have mixed RTL and LTR scripts. 1436 * <p> 1437 * http://b/37510906 1438 */ 1439 @Test testMixedRtlLtrRendering()1440 public void testMixedRtlLtrRendering() throws Exception { 1441 // 1442 final String layout = 1443 "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 1444 " android:layout_width=\"match_parent\"\n" + 1445 " android:layout_height=\"match_parent\"\n" + 1446 " android:orientation=\"vertical\">\n" + "\n" + 1447 " <TextView\n" + 1448 " android:layout_width=\"wrap_content\"\n" + 1449 " android:layout_height=\"wrap_content\"\n" + 1450 " android:textSize=\"30sp\"\n" + 1451 " android:background=\"#55FF0000\"\n" + 1452 " android:text=\"این یک رشته ایرانی است\"/>\n" + 1453 " <TextView\n" + 1454 " android:layout_width=\"wrap_content\"\n" + 1455 " android:layout_height=\"wrap_content\"\n" + 1456 " android:textSize=\"30sp\"\n" + 1457 " android:background=\"#55FF00FF\"\n" + 1458 " android:text=\"این یک رشته ایرانی است(\"/>\n" + 1459 " <TextView\n" + 1460 " android:layout_width=\"wrap_content\"\n" + 1461 " android:layout_height=\"wrap_content\"\n" + 1462 " android:textSize=\"30sp\"\n" + 1463 " android:background=\"#55FAF012\"\n" + 1464 " android:text=\")(این یک رشته ایرانی است(\"/>\n" + 1465 "</LinearLayout>"; 1466 1467 LayoutPullParser parser = LayoutPullParser.createFromString(layout); 1468 // Create LayoutLibCallback. 1469 LayoutLibTestCallback layoutLibCallback = 1470 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 1471 layoutLibCallback.initResources(); 1472 1473 SessionParams params = getSessionParamsBuilder() 1474 .setParser(parser) 1475 .setCallback(layoutLibCallback) 1476 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 1477 .setRenderingMode(RenderingMode.V_SCROLL) 1478 .disableDecoration() 1479 .build(); 1480 1481 renderAndVerify(params, "rtl_ltr.png", -1); 1482 } 1483 1484 @Test testViewStub()1485 public void testViewStub() throws Exception { 1486 // 1487 final String layout = 1488 "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 1489 " android:layout_width=\"match_parent\"\n" + 1490 " android:layout_height=\"match_parent\"\n" + 1491 " android:orientation=\"vertical\">\n" + "\n" + 1492 " <ViewStub\n" + 1493 " xmlns:tools=\"http://schemas.android.com/tools\"\n" + 1494 " android:layout_width=\"match_parent\"\n" + 1495 " android:layout_height=\"match_parent\"\n" + 1496 " android:layout=\"@layout/four_corners\"\n" + 1497 " tools:visibility=\"visible\" />" + 1498 "</LinearLayout>"; 1499 1500 // Create the layout pull parser. 1501 LayoutPullParser parser = LayoutPullParser.createFromString(layout); 1502 1503 // Create LayoutLibCallback. 1504 LayoutLibTestCallback layoutLibCallback = 1505 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 1506 layoutLibCallback.initResources(); 1507 1508 SessionParams params = getSessionParamsBuilder() 1509 .setParser(parser) 1510 .setCallback(layoutLibCallback) 1511 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 1512 .setRenderingMode(RenderingMode.V_SCROLL) 1513 .disableDecoration() 1514 .build(); 1515 1516 renderAndVerify(params, "view_stub.png", -1); 1517 } 1518 1519 @Test testImageResize()1520 public void testImageResize() throws ClassNotFoundException { 1521 LayoutLibTestCallback layoutLibCallback = 1522 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 1523 layoutLibCallback.initResources(); 1524 1525 LayoutPullParser parser = LayoutPullParser.createFromString( 1526 "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 1527 " android:layout_width=\"match_parent\"\n" + 1528 " android:layout_height=\"match_parent\"\n" + 1529 " android:background=\"@drawable/ninepatch\"\n" + 1530 " android:layout_margin=\"20dp\"\n" + 1531 " android:orientation=\"vertical\">\n\n" + 1532 " <Button\n" + 1533 " android:layout_width=\"wrap_content\"\n" + 1534 " android:layout_height=\"wrap_content\"\n" + 1535 " android:text=\"Button\" />\n\n" + 1536 " <Button\n" + 1537 " android:layout_width=\"wrap_content\"\n" + 1538 " android:layout_height=\"wrap_content\"\n" + 1539 " android:text=\"Button\" />\n" 1540 + "</LinearLayout>"); 1541 1542 // Ask for an image that it's 1/10th the size of the actual device image 1543 SessionParams params = getSessionParamsBuilder() 1544 .setParser(parser) 1545 .setCallback(layoutLibCallback) 1546 .setImageFactory((width, height) -> 1547 new BufferedImage(width / 10, height / 10, 1548 BufferedImage.TYPE_INT_ARGB)) 1549 .setFlag(RenderParamsFlags.FLAG_KEY_RESULT_IMAGE_AUTO_SCALE, true) 1550 .disableShadows() 1551 .build(); 1552 1553 renderAndVerify(params, "auto-scale-image.png"); 1554 } 1555 1556 @Test testTranslation()1557 public void testTranslation() throws ClassNotFoundException, FileNotFoundException { 1558 RenderResult res = renderAndVerify("translate_test.xml", "translate_test.png", false); 1559 ViewInfo rootInfo = res.getRootViews().get(0); 1560 ViewInfo buttonInfo = rootInfo.getChildren().get(0); 1561 assertEquals(100, buttonInfo.getLeft()); 1562 } 1563 1564 /** 1565 * Test a vector drawable that uses trimStart and trimEnd. It also tests all the primitives 1566 * for vector drawables (lines, moves and cubic and quadratic curves). 1567 */ 1568 @Test testCanvas()1569 public void testCanvas() throws ClassNotFoundException { 1570 // Create the layout pull parser. 1571 LayoutPullParser parser = LayoutPullParser.createFromString( 1572 "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 1573 " android:padding=\"16dp\"\n" + 1574 " android:orientation=\"horizontal\"\n" + 1575 " android:layout_width=\"fill_parent\"\n" + 1576 " android:layout_height=\"fill_parent\">\n" + 1577 " <com.android.layoutlib.test.myapplication.widgets.CanvasTestView\n" + 1578 " android:layout_height=\"fill_parent\"\n" + 1579 " android:layout_width=\"fill_parent\"\n" + 1580 " android:src=\"@drawable/android\" />\n" + "\n" + 1581 "</LinearLayout>"); 1582 // Create LayoutLibCallback. 1583 LayoutLibTestCallback layoutLibCallback = 1584 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 1585 layoutLibCallback.initResources(); 1586 1587 SessionParams params = getSessionParamsBuilder() 1588 .setParser(parser) 1589 .setCallback(layoutLibCallback) 1590 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 1591 .setRenderingMode(RenderingMode.V_SCROLL) 1592 .disableDecoration() 1593 .build(); 1594 1595 renderAndVerify(params, "canvas.png", TimeUnit.SECONDS.toNanos(2)); 1596 } 1597 1598 @Test testTypedArrays()1599 public void testTypedArrays() throws ClassNotFoundException, FileNotFoundException { 1600 renderAndVerify("typed_array.xml", "typed_arrays.png", false); 1601 } 1602 1603 /** 1604 * Tests that the gradients are correctly displayed when using transparent colors 1605 * and a wide range of offset values. 1606 * <p/> 1607 * http://b/112759140 1608 */ 1609 @Test testAnimatedVectorDrawableWithColorInterpolator()1610 public void testAnimatedVectorDrawableWithColorInterpolator() throws ClassNotFoundException { 1611 // Create the layout pull parser. 1612 LayoutPullParser parser = LayoutPullParser.createFromString( 1613 "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 1614 " android:padding=\"16dp\"\n" + 1615 " android:orientation=\"horizontal\"\n" + 1616 " android:layout_width=\"match_parent\"\n" + 1617 " android:layout_height=\"match_parent\">\n" + 1618 " <ImageView\n" + 1619 " android:layout_height=\"match_parent\"\n" + 1620 " android:layout_width=\"match_parent\"\n" + 1621 " android:src=\"@drawable/avd_color_interpolator\" />\n\n" + 1622 "</LinearLayout>"); 1623 // Create LayoutLibCallback. 1624 LayoutLibTestCallback layoutLibCallback = 1625 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 1626 layoutLibCallback.initResources(); 1627 1628 SessionParams params = getSessionParamsBuilder() 1629 .setParser(parser) 1630 .setCallback(layoutLibCallback) 1631 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 1632 .setRenderingMode(RenderingMode.V_SCROLL) 1633 .disableDecoration() 1634 .build(); 1635 1636 renderAndVerify(params, "color_interpolation.png", 1637 TimeUnit.SECONDS.toNanos(2)); 1638 } 1639 1640 @Test testManyLineBreaks()1641 public void testManyLineBreaks() throws Exception { 1642 String layout = 1643 "<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 1644 " android:layout_width=\"match_parent\"\n" + 1645 " android:layout_height=\"match_parent\">\n" + "\n" + 1646 " <EditText\n" + 1647 " android:layout_width=\"match_parent\"\n" + 1648 " android:layout_height=\"wrap_content\"\n" + 1649 " android:fallbackLineSpacing=\"true\"\n" + 1650 " android:text=\"A very very very very very very very very very " + 1651 "very very very very very very very very very very very very very very " + 1652 "very very very very very very very very very very very very very very " + 1653 "very very very very very very very very very very very very very very " + 1654 "very very very very very very very very very very very very very very " + 1655 "very very very very very very very very very very very very very very " + 1656 "very very very very very very very very very very very very very very " + 1657 "very very very very very very very very very very very very very very " + 1658 "very very very very very very very very very very very very very very " + 1659 "very very very very very very very very very very very very very very " + 1660 "very very very very very very very very very very very very very very " + 1661 "very very very very very very very very very very very very very very " + 1662 "very very very very very very very long text\"/>\n" + 1663 "</FrameLayout>"; 1664 1665 LayoutPullParser parser = LayoutPullParser.createFromString(layout); 1666 // Create LayoutLibCallback. 1667 LayoutLibTestCallback layoutLibCallback = 1668 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 1669 layoutLibCallback.initResources(); 1670 1671 SessionParams params = getSessionParamsBuilder() 1672 .setParser(parser) 1673 .setCallback(layoutLibCallback) 1674 .setTheme("Theme.Material.NoActionBar.Fullscreen", false) 1675 .setRenderingMode(RenderingMode.V_SCROLL) 1676 .disableDecoration() 1677 .build(); 1678 1679 renderAndVerify(params, "many_line_breaks.png", 1680 TimeUnit.SECONDS.toNanos(2)); 1681 } 1682 1683 @Test testHighQualityShadowWidgetWithScroll()1684 public void testHighQualityShadowWidgetWithScroll() throws Exception { 1685 LayoutPullParser parser = createParserFromPath("shadows_scrollview.xml"); 1686 LayoutLibTestCallback layoutLibCallback = 1687 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 1688 layoutLibCallback.initResources(); 1689 SessionParams params = getSessionParamsBuilder() 1690 .setParser(parser) 1691 .setCallback(layoutLibCallback) 1692 .build(); 1693 1694 renderAndVerify(params, "shadow_scrollview_test_high_quality.png"); 1695 // We expect fidelity warnings for Path.isConvex. Fail for anything else. 1696 sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported.")); 1697 sRenderMessages.removeIf(message -> message.equals("Font$Builder.nAddAxis is not supported.")); 1698 } 1699 1700 @Test testContentId()1701 public void testContentId() throws ClassNotFoundException { 1702 final String layout = 1703 "<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 1704 " android:layout_width=\"match_parent\"\n" + 1705 " android:layout_height=\"match_parent\">\n" + "\n" + 1706 " <com.android.layoutlib.bridge.test.widgets.ContentWidget\n" + 1707 " android:layout_width=\"match_parent\"\n" + 1708 " android:layout_height=\"wrap_content\"/>\n" + 1709 "</FrameLayout>"; 1710 1711 { 1712 // Create the layout pull parser. 1713 LayoutPullParser parser = LayoutPullParser.createFromString(layout); 1714 // Create LayoutLibCallback. 1715 LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 1716 layoutLibCallback.initResources(); 1717 1718 SessionParams params = getSessionParamsBuilder() 1719 .setParser(parser) 1720 .setCallback(layoutLibCallback) 1721 .build(); 1722 1723 RenderResult result = render(sBridge, params, TimeUnit.SECONDS.toNanos(2)); 1724 BufferedImage image = result.getImage(); 1725 assertNotNull(image); 1726 } 1727 1728 { 1729 // Create the layout pull parser. 1730 LayoutPullParser parser = LayoutPullParser.createFromString(layout); 1731 // Create LayoutLibCallback. 1732 LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 1733 layoutLibCallback.initResources(); 1734 1735 SessionParams params = getSessionParamsBuilder() 1736 .setParser(parser) 1737 .setCallback(layoutLibCallback) 1738 .disableDecoration() 1739 .build(); 1740 1741 RenderResult result = render(sBridge, params, TimeUnit.SECONDS.toNanos(2)); 1742 BufferedImage image = result.getImage(); 1743 assertNotNull(image); 1744 } 1745 } 1746 1747 /** 1748 * Tests that the TextClock widget renders without error 1749 * <p/> 1750 * http://b/150151293 1751 */ 1752 @Test testTextClock()1753 public void testTextClock() throws ClassNotFoundException { 1754 String layout = 1755 "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + 1756 " android:padding=\"16dp\"\n" + 1757 " android:orientation=\"horizontal\"\n" + 1758 " android:layout_width=\"fill_parent\"\n" + 1759 " android:layout_height=\"fill_parent\">\n" + 1760 " <TextClock\n" + 1761 " android:layout_height=\"wrap_content\"\n" + 1762 " android:layout_width=\"wrap_content\"\n" + 1763 " android:text=\"12:34\"" + 1764 " android:textSize=\"18sp\" />\n" + 1765 "</LinearLayout>\n"; 1766 LayoutPullParser parser = LayoutPullParser.createFromString(layout); 1767 // Create LayoutLibCallback. 1768 LayoutLibTestCallback layoutLibCallback = 1769 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 1770 layoutLibCallback.initResources(); 1771 SessionParams params = getSessionParamsBuilder() 1772 .setParser(parser) 1773 .setCallback(layoutLibCallback) 1774 .disableDecoration() 1775 .build(); 1776 1777 renderAndVerify(params, "textclock.png"); 1778 } 1779 } 1780