From c5708ef76d6ace5251f2d7f05bc7e8bd97655185 Mon Sep 17 00:00:00 2001 From: Diego Perez Date: Thu, 21 Jul 2016 17:54:42 +0100 Subject: Catch all exceptions in NativeAllocationRegistry free The NativeAllocationRegistry delegate free calls might run in the context of the finalizer thread. If a crash happens during the free call, it might bring down the finalizer thread and the VM. Bug: http://b.android.com/213927 Change-Id: I8d4b8ab5b8d0532aad46f27d039a943894e021a0 --- .../src/libcore/util/NativeAllocationRegistry_Delegate.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/layoutlib/bridge/src/libcore/util/NativeAllocationRegistry_Delegate.java b/tools/layoutlib/bridge/src/libcore/util/NativeAllocationRegistry_Delegate.java index 6246ec1b8661..04fabc242454 100644 --- a/tools/layoutlib/bridge/src/libcore/util/NativeAllocationRegistry_Delegate.java +++ b/tools/layoutlib/bridge/src/libcore/util/NativeAllocationRegistry_Delegate.java @@ -52,9 +52,15 @@ public class NativeAllocationRegistry_Delegate { @LayoutlibDelegate /*package*/ static void applyFreeFunction(long freeFunction, long nativePtr) { - NativeAllocationRegistry_Delegate delegate = sManager.getDelegate(freeFunction); - if (delegate != null) { - delegate.mFinalizer.free(nativePtr); + // This method MIGHT run in the context of the finalizer thread. If the delegate method + // crashes, it could bring down the VM. That's why we catch all the exceptions and ignore + // them. + try { + NativeAllocationRegistry_Delegate delegate = sManager.getDelegate(freeFunction); + if (delegate != null) { + delegate.mFinalizer.free(nativePtr); + } + } catch (Throwable ignore) { } } -- cgit v1.2.3-59-g8ed1b From f31c1e98d4fda5a1296a4dde4bc1ff6f73c5db64 Mon Sep 17 00:00:00 2001 From: Diego Perez Date: Tue, 2 Aug 2016 13:48:08 +0100 Subject: Avoid passing antialias when measuring scaled text This is a workaround for a JDK bug that crashes the VM when measuring scaled antialsed text. This disables antialiasing when measuring scaled text in a specific version of the VM. Bug: http://b.android.com/211659 Change-Id: I637ed03cf827b65c993550998ac55d42869237ad --- tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java index 21f36ceb0c1b..c6827a3c9c5f 100644 --- a/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java +++ b/tools/layoutlib/bridge/src/android/graphics/BidiRenderer.java @@ -30,6 +30,7 @@ import java.awt.Graphics2D; import java.awt.Toolkit; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.LinkedList; @@ -41,6 +42,7 @@ import java.util.List; */ @SuppressWarnings("deprecation") public class BidiRenderer { + private static String JAVA_VENDOR = System.getProperty("java.vendor"); private static class ScriptRun { int start; @@ -221,9 +223,16 @@ public class BidiRenderer { frc = mGraphics.getFontRenderContext(); } else { frc = Toolkit.getDefaultToolkit().getFontMetrics(font).getFontRenderContext(); + // Metrics obtained this way don't have anti-aliasing set. So, // we create a new FontRenderContext with anti-aliasing set. - frc = new FontRenderContext(font.getTransform(), mPaint.isAntiAliased(), frc.usesFractionalMetrics()); + AffineTransform transform = font.getTransform(); + if (mPaint.isAntiAliased() && + // Workaround for http://b.android.com/211659 + (transform.getScaleX() <= 9.9 || + !"JetBrains s.r.o".equals(JAVA_VENDOR))) { + frc = new FontRenderContext(transform, true, frc.usesFractionalMetrics()); + } } GlyphVector gv = font.layoutGlyphVector(frc, mText, start, limit, flag); int ng = gv.getNumGlyphs(); -- cgit v1.2.3-59-g8ed1b From 6782b0e74a1420ff112e23094ca922f801df2ec5 Mon Sep 17 00:00:00 2001 From: Diego Perez Date: Thu, 10 Nov 2016 16:29:22 +0000 Subject: Force animateFirstValue to false This CL forces both animateFirstValue and animateLayoutChanges to false in themes when running layoutlib. This helps with the rendering of some widgets so they do not rely on animations. Test: Test as part of testActivity Change-Id: Ic9214929d3582bc3e0a196d198cc4fb36347c782 --- .../layoutlib/bridge/android/BridgeContext.java | 19 +++++++++++++++++++ .../MyApplication/src/main/res/values/styles.xml | 1 - 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 1b3b563fb51e..7cedaec08f7e 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -113,6 +113,15 @@ import static com.android.layoutlib.bridge.android.RenderParamsFlags.FLAG_KEY_AP public final class BridgeContext extends Context { private static final String PREFIX_THEME_APPCOMPAT = "Theme.AppCompat"; + private static final Map FRAMEWORK_PATCHED_VALUES = new HashMap<>(2); + + static { + FRAMEWORK_PATCHED_VALUES.put("animateFirstView", new ResourceValue( + ResourceType.BOOL, "animateFirstView", "false", false)); + FRAMEWORK_PATCHED_VALUES.put("animateLayoutChanges", new ResourceValue( + ResourceType.BOOL, "animateFirstView", "false", false)); + }; + /** The map adds cookies to each view so that IDE can link xml tags to views. */ private final HashMap mViewKeyMap = new HashMap<>(); /** @@ -909,6 +918,16 @@ public final class BridgeContext extends Context { // if there's no direct value for this attribute in the XML, we look for default // values in the widget defStyle, and then in the theme. if (value == null) { + if (frameworkAttr) { + // For some framework values, layoutlib patches the actual value in the + // theme when it helps to improve the final preview. In most cases + // we just disable animations. + ResourceValue patchedValue = FRAMEWORK_PATCHED_VALUES.get(attrName); + if (patchedValue != null) { + defaultValue = patchedValue; + } + } + // if we found a value, we make sure this doesn't reference another value. // So we resolve it. if (defaultValue != null) { diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml index c8a5fec71f09..debe33bea72e 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml @@ -3,7 +3,6 @@ -- cgit v1.2.3-59-g8ed1b From 7d7ef8400da668e39306612ad19642427c642622 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Fri, 25 Nov 2016 17:28:05 +0000 Subject: Hack to deal with android:pointerIcon in layoutlib android:pointerIcon is a View attribute that can be an enum or a reference. Layoutlib cannot easily deal with the way that is handled in the platform. As the property would not have any impact on the result in layoutlib, that property is bypassed. Test: Main.testAllWidgets Change-Id: I38c6c6df45c1836d44b4f80245a453fb432ea251 --- .../src/android/view/PointerIcon_Delegate.java | 33 ++++++++++++++++++++++ .../src/main/res/layout/allwidgets.xml | 3 +- .../android/tools/layoutlib/create/CreateInfo.java | 1 + 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 tools/layoutlib/bridge/src/android/view/PointerIcon_Delegate.java (limited to 'tools') diff --git a/tools/layoutlib/bridge/src/android/view/PointerIcon_Delegate.java b/tools/layoutlib/bridge/src/android/view/PointerIcon_Delegate.java new file mode 100644 index 000000000000..4a5ea9b5bb65 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/view/PointerIcon_Delegate.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import com.android.tools.layoutlib.annotations.LayoutlibDelegate; + +import android.content.Context; +import android.content.res.Resources; + +public class PointerIcon_Delegate { + + @LayoutlibDelegate + /*package*/ static void loadResource(PointerIcon icon, Context context, Resources resources, + int resourceId) { + // HACK: This bypasses the problem of having an enum resolved as a resourceId. + // PointerIcon would not be displayed by layoutlib anyway, so we always return the null + // icon. + } +} diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/allwidgets.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/allwidgets.xml index adb58a322abb..05a3665deab1 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/allwidgets.xml +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/allwidgets.xml @@ -28,7 +28,8 @@ android:layout_alignParentStart="true" android:layout_below="@id/frameLayout" android:text="Large Text" - android:textAppearance="?android:attr/textAppearanceLarge" /> + android:textAppearance="?android:attr/textAppearanceLarge" + android:pointerIcon="hand" /> Date: Fri, 2 Dec 2016 11:16:26 +0000 Subject: Do not log errors while loading string arrays When arrays contain references, if we can not resolve them, just return the reference string. This matches the behaviour of resource resolution in BridgeTypeArray. Bug: http://b.android.com/228620 Test: Updates existing tests Change-Id: Ia324f18d9128b8abf2ba676a83d4b424914e2c88 --- .../android/content/res/Resources_Delegate.java | 3 -- .../MyApplication/src/main/res/values/arrays.xml | 1 + .../android/layoutlib/bridge/intensive/Main.java | 37 ++++++++++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java index c3d4cef61b35..f3af5aa8ca07 100644 --- a/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java +++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java @@ -405,9 +405,6 @@ public class Resources_Delegate { rv = resources.mContext.getRenderResources().resolveResValue(rv); if (rv != null) { return rv.getValue(); - } else { - Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE, - "Unable to resolve resource " + ref, null); } } // Not a reference. diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/arrays.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/arrays.xml index f6e14d2b83b9..5f58d390bf32 100644 --- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/arrays.xml +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/values/arrays.xml @@ -17,6 +17,7 @@ ?android:attr/candidatesTextStyleSpans @android:string/unknownName + ?EC diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java index cdcae89097b5..ecaecd3549cb 100644 --- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java @@ -69,6 +69,7 @@ import java.util.concurrent.TimeUnit; import com.google.android.collect.Lists; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -313,6 +314,12 @@ public class Main { sBridge = new Bridge(); sBridge.init(ConfigGenerator.loadProperties(buildProp), fontLocation, ConfigGenerator.getEnumMap(attrs), getLayoutLog()); + Bridge.getLock().lock(); + try { + Bridge.setLog(getLayoutLog()); + } finally { + Bridge.getLock().unlock(); + } } @Before @@ -624,6 +631,36 @@ public class Main { assertEquals("app_name", resources.getResourceEntryName(id)); } + @Test + public void testStringEscaping() throws Exception { + // Setup + // Create the layout pull parser for our resources (empty.xml can not be part of the test + // app as it won't compile). + LayoutPullParser parser = new LayoutPullParser("/empty.xml"); + // Create LayoutLibCallback. + LayoutLibTestCallback layoutLibCallback = + new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); + layoutLibCallback.initResources(); + SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_4, + layoutLibCallback, "AppTheme", true, RenderingMode.NORMAL, 22); + AssetManager assetManager = AssetManager.getSystem(); + DisplayMetrics metrics = new DisplayMetrics(); + Configuration configuration = RenderAction.getConfiguration(params); + Resources resources = new Resources(assetManager, metrics, configuration); + resources.mLayoutlibCallback = params.getLayoutlibCallback(); + resources.mContext = + new BridgeContext(params.getProjectKey(), metrics, params.getResources(), + params.getAssets(), params.getLayoutlibCallback(), configuration, + params.getTargetSdkVersion(), params.isRtlSupported()); + + int id = resources.mLayoutlibCallback.getResourceId(ResourceType.ARRAY, "string_array"); + String[] strings = resources.getStringArray(id); + assertArrayEquals( + new String[]{"mystring", "Hello world!", "candidates", "Unknown", "?EC"}, + strings); + assertTrue(sRenderMessages.isEmpty()); + } + @NonNull private LayoutPullParser createLayoutPullParser(String layoutPath) { return new LayoutPullParser(APP_TEST_RES + "/layout/" + layoutPath); -- cgit v1.2.3-59-g8ed1b From 37f9ddb1c41286ac22697c958e3ee31dd193f8dd Mon Sep 17 00:00:00 2001 From: Diego Perez Date: Mon, 5 Dec 2016 17:47:23 +0000 Subject: Fix plurals support in layoutlib Bug: http://b.android.com/213000 Test: Manually tested on Android Studio. Adding tests for this specific case requires bringing a new sdk-common prebuilt to the the maintenance branch so it's not really practical. Change-Id: I0646aab656d5d5769355c6cc026e877b8784d173 --- .../android/content/res/Resources_Delegate.java | 44 ++++++++++++++++++++++ .../android/tools/layoutlib/create/CreateInfo.java | 2 + 2 files changed, 46 insertions(+) (limited to 'tools') diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java index f3af5aa8ca07..e0f8e1c33bc6 100644 --- a/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java +++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java @@ -21,6 +21,7 @@ import com.android.ide.common.rendering.api.ArrayResourceValue; import com.android.ide.common.rendering.api.DensityBasedResourceValue; import com.android.ide.common.rendering.api.LayoutLog; import com.android.ide.common.rendering.api.LayoutlibCallback; +import com.android.ide.common.rendering.api.PluralsResourceValue; import com.android.ide.common.rendering.api.RenderResources; import com.android.ide.common.rendering.api.ResourceValue; import com.android.layoutlib.bridge.Bridge; @@ -43,6 +44,7 @@ import android.annotation.Nullable; import android.content.res.Resources.NotFoundException; import android.content.res.Resources.Theme; import android.graphics.drawable.Drawable; +import android.icu.text.PluralRules; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.LruCache; @@ -734,6 +736,48 @@ public class Resources_Delegate { return null; } + @LayoutlibDelegate + static String getQuantityString(Resources resources, int id, int quantity) throws + NotFoundException { + Pair value = getResourceValue(resources, id, mPlatformResourceFlag); + + if (value != null) { + if (value.getSecond() instanceof PluralsResourceValue) { + PluralsResourceValue pluralsResourceValue = (PluralsResourceValue) value.getSecond(); + PluralRules pluralRules = PluralRules.forLocale(resources.getConfiguration().getLocales() + .get(0)); + String strValue = pluralsResourceValue.getValue(pluralRules.select(quantity)); + if (strValue == null) { + strValue = pluralsResourceValue.getValue(PluralRules.KEYWORD_OTHER); + } + + return strValue; + } + else { + return value.getSecond().getValue(); + } + } + + // id was not found or not resolved. Throw a NotFoundException. + throwException(resources, id); + + // this is not used since the method above always throws + return null; + } + + @LayoutlibDelegate + static String getQuantityString(Resources resources, int id, int quantity, Object... formatArgs) + throws NotFoundException { + String raw = getQuantityString(resources, id, quantity); + return String.format(resources.getConfiguration().getLocales().get(0), raw, formatArgs); + } + + @LayoutlibDelegate + static CharSequence getQuantityText(Resources resources, int id, int quantity) throws + NotFoundException { + return getQuantityString(resources, id, quantity); + } + @LayoutlibDelegate static void getValue(Resources resources, int id, TypedValue outValue, boolean resolveRefs) throws NotFoundException { diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java index 07b7d0076402..741eb27558ed 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -154,6 +154,8 @@ public final class CreateInfo implements ICreateInfo { "android.content.res.Resources#getIntArray", "android.content.res.Resources#getInteger", "android.content.res.Resources#getLayout", + "android.content.res.Resources#getQuantityString", + "android.content.res.Resources#getQuantityText", "android.content.res.Resources#getResourceEntryName", "android.content.res.Resources#getResourceName", "android.content.res.Resources#getResourcePackageName", -- cgit v1.2.3-59-g8ed1b From 0c864fde5882488623665c793701641329e5955f Mon Sep 17 00:00:00 2001 From: Diego Perez Date: Fri, 9 Dec 2016 13:59:57 +0000 Subject: Add missing attributes to old themes Because we always use the latest framework code, some resources might fail to resolve when using old themes (they haven't been backported). Since this is an artifact caused by us using always the latest code, we check for some of those values and replace them here. Bug: http://b.android.com/225105 Test: Included new testActivityOnOldTheme Change-Id: Ia7a8a27fb81fe0b4a1e0c9610a2033a87720864d --- .../layoutlib/bridge/android/BridgeContext.java | 59 ++++++++++++--------- .../golden/simple_activity-old-theme.png | Bin 0 -> 1749 bytes .../android/layoutlib/bridge/intensive/Main.java | 14 +++++ 3 files changed, 47 insertions(+), 26 deletions(-) create mode 100644 tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity-old-theme.png (limited to 'tools') diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 7cedaec08f7e..663e56d2ccdf 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -66,7 +66,6 @@ import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.hardware.display.DisplayManager; import android.net.Uri; -import android.os.Build.VERSION_CODES; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -104,6 +103,7 @@ import java.util.IdentityHashMap; import java.util.List; import java.util.Map; +import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; import static com.android.layoutlib.bridge.android.RenderParamsFlags.FLAG_KEY_APPLICATION_PACKAGE; /** @@ -114,13 +114,26 @@ public final class BridgeContext extends Context { private static final String PREFIX_THEME_APPCOMPAT = "Theme.AppCompat"; private static final Map FRAMEWORK_PATCHED_VALUES = new HashMap<>(2); + private static final Map FRAMEWORK_REPLACE_VALUES = new HashMap<>(3); static { FRAMEWORK_PATCHED_VALUES.put("animateFirstView", new ResourceValue( ResourceType.BOOL, "animateFirstView", "false", false)); - FRAMEWORK_PATCHED_VALUES.put("animateLayoutChanges", new ResourceValue( - ResourceType.BOOL, "animateFirstView", "false", false)); - }; + FRAMEWORK_PATCHED_VALUES.put("animateLayoutChanges", + new ResourceValue(ResourceType.BOOL, "animateLayoutChanges", "false", false)); + + + FRAMEWORK_REPLACE_VALUES.put("textEditSuggestionItemLayout", + new ResourceValue(ResourceType.LAYOUT, "textEditSuggestionItemLayout", + "text_edit_suggestion_item", true)); + FRAMEWORK_REPLACE_VALUES.put("textEditSuggestionContainerLayout", + new ResourceValue(ResourceType.LAYOUT, "textEditSuggestionContainerLayout", + "text_edit_suggestion_container", true)); + FRAMEWORK_REPLACE_VALUES.put("textEditSuggestionHighlightStyle", + new ResourceValue(ResourceType.STYLE, "textEditSuggestionHighlightStyle", + "TextAppearance.Holo.SuggestionHighlight", true)); + + } /** The map adds cookies to each view so that IDE can link xml tags to views. */ private final HashMap mViewKeyMap = new HashMap<>(); @@ -321,7 +334,7 @@ public final class BridgeContext extends Context { * Returns the current parser at the top the of the stack. * @return a parser or null. */ - public BridgeXmlBlockParser getCurrentParser() { + private BridgeXmlBlockParser getCurrentParser() { return mParserStack.peek(); } @@ -415,7 +428,8 @@ public final class BridgeContext extends Context { } public Pair inflateView(ResourceReference resource, ViewGroup parent, - boolean attachToRoot, boolean skipCallbackParser) { + @SuppressWarnings("SameParameterValue") boolean attachToRoot, + boolean skipCallbackParser) { boolean isPlatformLayout = resource.isFramework(); if (!isPlatformLayout && !skipCallbackParser) { @@ -720,11 +734,7 @@ public final class BridgeContext extends Context { Object key = parser.getViewCookie(); if (key != null) { - defaultPropMap = mDefaultPropMaps.get(key); - if (defaultPropMap == null) { - defaultPropMap = new PropertiesMap(); - mDefaultPropMaps.put(key, defaultPropMap); - } + defaultPropMap = mDefaultPropMaps.computeIfAbsent(key, k -> new PropertiesMap()); } } else if (set instanceof BridgeLayoutParamsMapAttributes) { @@ -935,16 +945,21 @@ public final class BridgeContext extends Context { // exist, we should log a warning and omit it. String val = defaultValue.getValue(); if (val != null && val.startsWith(SdkConstants.PREFIX_THEME_REF)) { - if (!attrName.equals(RTL_ATTRS.get(val)) || - getApplicationInfo().targetSdkVersion < - VERSION_CODES.JELLY_BEAN_MR1) { + // Because we always use the latest framework code, some resources might + // fail to resolve when using old themes (they haven't been backported). + // Since this is an artifact caused by us using always the latest + // code, we check for some of those values and replace them here. + defaultValue = FRAMEWORK_REPLACE_VALUES.get(attrName); + + if (defaultValue == null && + (getApplicationInfo().targetSdkVersion < JELLY_BEAN_MR1 || + !attrName.equals(RTL_ATTRS.get(val)))) { // Only log a warning if the referenced value isn't one of the RTL // attributes, or the app targets old API. Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_RESOLVE_THEME_ATTR, String.format("Failed to find '%s' in current theme.", val), val); } - defaultValue = null; } } @@ -1963,7 +1978,7 @@ public final class BridgeContext extends Context { Map, Map>>> mCache; - public TypedArrayCache() { + private TypedArrayCache() { mCache = new IdentityHashMap<>(); } @@ -1984,17 +1999,9 @@ public final class BridgeContext extends Context { public void put(int[] attrs, List themes, int resId, Pair value) { Map, Map>> - cacheFromThemes = mCache.get(attrs); - if (cacheFromThemes == null) { - cacheFromThemes = new HashMap<>(); - mCache.put(attrs, cacheFromThemes); - } + cacheFromThemes = mCache.computeIfAbsent(attrs, k -> new HashMap<>()); Map> cacheFromResId = - cacheFromThemes.get(themes); - if (cacheFromResId == null) { - cacheFromResId = new HashMap<>(); - cacheFromThemes.put(themes, cacheFromResId); - } + cacheFromThemes.computeIfAbsent(themes, k -> new HashMap<>()); cacheFromResId.put(resId, value); } diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity-old-theme.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity-old-theme.png new file mode 100644 index 000000000000..eb431b0280da Binary files /dev/null and b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/simple_activity-old-theme.png differ diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java index ecaecd3549cb..5997ab5b1e3f 100644 --- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java @@ -333,6 +333,20 @@ public class Main { renderAndVerify("activity.xml", "activity.png"); } + @Test + public void testActivityOnOldTheme() throws ClassNotFoundException { + LayoutLibTestCallback layoutLibCallback = + new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); + layoutLibCallback.initResources(); + + LayoutPullParser parser = createLayoutPullParser("simple_activity.xml"); + SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5, + layoutLibCallback, "Theme.NoTitleBar", false, + RenderingMode.NORMAL, 22); + + renderAndVerify(params, "simple_activity-old-theme.png"); + } + @Test public void testTranslucentBars() throws ClassNotFoundException { LayoutLibTestCallback layoutLibCallback = -- cgit v1.2.3-59-g8ed1b