From e5b037a1e8340ec42bb7c0e71b4c45af225bafb3 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Thu, 16 Feb 2023 14:47:06 +0000 Subject: Update golden images following nav bar colour change The default colour for the navigation bar is now transparent. Bug: 74062470 Test: layoutlib tests Change-Id: I19a4258332054e92acc78e2c6bea760a639d6d69 (cherry picked from commit 67e86a65f66703ebbd533702133a14d12ff2e32b) Merged-In: I19a4258332054e92acc78e2c6bea760a639d6d69 --- .../res/testApp/MyApplication/golden/activity.png | Bin 89998 -> 88377 bytes .../testApp/MyApplication/golden/adaptive_icon.png | Bin 23893 -> 24116 bytes .../MyApplication/golden/adaptive_icon_circle.png | Bin 26576 -> 26796 bytes .../golden/adaptive_icon_dynamic_green.png | Bin 25586 -> 26231 bytes .../golden/adaptive_icon_dynamic_orange.png | Bin 25703 -> 26348 bytes .../golden/adaptive_icon_rounded_corners.png | Bin 24654 -> 24874 bytes .../golden/adaptive_icon_squircle.png | Bin 27241 -> 27462 bytes .../testApp/MyApplication/golden/allwidgets.png | Bin 161814 -> 159826 bytes .../MyApplication/golden/allwidgets_tab.png | Bin 62790 -> 62633 bytes .../MyApplication/golden/animated_vector.png | Bin 42570 -> 42995 bytes .../MyApplication/golden/animated_vector_1.png | Bin 37425 -> 37864 bytes .../res/testApp/MyApplication/golden/asset.png | Bin 415465 -> 415699 bytes .../MyApplication/golden/auto-scale-image.png | Bin 1462 -> 1428 bytes .../MyApplication/golden/context_theme_wrapper.png | Bin 20275 -> 20502 bytes .../MyApplication/golden/expand_horz_layout.png | Bin 9922 -> 8091 bytes .../MyApplication/golden/expand_vert_layout.png | Bin 17097 -> 15384 bytes .../testApp/MyApplication/golden/four_corners.png | Bin 50506 -> 48696 bytes .../MyApplication/golden/ninepatch_background.png | Bin 32322 -> 33105 bytes .../testApp/MyApplication/golden/ondraw_crash.png | Bin 22662 -> 22926 bytes .../MyApplication/golden/onmeasure_crash.png | Bin 20498 -> 20738 bytes .../golden/shadow_scrollview_test.png | Bin 33933 -> 32054 bytes .../MyApplication/golden/shadow_sizes_test.png | Bin 43315 -> 41450 bytes .../golden/shadows_test_rounded_edge.png | Bin 38459 -> 36476 bytes .../MyApplication/golden/simple_activity.png | Bin 27254 -> 25314 bytes .../golden/simple_activity_noactionbar.png | Bin 27185 -> 25119 bytes .../MyApplication/golden/vector_drawable_91383.png | Bin 35615 -> 36084 bytes .../golden/vector_drawable_gradient.png | Bin 37923 -> 38214 bytes .../golden/vector_drawable_radial_gradient.png | Bin 62205 -> 62460 bytes .../vector_drawable_with_tint_in_image_view.png | Bin 82624 -> 80981 bytes .../golden/vector_drawable_with_tint_itself.png | Bin 43863 -> 42194 bytes 30 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bridge/tests/res/testApp/MyApplication/golden/activity.png b/bridge/tests/res/testApp/MyApplication/golden/activity.png index a05349d73c..4546682d06 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/activity.png and b/bridge/tests/res/testApp/MyApplication/golden/activity.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon.png b/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon.png index 2d6938aa28..b438464c6c 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon.png and b/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_circle.png b/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_circle.png index 5570291230..e939a572ec 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_circle.png and b/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_circle.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_dynamic_green.png b/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_dynamic_green.png index 61f1f18af1..b70c65d05e 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_dynamic_green.png and b/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_dynamic_green.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_dynamic_orange.png b/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_dynamic_orange.png index dd1dd57027..31647c615d 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_dynamic_orange.png and b/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_dynamic_orange.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_rounded_corners.png b/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_rounded_corners.png index e0b60374cd..67deb6e4d4 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_rounded_corners.png and b/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_rounded_corners.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_squircle.png b/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_squircle.png index 3e41ccc2c1..6e63ef2286 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_squircle.png and b/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_squircle.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png b/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png index 48a40cd191..fb5e970dc4 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png and b/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png b/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png index f8cec3261b..5d452ef48d 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png and b/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/animated_vector.png b/bridge/tests/res/testApp/MyApplication/golden/animated_vector.png index c00823d326..3887e292e3 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/animated_vector.png and b/bridge/tests/res/testApp/MyApplication/golden/animated_vector.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/animated_vector_1.png b/bridge/tests/res/testApp/MyApplication/golden/animated_vector_1.png index db0b343eb3..9588148737 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/animated_vector_1.png and b/bridge/tests/res/testApp/MyApplication/golden/animated_vector_1.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/asset.png b/bridge/tests/res/testApp/MyApplication/golden/asset.png index b6193f61e4..f4467d6c1d 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/asset.png and b/bridge/tests/res/testApp/MyApplication/golden/asset.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/auto-scale-image.png b/bridge/tests/res/testApp/MyApplication/golden/auto-scale-image.png index 6a23995415..7cabc39941 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/auto-scale-image.png and b/bridge/tests/res/testApp/MyApplication/golden/auto-scale-image.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/context_theme_wrapper.png b/bridge/tests/res/testApp/MyApplication/golden/context_theme_wrapper.png index 323d51493e..9e08e22488 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/context_theme_wrapper.png and b/bridge/tests/res/testApp/MyApplication/golden/context_theme_wrapper.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png b/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png index 5ed270620f..7b1f1f1e02 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png and b/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/expand_vert_layout.png b/bridge/tests/res/testApp/MyApplication/golden/expand_vert_layout.png index 80e72b0199..d6a4c5c586 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/expand_vert_layout.png and b/bridge/tests/res/testApp/MyApplication/golden/expand_vert_layout.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/four_corners.png b/bridge/tests/res/testApp/MyApplication/golden/four_corners.png index 82e40ac58e..4e7feb443f 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/four_corners.png and b/bridge/tests/res/testApp/MyApplication/golden/four_corners.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/ninepatch_background.png b/bridge/tests/res/testApp/MyApplication/golden/ninepatch_background.png index fefb3b7181..6403637078 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/ninepatch_background.png and b/bridge/tests/res/testApp/MyApplication/golden/ninepatch_background.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/ondraw_crash.png b/bridge/tests/res/testApp/MyApplication/golden/ondraw_crash.png index d69667c6b7..4051b05ca2 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/ondraw_crash.png and b/bridge/tests/res/testApp/MyApplication/golden/ondraw_crash.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/onmeasure_crash.png b/bridge/tests/res/testApp/MyApplication/golden/onmeasure_crash.png index 4d9f7769d9..e27ae9eb39 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/onmeasure_crash.png and b/bridge/tests/res/testApp/MyApplication/golden/onmeasure_crash.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/shadow_scrollview_test.png b/bridge/tests/res/testApp/MyApplication/golden/shadow_scrollview_test.png index 19e65aa167..55a9982b5d 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/shadow_scrollview_test.png and b/bridge/tests/res/testApp/MyApplication/golden/shadow_scrollview_test.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/shadow_sizes_test.png b/bridge/tests/res/testApp/MyApplication/golden/shadow_sizes_test.png index 84b7299a56..6093824921 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/shadow_sizes_test.png and b/bridge/tests/res/testApp/MyApplication/golden/shadow_sizes_test.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/shadows_test_rounded_edge.png b/bridge/tests/res/testApp/MyApplication/golden/shadows_test_rounded_edge.png index 7d9a51d793..f1437af29a 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/shadows_test_rounded_edge.png and b/bridge/tests/res/testApp/MyApplication/golden/shadows_test_rounded_edge.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/simple_activity.png b/bridge/tests/res/testApp/MyApplication/golden/simple_activity.png index 2b2aab8a0e..1300dd0cca 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/simple_activity.png and b/bridge/tests/res/testApp/MyApplication/golden/simple_activity.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/simple_activity_noactionbar.png b/bridge/tests/res/testApp/MyApplication/golden/simple_activity_noactionbar.png index 38924a322c..7852c9e323 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/simple_activity_noactionbar.png and b/bridge/tests/res/testApp/MyApplication/golden/simple_activity_noactionbar.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_91383.png b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_91383.png index 5832c67a71..03da31efc0 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_91383.png and b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_91383.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_gradient.png b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_gradient.png index 769406e5fb..67e502fccd 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_gradient.png and b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_gradient.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_radial_gradient.png b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_radial_gradient.png index 6882d79b87..4b1425ac89 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_radial_gradient.png and b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_radial_gradient.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_with_tint_in_image_view.png b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_with_tint_in_image_view.png index 759d535f6e..055af89473 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_with_tint_in_image_view.png and b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_with_tint_in_image_view.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_with_tint_itself.png b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_with_tint_itself.png index 4396a51816..99e37aed57 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_with_tint_itself.png and b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_with_tint_itself.png differ -- cgit v1.2.3 From 4866e72882e87f11cd36b3271a4556ac6ca411dc Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Thu, 16 Feb 2023 14:49:02 +0000 Subject: Update test script to clean previous results by default Bug: N/A Test: N/A Change-Id: I1c68f9e6fa9e9603c9c5e6d13d2dfb45a86afd81 (cherry picked from commit b82d4c2ad9a0ee0fc072d5b46abe8990fd206bc6) Merged-In: I1c68f9e6fa9e9603c9c5e6d13d2dfb45a86afd81 --- bridge/tests/run_tests.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bridge/tests/run_tests.sh b/bridge/tests/run_tests.sh index 91e88b6c94..bf338102bc 100755 --- a/bridge/tests/run_tests.sh +++ b/bridge/tests/run_tests.sh @@ -9,7 +9,7 @@ echo "BASE_DIR: $BASE_DIR" readonly FAILURE_DIR=layoutlib-test-failures readonly FAILURE_ZIP=layoutlib-test-failures.zip -readonly CLEAN_TMP_FILES=0 +readonly CLEAN_TMP_FILES=1 readonly USE_SOONG=1 readonly APP_NAME="regression" @@ -76,6 +76,7 @@ set +x # Create zip of all failure screenshots +rm -f ${OUT_DIR}/${FAILURE_ZIP} if [[ -d "${OUT_DIR}/${FAILURE_DIR}" ]]; then zip -q -j -r ${OUT_DIR}/${FAILURE_ZIP} ${OUT_DIR}/${FAILURE_DIR} fi -- cgit v1.2.3 From b97b10d60b275577b7bcfbb98049b3b2b3ebe2b3 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Thu, 16 Feb 2023 15:42:24 +0000 Subject: Assume no window transformation for Accessibility AccessibilityManager tries to figure out if the window containing the current views has been transformed in some way. To do this it calls on to AccessibilityManagerService which is not supported in layoutlib. This simply returns a default value corresponding to no window transformation. Bug: 74062470 Test: layoutlib tests Change-Id: Ib3fcbb2fcf7b48c33e6947246719537227530bd2 (cherry picked from commit 35b841ebcfaa3ae25e8b2d0283689237f8b18759) Merged-In: Ib3fcbb2fcf7b48c33e6947246719537227530bd2 --- .../AccessibilityManager_Delegate.java | 41 ++++++++++++++++++++++ .../tools/layoutlib/create/NativeConfig.java | 1 + 2 files changed, 42 insertions(+) create mode 100644 bridge/src/android/view/accessibility/AccessibilityManager_Delegate.java diff --git a/bridge/src/android/view/accessibility/AccessibilityManager_Delegate.java b/bridge/src/android/view/accessibility/AccessibilityManager_Delegate.java new file mode 100644 index 0000000000..dd5b33ab06 --- /dev/null +++ b/bridge/src/android/view/accessibility/AccessibilityManager_Delegate.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2023 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.accessibility; + +import com.android.tools.layoutlib.annotations.LayoutlibDelegate; + +import android.graphics.Matrix; +import android.view.MagnificationSpec; +import android.view.accessibility.IAccessibilityManager.WindowTransformationSpec; + +public class AccessibilityManager_Delegate { + private static WindowTransformationSpec sInstance; + + @LayoutlibDelegate + public static IAccessibilityManager.WindowTransformationSpec getWindowTransformationSpec( + AccessibilityManager thisManager, int windowId) { + if (sInstance == null) { + WindowTransformationSpec spec = new WindowTransformationSpec(); + spec.magnificationSpec = new MagnificationSpec(); + float[] matrix = new float[9]; + Matrix.IDENTITY_MATRIX.getValues(matrix); + spec.transformationMatrix = matrix; + sInstance = spec; + } + return sInstance; + } +} diff --git a/common/src/com/android/tools/layoutlib/create/NativeConfig.java b/common/src/com/android/tools/layoutlib/create/NativeConfig.java index 60a65efd95..a3e89ebdb2 100644 --- a/common/src/com/android/tools/layoutlib/create/NativeConfig.java +++ b/common/src/com/android/tools/layoutlib/create/NativeConfig.java @@ -137,6 +137,7 @@ public class NativeConfig { "android.view.View#measure", "android.view.ViewRootImpl#performHapticFeedback", "android.view.WindowManagerGlobal#getWindowManagerService", + "android.view.accessibility.AccessibilityManager#getWindowTransformationSpec", "android.view.inputmethod.InputMethodManager#hideSoftInputFromWindow", "android.view.inputmethod.InputMethodManager#isInEditMode", "android.view.inputmethod.InputMethodManager#showSoftInput", -- cgit v1.2.3 From 461ee31bc61e7ec619b2fa905f6795d1f6963597 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Thu, 16 Feb 2023 17:30:08 +0000 Subject: Fix test after move back to JDK 11 Bug: 74062470 Test: test code Change-Id: I1d00bf82f605f90380bf181f386aa9007c4cbde2 (cherry picked from commit b7e91aec2724c8d9ab5a80b55f1cc1cb19cdd5a8) Merged-In: I1d00bf82f605f90380bf181f386aa9007c4cbde2 --- .idea/misc.xml | 2 +- .../android/tools/layoutlib/create/PromoteClassClassAdapterTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 0a1e4e0324..d47ec03f54 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -53,7 +53,7 @@ - + \ No newline at end of file diff --git a/create/tests/src/com/android/tools/layoutlib/create/PromoteClassClassAdapterTest.java b/create/tests/src/com/android/tools/layoutlib/create/PromoteClassClassAdapterTest.java index 3655ec23b7..0fa7ecb764 100644 --- a/create/tests/src/com/android/tools/layoutlib/create/PromoteClassClassAdapterTest.java +++ b/create/tests/src/com/android/tools/layoutlib/create/PromoteClassClassAdapterTest.java @@ -155,7 +155,7 @@ public class PromoteClassClassAdapterTest { PromoteClassClassAdapter adapter = new PromoteClassClassAdapter(log, Set.of( PackageProtectedClass.class.getName())); reader.accept(adapter, 0); - assertTrue(log.mLog.contains("[visit] - version=61, access=[public], " + + assertTrue(log.mLog.contains("[visit] - version=55, access=[public], " + "name=com/android/tools/layoutlib/create/PackageProtectedClass, signature=null, " + "superName=java/lang/Object, interfaces=[]")); -- cgit v1.2.3 From e565c0d5769190b616866a29caec7a6fed0921e2 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Thu, 23 Feb 2023 16:56:55 +0000 Subject: Clean up accessibility cache on dispose When creating a connection to get access to accessibility info, that connection is cached. This ensures that the cache is cleaned up when the render session that created it is disposed. Bug: N/A Test: Test added Change-Id: I5c0489c252181162a3880e4c9ea4eb77f173c22d (cherry picked from commit d10ffb76edff5ee024b6b8af2e6b4ca7391eb547) Merged-In: I5c0489c252181162a3880e4c9ea4eb77f173c22d --- bridge/src/android/view/AttachInfo_Accessor.java | 4 ++++ bridge/src/android/view/ViewRootImpl_Accessor.java | 5 +++++ .../src/com/android/tools/idea/validator/LayoutValidatorTests.java | 6 ++++++ 3 files changed, 15 insertions(+) diff --git a/bridge/src/android/view/AttachInfo_Accessor.java b/bridge/src/android/view/AttachInfo_Accessor.java index cd35899c43..2e38b31793 100644 --- a/bridge/src/android/view/AttachInfo_Accessor.java +++ b/bridge/src/android/view/AttachInfo_Accessor.java @@ -46,7 +46,11 @@ public class AttachInfo_Accessor { public static void detachFromWindow(final View view) { if (view != null) { + final View.AttachInfo attachInfo = view.mAttachInfo; view.dispatchDetachedFromWindow(); + if (attachInfo != null) { + ViewRootImpl_Accessor.detachFromWindow(attachInfo.mViewRootImpl); + } } } diff --git a/bridge/src/android/view/ViewRootImpl_Accessor.java b/bridge/src/android/view/ViewRootImpl_Accessor.java index 81ffe2e324..691f59ae46 100644 --- a/bridge/src/android/view/ViewRootImpl_Accessor.java +++ b/bridge/src/android/view/ViewRootImpl_Accessor.java @@ -30,4 +30,9 @@ public class ViewRootImpl_Accessor { viewRoot.mWidth = child.getWidth(); viewRoot.mHeight = child.getHeight(); } + + public static void detachFromWindow(ViewRootImpl viewRoot) { + viewRoot.mAccessibilityInteractionConnectionManager.ensureNoConnection(); + viewRoot.mAccessibilityInteractionConnectionManager.ensureNoDirectConnection(); + } } diff --git a/bridge/tests/src/com/android/tools/idea/validator/LayoutValidatorTests.java b/bridge/tests/src/com/android/tools/idea/validator/LayoutValidatorTests.java index fd5e7f1780..a2c1ba493d 100644 --- a/bridge/tests/src/com/android/tools/idea/validator/LayoutValidatorTests.java +++ b/bridge/tests/src/com/android/tools/idea/validator/LayoutValidatorTests.java @@ -21,6 +21,7 @@ import com.android.layoutlib.bridge.android.RenderTestBase; import com.android.layoutlib.bridge.intensive.LayoutLibTestCallback; import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator; import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser; +import com.android.layoutlib.common.util.ReflectionUtils; import com.android.tools.idea.validator.ValidatorData.CompoundFix; import com.android.tools.idea.validator.ValidatorData.Issue; import com.android.tools.idea.validator.ValidatorData.Level; @@ -29,7 +30,9 @@ import com.android.tools.idea.validator.ValidatorData.Type; import org.junit.Test; +import android.util.SparseArray; import android.view.View; +import android.view.accessibility.AccessibilityInteractionClient; import java.util.ArrayList; import java.util.EnumSet; @@ -73,6 +76,9 @@ public class LayoutValidatorTests extends RenderTestBase { .build(); renderAndVerify(params, "a11y_test1.png"); + Object connectionCache = ReflectionUtils.getFieldValue(AccessibilityInteractionClient.class, + AccessibilityInteractionClient.getInstance(), "sConnectionCache"); + assertEquals(0, ((SparseArray)connectionCache).size()); } @Test -- cgit v1.2.3 From 536b7b3fe3a4d91f28d15107aa655131a029ca69 Mon Sep 17 00:00:00 2001 From: Asmita Poddar Date: Wed, 1 Mar 2023 12:53:57 +0000 Subject: Add support for InputManagerGlobal Addressing an instance where the old InputManager constructor was being used. This was done along with ag/21609952 Bug: b/267758905 Test: Pre-submit Change-Id: I2c69323d14b8cf77ebbdc49e90892bdf29ff0450 --- bridge/src/com/android/layoutlib/bridge/Bridge.java | 5 +++-- create/src/com/android/tools/layoutlib/create/CreateInfo.java | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/bridge/src/com/android/layoutlib/bridge/Bridge.java b/bridge/src/com/android/layoutlib/bridge/Bridge.java index 6e8e34301e..3c62193dad 100644 --- a/bridge/src/com/android/layoutlib/bridge/Bridge.java +++ b/bridge/src/com/android/layoutlib/bridge/Bridge.java @@ -48,6 +48,7 @@ import android.graphics.Typeface; import android.graphics.fonts.SystemFonts_Delegate; import android.hardware.input.IInputManager; import android.hardware.input.InputManager; +import android.hardware.input.InputManagerGlobal; import android.icu.util.ULocale; import android.os.Looper; import android.os.Looper_Accessor; @@ -760,8 +761,8 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { for (InputDevice device : devices) { idToDevice.append(device.getId(), device); } - InputManager.sInstance = new InputManager(new IInputManager.Default() { - @Override + InputManagerGlobal.sInstance = new InputManagerGlobal(new IInputManager.Default() { + @Override public int[] getInputDeviceIds() { return ids; } diff --git a/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/create/src/com/android/tools/layoutlib/create/CreateInfo.java index 8d93de1338..fb50c46ff1 100644 --- a/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -327,7 +327,7 @@ public final class CreateInfo implements ICreateInfo { "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT#mPendingAnimationActions", "android.graphics.drawable.AnimatedVectorDrawable#mAnimatorSet", "android.graphics.drawable.DrawableInflater#mRes", - "android.hardware.input.InputManager#sInstance", + "android.hardware.input.InputManagerGlobal#sInstance", "android.view.Choreographer#mCallbackQueues", // required for tests only "android.view.Choreographer$CallbackQueue#mHead", // required for tests only "android.view.ViewRootImpl#mTmpFrames", @@ -344,7 +344,7 @@ public final class CreateInfo implements ICreateInfo { "android.graphics.Bitmap#setNinePatchChunk", "android.graphics.Path#nInit", "android.graphics.Typeface$Builder#createAssetUid", - "android.hardware.input.InputManager#", + "android.hardware.input.InputManagerGlobal#", "android.media.ImageReader#nativeClassInit", "android.view.Choreographer#doFrame", "android.view.Choreographer#postCallbackDelayedInternal", -- cgit v1.2.3 From 93c9fd10add7c49f67f11402a6631f11164ff529 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Wed, 1 Mar 2023 15:39:53 +0000 Subject: Add no-op support for Vibrator service This uses no-op Vibrator and VibratorManager to avoid unsupported service exception. Bug: 248802205 Test: N/A Change-Id: I4f41831d0ab9abb29acee805e3206eaaf2431f57 (cherry picked from commit 139f7647b417b3ad0b9a3793e5e23683615aba82) Merged-In: I4f41831d0ab9abb29acee805e3206eaaf2431f57 --- bridge/src/android/os/NullVibratorManager.java | 52 ++++++++++++++++++++++ .../layoutlib/bridge/android/BridgeContext.java | 9 ++++ 2 files changed, 61 insertions(+) create mode 100644 bridge/src/android/os/NullVibratorManager.java diff --git a/bridge/src/android/os/NullVibratorManager.java b/bridge/src/android/os/NullVibratorManager.java new file mode 100644 index 0000000000..fe269c7d66 --- /dev/null +++ b/bridge/src/android/os/NullVibratorManager.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2023 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.os; + +public class NullVibratorManager extends VibratorManager { + private static final NullVibratorManager sInstance = new NullVibratorManager(); + + public static NullVibratorManager getInstance() { + return sInstance; + } + + private NullVibratorManager() { } + + @Override + public int[] getVibratorIds() { + return new int[0]; + } + + @Override + public Vibrator getVibrator(int vibratorId) { + return NullVibrator.getInstance(); + } + + @Override + public Vibrator getDefaultVibrator() { + return NullVibrator.getInstance(); + } + + @Override + public void vibrate(int uid, String opPkg, CombinedVibration effect, String reason, + VibrationAttributes attributes) { } + + @Override + public void cancel() { } + + @Override + public void cancel(int usageFilter) { } +} diff --git a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 3bef2fb5ce..5c27d540a6 100644 --- a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -81,12 +81,15 @@ import android.os.Handler; import android.os.IBinder; import android.os.IInterface; import android.os.Looper; +import android.os.NullVibrator; +import android.os.NullVibratorManager; import android.os.Parcel; import android.os.PowerManager; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.UserHandle; +import android.os.Vibrator; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Pair; @@ -688,6 +691,12 @@ public class BridgeContext extends Context { case INPUT_SERVICE: return InputManager.getInstance(this); + case VIBRATOR_SERVICE: + return NullVibrator.getInstance(); + + case VIBRATOR_MANAGER_SERVICE: + return NullVibratorManager.getInstance(); + case TEXT_CLASSIFICATION_SERVICE: case CONTENT_CAPTURE_MANAGER_SERVICE: case ALARM_SERVICE: -- cgit v1.2.3 From bdcbbbe6b610daa7fd6297a3d84d814d28c409c2 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Wed, 1 Mar 2023 19:49:31 +0000 Subject: Add accessibility data to ValidatorResult ATF uses AccessibilityNodeInfo in addition to View in order to detect issues. The View data was already being saved in ValidatorResult so that it could be referenced from Studio. This adds AccessibilityNodeInfo to ValidatorResult for the same purpose. Bug: 266200622 Test: tests updated Change-Id: I55968d7d14084430e029b8dba4e9ec8dc704f9b2 (cherry picked from commit c77c31d892d95dfc95ff07c0412a7d8f00274d52) Merged-In: I55968d7d14084430e029b8dba4e9ec8dc704f9b2 --- .../tools/idea/validator/LayoutValidatorTests.java | 2 ++ .../tools/idea/validator/ValidatorResultTests.java | 1 + .../tools/idea/validator/ValidatorResult.java | 20 ++++++++++++++++++-- .../android/tools/idea/validator/ValidatorUtil.java | 1 + 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/bridge/tests/src/com/android/tools/idea/validator/LayoutValidatorTests.java b/bridge/tests/src/com/android/tools/idea/validator/LayoutValidatorTests.java index a2c1ba493d..44b42aef4c 100644 --- a/bridge/tests/src/com/android/tools/idea/validator/LayoutValidatorTests.java +++ b/bridge/tests/src/com/android/tools/idea/validator/LayoutValidatorTests.java @@ -89,6 +89,8 @@ public class LayoutValidatorTests extends RenderTestBase { null, SCALE_X_FOR_NEXUS_5, SCALE_Y_FOR_NEXUS_5); + assertEquals(4, result.getSrcMap().size()); + assertEquals(4, result.getNodeInfoMap().size()); assertEquals(31, result.getIssues().size()); ArrayList errorIssues = new ArrayList<>(); for (Issue issue : result.getIssues()) { diff --git a/bridge/tests/src/com/android/tools/idea/validator/ValidatorResultTests.java b/bridge/tests/src/com/android/tools/idea/validator/ValidatorResultTests.java index 618200c921..b7e0e135f4 100644 --- a/bridge/tests/src/com/android/tools/idea/validator/ValidatorResultTests.java +++ b/bridge/tests/src/com/android/tools/idea/validator/ValidatorResultTests.java @@ -39,6 +39,7 @@ public class ValidatorResultTests { assertNotNull(result); assertTrue(result.getIssues().isEmpty()); assertTrue(result.getSrcMap().isEmpty()); + assertTrue(result.getNodeInfoMap().isEmpty()); assertNotNull(result.getMetric()); assertEquals("Result containing 0 issues:\n", result.toString()); } diff --git a/validator/src/com/android/tools/idea/validator/ValidatorResult.java b/validator/src/com/android/tools/idea/validator/ValidatorResult.java index 7f25d46489..9d708b5bdf 100644 --- a/validator/src/com/android/tools/idea/validator/ValidatorResult.java +++ b/validator/src/com/android/tools/idea/validator/ValidatorResult.java @@ -21,6 +21,7 @@ import com.android.tools.idea.validator.ValidatorData.Level; import com.android.tools.layoutlib.annotations.NotNull; import android.view.View; +import android.view.accessibility.AccessibilityNodeInfo; import java.util.ArrayList; import java.util.List; @@ -35,14 +36,21 @@ import com.google.common.collect.ImmutableBiMap; public class ValidatorResult { @NotNull private final ImmutableBiMap mSrcMap; + @NotNull private final ImmutableBiMap mNodeInfoMap; @NotNull private final ArrayList mIssues; @NotNull private final Metric mMetric; /** * Please use {@link Builder} for creating results. */ - private ValidatorResult(BiMap srcMap, ArrayList issues, Metric metric) { + private ValidatorResult(BiMap srcMap, + BiMap nodeInfoMap, + ArrayList issues, + Metric metric) { mSrcMap = ImmutableBiMap.builder().putAll(srcMap).build(); + mNodeInfoMap = ImmutableBiMap.builder() + .putAll(nodeInfoMap) + .build(); mIssues = issues; mMetric = metric; } @@ -54,6 +62,13 @@ public class ValidatorResult { return mSrcMap; } + /** + * @return the map from source ID to AccessibilityNodeInfo. + */ + public ImmutableBiMap getNodeInfoMap() { + return mNodeInfoMap; + } + /** * @return list of issues. */ @@ -89,11 +104,12 @@ public class ValidatorResult { public static class Builder { @NotNull public final BiMap mSrcMap = HashBiMap.create(); + @NotNull public final BiMap mNodeInfoMap = HashBiMap.create(); @NotNull public final ArrayList mIssues = new ArrayList<>(); @NotNull public final Metric mMetric = new Metric(); public ValidatorResult build() { - return new ValidatorResult(mSrcMap, mIssues, mMetric); + return new ValidatorResult(mSrcMap, mNodeInfoMap, mIssues, mMetric); } } diff --git a/validator/src/com/android/tools/idea/validator/ValidatorUtil.java b/validator/src/com/android/tools/idea/validator/ValidatorUtil.java index 6078046de5..f3a52e0c53 100644 --- a/validator/src/com/android/tools/idea/validator/ValidatorUtil.java +++ b/validator/src/com/android/tools/idea/validator/ValidatorUtil.java @@ -131,6 +131,7 @@ public class ValidatorUtil { hierarchy.mView = AccessibilityHierarchyAndroid .newBuilder(view) .setViewOriginMap(builder.mSrcMap) + .setNodeInfoOriginMap(builder.mNodeInfoMap) .setObtainCharacterLocations(LayoutValidator.obtainCharacterLocations()) .setCharacterLocationArgMaxLength(CHARACTER_LOCATION_ARG_MAX_LENGTH) .setCustomViewBuilder(new CustomViewBuilderAndroid() { -- cgit v1.2.3 From 62f466ab8f0a1767790680b2b559de2589979038 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Wed, 1 Mar 2023 17:49:46 +0000 Subject: Use custom parser to create ViewInfo hierarchy If a custom parser is passed to the render session, use it to build the ViewInfo hierarchy. Bug: 266200622 Test: test added Change-Id: Ib826f6885816b09305483e17a1f4bcad6dd278a1 (cherry picked from commit c55dc2e95d257a3c0c941287b4594ae8eab43d89) Merged-In: Ib826f6885816b09305483e17a1f4bcad6dd278a1 --- .../layoutlib/bridge/impl/RenderSessionImpl.java | 45 +++++++++++---------- .../layoutlib/bridge/impl/SystemViewInfo.java | 5 ++- .../bridge/android/AccessibilityTest.java | 46 ++++++++++++++++++++++ 3 files changed, 74 insertions(+), 22 deletions(-) diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index ae5e401edc..25aab92ba8 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -92,6 +92,7 @@ import java.util.ArrayList; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; +import java.util.function.Function; import static com.android.ide.common.rendering.api.Result.Status.ERROR_INFLATION; import static com.android.ide.common.rendering.api.Result.Status.ERROR_NOT_INFLATED; @@ -368,8 +369,7 @@ public class RenderSessionImpl extends RenderAction { } mSystemViewInfoList = - visitAllChildren(mViewRoot, 0, 0, params.getExtendedViewInfoMode(), - false); + visitAllChildren(mViewRoot, 0, 0, params, false); return SUCCESS.createResult(); } catch (PostInflateException e) { @@ -570,8 +570,7 @@ public class RenderSessionImpl extends RenderAction { } mSystemViewInfoList = - visitAllChildren(mViewRoot, 0, 0, params.getExtendedViewInfoMode(), - false); + visitAllChildren(mViewRoot, 0, 0, params, false); boolean enableLayoutValidation = Boolean.TRUE.equals(params.getFlag(RenderParamsFlags.FLAG_ENABLE_LAYOUT_VALIDATOR)); boolean enableLayoutValidationImageCheck = Boolean.TRUE.equals( @@ -853,15 +852,16 @@ public class RenderSessionImpl extends RenderAction { * * @return {@code ViewInfo} containing the bounds of the view and it children otherwise. */ - private ViewInfo visit(View view, int hOffset, int vOffset, boolean setExtendedInfo, + private ViewInfo visit(View view, int hOffset, int vOffset, SessionParams params, boolean isContentFrame) { - ViewInfo result = createViewInfo(view, hOffset, vOffset, setExtendedInfo, isContentFrame); + ViewInfo result = createViewInfo(view, hOffset, vOffset, params.getExtendedViewInfoMode(), + isContentFrame); if (view instanceof ViewGroup) { ViewGroup group = ((ViewGroup) view); result.setChildren(visitAllChildren(group, isContentFrame ? 0 : hOffset, isContentFrame ? 0 : vOffset, - setExtendedInfo, isContentFrame)); + params, isContentFrame)); } return result; } @@ -880,7 +880,7 @@ public class RenderSessionImpl extends RenderAction { * part of the system decor. */ private List visitAllChildren(ViewGroup viewGroup, int hOffset, int vOffset, - boolean setExtendedInfo, boolean isContentFrame) { + SessionParams params, boolean isContentFrame) { if (viewGroup == null) { return null; } @@ -896,8 +896,7 @@ public class RenderSessionImpl extends RenderAction { List childrenWithOffset = new ArrayList<>(childCount); for (int i = 0; i < childCount; i++) { ViewInfo[] childViewInfo = - visitContentRoot(viewGroup.getChildAt(i), hOffset, vOffset, - setExtendedInfo); + visitContentRoot(viewGroup.getChildAt(i), hOffset, vOffset, params); childrenWithoutOffset.add(childViewInfo[0]); childrenWithOffset.add(childViewInfo[1]); } @@ -906,7 +905,7 @@ public class RenderSessionImpl extends RenderAction { } else { List children = new ArrayList<>(childCount); for (int i = 0; i < childCount; i++) { - children.add(visit(viewGroup.getChildAt(i), hOffset, vOffset, setExtendedInfo, + children.add(visit(viewGroup.getChildAt(i), hOffset, vOffset, params, isContentFrame)); } return children; @@ -920,26 +919,32 @@ public class RenderSessionImpl extends RenderAction { * get the right bounds if the {@code ViewInfo} hierarchy is accessed from * {@code mViewInfoList}. When the hierarchy is accessed via {@code mSystemViewInfoList}, the * offset is not needed. + * If a custom parser was passed inside the {@link SessionParams} argument, this will be used + * to generate the {@link ViewInfo}s. Otherwise, {@link RenderSessionImpl#visitAllChildren} + * will be used. * * @return an array of length two, with ViewInfo at index 0 is without offset and ViewInfo at * index 1 is with the offset. */ @NonNull - private ViewInfo[] visitContentRoot(View view, int hOffset, int vOffset, - boolean setExtendedInfo) { + private ViewInfo[] visitContentRoot(View view, int hOffset, int vOffset, SessionParams params) { ViewInfo[] result = new ViewInfo[2]; if (view == null) { return result; } + boolean setExtendedInfo = params.getExtendedViewInfoMode(); result[0] = createViewInfo(view, 0, 0, setExtendedInfo, true); result[1] = createViewInfo(view, hOffset, vOffset, setExtendedInfo, true); - if (view instanceof ViewGroup) { - List children = - visitAllChildren((ViewGroup) view, 0, 0, setExtendedInfo, true); - result[0].setChildren(children); - result[1].setChildren(children); + Function> customParser = params.getCustomContentHierarchyParser(); + List children = null; + if (customParser != null) { + children = customParser.apply(view); + } else if (view instanceof ViewGroup) { + children = visitAllChildren((ViewGroup) view, 0, 0, params, true); } + result[0].setChildren(children); + result[1].setChildren(children); return result; } @@ -975,13 +980,13 @@ public class RenderSessionImpl extends RenderAction { shiftY + view.getTop(), shiftX + view.getRight(), shiftY + view.getBottom(), - view, view.getLayoutParams()); + view, null, view.getLayoutParams()); } else { // We are part of the system decor. SystemViewInfo r = new SystemViewInfo(view.getClass().getName(), getViewKey(view), view.getLeft(), view.getTop(), view.getRight(), - view.getBottom(), view, view.getLayoutParams()); + view.getBottom(), view, null, view.getLayoutParams()); result = r; // We currently mark three kinds of views: // 1. Menus in the Action Bar diff --git a/bridge/src/com/android/layoutlib/bridge/impl/SystemViewInfo.java b/bridge/src/com/android/layoutlib/bridge/impl/SystemViewInfo.java index 9fea1677d5..6f9092cc12 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/SystemViewInfo.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/SystemViewInfo.java @@ -32,8 +32,9 @@ public class SystemViewInfo extends ViewInfo { } public SystemViewInfo(String name, Object cookie, int left, int top, - int right, int bottom, Object viewObject, Object layoutParamsObject) { - super(name, cookie, left, top, right, bottom, viewObject, + int right, int bottom, Object viewObject, Object accessibilityObject, + Object layoutParamsObject) { + super(name, cookie, left, top, right, bottom, viewObject, accessibilityObject, layoutParamsObject); } diff --git a/bridge/tests/src/com/android/layoutlib/bridge/android/AccessibilityTest.java b/bridge/tests/src/com/android/layoutlib/bridge/android/AccessibilityTest.java index ed90d9b60c..149680868e 100644 --- a/bridge/tests/src/com/android/layoutlib/bridge/android/AccessibilityTest.java +++ b/bridge/tests/src/com/android/layoutlib/bridge/android/AccessibilityTest.java @@ -19,6 +19,7 @@ package com.android.layoutlib.bridge.android; import com.android.ide.common.rendering.api.RenderSession; import com.android.ide.common.rendering.api.Result; import com.android.ide.common.rendering.api.SessionParams; +import com.android.ide.common.rendering.api.ViewInfo; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.intensive.LayoutLibTestCallback; import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator; @@ -28,9 +29,12 @@ import org.junit.BeforeClass; import org.junit.Test; import android.view.View; +import android.view.ViewGroup; import android.view.accessibility.AccessibilityNodeInfo; import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -71,4 +75,46 @@ public class AccessibilityTest extends RenderTestBase { session.dispose(); } } + + @Test + public void customHierarchyParserTest() throws FileNotFoundException, + ClassNotFoundException { + LayoutPullParser parser = createParserFromPath("allwidgets.xml"); + LayoutLibTestCallback layoutLibCallback = + new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); + layoutLibCallback.initResources(); + SessionParams params = getSessionParamsBuilder() + .setParser(parser) + .setConfigGenerator(ConfigGenerator.NEXUS_5) + .setCallback(layoutLibCallback) + .build(); + params.setCustomContentHierarchyParser(viewObject -> { + List result = new ArrayList<>(); + if (viewObject instanceof ViewGroup) { + ViewGroup view = (ViewGroup)viewObject; + for (int i = 0; i < view.getChildCount(); i++) { + View child = view.getChildAt(i); + ViewInfo childInfo = + new ViewInfo(child.toString(), null, child.getLeft(), child.getTop(), + child.getRight(), child.getBottom(), child, + child.createAccessibilityNodeInfo(), null); + childInfo.setChildren(null); + result.add(childInfo); + } + } + return result; + }); + RenderSession session = sBridge.createSession(params); + try { + Result renderResult = session.render(50000); + assertTrue(renderResult.isSuccess()); + ViewInfo contentRootViewInfo = session.getRootViews().get(0); + contentRootViewInfo.getChildren().forEach(child -> { + assertNotNull(child.getAccessibilityObject()); + assertEquals(0, child.getChildren().size()); + }); + } finally { + session.dispose(); + } + } } -- cgit v1.2.3 From 386f3f90325f8ab1a256cbcdb7a2d281b5e6f458 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Fri, 3 Mar 2023 10:27:54 +0000 Subject: Update dynamic theming tests following platform change The platform changed the definition of the neutral 1 tone for dynamic colours. This updates the relevant tests. Bug: 74062470 Test: tests updated Change-Id: I195d1ec55cf4efec751bbe1a9a1cce0f827c413e --- .../src/com/android/layoutlib/bridge/android/BridgeContextTest.java | 4 ++-- .../layoutlib/bridge/android/DynamicRenderResourcesTest.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeContextTest.java b/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeContextTest.java index b12adc93e4..6aca0d816f 100644 --- a/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeContextTest.java +++ b/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeContextTest.java @@ -174,12 +174,12 @@ public class BridgeContextTest extends RenderTestBase { ((DynamicRenderResources) context.getRenderResources()).setWallpaper( "/com/android/layoutlib/testdata/wallpaper1.webp", configuration.isNightModeActive()); - assertEquals(-13226195, context.getResources().getColor(android.R.color.system_neutral1_800, null)); + assertEquals(-13029845, context.getResources().getColor(android.R.color.system_neutral1_800, null)); ((DynamicRenderResources) context.getRenderResources()).setWallpaper( "/com/android/layoutlib/testdata/wallpaper2.webp", configuration.isNightModeActive()); - assertEquals(-13749969, context.getResources().getColor(android.R.color.system_neutral1_800, null)); + assertEquals(-13946321, context.getResources().getColor(android.R.color.system_neutral1_800, null)); } finally { context.disposeResources(); } diff --git a/bridge/tests/src/com/android/layoutlib/bridge/android/DynamicRenderResourcesTest.java b/bridge/tests/src/com/android/layoutlib/bridge/android/DynamicRenderResourcesTest.java index 16a809b3e7..ec7aa768fd 100644 --- a/bridge/tests/src/com/android/layoutlib/bridge/android/DynamicRenderResourcesTest.java +++ b/bridge/tests/src/com/android/layoutlib/bridge/android/DynamicRenderResourcesTest.java @@ -50,9 +50,9 @@ public class DynamicRenderResourcesTest extends RenderTestBase { assertEquals(-4478092, (int)dynamicColorMap.get("system_accent3_300")); assertEquals(-12963835, (int)dynamicColorMap.get("system_accent3_800")); assertEquals(-1, (int)dynamicColorMap.get("system_neutral1_0")); - assertEquals(-266518, (int)dynamicColorMap.get("system_neutral1_50")); - assertEquals(-4937306, (int)dynamicColorMap.get("system_neutral1_300")); - assertEquals(-13226195, (int)dynamicColorMap.get("system_neutral1_800")); + assertEquals(-4632, (int)dynamicColorMap.get("system_neutral1_50")); + assertEquals(-4675421, (int)dynamicColorMap.get("system_neutral1_300")); + assertEquals(-13029845, (int)dynamicColorMap.get("system_neutral1_800")); assertEquals(-1, (int)dynamicColorMap.get("system_neutral2_0")); assertEquals(-4632, (int)dynamicColorMap.get("system_neutral2_50")); assertEquals(-4413535, (int)dynamicColorMap.get("system_neutral2_300")); -- cgit v1.2.3 From 6fcb3c69b4c0e984f71e407311118a16254f63ff Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Tue, 7 Mar 2023 12:20:54 +0000 Subject: Use theme when rendering drawable using RenderDrawable This ensures that drawables defined using theme attributes can be rendered. Fixes: 223815263 Test: Tested from Studio Change-Id: Ic54def92ae9b90bd62554e3b0daeda43959ad26c (cherry picked from commit on googleplex-android-review.googlesource.com host: 47ceaa28790da47454ea882dfa842703a12c7ba7) Merged-In: Ic54def92ae9b90bd62554e3b0daeda43959ad26c --- bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java index 6a6e184617..f66734906c 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java @@ -78,7 +78,7 @@ public class RenderDrawable extends RenderAction { return Status.ERROR_NOT_A_DRAWABLE.createResult(); } - Drawable d = ResourceHelper.getDrawable(drawableResource, context); + Drawable d = ResourceHelper.getDrawable(drawableResource, context, context.getTheme()); if (d == null) { return Status.ERROR_NOT_A_DRAWABLE.createResult(); } -- cgit v1.2.3 From dbb075065d3d3365948bc5b810be32b8395e50c5 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Tue, 7 Mar 2023 16:35:32 +0000 Subject: Modify scaling for RenderDrawable When rendering a drawable, this first renders it full size and then uses bitmap scaling to potentially downscale it to the required size. This ensures that the full drawable is visable in the end, as trying to render on a smaller image at first can sometimes result in only a small part of the original drawable being rendered. In addition, this cleans up the conversion between Bitmap and BufferedImage to avoid unnecessary allocations. Fixes: 173833413 Test: Tested from Studio Change-Id: I49e0b09144f35aeecbfe7071a4a3e91c63f32590 (cherry picked from commit on googleplex-android-review.googlesource.com host: db2d1d5bdd8c2b1e74e00452daf2c99af6e579db) Merged-In: I49e0b09144f35aeecbfe7071a4a3e91c63f32590 --- .../layoutlib/bridge/impl/RenderDrawable.java | 54 ++++++---------------- 1 file changed, 15 insertions(+), 39 deletions(-) diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java index f66734906c..0dd35ce055 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java @@ -39,6 +39,7 @@ import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Graphics2D; import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -128,15 +129,6 @@ public class RenderDrawable extends RenderAction { // Use screen size when either intrinsic width or height isn't available. w = screenWidth; h = screenHeight; - } else if (w > screenWidth || h > screenHeight) { - // If image wouldn't fit to the screen, resize it to avoid cropping. - - // We need to find scale such that scale * w <= screenWidth, scale * h <= screenHeight. - double scale = Math.min((double) screenWidth / w, (double) screenHeight / h); - - // scale * w / scale * h = w / h, so, proportions are preserved. - w = (int) Math.floor(scale * w); - h = (int) Math.floor(scale * h); } int w_spec = MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY); @@ -149,46 +141,30 @@ public class RenderDrawable extends RenderAction { // Pre-draw setup. AttachInfo_Accessor.dispatchOnPreDraw(content); - // Draw into a new image. - BufferedImage image = getImage(w, h); - - // Create an Android bitmap around the BufferedImage. - Bitmap bitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), - Config.ARGB_8888); - bitmap.setPixels(image.getRGB(0, 0, image.getWidth(), image.getHeight(), - null, 0, image.getWidth()), 0, image.getWidth(), 0, 0, image - .getWidth(), image.getHeight()); - - // Create a Canvas around the Android bitmap. + Bitmap bitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); canvas.setDensity(hardwareConfig.getDensity().getDpiValue()); // Draw. content.draw(canvas); - int[] pixels = new int[image.getWidth() * image.getHeight()]; - bitmap.getPixels(pixels, 0, image.getWidth(), 0, 0, image.getWidth(), - image.getHeight()); - image.setRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth()); - // Detach root from window after draw. - AttachInfo_Accessor.detachFromWindow(content); + if (w > screenWidth || h > screenHeight) { + // If image wouldn't fit to the screen, resize it to avoid cropping. - return image; - } + // We need to find scale such that scale * w <= screenWidth, scale * h <= screenHeight. + double scale = Math.min((double) screenWidth / w, (double) screenHeight / h); + bitmap = Bitmap.createScaledBitmap(bitmap, (int) (w * scale), (int) (h * scale), true); + } - @NonNull - protected BufferedImage getImage(int w, int h) { - BufferedImage image = new BufferedImage(w > 0 ? w : 1, - h > 0 ? h : 1, + // Copy bitmap into BufferedImage. + BufferedImage image = new BufferedImage(bitmap.getWidth(), bitmap.getHeight(), BufferedImage.TYPE_INT_ARGB); - Graphics2D gc = image.createGraphics(); - gc.setComposite(AlphaComposite.Src); - - gc.setColor(new Color(0x00000000, true)); - gc.fillRect(0, 0, w, h); + int[] imageData = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); + bitmap.getPixels(imageData, 0, image.getWidth(), 0, 0, image.getWidth(), + image.getHeight()); - // done - gc.dispose(); + // Detach root from window after draw. + AttachInfo_Accessor.detachFromWindow(content); return image; } -- cgit v1.2.3 From 5bc63d0dfe779e12f5066c27f106cb82f130da9b Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Mon, 13 Mar 2023 19:13:00 +0000 Subject: Consider windowLightStatusBar for building the status bar It alters the foreground of the status bar to be what it would have been for a light theme even if it's not a light theme. Bug: 241581120 Test: test added Change-Id: I1a73ac96df5529a20b6104f189fa4db65bad5d87 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:31303581a30684dfe21897f4dbe7161591451869) Merged-In: I1a73ac96df5529a20b6104f189fa4db65bad5d87 --- .../android/layoutlib/bridge/bars/CustomBar.java | 46 ++--------------- .../android/layoutlib/bridge/bars/StatusBar.java | 57 ++++++++++++++++++--- .../layoutlib/bridge/resources/SysUiResources.java | 8 ++- .../MyApplication/golden/dark_status_bar.png | Bin 0 -> 32362 bytes .../MyApplication/golden/light_status_bar.png | Bin 0 -> 31660 bytes .../MyApplication/src/main/res/values/styles.xml | 9 ++++ .../layoutlib/bridge/intensive/RenderTests.java | 36 +++++++++++++ 7 files changed, 103 insertions(+), 53 deletions(-) create mode 100644 bridge/tests/res/testApp/MyApplication/golden/dark_status_bar.png create mode 100644 bridge/tests/res/testApp/MyApplication/golden/light_status_bar.png diff --git a/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java index 63efec36f1..defea14b29 100644 --- a/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java +++ b/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java @@ -24,18 +24,13 @@ import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.android.BridgeContext; import com.android.layoutlib.bridge.android.BridgeXmlBlockParser; import com.android.layoutlib.bridge.impl.ResourceHelper; -import com.android.layoutlib.bridge.resources.IconLoader; import com.android.layoutlib.bridge.resources.SysUiResources; import com.android.resources.Density; -import com.android.resources.LayoutDirection; import com.android.resources.ResourceType; import android.annotation.NonNull; import android.content.res.ColorStateList; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.BitmapFactory.Options; -import android.graphics.drawable.BitmapDrawable; +import android.graphics.Color; import android.graphics.drawable.Drawable; import android.util.TypedValue; import android.view.Gravity; @@ -45,8 +40,6 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; -import java.io.InputStream; - import static android.os._Original_Build.VERSION_CODES.LOLLIPOP; /** @@ -88,9 +81,9 @@ abstract class CustomBar extends LinearLayout { layoutName); } - protected ImageView loadIcon(ImageView imageView, String iconName, Density density) { + protected ImageView loadIcon(ImageView imageView, String iconName, Density density, int color) { return SysUiResources.loadIcon(mContext, mSimulatedPlatformVersion, imageView, iconName, - density, false); + density, false, color); } protected ImageView loadIcon(int index, String iconName, Density density, boolean isRtl) { @@ -98,39 +91,12 @@ abstract class CustomBar extends LinearLayout { if (child instanceof ImageView) { ImageView imageView = (ImageView) child; return SysUiResources.loadIcon(mContext, mSimulatedPlatformVersion, imageView, iconName, - density, isRtl); + density, isRtl, Color.WHITE); } return null; } - protected ImageView loadIcon(ImageView imageView, String iconName, Density density, - boolean isRtl) { - LayoutDirection dir = isRtl ? LayoutDirection.RTL : null; - IconLoader iconLoader = new IconLoader(iconName, density, mSimulatedPlatformVersion, dir); - InputStream stream = iconLoader.getIcon(); - - if (stream != null) { - density = iconLoader.getDensity(); - String path = iconLoader.getPath(); - // look for a cached bitmap - Bitmap bitmap = Bridge.getCachedBitmap(path, Boolean.TRUE /*isFramework*/); - if (bitmap == null) { - Options options = new Options(); - options.inDensity = density.getDpiValue(); - bitmap = BitmapFactory.decodeStream(stream, null, options); - Bridge.setCachedBitmap(path, bitmap, Boolean.TRUE /*isFramework*/); - } - - if (bitmap != null) { - BitmapDrawable drawable = new BitmapDrawable(getContext().getResources(), bitmap); - imageView.setImageDrawable(drawable); - } - } - - return imageView; - } - protected TextView setText(int index, String string) { View child = getChildAt(index); if (child instanceof TextView) { @@ -247,9 +213,7 @@ abstract class CustomBar extends LinearLayout { resource = renderResources.resolveResValue(resource); if (resource != null) { ResourceType type = resource.getResourceType(); - if (type == null || type == ResourceType.COLOR) { - // if no type is specified, the value may have been specified directly in the style - // file, rather than referencing a color resource value. + if (type == ResourceType.STYLE_ITEM || type == ResourceType.COLOR) { try { return ResourceHelper.getColor(resource.getValue()); } catch (NumberFormatException e) { diff --git a/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java b/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java index dc823f7e37..c39ec8b704 100644 --- a/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java +++ b/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java @@ -17,11 +17,13 @@ package com.android.layoutlib.bridge.bars; import com.android.ide.common.rendering.api.ILayoutLog; +import com.android.ide.common.rendering.api.RenderResources; import com.android.ide.common.rendering.api.ResourceNamespace; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.android.BridgeContext; import com.android.layoutlib.bridge.android.BridgeXmlBlockParser; import com.android.layoutlib.bridge.impl.ParserFactory; +import com.android.layoutlib.bridge.impl.ResourceHelper; import com.android.layoutlib.bridge.resources.IconLoader; import com.android.resources.Density; @@ -42,9 +44,24 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import static android.graphics.Color.WHITE; +import static android.os._Original_Build.VERSION_CODES.M; +import static com.android.layoutlib.bridge.bars.Config.getTimeColor; +import static com.android.layoutlib.bridge.bars.Config.isGreaterOrEqual; + public class StatusBar extends CustomBar { private final int mSimulatedPlatformVersion; + /** + * Color corresponding to light_mode_icon_color_single_tone + * from frameworks/base/packages/SettingsLib/res/values/colors.xml + */ + private static final int LIGHT_ICON_COLOR = 0xffffffff; + /** + * Color corresponding to dark_mode_icon_color_single_tone + * from frameworks/base/packages/SettingsLib/res/values/colors.xml + */ + private static final int DARK_ICON_COLOR = 0x99000000; /** Status bar background color attribute name. */ private static final String ATTR_COLOR = "statusBarColor"; /** Attribute for translucency property. */ @@ -95,20 +112,45 @@ public class StatusBar extends CustomBar { return; } + int foregroundColor = getForegroundColor(simulatedPlatformVersion); // Cannot access the inside items through id because no R.id values have been // created for them. // We do know the order though. loadIcon(icons.get(0), "stat_sys_wifi_signal_4_fully." - + Config.getWifiIconType(simulatedPlatformVersion), density); - loadIcon(icons.get(1), "stat_sys_battery_100.png", density); + + Config.getWifiIconType(simulatedPlatformVersion), density,foregroundColor); + loadIcon(icons.get(1), "stat_sys_battery_100.png", density, foregroundColor); clockView.setText(Config.getTime(simulatedPlatformVersion)); - clockView.setTextColor(Config.getTimeColor(simulatedPlatformVersion)); + clockView.setTextColor(foregroundColor); + } + + private int getForegroundColor(int platformVersion) { + if (isGreaterOrEqual(platformVersion, M)) { + RenderResources renderResources = getContext().getRenderResources(); + boolean translucentBackground = + ResourceHelper.getBooleanThemeFrameworkAttrValue(renderResources, + ATTR_TRANSLUCENT, false); + if (translucentBackground) { + return WHITE; + } + boolean drawnByWindow = + ResourceHelper.getBooleanThemeFrameworkAttrValue(renderResources, + "windowDrawsSystemBarBackgrounds", false); + if (drawnByWindow) { + boolean lightStatusBar = + ResourceHelper.getBooleanThemeFrameworkAttrValue(renderResources, + "windowLightStatusBar", false); + return lightStatusBar ? DARK_ICON_COLOR : LIGHT_ICON_COLOR; + } + return WHITE; + } else { + return getTimeColor(platformVersion); + } } @Override - protected ImageView loadIcon(ImageView imageView, String iconName, Density density) { + protected ImageView loadIcon(ImageView imageView, String iconName, Density density, int color) { if (!iconName.endsWith(".xml")) { - return super.loadIcon(imageView, iconName, density); + return super.loadIcon(imageView, iconName, density, color); } // The xml is stored only in xhdpi. @@ -123,8 +165,9 @@ public class StatusBar extends CustomBar { ParserFactory.create(stream, iconName), (BridgeContext) mContext, ResourceNamespace.ANDROID); - imageView.setImageDrawable( - Drawable.createFromXml(mContext.getResources(), parser)); + Drawable drawable = Drawable.createFromXml(mContext.getResources(), parser); + drawable.setTint(color); + imageView.setImageDrawable(drawable); } catch (XmlPullParserException e) { Bridge.getLog().error(ILayoutLog.TAG_BROKEN, "Unable to draw wifi icon", e, null, null); diff --git a/bridge/src/com/android/layoutlib/bridge/resources/SysUiResources.java b/bridge/src/com/android/layoutlib/bridge/resources/SysUiResources.java index 84ed6a04c4..f8884d4b2e 100644 --- a/bridge/src/com/android/layoutlib/bridge/resources/SysUiResources.java +++ b/bridge/src/com/android/layoutlib/bridge/resources/SysUiResources.java @@ -36,7 +36,6 @@ import android.graphics.BitmapFactory.Options; import android.graphics.drawable.BitmapDrawable; import android.widget.ImageView; -import java.io.IOException; import java.io.InputStream; public class SysUiResources { @@ -67,10 +66,8 @@ public class SysUiResources { return null; } - public static ImageView loadIcon(Context context, int api, ImageView imageView, String - iconName, - Density density, boolean - isRtl) { + public static ImageView loadIcon(Context context, int api, ImageView imageView, + String iconName, Density density, boolean isRtl, int color) { LayoutDirection dir = isRtl ? LayoutDirection.RTL : null; IconLoader iconLoader = new IconLoader(iconName, density, api, dir); @@ -90,6 +87,7 @@ public class SysUiResources { if (bitmap != null) { BitmapDrawable drawable = new BitmapDrawable(context.getResources(), bitmap); + drawable.setTint(color); imageView.setImageDrawable(drawable); } } diff --git a/bridge/tests/res/testApp/MyApplication/golden/dark_status_bar.png b/bridge/tests/res/testApp/MyApplication/golden/dark_status_bar.png new file mode 100644 index 0000000000..f7c1f9610a Binary files /dev/null and b/bridge/tests/res/testApp/MyApplication/golden/dark_status_bar.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/light_status_bar.png b/bridge/tests/res/testApp/MyApplication/golden/light_status_bar.png new file mode 100644 index 0000000000..1391b2ec02 Binary files /dev/null and b/bridge/tests/res/testApp/MyApplication/golden/light_status_bar.png differ diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml index 7b338d1dc6..d75aab1c1c 100644 --- a/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml +++ b/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml @@ -16,4 +16,13 @@ @drawable/theme_attribute_drawable + + + + diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java index 7b9c163634..a8b01e0825 100644 --- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java +++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java @@ -2130,4 +2130,40 @@ public class RenderTests extends RenderTestBase { renderAndVerify(params, "html.png", TimeUnit.SECONDS.toNanos(2)); } + + @Test + public void testStatusBar() throws ClassNotFoundException { + final String layout = + "\n" + "\n" + + " \n" + + ""; + // Create LayoutLibCallback. + LayoutLibTestCallback layoutLibCallback = + new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); + layoutLibCallback.initResources(); + + SessionParams params = getSessionParamsBuilder() + .setParser(LayoutPullParser.createFromString(layout)) + .setCallback(layoutLibCallback) + .setTheme("DarkStatusBarTheme", true) + .setRenderingMode(RenderingMode.V_SCROLL) + .build(); + + renderAndVerify(params, "dark_status_bar.png", TimeUnit.SECONDS.toNanos(2)); + + params = getSessionParamsBuilder() + .setParser(LayoutPullParser.createFromString(layout)) + .setCallback(layoutLibCallback) + .setTheme("LightStatusBarTheme", true) + .setRenderingMode(RenderingMode.V_SCROLL) + .build(); + + renderAndVerify(params, "light_status_bar.png", TimeUnit.SECONDS.toNanos(2)); + } } -- cgit v1.2.3 From 55278e53dac5fa605013d548d1677706535a26bd Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Wed, 15 Mar 2023 15:22:46 +0000 Subject: Update golden images Bug: 74062470 Test: layoutlib tests Change-Id: I37da3bf2588e6880295a40c128ab88b88be7aebc --- .../MyApplication/golden/dark_status_bar.png | Bin 32362 -> 27186 bytes .../MyApplication/golden/light_status_bar.png | Bin 31660 -> 26769 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bridge/tests/res/testApp/MyApplication/golden/dark_status_bar.png b/bridge/tests/res/testApp/MyApplication/golden/dark_status_bar.png index f7c1f9610a..34ff1adccf 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/dark_status_bar.png and b/bridge/tests/res/testApp/MyApplication/golden/dark_status_bar.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/light_status_bar.png b/bridge/tests/res/testApp/MyApplication/golden/light_status_bar.png index 1391b2ec02..a37d8dee26 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/light_status_bar.png and b/bridge/tests/res/testApp/MyApplication/golden/light_status_bar.png differ -- cgit v1.2.3 From 4d70ebd8368ceec229c447ffffdbead124c4a19a Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Mon, 20 Mar 2023 12:38:29 +0000 Subject: Update status bar time for Android 14 Bug: N/A Test: N/A Change-Id: Ieaaece82de00702346515a8d5f90dfb7c565b2f2 --- bridge/src/com/android/layoutlib/bridge/bars/Config.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bridge/src/com/android/layoutlib/bridge/bars/Config.java b/bridge/src/com/android/layoutlib/bridge/bars/Config.java index d89960ea68..794990852a 100644 --- a/bridge/src/com/android/layoutlib/bridge/bars/Config.java +++ b/bridge/src/com/android/layoutlib/bridge/bars/Config.java @@ -92,8 +92,8 @@ public class Config { } public static String getTime(int platformVersion) { - if (isGreaterOrEqual(platformVersion, TIRAMISU)) { - return "13:00"; + if (isGreaterOrEqual(platformVersion, UPSIDE_DOWN_CAKE)) { + return "14:00"; } if (platformVersion < GINGERBREAD) { return "2:20"; @@ -143,6 +143,9 @@ public class Config { if (platformVersion < TIRAMISU) { return "12:00"; } + if (platformVersion < UPSIDE_DOWN_CAKE) { + return "13:00"; + } // Should never happen. return "4:04"; } -- cgit v1.2.3 From 1f2858819d5a2cf2c53b1754c7425f88c5413922 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Date: Tue, 21 Mar 2023 15:50:08 +0000 Subject: Updated BridgeContentProvider#getStreamTypes with attributionSource Test: build Bug: b/274595210 Change-Id: I8b53bfe9c90d27e0cff3ce67dbd7cde12f47921f --- .../com/android/layoutlib/bridge/android/BridgeContentProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java b/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java index cc060a9b52..a194dc5b1b 100644 --- a/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java +++ b/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java @@ -159,7 +159,8 @@ public final class BridgeContentProvider implements IContentProvider { } @Override - public String[] getStreamTypes(Uri arg0, String arg1) throws RemoteException { + public String[] getStreamTypes(AttributionSource attributionSource, Uri arg0, String arg1) + throws RemoteException { // TODO Auto-generated method stub return null; } -- cgit v1.2.3 From 3e28cd5a7746197eeceb91230da9580b7b0a1440 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Fri, 31 Mar 2023 13:31:47 +0100 Subject: Add static field to set custom Sdk version This is to be accessed from user or library code when running inside Studio. That will be used instead of the SDK_INT version coming from layoutlib. Bug: 250806506 Test: N/A (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:42294a5111ae4ee6a788865b9b286d197a0971c8) Merged-In: I8527e918569f5b60102ba2f6bbae4789ba01f17a Change-Id: I8527e918569f5b60102ba2f6bbae4789ba01f17a --- bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java | 8 ++++++++ .../src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java index c2430a8959..4288c9fa37 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java @@ -51,6 +51,7 @@ import java.util.WeakHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; +import static android.os._Original_Build.VERSION.SDK_INT; import static com.android.ide.common.rendering.api.Result.Status.ERROR_LOCK_INTERRUPTED; import static com.android.ide.common.rendering.api.Result.Status.ERROR_TIMEOUT; import static com.android.ide.common.rendering.api.Result.Status.SUCCESS; @@ -68,6 +69,12 @@ import static com.android.ide.common.rendering.api.Result.Status.SUCCESS; * */ public abstract class RenderAction { + /** + * Static field to store an SDK version coming from the render configuration. + * This is to be accessed when wanting to know the simulated SDK version instead + * of Build.VERSION.SDK_INT. + */ + public static int sSimulatedSdk; private static final Set COMPOSE_CLASS_FQNS = Set.of("androidx.compose.ui.tooling.ComposeViewAdapter", @@ -99,6 +106,7 @@ public abstract class RenderAction { */ protected RenderAction(T params) { mParams = params; + sSimulatedSdk = SDK_INT; } /** diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index 25aab92ba8..082ea1444a 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -94,6 +94,7 @@ import java.util.List; import java.util.Map; import java.util.function.Function; +import static android.os._Original_Build.VERSION.SDK_INT; import static com.android.ide.common.rendering.api.Result.Status.ERROR_INFLATION; import static com.android.ide.common.rendering.api.Result.Status.ERROR_NOT_INFLATED; import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN; @@ -311,6 +312,9 @@ public class RenderSessionImpl extends RenderAction { SessionParams params = getParams(); BridgeContext context = getContext(); + int simulatedVersion = params.getSimulatedPlatformVersion(); + sSimulatedSdk = simulatedVersion > 0 ? simulatedVersion : SDK_INT; + if (Bridge.isLocaleRtl(params.getLocale())) { if (!params.isRtlSupported()) { Bridge.getLog().warning(ILayoutLog.TAG_RTL_NOT_ENABLED, @@ -480,6 +484,9 @@ public class RenderSessionImpl extends RenderAction { SessionParams params = getParams(); + int simulatedVersion = params.getSimulatedPlatformVersion(); + sSimulatedSdk = simulatedVersion > 0 ? simulatedVersion : SDK_INT; + try { if (mViewRoot == null) { return ERROR_NOT_INFLATED.createResult(); -- cgit v1.2.3 From 5826c0171c448f09bbfe86156226f600ba71c368 Mon Sep 17 00:00:00 2001 From: Diego Perez Date: Wed, 5 Apr 2023 13:47:56 +0000 Subject: Return defaultValue in resolveResValue BridgeXmlPullAttributes.resolveResValue never returned the default value when the attribute could not be resolved. This updates the resolution to handle that case. Bug: 277034283 Test: BridgeXmlPullAttributesTest Change-Id: I478efb7686bdec3d5ea5a70088f14725bd6b8b9a --- .../src/android/util/BridgeXmlPullAttributes.java | 3 + .../android/util/BridgeXmlPullAttributesTest.java | 78 ++++++++++++++-------- 2 files changed, 55 insertions(+), 26 deletions(-) diff --git a/bridge/src/android/util/BridgeXmlPullAttributes.java b/bridge/src/android/util/BridgeXmlPullAttributes.java index 8a78fa3843..07bc437b12 100644 --- a/bridge/src/android/util/BridgeXmlPullAttributes.java +++ b/bridge/src/android/util/BridgeXmlPullAttributes.java @@ -151,6 +151,9 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes implements Resolv @Override public int getAttributeResourceValue(String namespace, String attribute, int defaultValue) { String value = getAttributeValue(namespace, attribute); + if (value == null) { + return defaultValue; + } return resolveResourceValue(value, defaultValue); } diff --git a/bridge/tests/src/android/util/BridgeXmlPullAttributesTest.java b/bridge/tests/src/android/util/BridgeXmlPullAttributesTest.java index f995d1abaa..a40dfed432 100644 --- a/bridge/tests/src/android/util/BridgeXmlPullAttributesTest.java +++ b/bridge/tests/src/android/util/BridgeXmlPullAttributesTest.java @@ -20,8 +20,10 @@ import com.android.ide.common.rendering.api.LayoutlibCallback; import com.android.ide.common.rendering.api.RenderResources; import com.android.ide.common.rendering.api.ResourceNamespace; import com.android.ide.common.rendering.api.ResourceNamespace.Resolver; +import com.android.ide.common.rendering.api.ResourceValue; import com.android.layoutlib.bridge.BridgeConstants; import com.android.layoutlib.bridge.android.BridgeContext; +import com.android.tools.layoutlib.annotations.NotNull; import org.junit.Test; import org.xmlpull.v1.XmlPullParser; @@ -34,12 +36,10 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class BridgeXmlPullAttributesTest { - - @Test - public void testGetAttributeIntValueForEnums() { - RenderResources renderResources = new RenderResources(); - + @NotNull + private static XmlPullParser prepareParser() { XmlPullParser parser = mock(XmlPullParser.class); + when(parser.getAttributeValue(BridgeConstants.NS_RESOURCES, "layout_width")) .thenReturn("match_parent"); when(parser.getAttributeName(0)).thenReturn("layout_width"); @@ -50,34 +50,53 @@ public class BridgeXmlPullAttributesTest { when(parser.getAttributeName(1)).thenReturn("my_custom_attr"); when(parser.getAttributeNamespace(1)).thenReturn(BridgeConstants.NS_APP_RES_AUTO); + return parser; + } + + @NotNull + private static BridgeContext prepareContext() { BridgeContext context = mock(BridgeContext.class); + RenderResources renderResources = new RenderResources() { + @Override + public ResourceValue resolveResValue(ResourceValue value) { + // Simulate behaviour from the actual resolver where a failed resolution will + // return the passed value. + return value; + } + }; when(context.getRenderResources()).thenReturn(renderResources); - LayoutlibCallback callback = mock(LayoutlibCallback.class); when(callback.getImplicitNamespaces()).thenReturn(Resolver.EMPTY_RESOLVER); when(context.getLayoutlibCallback()).thenReturn(callback); - BridgeXmlPullAttributes attributes = new BridgeXmlPullAttributes( - parser, - context, - ResourceNamespace.RES_AUTO, - attrName -> { - if ("layout_width".equals(attrName)) { - return ImmutableMap.of( - "match_parent", 123); - } - return ImmutableMap.of(); - }, - (ns, attrName) -> { - if ("my_custom_attr".equals(attrName)) { - return ImmutableMap.of( - "a", 1, - "b", 2 - ); - } - return ImmutableMap.of(); - }); + return context; + } + + private final XmlPullParser parser = prepareParser(); + private final BridgeContext context = prepareContext(); + private final BridgeXmlPullAttributes attributes = new BridgeXmlPullAttributes( + parser, + context, + ResourceNamespace.RES_AUTO, + attrName -> { + if ("layout_width".equals(attrName)) { + return ImmutableMap.of( + "match_parent", 123); + } + return ImmutableMap.of(); + }, + (ns, attrName) -> { + if ("my_custom_attr".equals(attrName)) { + return ImmutableMap.of( + "a", 1, + "b", 2 + ); + } + return ImmutableMap.of(); + }); + @Test + public void testGetAttributeIntValueForEnums() { // Test a framework defined enum attribute assertEquals(123, attributes.getAttributeIntValue(BridgeConstants.NS_RESOURCES, "layout_width", 500)); @@ -115,4 +134,11 @@ public class BridgeXmlPullAttributesTest { "my_other_attr", 500)); } + @Test + public void testNotExistingAttributes() { + assertEquals(501, attributes.getAttributeUnsignedIntValue(BridgeConstants.NS_APP_RES_AUTO, + "my_other_attr", 501)); + assertEquals(502, attributes.getAttributeResourceValue(BridgeConstants.NS_APP_RES_AUTO, + "my_other_attr", 502)); + } } -- cgit v1.2.3 From 3bf90dc5aacd1551cc21df9168529d3eb870c47b Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Mon, 17 Apr 2023 14:27:30 +0100 Subject: Update golden image This follows a change in the underlying platform code. Bug: 74062470 Test: layoutlib test Change-Id: Ifd2ef3adefea602d1341f2677cb846df5b432677 --- .../testApp/MyApplication/golden/bitmap_decoder.png | Bin 1567 -> 1573 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bridge/tests/res/testApp/MyApplication/golden/bitmap_decoder.png b/bridge/tests/res/testApp/MyApplication/golden/bitmap_decoder.png index 20f15a9ecd..5be2d1a800 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/bitmap_decoder.png and b/bridge/tests/res/testApp/MyApplication/golden/bitmap_decoder.png differ -- cgit v1.2.3 From c3b50fcc5d68c57f92643ed487256c9537f55c3b Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Fri, 21 Apr 2023 15:13:47 +0100 Subject: Update mac binary splitting script This ensures that the destination directory is created by this script if it doesn't exist. Bug: 74062470 Test: N/A Change-Id: I1e11dc1d055aefe8b066094b8236d629aacde41b --- split_universal_binary.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/split_universal_binary.sh b/split_universal_binary.sh index bd57245a7a..55b5b3829b 100755 --- a/split_universal_binary.sh +++ b/split_universal_binary.sh @@ -26,6 +26,7 @@ done # Put the single architecture binaries inside the DIST folder to be accessible on ab/ if [[ -d "${DIST_DIR}" ]]; then + mkdir -p ${DIST_DIR}/layoutlib_native/darwin cp -r ${OUT_DIR}/${ARM} ${DIST_DIR}/layoutlib_native/darwin cp -r ${OUT_DIR}/${X86} ${DIST_DIR}/layoutlib_native/darwin fi -- cgit v1.2.3 From d1a10d93b31e0076c3aa52bac450c6c8bab07bca Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Tue, 23 May 2023 18:53:44 +0100 Subject: Set max bounds for window configuration This sets the window configuration max bounds to be the size of the screen to be displayed. Those max bounds represent the size of the software layer that can be used to draw views that specify they are to be drawn in a software layer. Bug: 282993669 Test: test added (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:4699f9fa49cb0c2d0faed809999d214f0fcf4109) Merged-In: Iae8d169bf1307283592d31e74c25e3ecc594d49b Change-Id: Iae8d169bf1307283592d31e74c25e3ecc594d49b --- .../android/content/res/Resources_Delegate.java | 2 + .../MyApplication/golden/software_layer.png | Bin 0 -> 17458 bytes .../myapplication.widgets/SoftwareTextView.java | 52 +++++++++++++++++++++ .../layoutlib/bridge/intensive/RenderTests.java | 30 ++++++++++++ 4 files changed, 84 insertions(+) create mode 100644 bridge/tests/res/testApp/MyApplication/golden/software_layer.png create mode 100644 bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/SoftwareTextView.java diff --git a/bridge/src/android/content/res/Resources_Delegate.java b/bridge/src/android/content/res/Resources_Delegate.java index 7aa02f9464..4eb6bddeed 100644 --- a/bridge/src/android/content/res/Resources_Delegate.java +++ b/bridge/src/android/content/res/Resources_Delegate.java @@ -87,6 +87,8 @@ public class Resources_Delegate { "Resources_Delegate.initSystem called twice before disposeSystem was called"; Resources resources = new Resources(Resources_Delegate.class.getClassLoader()); resources.setImpl(new ResourcesImpl(assets, metrics, config, new DisplayAdjustments())); + resources.getConfiguration().windowConfiguration.setMaxBounds(0, 0, metrics.widthPixels, + metrics.heightPixels); sContexts.put(resources, Objects.requireNonNull(context)); sLayoutlibCallbacks.put(resources, Objects.requireNonNull(layoutlibCallback)); return Resources.mSystem = resources; diff --git a/bridge/tests/res/testApp/MyApplication/golden/software_layer.png b/bridge/tests/res/testApp/MyApplication/golden/software_layer.png new file mode 100644 index 0000000000..70465cf27b Binary files /dev/null and b/bridge/tests/res/testApp/MyApplication/golden/software_layer.png differ diff --git a/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/SoftwareTextView.java b/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/SoftwareTextView.java new file mode 100644 index 0000000000..3d8cb0c75d --- /dev/null +++ b/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/SoftwareTextView.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2023 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 com.android.layoutlib.test.myapplication.widgets; + +import android.content.Context; +import android.graphics.Color; +import android.util.AttributeSet; +import android.widget.TextView; + +public class SoftwareTextView extends TextView { + + public SoftwareTextView(Context context) { + super(context); + init(); + } + + public SoftwareTextView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public SoftwareTextView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + public SoftwareTextView(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(); + } + + private void init() { + setLayerType(LAYER_TYPE_SOFTWARE, null); + setBackgroundColor(Color.RED); + setText("Software Layer"); + } +} diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java index a8b01e0825..662d38290a 100644 --- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java +++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java @@ -2166,4 +2166,34 @@ public class RenderTests extends RenderTestBase { renderAndVerify(params, "light_status_bar.png", TimeUnit.SECONDS.toNanos(2)); } + + @Test + public void testSoftwareLayer() throws Exception { + String layout = + "\n" + + " \n" + + "\n"; + LayoutPullParser parser = LayoutPullParser.createFromString(layout); + // Create LayoutLibCallback. + LayoutLibTestCallback layoutLibCallback = + new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); + layoutLibCallback.initResources(); + + SessionParams params = getSessionParamsBuilder() + .setParser(parser) + .setCallback(layoutLibCallback) + .setTheme("Theme.Material.Light.NoActionBar.Fullscreen", false) + .setRenderingMode(RenderingMode.V_SCROLL) + .disableDecoration() + .build(); + + renderAndVerify(params, "software_layer.png", + TimeUnit.SECONDS.toNanos(2)); + } } -- cgit v1.2.3 From 650eac5c5348dd4c4fef7312c84e3dd189a2dd41 Mon Sep 17 00:00:00 2001 From: Paul Milian Date: Fri, 2 Jun 2023 15:07:00 +0100 Subject: Fix typos in comments Bug: N/A Test: N/A (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:a6187c1b7ad377155d949ec9e40b78c0413bc88b) Merged-In: I8ae280dd245179a7e51114afd8df9619556d1031 Change-Id: I8ae280dd245179a7e51114afd8df9619556d1031 --- bridge/src/com/android/layoutlib/bridge/Bridge.java | 2 +- bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java | 2 +- bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java | 2 +- .../com/android/tools/layoutlib/create/StubExceptionMethodAdapter.java | 2 +- .../tests/src/com/android/tools/layoutlib/create/AsmGeneratorTest.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bridge/src/com/android/layoutlib/bridge/Bridge.java b/bridge/src/com/android/layoutlib/bridge/Bridge.java index 3c62193dad..ce0fb2ddd8 100644 --- a/bridge/src/com/android/layoutlib/bridge/Bridge.java +++ b/bridge/src/com/android/layoutlib/bridge/Bridge.java @@ -337,7 +337,7 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { } /** - * Tests if the field is pubic, static and one of int or int[]. + * Tests if the field is public, static and one of int or int[]. */ private static boolean isValidRField(Field field) { int modifiers = field.getModifiers(); diff --git a/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java index defea14b29..98378e63e1 100644 --- a/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java +++ b/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java @@ -43,7 +43,7 @@ import android.widget.TextView; import static android.os._Original_Build.VERSION_CODES.LOLLIPOP; /** - * Base "bar" class for the window decor around the the edited layout. + * Base "bar" class for the window decor around the edited layout. * This is basically an horizontal layout that loads a given layout on creation (it is read * through {@link Class#getResourceAsStream(String)}). *

diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index 082ea1444a..375891a7d4 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -200,7 +200,7 @@ public class RenderSessionImpl extends RenderAction { } /** - * Measures the the current layout if needed (see {@link #invalidateRenderingSize}). + * Measures the current layout if needed (see {@link #invalidateRenderingSize}). */ private void measureLayout(@NonNull SessionParams params) { // only do the screen measure when needed. diff --git a/create/src/com/android/tools/layoutlib/create/StubExceptionMethodAdapter.java b/create/src/com/android/tools/layoutlib/create/StubExceptionMethodAdapter.java index 73a57a2190..322f0656a3 100644 --- a/create/src/com/android/tools/layoutlib/create/StubExceptionMethodAdapter.java +++ b/create/src/com/android/tools/layoutlib/create/StubExceptionMethodAdapter.java @@ -24,7 +24,7 @@ import org.objectweb.asm.Type; /** - * {@link MethodVisitor} that replaces the method the implementation of the method with + * {@link MethodVisitor} that replaces the implementation of the method with * * throw new RuntimeException("Stub!"); * diff --git a/create/tests/src/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/create/tests/src/com/android/tools/layoutlib/create/AsmGeneratorTest.java index aadab22173..334bcd2aa1 100644 --- a/create/tests/src/com/android/tools/layoutlib/create/AsmGeneratorTest.java +++ b/create/tests/src/com/android/tools/layoutlib/create/AsmGeneratorTest.java @@ -64,7 +64,7 @@ public class AsmGeneratorTest { private String mOsDestJar; private File mTempFile; - // ASM internal name for the the class in java package that should be refactored. + // ASM internal name for the class in java package that should be refactored. private static final String JAVA_CLASS_NAME = "notjava.lang.JavaClass"; @Before -- cgit v1.2.3 From 4750996bf651ef58eebf5bfd2158816b832397b8 Mon Sep 17 00:00:00 2001 From: Paul Milian Date: Fri, 2 Jun 2023 15:07:20 +0100 Subject: Remove extra semicolon Bug: N/A Test: N/A (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:3561030564bc1a7768390b6496cbb0f561ea425c) Merged-In: I18707117db2fcf7430377d981d735b134aa9c2e7 Change-Id: I18707117db2fcf7430377d981d735b134aa9c2e7 --- .../tools/layoutlib/create/DeferStaticInitializerClassAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/create/src/com/android/tools/layoutlib/create/DeferStaticInitializerClassAdapter.java b/create/src/com/android/tools/layoutlib/create/DeferStaticInitializerClassAdapter.java index b5c331d838..3ce901a10b 100644 --- a/create/src/com/android/tools/layoutlib/create/DeferStaticInitializerClassAdapter.java +++ b/create/src/com/android/tools/layoutlib/create/DeferStaticInitializerClassAdapter.java @@ -47,7 +47,7 @@ public class DeferStaticInitializerClassAdapter extends ClassVisitor { // Java 9 does not allow static final field to be modified outside of . // So if a field is static, it has to be non-final. if ((access & Opcodes.ACC_STATIC) != 0 ) { - access = access & ~Opcodes.ACC_FINAL;; + access = access & ~Opcodes.ACC_FINAL; } return super.visitField(access, name, desc, signature, value); } -- cgit v1.2.3 From bad12fcf617007fd868e005ce7ec8a38193d254c Mon Sep 17 00:00:00 2001 From: Paul Milian Date: Fri, 2 Jun 2023 15:00:04 +0100 Subject: Add ability to remove the final modifier from ... fields Bug: 282724670 Test: manual (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:c1778e922601f0cae7b585906812521481bc4e50) Merged-In: I674cf470a724ff2f14ee5838bc0073586ee45a11 Change-Id: I674cf470a724ff2f14ee5838bc0073586ee45a11 --- .../tools/layoutlib/create/AsmGenerator.java | 10 +++++ .../android/tools/layoutlib/create/CreateInfo.java | 11 ++++++ .../tools/layoutlib/create/ICreateInfo.java | 7 ++++ .../RemoveFinalModifierFieldClassAdapter.java | 46 ++++++++++++++++++++++ .../tools/layoutlib/create/CreateInfoAdapter.java | 5 +++ 5 files changed, 79 insertions(+) create mode 100644 create/src/com/android/tools/layoutlib/create/RemoveFinalModifierFieldClassAdapter.java diff --git a/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/create/src/com/android/tools/layoutlib/create/AsmGenerator.java index 98055e3a90..55de0afe0f 100644 --- a/create/src/com/android/tools/layoutlib/create/AsmGenerator.java +++ b/create/src/com/android/tools/layoutlib/create/AsmGenerator.java @@ -94,6 +94,8 @@ public class AsmGenerator { private final Set mMethodReplacers; private boolean mKeepAllNativeClasses; + /** A map { FQCN => set { field names } } which should have their final modifier removed */ + private final Map> mRemoveFinalModifierFields; /** * Creates a new generator that can generate the output JAR with the stubbed classes. @@ -218,6 +220,9 @@ public class AsmGenerator { mRenameStaticInitializerClasses = Arrays.stream(createInfo.getDeferredStaticInitializerClasses()).collect(Collectors.toSet()); + + mRemoveFinalModifierFields = new HashMap<>(); + addToMap(createInfo.getRemovedFinalModifierFields(), mRemoveFinalModifierFields); } /** @@ -427,6 +432,11 @@ public class AsmGenerator { cv = new DeferStaticInitializerClassAdapter(cv); } + Set removeFinalModifierFields = mRemoveFinalModifierFields.get(className); + if (removeFinalModifierFields != null && !removeFinalModifierFields.isEmpty()) { + cv = new RemoveFinalModifierFieldClassAdapter(cv, removeFinalModifierFields); + } + // Make sure no class file has a version above 55 (corresponding to Java 11), // so that layoutlib can be run with JDK 11. cv = new ChangeFileVersionAdapter(mLog, 55, cv); diff --git a/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/create/src/com/android/tools/layoutlib/create/CreateInfo.java index fb50c46ff1..4489966d83 100644 --- a/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -129,6 +129,11 @@ public final class CreateInfo implements ICreateInfo { return DEFERRED_STATIC_INITIALIZER_CLASSES; } + @Override + public String[] getRemovedFinalModifierFields() { + return REMOVED_FINAL_MODIFIER_FIELDS; + } + //----- private static final MethodReplacer[] METHOD_REPLACERS = new MethodReplacer[] { @@ -381,6 +386,12 @@ public final class CreateInfo implements ICreateInfo { private final static Map INJECTED_METHODS = Map.of( "android.content.Context", InjectMethodRunnables.CONTEXT_GET_FRAMEWORK_CLASS_LOADER); + /** + * List of fields for which we will remove the final modifier. + */ + private final static String[] REMOVED_FINAL_MODIFIER_FIELDS = + new String[]{}; + public static class LinkedHashMapEldestReplacer implements MethodReplacer { private final String VOID_TO_MAP_ENTRY = diff --git a/create/src/com/android/tools/layoutlib/create/ICreateInfo.java b/create/src/com/android/tools/layoutlib/create/ICreateInfo.java index 83c5b24523..e536bdc903 100644 --- a/create/src/com/android/tools/layoutlib/create/ICreateInfo.java +++ b/create/src/com/android/tools/layoutlib/create/ICreateInfo.java @@ -129,6 +129,13 @@ public interface ICreateInfo { String[] getDeferredStaticInitializerClasses(); + /** + * Returns a list of fields which should have their final modifier removed. + * The array values are in the form of the binary FQCN of the class containing the field and + * the field name separated by a '#'. + */ + String[] getRemovedFinalModifierFields(); + interface MethodReplacer { boolean isNeeded(String owner, String name, String desc, String sourceClass); diff --git a/create/src/com/android/tools/layoutlib/create/RemoveFinalModifierFieldClassAdapter.java b/create/src/com/android/tools/layoutlib/create/RemoveFinalModifierFieldClassAdapter.java new file mode 100644 index 0000000000..2f2d6007c7 --- /dev/null +++ b/create/src/com/android/tools/layoutlib/create/RemoveFinalModifierFieldClassAdapter.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2023 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 com.android.tools.layoutlib.create; + +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; + +import java.util.Set; + +import static org.objectweb.asm.Opcodes.ACC_FINAL; + +/** + * Removes the final modifier from the given fields. + */ +public class RemoveFinalModifierFieldClassAdapter extends ClassVisitor { + + private final Set mFieldNames; + + public RemoveFinalModifierFieldClassAdapter(ClassVisitor cv, Set fieldNames) { + super(Main.ASM_VERSION, cv); + mFieldNames = fieldNames; + } + + @Override + public FieldVisitor visitField(int access, String name, String desc, String signature, + Object value) { + if (mFieldNames.contains(name)) { + access = access & ~ACC_FINAL; + } + return super.visitField(access, name, desc, signature, value); + } +} diff --git a/create/tests/src/com/android/tools/layoutlib/create/CreateInfoAdapter.java b/create/tests/src/com/android/tools/layoutlib/create/CreateInfoAdapter.java index 3b1cb06a1f..778a191aaf 100644 --- a/create/tests/src/com/android/tools/layoutlib/create/CreateInfoAdapter.java +++ b/create/tests/src/com/android/tools/layoutlib/create/CreateInfoAdapter.java @@ -106,4 +106,9 @@ class CreateInfoAdapter implements ICreateInfo { public String[] getDeferredStaticInitializerClasses() { return EMPTY_STRING_ARRAY; } + + @Override + public String[] getRemovedFinalModifierFields() { + return EMPTY_STRING_ARRAY; + } } -- cgit v1.2.3 From fc4f1d51521560ba8efbf4a0dd13328badc124e8 Mon Sep 17 00:00:00 2001 From: Paul Milian Date: Fri, 2 Jun 2023 15:04:35 +0100 Subject: Replace AnimationHandler's ThreadLocal with ... a bridge context specific thread local to ensure each render session has its own instance of AnimationHandler. This is to prevent issues due to one render session disposing the callbacks that were registered in another. Bug: 282724670 Test: manual (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:b41cb105a0fc7dc23ee740cf23b2928800dba075) Merged-In: I2e48c3eea43752259f1eba3ae9bf662cc6558b0a Change-Id: I2e48c3eea43752259f1eba3ae9bf662cc6558b0a --- .../com/android/layoutlib/bridge/android/BridgeContext.java | 7 +++++++ bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java | 10 ++++++++++ .../com/android/layoutlib/bridge/impl/RenderSessionImpl.java | 7 ------- create/src/com/android/tools/layoutlib/create/CreateInfo.java | 2 +- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 9f8a8f5b44..67fb53497d 100644 --- a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -40,6 +40,7 @@ import com.android.tools.layoutlib.annotations.NotNull; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import android.animation.AnimationHandler; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; @@ -206,6 +207,7 @@ public class BridgeContext extends Context { private final Map, Object> mUserData = new HashMap<>(); private final SessionInteractiveData mSessionInteractiveData; + private final ThreadLocal mAnimationHandlerThreadLocal = new ThreadLocal<>(); /** * Some applications that target both pre API 17 and post API 17, set the newer attrs to @@ -2298,4 +2300,9 @@ public class BridgeContext extends Context { public void applyWallpaper(String wallpaperPath) { mRenderResources.setWallpaper(wallpaperPath, mConfig.isNightModeActive()); } + + @NotNull + public ThreadLocal getAnimationHandlerThreadLocal() { + return mAnimationHandlerThreadLocal; + } } diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java index 4288c9fa37..8048ff1e1a 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java @@ -32,6 +32,7 @@ import com.android.tools.layoutlib.annotations.NotNull; import com.android.tools.layoutlib.annotations.Nullable; import com.android.tools.layoutlib.annotations.VisibleForTesting; +import android.animation.AnimationHandler; import android.animation.PropertyValuesHolder_Accessor; import android.content.res.Configuration; import android.graphics.drawable.AdaptiveIconDrawable_Delegate; @@ -284,6 +285,7 @@ public abstract class RenderAction { ILayoutLog currentLog = mParams.getLog(); Bridge.setLog(currentLog); mContext.getRenderResources().setLogger(currentLog); + AnimationHandler.sAnimatorHandler = mContext.getAnimationHandlerThreadLocal(); } /** @@ -475,6 +477,14 @@ public abstract class RenderAction { if (sCurrentContext != null) { // quit HandlerThread created during this session. HandlerThread_Delegate.cleanUp(sCurrentContext); + + AnimationHandler animationHandler = + sCurrentContext.getAnimationHandlerThreadLocal().get(); + if (animationHandler != null) { + animationHandler.mDelayedCallbackStartTime.clear(); + animationHandler.mAnimationCallbacks.clear(); + animationHandler.mCommitCallbacks.clear(); + } } sCurrentContext = null; diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index 375891a7d4..faeeb19f1a 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -50,7 +50,6 @@ import com.android.tools.idea.validator.ValidatorHierarchy; import com.android.tools.idea.validator.hierarchy.CustomHierarchyHelper; import com.android.tools.layoutlib.annotations.NotNull; -import android.animation.AnimationHandler; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; @@ -1210,12 +1209,6 @@ public class RenderSessionImpl extends RenderAction { mImage = null; // detachFromWindow might create Handler callbacks, thus before Handler_Delegate.dispose AttachInfo_Accessor.detachFromWindow(mViewRoot); - AnimationHandler animationHandler = AnimationHandler.sAnimatorHandler.get(); - if (animationHandler != null) { - animationHandler.mDelayedCallbackStartTime.clear(); - animationHandler.mAnimationCallbacks.clear(); - animationHandler.mCommitCallbacks.clear(); - } getContext().getSessionInteractiveData().dispose(); if (mViewInfoList != null) { mViewInfoList.clear(); diff --git a/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/create/src/com/android/tools/layoutlib/create/CreateInfo.java index 4489966d83..b2b7e7084b 100644 --- a/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -390,7 +390,7 @@ public final class CreateInfo implements ICreateInfo { * List of fields for which we will remove the final modifier. */ private final static String[] REMOVED_FINAL_MODIFIER_FIELDS = - new String[]{}; + new String[]{"android.animation.AnimationHandler#sAnimatorHandler"}; public static class LinkedHashMapEldestReplacer implements MethodReplacer { -- cgit v1.2.3 From 76d28dfbeea07590128b92de072af37952f963ad Mon Sep 17 00:00:00 2001 From: Sijie Chen Date: Wed, 7 Jun 2023 17:45:31 +0000 Subject: Add isBatterySaverConfigSupported method to BridgePowerManager Bug: 272527415 Test: m layoutlib Change-Id: Ib236ed8bdb126a7fb02a8de69b51848566fa6593 --- .../src/com/android/layoutlib/bridge/android/BridgePowerManager.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java index 85bf637d00..c376429186 100644 --- a/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java +++ b/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java @@ -60,6 +60,11 @@ public class BridgePowerManager implements IPowerManager { return false; } + @Override + public boolean isBatterySaverSupported() throws RemoteException { + return true; + } + @Override public BatterySaverPolicyConfig getFullPowerSavePolicy() { return new BatterySaverPolicyConfig.Builder().build(); -- cgit v1.2.3 From 792a7db33fce6de0bf373c5987c9fdb096ff6f78 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Wed, 14 Jun 2023 19:00:29 +0100 Subject: Do not store a static instance of AccessibilityManager Instead this creates an AccessibilityManager per BridgeContext and stores it within the BridgeContext so that it will not cause leaks. Bug: 284186358 Test: N/A (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:055e44eb3e64b5052d4765371b6b6995c68d4655) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:365818ae63d6d0048ef03fe44f8a16ae78d8d66b) Merged-In: I914b70b1b6a503e9a76a0582fa318b0f09c57aaf Change-Id: I914b70b1b6a503e9a76a0582fa318b0f09c57aaf --- .../android/view/accessibility/AccessibilityManager_Delegate.java | 8 ++++++++ .../src/com/android/layoutlib/bridge/android/BridgeContext.java | 8 ++++++++ common/src/com/android/tools/layoutlib/create/NativeConfig.java | 1 + 3 files changed, 17 insertions(+) diff --git a/bridge/src/android/view/accessibility/AccessibilityManager_Delegate.java b/bridge/src/android/view/accessibility/AccessibilityManager_Delegate.java index dd5b33ab06..9408f79c66 100644 --- a/bridge/src/android/view/accessibility/AccessibilityManager_Delegate.java +++ b/bridge/src/android/view/accessibility/AccessibilityManager_Delegate.java @@ -16,8 +16,10 @@ package android.view.accessibility; +import com.android.layoutlib.bridge.android.BridgeContext; import com.android.tools.layoutlib.annotations.LayoutlibDelegate; +import android.content.Context; import android.graphics.Matrix; import android.view.MagnificationSpec; import android.view.accessibility.IAccessibilityManager.WindowTransformationSpec; @@ -38,4 +40,10 @@ public class AccessibilityManager_Delegate { } return sInstance; } + + @LayoutlibDelegate + public static AccessibilityManager getInstance(Context context) { + Context baseContext = BridgeContext.getBaseContext(context); + return ((BridgeContext)baseContext).getAccessibilityManager(); + } } diff --git a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 67fb53497d..abcba09ba7 100644 --- a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -203,6 +203,7 @@ public class BridgeContext extends Context { private Boolean mIsThemeAppCompat; private boolean mUseThemedIcon; private Context mApplicationContext; + private AccessibilityManager mAccessibilityManager; private final ResourceNamespace mAppCompatNamespace; private final Map, Object> mUserData = new HashMap<>(); @@ -606,6 +607,13 @@ public class BridgeContext extends Context { return isThemeAppCompat; } + public AccessibilityManager getAccessibilityManager() { + if (mAccessibilityManager == null) { + mAccessibilityManager = new AccessibilityManager(this, null, UserHandle.USER_CURRENT); + } + return mAccessibilityManager; + } + // ------------ Context methods @Override diff --git a/common/src/com/android/tools/layoutlib/create/NativeConfig.java b/common/src/com/android/tools/layoutlib/create/NativeConfig.java index a3e89ebdb2..8c954ce3dc 100644 --- a/common/src/com/android/tools/layoutlib/create/NativeConfig.java +++ b/common/src/com/android/tools/layoutlib/create/NativeConfig.java @@ -137,6 +137,7 @@ public class NativeConfig { "android.view.View#measure", "android.view.ViewRootImpl#performHapticFeedback", "android.view.WindowManagerGlobal#getWindowManagerService", + "android.view.accessibility.AccessibilityManager#getInstance", "android.view.accessibility.AccessibilityManager#getWindowTransformationSpec", "android.view.inputmethod.InputMethodManager#hideSoftInputFromWindow", "android.view.inputmethod.InputMethodManager#isInEditMode", -- cgit v1.2.3 From a1f7764999ae968dc454bff946be8050649f03fd Mon Sep 17 00:00:00 2001 From: Fedor Kudasov Date: Thu, 29 Jun 2023 14:03:05 +0100 Subject: Handle null value in TypedArray Fixes: 257209913 Test: manually verified (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:2c24df9e1824f9836bde4c3c79fb8f0bf556e6ef) Merged-In: I03f4738258286a761635211b1ed983cb02424389 Change-Id: I03f4738258286a761635211b1ed983cb02424389 --- bridge/src/android/content/res/BridgeTypedArray.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridge/src/android/content/res/BridgeTypedArray.java b/bridge/src/android/content/res/BridgeTypedArray.java index da59fb79a6..ae6f538178 100644 --- a/bridge/src/android/content/res/BridgeTypedArray.java +++ b/bridge/src/android/content/res/BridgeTypedArray.java @@ -907,7 +907,7 @@ public final class BridgeTypedArray extends TypedArray { boolean found = false; String value = mResourceData[index].getValue(); - if (!value.isEmpty()) { + if (value != null && !value.isEmpty()) { // Check if the value string is already representing an integer and return it if so. // Resources coming from res.apk in an AAR may have flags and enums in integer form. char c = value.charAt(0); -- cgit v1.2.3 From 769bddaa65f903e7874b0bc35a7b125a97c05ce2 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Fri, 30 Jun 2023 13:20:41 +0100 Subject: Handle dimensions in BridgeContext.resolveThemeAttribute This ensures that the TypedValue is correctly set up when the attribute resolves to a dimension. That means setting up the correct type and data. Fixes: 281942492 Test: Moved testTypedValue from RenderTests to BridgeContextTest, and added new case corresponding to dimension. (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:212b8022361da4dc60dcb73f74e6810d3469845e) Merged-In: I701b4b1df26f104db7f505e31912d69abd289172 Change-Id: I701b4b1df26f104db7f505e31912d69abd289172 --- .../layoutlib/bridge/android/BridgeContext.java | 10 ++-- .../bridge/android/BridgeContextTest.java | 63 ++++++++++++++++++++++ .../layoutlib/bridge/intensive/RenderTests.java | 58 -------------------- 3 files changed, 69 insertions(+), 62 deletions(-) diff --git a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index abcba09ba7..0efe9a0c86 100644 --- a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -90,7 +90,6 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.UserHandle; -import android.os.Vibrator; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Pair; @@ -468,9 +467,12 @@ public class BridgeContext extends Context { try { outValue.data = Integer.parseInt(stringValue); outValue.type = TypedValue.TYPE_INT_DEC; - } catch (NumberFormatException e) { - outValue.type = TypedValue.TYPE_STRING; - outValue.string = stringValue; + } + catch (NumberFormatException e) { + if (!ResourceHelper.parseFloatAttribute(null, stringValue, outValue, false)) { + outValue.type = TypedValue.TYPE_STRING; + outValue.string = stringValue; + } } } } diff --git a/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeContextTest.java b/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeContextTest.java index 6aca0d816f..83a4f80111 100644 --- a/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeContextTest.java +++ b/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeContextTest.java @@ -21,6 +21,7 @@ import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.impl.RenderAction; import com.android.layoutlib.bridge.impl.RenderActionTestUtil; import com.android.layoutlib.bridge.intensive.LayoutLibTestCallback; +import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator; import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser; import org.junit.BeforeClass; @@ -33,10 +34,13 @@ import android.content.res.Configuration; import android.content.res.TypedArray; import android.os.PowerManager; import android.util.DisplayMetrics; +import android.util.TypedValue; import android.view.ContextThemeWrapper; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -204,4 +208,63 @@ public class BridgeContextTest extends RenderTestBase { assertFalse(powerManager.isPowerSaveMode()); assertTrue(powerManager.isInteractive()); } + + @Test + public void testTypedValue() 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 = LayoutPullParser.createFromPath("/empty.xml"); + // Create LayoutLibCallback. + LayoutLibTestCallback layoutLibCallback = + new LayoutLibTestCallback(RenderTestBase.getLogger(), mDefaultClassLoader); + layoutLibCallback.initResources(); + SessionParams params = getSessionParamsBuilder() + .setConfigGenerator(ConfigGenerator.NEXUS_4) + .setParser(parser) + .setCallback(layoutLibCallback) + .build(); + DisplayMetrics metrics = new DisplayMetrics(); + Configuration configuration = RenderAction.getConfiguration(params); + + BridgeContext mContext = + new BridgeContext(params.getProjectKey(), metrics, params.getResources(), + params.getAssets(), params.getLayoutlibCallback(), configuration, + params.getTargetSdkVersion(), params.isRtlSupported()); + + TypedValue outValue = new TypedValue(); + mContext.resolveThemeAttribute(android.R.attr.colorPrimary, outValue, true); + assertEquals(TypedValue.TYPE_INT_COLOR_ARGB8, outValue.type); + assertNotEquals(0, outValue.data); + + outValue = new TypedValue(); + mContext.resolveThemeAttribute(android.R.attr.colorError, outValue, true); + assertEquals(TypedValue.TYPE_INT_COLOR_RGB4, outValue.type); + assertEquals(-65536, outValue.data); + + outValue = new TypedValue(); + mContext.resolveThemeAttribute(attr.colorActivatedHighlight, outValue, true); + assertEquals(TypedValue.TYPE_INT_COLOR_ARGB4, outValue.type); + assertEquals(-872349952, outValue.data); + + outValue = new TypedValue(); + mContext.resolveThemeAttribute(android.R.attr.isLightTheme, outValue, true); + assertEquals(TypedValue.TYPE_INT_BOOLEAN, outValue.type); + assertEquals(1, outValue.data); + + outValue = new TypedValue(); + mContext.resolveThemeAttribute(android.R.attr.scrollbarFadeDuration, outValue, true); + assertEquals(TypedValue.TYPE_INT_DEC, outValue.type); + assertEquals(250, outValue.data); + + outValue = new TypedValue(); + mContext.resolveThemeAttribute(android.R.attr.scrollbarThumbHorizontal, outValue, true); + assertEquals(TypedValue.TYPE_STRING, outValue.type); + assertNotNull(outValue.string); + + outValue = new TypedValue(); + mContext.resolveThemeAttribute(android.R.attr.actionBarSize, outValue, true); + assertEquals(TypedValue.TYPE_DIMENSION, outValue.type); + assertEquals(14337, outValue.data); + } } diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java index 662d38290a..5e5170e92e 100644 --- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java +++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java @@ -46,7 +46,6 @@ import org.junit.Test; import org.kxml2.io.KXmlParser; import org.xmlpull.v1.XmlPullParser; -import android.R.attr; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.res.AssetManager; @@ -57,7 +56,6 @@ import android.content.res.Resources_Delegate; import android.graphics.Color; import android.util.DisplayMetrics; import android.util.StateSet; -import android.util.TypedValue; import android.widget.Button; import android.widget.LinearLayout; @@ -75,7 +73,6 @@ import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -973,61 +970,6 @@ public class RenderTests extends RenderTestBase { renderAndVerify(params, "adaptive_icon_squircle.png"); } - @Test - public void testTypedValue() 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 = LayoutPullParser.createFromPath("/empty.xml"); - // Create LayoutLibCallback. - LayoutLibTestCallback layoutLibCallback = - new LayoutLibTestCallback(RenderTestBase.getLogger(), mDefaultClassLoader); - layoutLibCallback.initResources(); - SessionParams params = getSessionParamsBuilder() - .setConfigGenerator(ConfigGenerator.NEXUS_4) - .setParser(parser) - .setCallback(layoutLibCallback) - .build(); - DisplayMetrics metrics = new DisplayMetrics(); - Configuration configuration = RenderAction.getConfiguration(params); - - BridgeContext mContext = - new BridgeContext(params.getProjectKey(), metrics, params.getResources(), - params.getAssets(), params.getLayoutlibCallback(), configuration, - params.getTargetSdkVersion(), params.isRtlSupported()); - - TypedValue outValue = new TypedValue(); - mContext.resolveThemeAttribute(android.R.attr.colorPrimary, outValue, true); - assertEquals(TypedValue.TYPE_INT_COLOR_ARGB8, outValue.type); - assertNotEquals(0, outValue.data); - - outValue = new TypedValue(); - mContext.resolveThemeAttribute(android.R.attr.colorError, outValue, true); - assertEquals(TypedValue.TYPE_INT_COLOR_RGB4, outValue.type); - assertEquals(-65536, outValue.data); - - outValue = new TypedValue(); - mContext.resolveThemeAttribute(attr.colorActivatedHighlight, outValue, true); - assertEquals(TypedValue.TYPE_INT_COLOR_ARGB4, outValue.type); - assertEquals(-872349952, outValue.data); - - outValue = new TypedValue(); - mContext.resolveThemeAttribute(android.R.attr.isLightTheme, outValue, true); - assertEquals(TypedValue.TYPE_INT_BOOLEAN, outValue.type); - assertEquals(1, outValue.data); - - outValue = new TypedValue(); - mContext.resolveThemeAttribute(android.R.attr.scrollbarFadeDuration, outValue, true); - assertEquals(TypedValue.TYPE_INT_DEC, outValue.type); - assertEquals(250, outValue.data); - - outValue = new TypedValue(); - mContext.resolveThemeAttribute(android.R.attr.scrollbarThumbHorizontal, outValue, true); - assertEquals(TypedValue.TYPE_STRING, outValue.type); - assertNotNull(outValue.string); - assertTrue(sRenderMessages.isEmpty()); - } - @Test public void testColorStateList() throws Exception { final String STATE_LIST = -- cgit v1.2.3 From cf04a4141c041b5f047c9cceb9f8ef10f7d3542b Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Wed, 23 Aug 2023 12:27:25 +0100 Subject: Use newly update ATF prebuilt Bug: N/A Test: existing tests (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:768eeea0e4f655b7d863dbd1d173e115ea02e66c) Merged-In: I2826cb3c54b208f7d4cdd24d7958b135f06adcee Change-Id: I2826cb3c54b208f7d4cdd24d7958b135f06adcee --- Android.bp | 2 +- create/Android.bp | 2 +- validator/resources/strings.properties | 14 ++++++++++++++ .../android/tools/idea/validator/ValidatorUtil.java | 3 +-- .../validator/hierarchy/CustomHierarchyHelper.java | 18 +++++++++++++++++- 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/Android.bp b/Android.bp index 76bc916b23..5fd342d124 100644 --- a/Android.bp +++ b/Android.bp @@ -30,7 +30,7 @@ java_genrule_host { tools: ["layoutlib_create"], out: ["temp_layoutlib.jar"], srcs: [ - ":atf-prebuilt-502584086{.jar}", + ":atf-prebuilt-557133692{.jar}", ":core-icu4j-for-host{.jar}", ":core-libart-for-host{.jar}", ":framework-all{.jar}", diff --git a/create/Android.bp b/create/Android.bp index 13a00a878f..a8dcdaa5eb 100644 --- a/create/Android.bp +++ b/create/Android.bp @@ -30,7 +30,7 @@ java_binary_host { "guava", "layoutlib-common", "layoutlib_create-classpath", - "atf-prebuilt-502584086", + "atf-prebuilt-557133692", "libprotobuf-java-lite", ], } diff --git a/validator/resources/strings.properties b/validator/resources/strings.properties index 27f310cfa3..3a07104c0c 100644 --- a/validator/resources/strings.properties +++ b/validator/resources/strings.properties @@ -16,6 +16,7 @@ # result_message_not_important_for_accessibility = This item was not found to be important for accessibility. result_message_no_content_desc = This item has no android:contentDescription. +result_message_no_content_desc_generic = This item has no content description. result_message_not_visible = This item is not visible. result_message_not_enabled = This item isn\'t enabled. result_message_not_text_view = This item is not a TextView. @@ -38,6 +39,7 @@ non_clickable = non-clickable long_clickable = long clickable clickable_and_long_clickable = clickable and long clickable actionable = actionable +result_message_addendum_conflicting_elements_list = Conflicting element(s): %1$s. check_title_duplicate_speakable_text = Item descriptions result_message_brief_same_speakable_text = Multiple items have the same description. result_message_same_speakable_text = This %1$s item\'s speakable text: \"%2$s\" is identical to that of %3$d other item(s). @@ -55,10 +57,14 @@ result_message_image_customized_contrast_not_sufficient_confirmed = The image\'s check_title_redundant_description = Item type label result_message_english_locale_only = This check only runs on devices with locales set to English. result_message_brief_content_desc_contains_redundant_word = This item\'s android:contentDescription might contain unnecessary text. +result_message_brief_content_desc_contains_redundant_word_generic = This item\'s content description might contain unnecessary text. result_message_content_desc_ends_with_view_type = This item\'s android:contentDescription, \"%1$s\" ends with the item\'s type. result_message_content_desc_contains_redundant_word = This item\'s android:contentDescription, \"%1$s\" contains the item type \"%2$s\". +result_message_content_desc_contains_redundant_word_generic = This item\'s content description, \"%1$s\" contains the item type \"%2$s\". result_message_content_desc_contains_action = This item\'s android:contentDescription, \"%1$s\", contains the action \"%2$s\". +result_message_content_desc_contains_action_generic = This item\'s content description, \"%1$s\", contains the action \"%2$s\". result_message_content_desc_contains_state = This item\'s android:contentDescription, \"%1$s\", contains the state \"%2$s\". +result_message_content_desc_contains_state_generic = This item\'s content description, \"%1$s\", contains the state \"%2$s\". button_item_type = button checkbox_item_type = checkbox checkbox_item_type_separate_words = check box @@ -73,6 +79,7 @@ check_title_speakable_text_present = Item label result_message_should_not_focus = This item would not be focused by a screen reader. result_message_web_content = Web content is not evaluated. result_message_unsupported_compose_content = Composable content is not evaluated in this environment. +result_message_unsupported_flutter_content = Flutter content is not evaluated in this environment. result_message_missing_speakable_text = This item may not have a label readable by screen readers. check_title_text_contrast = Text contrast result_message_textview_empty = This TextView is empty. @@ -158,12 +165,19 @@ result_message_item_type_with_text_size_unit = %1$s with text size unit result_message_small_fixed_text_size = This text is small and may be difficult for some users to read. Consider using a larger size or specifying the text size in scaled pixels (sp). result_message_fixed_text_size = Consider specifying the text size in scaled pixels (sp). result_message_brief_fixed_width_text_view_with_scaled_text = This TextView has a fixed width and scalable text. +result_message_brief_fixed_width_text_view_with_scaled_text_compose = This Text has a fixed width and scalable text. result_message_brief_fixed_height_text_view_with_scaled_text = This TextView has a fixed height and scalable text. +result_message_brief_fixed_height_text_with_scaled_text_compose = This Text has a fixed height and scalable text. result_message_brief_fixed_size_text_view_with_scaled_text = This TextView has a fixed size and scalable text. +result_message_brief_fixed_size_text_with_scaled_text_compose = This Text has a fixed size and scalable text. result_message_brief_fixed_width_view_group_with_scaled_text = This ViewGroup has a fixed width and contains a TextView with scalable text. +result_message_brief_fixed_width_parent_with_scaled_text_compose = This element has a fixed width and contains a Text element with scalable text. result_message_brief_fixed_height_view_group_with_scaled_text = This ViewGroup has a fixed height and contains a TextView with scalable text. +result_message_brief_fixed_height_parent_with_scaled_text_compose = This element has a fixed height and contains a Text element with scalable text. result_message_brief_fixed_size_view_group_with_scaled_text = This ViewGroup has a fixed size and contains a TextView with scalable text. +result_message_brief_fixed_size_parent_with_scaled_text_compose = This element has a fixed size and contains a Text element with scalable text. result_message_fixed_size_text_view_with_scaled_text = Consider modifying the LayoutParams to allow for text expansion. +result_message_fixed_size_text_with_scaled_text_compose = Consider modifying the size modifiers using sizeIn to allow for text expansion. check_title_unexposed_text = Unexposed Text result_message_unexposed_text = Ensure this item's accessibility label includes its visible text. result_message_text_detected_in_image_view = OCR results were detected inside this ImageView. diff --git a/validator/src/com/android/tools/idea/validator/ValidatorUtil.java b/validator/src/com/android/tools/idea/validator/ValidatorUtil.java index f3a52e0c53..fa2862d191 100644 --- a/validator/src/com/android/tools/idea/validator/ValidatorUtil.java +++ b/validator/src/com/android/tools/idea/validator/ValidatorUtil.java @@ -83,8 +83,6 @@ public class ValidatorUtil { * uses be redirected. */ StringManager.setResourceBundleProvider(locale -> ResourceBundle.getBundle("strings")); - // Enable using AccessibilityNodeInfo in addition to View for accessibility testing - AccessibilityHierarchyAndroid.viewOverlayEnabled = true; } // Visible for testing. @@ -130,6 +128,7 @@ public class ValidatorUtil { try { hierarchy.mView = AccessibilityHierarchyAndroid .newBuilder(view) + .enableViewOverlay() .setViewOriginMap(builder.mSrcMap) .setNodeInfoOriginMap(builder.mNodeInfoMap) .setObtainCharacterLocations(LayoutValidator.obtainCharacterLocations()) diff --git a/validator/src/com/android/tools/idea/validator/hierarchy/CustomHierarchyHelper.java b/validator/src/com/android/tools/idea/validator/hierarchy/CustomHierarchyHelper.java index eee2f32c36..5c8b2e9a39 100644 --- a/validator/src/com/android/tools/idea/validator/hierarchy/CustomHierarchyHelper.java +++ b/validator/src/com/android/tools/idea/validator/hierarchy/CustomHierarchyHelper.java @@ -48,13 +48,29 @@ public class CustomHierarchyHelper { // This is required as layoutlib does not know the support library such as // MaterialButton. LayoutlibCallback calls for studio which understands all the maven // pulled library. - Class button = callback.findClass( + Class button = callback.findClass( "com.google.android.material.button.MaterialButton"); if (button.isInstance(fromView)) { Method isCheckable = button.getMethod("isCheckable"); Object toReturn = isCheckable.invoke(fromView); return (toReturn instanceof Boolean) && ((Boolean) toReturn); } + + Class card = callback.findClass( + "com.google.android.material.card.MaterialCardView"); + if (card.isInstance(fromView)) { + Method isCheckable = card.getMethod("isCheckable"); + Object toReturn = isCheckable.invoke(fromView); + return (toReturn instanceof Boolean) && ((Boolean) toReturn); + } + + Class chip = callback.findClass( + "com.google.android.material.chip.Chip"); + if (chip.isInstance(fromView)) { + Method isCheckable = chip.getMethod("isCheckable"); + Object toReturn = isCheckable.invoke(fromView); + return (toReturn instanceof Boolean) && ((Boolean) toReturn); + } } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | -- cgit v1.2.3 From 64b3e6e90311e5221460ecee0655a148df3026c1 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Thu, 31 Aug 2023 17:49:56 +0100 Subject: Use ApplicationContext to create BridgeContentResolver BridgeContentResolver holds a reference to the context that is used to create it. This means that if user/library code stores a content resolver, that can lead to a leak of the BridgeContext. To prevent this, we create BridgeContentResolver with the ApplicationContext, which only holds a weak reference to the BridgeContext. Bug: 290990640 Test: N/A (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:044f194cf028afac353634b618a486110d9feb52) Merged-In: Ib5a5429d2bb11a75dc5ecfdf20effc98b797a2cc Change-Id: Ib5a5429d2bb11a75dc5ecfdf20effc98b797a2cc --- bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 0efe9a0c86..65cf9619d3 100644 --- a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -1546,7 +1546,7 @@ public class BridgeContext extends Context { @Override public ContentResolver getContentResolver() { if (mContentResolver == null) { - mContentResolver = new BridgeContentResolver(this); + mContentResolver = new BridgeContentResolver(getApplicationContext()); } return mContentResolver; } -- cgit v1.2.3 From 9bece20919d659f126da8b5ea285651653dc9039 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Wed, 13 Sep 2023 12:25:07 +0100 Subject: Update code to use new Density API This replaces usages of Density.getEnum with Density.create following changes in the Density class. This ensures that the Density object will always exist, whether its value is one of the predefined ones or not. Bug: N/A Test: layoutlib tests (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:24126e81abc58ee0241c5337563772a5f3a665f9) Merged-In: Ia728f677127280dce091b3ae3639642667c8a9be Change-Id: Ia728f677127280dce091b3ae3639642667c8a9be --- bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java | 2 +- bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java b/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java index c39ec8b704..68423337a0 100644 --- a/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java +++ b/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java @@ -74,7 +74,7 @@ public class StatusBar extends CustomBar { @SuppressWarnings("UnusedParameters") public StatusBar(Context context, AttributeSet attrs) { this((BridgeContext) context, - Density.getEnum(((BridgeContext) context).getMetrics().densityDpi), + Density.create(((BridgeContext) context).getMetrics().densityDpi), ((BridgeContext) context).getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL, (context.getApplicationInfo().flags & ApplicationInfo.FLAG_SUPPORTS_RTL) != 0, diff --git a/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java index 87bed3d967..4200537f40 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java @@ -368,7 +368,7 @@ public final class ResourceHelper { if (value instanceof DensityBasedResourceValue) { density = ((DensityBasedResourceValue) value).getResourceDensity(); if (density == Density.NODPI || density == Density.ANYDPI) { - density = Density.getEnum(context.getConfiguration().densityDpi); + density = Density.create(context.getConfiguration().densityDpi); } } -- cgit v1.2.3 From cf5f6c63917fa0fe30ebd91718f53c7f4228f1b7 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Tue, 19 Sep 2023 16:19:41 +0100 Subject: Complete layoutlib SurfaceView This adds to the layoutlib version of SurfaceView missing public methods from the original SurfaceView. Bug: 301064843 Test: N/A (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:d55d2e8ab60b4ab747ed155fa6eae29c761ec2ee) Merged-In: I7ff96ce1ee513aebb2db819c332385e67c48f927 Change-Id: I7ff96ce1ee513aebb2db819c332385e67c48f927 --- bridge/src/android/view/SurfaceView.java | 73 ++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/bridge/src/android/view/SurfaceView.java b/bridge/src/android/view/SurfaceView.java index ebb2af4532..2c1d6747e7 100644 --- a/bridge/src/android/view/SurfaceView.java +++ b/bridge/src/android/view/SurfaceView.java @@ -18,11 +18,17 @@ package android.view; import com.android.layoutlib.bridge.MockView; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.Region; +import android.os.IBinder; import android.util.AttributeSet; +import android.view.SurfaceControl.Transaction; + +import java.util.function.Consumer; /** * Mock version of the SurfaceView. @@ -50,6 +56,11 @@ public class SurfaceView extends MockView { super(context, attrs, defStyleAttr, defStyleRes); } + public SurfaceView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, + int defStyleRes, boolean disableBackgroundLayer) { + super(context, attrs, defStyleAttr, defStyleRes); + } + public boolean gatherTransparentRegion(Region region) { return false; } @@ -60,6 +71,14 @@ public class SurfaceView extends MockView { public void setZOrderOnTop(boolean onTop) { } + public boolean isZOrderedOnTop() { + return false; + } + + public boolean setZOrderedOnTop(boolean onTop, boolean allowDynamicChange) { + return true; + } + public void setSecure(boolean isSecure) { } @@ -67,6 +86,60 @@ public class SurfaceView extends MockView { return mSurfaceHolder; } + public void setUseAlpha() { + } + + public void setEnableSurfaceClipping(boolean enabled) { + } + + public void setCornerRadius(float cornerRadius) { + } + + public float getCornerRadius() { + return 0; + } + + public void setSurfaceLifecycle(int lifecycleStrategy) { + } + + public String getName() { + return "MockSurfaceView"; + } + + public void requestUpdateSurfacePositionAndScale() { + } + + public @NonNull Rect getSurfaceRenderPosition() { + return new Rect(); + } + + public boolean isFixedSize() { + return true; + } + + public void setResizeBackgroundColor(int bgColor) { + } + + public void setResizeBackgroundColor(@NonNull SurfaceControl.Transaction t, int bgColor) { + } + + public SurfaceControl getSurfaceControl() { + return null; + } + + public @Nullable IBinder getHostToken() { + return null; + } + + public void setChildSurfacePackage(@NonNull SurfaceControlViewHost.SurfacePackage p) { + } + + public void syncNextFrame(Consumer t) { + } + + public void applyTransactionToFrame(@NonNull SurfaceControl.Transaction transaction) { + } + private SurfaceHolder mSurfaceHolder = new SurfaceHolder() { @Override -- cgit v1.2.3 From cdb5616ca343b7fbf828eaa26d05bc6c5ccf97df Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Tue, 26 Sep 2023 15:52:27 +0100 Subject: Log a warning if the simulated SDK is higher than original If the user picks a simulated SDK that is higher than the version from which layoutlib is built, this can lead to crashes. This adds a warning to inform the developer. Bug: 300719286 Test: test added (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:5d302a621d63dec38842d20719dacaef39cec61b) Merged-In: I9e2eb24fc51177d8bd3094572e9e89e530fe0ed6 Change-Id: I9e2eb24fc51177d8bd3094572e9e89e530fe0ed6 --- .../intensive/util/SessionParamsBuilder.java | 9 +++++- .../layoutlib/bridge/impl/RenderSessionImpl.java | 12 +++++++ .../layoutlib/bridge/intensive/RenderTests.java | 37 ++++++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/bridge/bridge_client/src/com/android/layoutlib/bridge/intensive/util/SessionParamsBuilder.java b/bridge/bridge_client/src/com/android/layoutlib/bridge/intensive/util/SessionParamsBuilder.java index 35ade3454c..c0e22d3619 100644 --- a/bridge/bridge_client/src/com/android/layoutlib/bridge/intensive/util/SessionParamsBuilder.java +++ b/bridge/bridge_client/src/com/android/layoutlib/bridge/intensive/util/SessionParamsBuilder.java @@ -56,6 +56,7 @@ public class SessionParamsBuilder { private LayoutlibCallback mLayoutlibCallback; private int mTargetSdk; private int mMinSdk = 0; + private int mSimulatedSdk = 0; private ILayoutLog mLayoutLog; private Map mFlags = new HashMap<>(); private AssetRepository mAssetRepository = null; @@ -134,6 +135,12 @@ public class SessionParamsBuilder { return this; } + @NonNull + public SessionParamsBuilder setSimulatedSdk(int simulatedSdk) { + mSimulatedSdk = simulatedSdk; + return this; + } + @NonNull public SessionParamsBuilder setLayoutLog(@NonNull ILayoutLog layoutLog) { mLayoutLog = layoutLog; @@ -202,7 +209,7 @@ public class SessionParamsBuilder { SessionParams params = new SessionParams(mLayoutParser, mRenderingMode, mProjectKey /* for caching */, mConfigGenerator.getHardwareConfig(), resourceResolver, mLayoutlibCallback, - mMinSdk, mTargetSdk, mLayoutLog); + mMinSdk, mTargetSdk, mLayoutLog, mSimulatedSdk); params.setFlag(RenderParamsFlags.FLAG_ENABLE_LAYOUT_VALIDATOR, enableLayoutValidator); params.setFlag( RenderParamsFlags.FLAG_ENABLE_LAYOUT_VALIDATOR_IMAGE_CHECK, diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index faeeb19f1a..ec775b2ec9 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -110,6 +110,10 @@ import static com.android.layoutlib.common.util.ReflectionUtils.isInstanceOf; public class RenderSessionImpl extends RenderAction { private static final Canvas NOP_CANVAS = new NopCanvas(); + private static final String SIMULATED_SDK_TOO_HIGH = + String.format("The current rendering only supports APIs up to %d. You may encounter " + + "crashes if using with higher APIs. To avoid, you can set a lower API for " + + "your previews.", SDK_INT); // scene state private RenderSession mScene; @@ -313,6 +317,10 @@ public class RenderSessionImpl extends RenderAction { int simulatedVersion = params.getSimulatedPlatformVersion(); sSimulatedSdk = simulatedVersion > 0 ? simulatedVersion : SDK_INT; + if (sSimulatedSdk > SDK_INT) { + Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED, SIMULATED_SDK_TOO_HIGH, + null, null, null); + } if (Bridge.isLocaleRtl(params.getLocale())) { if (!params.isRtlSupported()) { @@ -485,6 +493,10 @@ public class RenderSessionImpl extends RenderAction { int simulatedVersion = params.getSimulatedPlatformVersion(); sSimulatedSdk = simulatedVersion > 0 ? simulatedVersion : SDK_INT; + if (sSimulatedSdk > SDK_INT) { + Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED, SIMULATED_SDK_TOO_HIGH, + null, null, null); + } try { if (mViewRoot == null) { diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java index 5e5170e92e..c5ef0e0488 100644 --- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java +++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java @@ -70,6 +70,7 @@ import java.io.PrintWriter; import java.lang.reflect.Field; import java.util.concurrent.TimeUnit; +import static android.os._Original_Build.VERSION.SDK_INT; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -2138,4 +2139,40 @@ public class RenderTests extends RenderTestBase { renderAndVerify(params, "software_layer.png", TimeUnit.SECONDS.toNanos(2)); } + + @Test + public void testHighSimulatedSdk() throws Exception { + String layout = + "\n" + + " \n" + + "\n"; + LayoutPullParser parser = LayoutPullParser.createFromString(layout); + // Create LayoutLibCallback. + LayoutLibTestCallback layoutLibCallback = + new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); + layoutLibCallback.initResources(); + + SessionParams params = getSessionParamsBuilder() + .setParser(parser) + .setCallback(layoutLibCallback) + .setTheme("Theme.Material.Light.NoActionBar.Fullscreen", false) + .setRenderingMode(RenderingMode.V_SCROLL) + .setSimulatedSdk(SDK_INT + 1) + .disableDecoration() + .build(); + + render(sBridge, params, -1); + boolean hasApiError = sRenderMessages.removeIf(message -> message.equals(String.format( + "The current rendering only supports APIs up to %d. You may encounter crashes if " + + "using with higher APIs. To avoid, you can set a lower API for your " + + "previews.", SDK_INT))); + assertTrue(hasApiError); + } } -- cgit v1.2.3 From f9f34a0b9fb283c55c129091fed9f13a3be27782 Mon Sep 17 00:00:00 2001 From: Fedor Kudasov Date: Tue, 3 Oct 2023 13:57:07 +0000 Subject: Allow floats that end with the '.' Floats like 9999.are allowed in Android and should be correctly parsed. Bug: 299149585 Test: added case to BridgeTypedArrayTest (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:282976a50ef9c99bf2e6d8484d8123a3decda0c1) Merged-In: I28fabe0d9ff8e29e5e545d64cb706945d9c587ac Change-Id: I28fabe0d9ff8e29e5e545d64cb706945d9c587ac --- bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java | 2 +- bridge/tests/src/android/content/res/BridgeTypedArrayTest.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java index 4200537f40..358795f256 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java @@ -111,7 +111,7 @@ import static android.content.res.AssetManager.ACCESS_STREAMING; public final class ResourceHelper { private static final Key> KEY_GET_DRAWABLE = Key.create("ResourceHelper.getDrawable"); - private static final Pattern sFloatPattern = Pattern.compile("(-?[0-9]*(?:\\.[0-9]+)?)(.*)"); + private static final Pattern sFloatPattern = Pattern.compile("(-?[0-9]*(?:\\.[0-9]*)?)(.*)"); private static final float[] sFloatOut = new float[1]; private static final TypedValue mValue = new TypedValue(); diff --git a/bridge/tests/src/android/content/res/BridgeTypedArrayTest.java b/bridge/tests/src/android/content/res/BridgeTypedArrayTest.java index 39759279a3..dba0f76ee8 100644 --- a/bridge/tests/src/android/content/res/BridgeTypedArrayTest.java +++ b/bridge/tests/src/android/content/res/BridgeTypedArrayTest.java @@ -52,6 +52,7 @@ public class BridgeTypedArrayTest { assertEquals(TYPE_STRING, BridgeTypedArray.getType("#notacolor")); assertEquals(TYPE_DIMENSION, BridgeTypedArray.getType("16dp")); assertEquals(TYPE_DIMENSION, BridgeTypedArray.getType(".16dp")); + assertEquals(TYPE_DIMENSION, BridgeTypedArray.getType("9999.dp")); assertEquals(TYPE_STRING, BridgeTypedArray.getType("16notaunit")); assertEquals(TYPE_INT_DEC, BridgeTypedArray.getType("98543")); assertEquals(TYPE_FLOAT, BridgeTypedArray.getType("43.364")); -- cgit v1.2.3 From 2aad4bb7a40586aa62188c285afa34e4ed09e102 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Thu, 24 Aug 2023 15:52:49 +0100 Subject: Apply image transformation coming through layoutlib-api As part of SessionParams, an image transformation can be passed to layoutlib. It is meant to apply to the rendered image before it is passes to ATF so that ATF analyses the modified image, and the modified image is the one returned by RenderSession.getImage. Bug: 291874189 Test: N/A (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:d4bf1e4f1d5a6fdce3a291449b0b8c41f9bd2fdf) Merged-In: I55cb76238adf0d4924fc927cfb9c41cbb649807a Change-Id: I55cb76238adf0d4924fc927cfb9c41cbb649807a --- bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index ec775b2ec9..de7f651bab 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -91,6 +91,7 @@ import java.util.ArrayList; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import java.util.function.Function; import static android.os._Original_Build.VERSION.SDK_INT; @@ -590,6 +591,11 @@ public class RenderSessionImpl extends RenderAction { mSystemViewInfoList = visitAllChildren(mViewRoot, 0, 0, params, false); + Consumer imageTransformation = getParams().getImageTransformation(); + if (imageTransformation != null) { + imageTransformation.accept(mImage); + } + boolean enableLayoutValidation = Boolean.TRUE.equals(params.getFlag(RenderParamsFlags.FLAG_ENABLE_LAYOUT_VALIDATOR)); boolean enableLayoutValidationImageCheck = Boolean.TRUE.equals( params.getFlag(RenderParamsFlags.FLAG_ENABLE_LAYOUT_VALIDATOR_IMAGE_CHECK)); -- cgit v1.2.3 From f401b0f2c17ba472dc7ee559cc46727c78705d18 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Wed, 18 Oct 2023 17:02:36 +0000 Subject: Revert "Apply image transformation coming through layoutlib-api" This reverts commit 2aad4bb7a40586aa62188c285afa34e4ed09e102. Reason for revert: b/303394972 Change-Id: Ia26a9c071d65419945cc6bc7d2a3dc18c31f6c35 --- bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index de7f651bab..ec775b2ec9 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -91,7 +91,6 @@ import java.util.ArrayList; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; -import java.util.function.Consumer; import java.util.function.Function; import static android.os._Original_Build.VERSION.SDK_INT; @@ -591,11 +590,6 @@ public class RenderSessionImpl extends RenderAction { mSystemViewInfoList = visitAllChildren(mViewRoot, 0, 0, params, false); - Consumer imageTransformation = getParams().getImageTransformation(); - if (imageTransformation != null) { - imageTransformation.accept(mImage); - } - boolean enableLayoutValidation = Boolean.TRUE.equals(params.getFlag(RenderParamsFlags.FLAG_ENABLE_LAYOUT_VALIDATOR)); boolean enableLayoutValidationImageCheck = Boolean.TRUE.equals( params.getFlag(RenderParamsFlags.FLAG_ENABLE_LAYOUT_VALIDATOR_IMAGE_CHECK)); -- cgit v1.2.3 From dc9892f1bc19a39981f1a2cf027dbc3aea9293a9 Mon Sep 17 00:00:00 2001 From: Xiang Wang Date: Wed, 18 Oct 2023 14:20:51 -0700 Subject: Add getThermalHeadroomThresholds Bug: 288119641 Test: mm Change-Id: I71d4d12f4380224b56dac5f23cc5e01decb298ec --- .../com/android/layoutlib/bridge/android/BridgeThermalService.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bridge/src/com/android/layoutlib/bridge/android/BridgeThermalService.java b/bridge/src/com/android/layoutlib/bridge/android/BridgeThermalService.java index 5fe116ea0c..0122da1818 100644 --- a/bridge/src/com/android/layoutlib/bridge/android/BridgeThermalService.java +++ b/bridge/src/com/android/layoutlib/bridge/android/BridgeThermalService.java @@ -90,4 +90,9 @@ public class BridgeThermalService implements IThermalService { public float getThermalHeadroom(int forecastSeconds) { return Float.NaN; } + + @Override + public float[] getThermalHeadroomThresholds() { + return new float[]{}; + } } -- cgit v1.2.3 From b52236e3a302cc81fc9044b75618d0a87ab78f42 Mon Sep 17 00:00:00 2001 From: Jared Duke Date: Fri, 20 Oct 2023 22:38:47 +0000 Subject: Remove LayoutInflater delegate support for compiled views This feature did not ship and is being removed. Remove the associated LayoutInflater delegate support. Bug: 158121974 Test: m Change-Id: I7bb9227cf03e9ef5bea795cbb7cc2f9c26f1808e --- bridge/src/android/view/LayoutInflater_Delegate.java | 11 ----------- .../src/com/android/tools/layoutlib/create/NativeConfig.java | 1 - 2 files changed, 12 deletions(-) diff --git a/bridge/src/android/view/LayoutInflater_Delegate.java b/bridge/src/android/view/LayoutInflater_Delegate.java index cb446e7610..51c413d47d 100644 --- a/bridge/src/android/view/LayoutInflater_Delegate.java +++ b/bridge/src/android/view/LayoutInflater_Delegate.java @@ -233,15 +233,4 @@ public class LayoutInflater_Delegate { LayoutInflater.consumeChildElements(parser); } - - @LayoutlibDelegate - /* package */ static void initPrecompiledViews(LayoutInflater thisInflater) { - initPrecompiledViews(thisInflater, false); - } - - @LayoutlibDelegate - /* package */ static void initPrecompiledViews(LayoutInflater thisInflater, - boolean enablePrecompiledViews) { - thisInflater.initPrecompiledViews_Original(enablePrecompiledViews); - } } diff --git a/common/src/com/android/tools/layoutlib/create/NativeConfig.java b/common/src/com/android/tools/layoutlib/create/NativeConfig.java index 8c954ce3dc..def9aef674 100644 --- a/common/src/com/android/tools/layoutlib/create/NativeConfig.java +++ b/common/src/com/android/tools/layoutlib/create/NativeConfig.java @@ -120,7 +120,6 @@ public class NativeConfig { "android.view.DisplayEventReceiver#nativeGetDisplayEventReceiverFinalizer", "android.view.DisplayEventReceiver#nativeInit", "android.view.HandlerActionQueue#postDelayed", - "android.view.LayoutInflater#initPrecompiledViews", "android.view.LayoutInflater#parseInclude", "android.view.LayoutInflater#rInflate", "android.view.MenuInflater#registerMenu", -- cgit v1.2.3 From f437648fc548a551fa9a9077c34f9d27855c0833 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Mon, 23 Oct 2023 11:33:10 +0000 Subject: Revert "Revert "Apply image transformation coming through layout..." Revert submission 25099732-revert-update-layoutlib-main-prebuilts Reason for revert: Reverting the CL did not fix the metrics issue of b/303394972, so this was not the cause. Reverted changes: /q/submissionid:25099732-revert-update-layoutlib-main-prebuilts Change-Id: Ia7866c4ad1ca6c237f75aa4e41cc6c61b8a5d179 --- bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index ec775b2ec9..de7f651bab 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -91,6 +91,7 @@ import java.util.ArrayList; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import java.util.function.Function; import static android.os._Original_Build.VERSION.SDK_INT; @@ -590,6 +591,11 @@ public class RenderSessionImpl extends RenderAction { mSystemViewInfoList = visitAllChildren(mViewRoot, 0, 0, params, false); + Consumer imageTransformation = getParams().getImageTransformation(); + if (imageTransformation != null) { + imageTransformation.accept(mImage); + } + boolean enableLayoutValidation = Boolean.TRUE.equals(params.getFlag(RenderParamsFlags.FLAG_ENABLE_LAYOUT_VALIDATOR)); boolean enableLayoutValidationImageCheck = Boolean.TRUE.equals( params.getFlag(RenderParamsFlags.FLAG_ENABLE_LAYOUT_VALIDATOR_IMAGE_CHECK)); -- cgit v1.2.3 From 9fe32203040f6af8ef9d7c6403c17b387139cb82 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Tue, 7 Mar 2023 20:17:50 +0000 Subject: Fix DisplayEventReceiver_Delegate The signature of DisplayEventReceiver.nativeInit was changed in the Android framework. This updates the corresponding delegate. Bug: 74062470 Test: N/A (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:1d2e35945970f9fc3fe17c065c425f72e796414b) Merged-In: Iaed9e91efd11334f64e9c6700cac3304602bc4ed Change-Id: Iaed9e91efd11334f64e9c6700cac3304602bc4ed --- bridge/src/android/view/DisplayEventReceiver_Delegate.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bridge/src/android/view/DisplayEventReceiver_Delegate.java b/bridge/src/android/view/DisplayEventReceiver_Delegate.java index f1d4e65725..0ca568cd86 100644 --- a/bridge/src/android/view/DisplayEventReceiver_Delegate.java +++ b/bridge/src/android/view/DisplayEventReceiver_Delegate.java @@ -20,6 +20,7 @@ import com.android.layoutlib.bridge.impl.DelegateManager; import com.android.tools.layoutlib.annotations.LayoutlibDelegate; import android.os.MessageQueue; +import android.view.DisplayEventReceiver.VsyncEventData; import java.lang.ref.WeakReference; @@ -32,7 +33,8 @@ public class DisplayEventReceiver_Delegate { @LayoutlibDelegate /*package*/ static long nativeInit(WeakReference receiver, - MessageQueue messageQueue, int vsyncSource, int eventRegistration, long layerHandle) { + WeakReference vsyncEventData, MessageQueue messageQueue, + int vsyncSource, int eventRegistration, long layerHandle) { return sManager.addNewDelegate(new DisplayEventReceiver_Delegate()); } -- cgit v1.2.3 From 783d88862567d84fbb6622e7df0a2d5041990198 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Fri, 14 Jul 2023 12:47:49 +0100 Subject: Update PermissionManager_Delegate The signature of the checkPermission method was changed. Bug: 74062470 Test: layoutlib tests (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:bdb16b10bb63c97532aeef9a3a2ef77115e470be) Merged-In: I45078aa3e7908ffc305a65a586b108075f8b769a Change-Id: I45078aa3e7908ffc305a65a586b108075f8b769a --- bridge/src/android/permission/PermissionManager_Delegate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridge/src/android/permission/PermissionManager_Delegate.java b/bridge/src/android/permission/PermissionManager_Delegate.java index 1aad83062d..642b015a2b 100644 --- a/bridge/src/android/permission/PermissionManager_Delegate.java +++ b/bridge/src/android/permission/PermissionManager_Delegate.java @@ -23,7 +23,7 @@ import android.content.pm.PackageManager; public class PermissionManager_Delegate { @LayoutlibDelegate - public static int checkPermission(String permission, int pid, int uid) { + public static int checkPermission(String permission, int pid, int uid, int deviceId) { return PackageManager.PERMISSION_GRANTED; } } -- cgit v1.2.3 From 66b3d4491f264ca09b1b06983d390d6aad52b329 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Tue, 17 Oct 2023 14:08:09 +0100 Subject: Add delegate for VMRuntime.is64Bit Android only supports 64 bit artifacts now, and it relies on having VMRuntime.is64Bit to return true for the system properties to be correctly set up. Bug: 74062470 Test: layoutlib tests (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:acf80529e1265c527e7251a1f928fab1508c5160) Merged-In: I0a3cc0a9c8746f62c0ac23937ccbaa8a5e907dee Change-Id: I0a3cc0a9c8746f62c0ac23937ccbaa8a5e907dee --- bridge/src/dalvik/system/VMRuntime_Delegate.java | 5 +++++ common/src/com/android/tools/layoutlib/create/NativeConfig.java | 1 + 2 files changed, 6 insertions(+) diff --git a/bridge/src/dalvik/system/VMRuntime_Delegate.java b/bridge/src/dalvik/system/VMRuntime_Delegate.java index 2fe10154b8..23faf55518 100644 --- a/bridge/src/dalvik/system/VMRuntime_Delegate.java +++ b/bridge/src/dalvik/system/VMRuntime_Delegate.java @@ -36,4 +36,9 @@ public class VMRuntime_Delegate { /*package*/ static int getNotifyNativeInterval() { return VMRuntimeCommonHelper.getNotifyNativeInterval(); } + + @LayoutlibDelegate + public static boolean is64Bit(VMRuntime runtime) { + return true; + } } diff --git a/common/src/com/android/tools/layoutlib/create/NativeConfig.java b/common/src/com/android/tools/layoutlib/create/NativeConfig.java index def9aef674..c2e9783dab 100644 --- a/common/src/com/android/tools/layoutlib/create/NativeConfig.java +++ b/common/src/com/android/tools/layoutlib/create/NativeConfig.java @@ -147,6 +147,7 @@ public class NativeConfig { "com.android.internal.util.XmlUtils#convertValueToInt", "com.android.internal.view.menu.MenuBuilder#createNewMenuItem", "dalvik.system.VMRuntime#getNotifyNativeInterval", + "dalvik.system.VMRuntime#is64Bit", "dalvik.system.VMRuntime#newUnpaddedArray", "libcore.io.MemoryMappedFile#bigEndianIterator", "libcore.io.MemoryMappedFile#close", -- cgit v1.2.3 From ef3cefd015260484c570d974a181e5810bb11c08 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Thu, 26 Oct 2023 17:03:10 +0100 Subject: Update test golden image Bug: 74062470 Test: layoutlib tests (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:cac55c59b52f3bb64c4012104ef95f901b23efba) Merged-In: I6a70c64fa4908859236c3474d6db995b2551aa53 Change-Id: I6a70c64fa4908859236c3474d6db995b2551aa53 --- .../res/testApp/MyApplication/golden/rtl_ltr.png | Bin 50572 -> 51042 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bridge/tests/res/testApp/MyApplication/golden/rtl_ltr.png b/bridge/tests/res/testApp/MyApplication/golden/rtl_ltr.png index 118e926796..fab98dc2d4 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/rtl_ltr.png and b/bridge/tests/res/testApp/MyApplication/golden/rtl_ltr.png differ -- cgit v1.2.3 From 569b6b64a6f3bce9ece54bb0d05c2f3c72b9f717 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Wed, 1 Nov 2023 18:49:28 +0000 Subject: Update layoutlib golden images Bug: 74062470 Test: N/A Merged-In: I9b24fd7c777515f33ed17cd4d9f6747a45453039 Change-Id: I3fc9040cf590ad02cda58cbe679d7675251e4126 --- .../testApp/MyApplication/golden/allwidgets.png | Bin 159826 -> 157879 bytes .../MyApplication/golden/allwidgets_tab.png | Bin 62633 -> 61523 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png b/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png index fb5e970dc4..7ac28b683a 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png and b/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png differ diff --git a/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png b/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png index 5d452ef48d..50b5f26443 100644 Binary files a/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png and b/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png differ -- cgit v1.2.3 From b4c3716974fd4faa77ae12fb1298cc735f6f5efc Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Thu, 2 Nov 2023 16:23:29 +0000 Subject: Add Setting.Config delegate This is called during the initialization of AutofillManager, and needs to happen after BridgeCotnext has been created. So we also move the creation of AutofillManager to the first time it is called for. Bug: 74062470 Test: layoutlib tests (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:e4b7f0116fed12a9609124eca1a0b75115fc72cd) Merged-In: I54b568f94c76466d36504fb9bf80031bfaf90f91 Change-Id: I54b568f94c76466d36504fb9bf80031bfaf90f91 --- .../android/provider/Settings_Config_Delegate.java | 35 ++++++++++++++++++++++ .../layoutlib/bridge/android/BridgeContext.java | 6 ++-- .../tools/layoutlib/create/NativeConfig.java | 1 + 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 bridge/src/android/provider/Settings_Config_Delegate.java diff --git a/bridge/src/android/provider/Settings_Config_Delegate.java b/bridge/src/android/provider/Settings_Config_Delegate.java new file mode 100644 index 0000000000..ae802ddc2b --- /dev/null +++ b/bridge/src/android/provider/Settings_Config_Delegate.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2023 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.provider; + +import com.android.layoutlib.bridge.impl.RenderAction; +import com.android.tools.layoutlib.annotations.LayoutlibDelegate; + +import android.content.ContentResolver; + +/** + * Delegate that provides alternative implementation for methods in {@link Settings.Config} + *

+ * Through the layoutlib_create tool, selected methods of DeviceConfig have been replaced by + * calls to methods of the same name in this delegate class. + */ +public class Settings_Config_Delegate { + @LayoutlibDelegate + static ContentResolver getContentResolver() { + return RenderAction.getCurrentContext().getContentResolver(); + } +} diff --git a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 65cf9619d3..9bffc23eb3 100644 --- a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -173,7 +173,7 @@ public class BridgeContext extends Context { private final LayoutlibCallback mLayoutlibCallback; private final WindowManager mWindowManager; private final DisplayManager mDisplayManager; - private final AutofillManager mAutofillManager; + private AutofillManager mAutofillManager; private final ClipboardManager mClipboardManager; private final ActivityManager mActivityManager; private final ConnectivityManager mConnectivityManager; @@ -268,7 +268,6 @@ public class BridgeContext extends Context { mWindowManager = new WindowManagerImpl(this, mMetrics); mDisplayManager = new DisplayManager(this); - mAutofillManager = new AutofillManager(this, new Default()); mClipboardManager = new ClipboardManager(this, null); mActivityManager = ActivityManager_Accessor.getActivityManagerInstance(this); mConnectivityManager = new ConnectivityManager(this, null); @@ -688,6 +687,9 @@ public class BridgeContext extends Context { return InputMethodManager.forContext(this); case AUTOFILL_MANAGER_SERVICE: + if (mAutofillManager == null) { + mAutofillManager = new AutofillManager(this, new Default()); + } return mAutofillManager; case CLIPBOARD_SERVICE: diff --git a/common/src/com/android/tools/layoutlib/create/NativeConfig.java b/common/src/com/android/tools/layoutlib/create/NativeConfig.java index c2e9783dab..339ce786ee 100644 --- a/common/src/com/android/tools/layoutlib/create/NativeConfig.java +++ b/common/src/com/android/tools/layoutlib/create/NativeConfig.java @@ -109,6 +109,7 @@ public class NativeConfig { "android.provider.DeviceConfig#getLong", "android.provider.DeviceConfig#getProperty", "android.provider.DeviceConfig#getString", + "android.provider.Settings$Config#getContentResolver", "android.text.format.DateFormat#is24HourFormat", "android.util.Xml#newPullParser", "android.view.Choreographer#getFrameTimeNanos", -- cgit v1.2.3 From 42b2f350a10765aa3d47b807402fd55d6cd0351d Mon Sep 17 00:00:00 2001 From: Luis Santiago Re Date: Fri, 10 Nov 2023 15:13:49 +0000 Subject: Make sure to try using a custom inflater only if wanted Bug: 310189265 Test: N/A (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:777536016b841d504210278b2d7d4750bee97d55) Merged-In: Ie365965d695a96f5d94108cc66cb9588832925f9 Change-Id: Ie365965d695a96f5d94108cc66cb9588832925f9 --- bridge/src/android/view/BridgeInflater.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bridge/src/android/view/BridgeInflater.java b/bridge/src/android/view/BridgeInflater.java index ec8476dfb5..ad9a442da7 100644 --- a/bridge/src/android/view/BridgeInflater.java +++ b/bridge/src/android/view/BridgeInflater.java @@ -250,6 +250,9 @@ public final class BridgeInflater extends LayoutInflater { */ @Nullable private View createViewFromCustomInflater(@NotNull String name, @NotNull AttributeSet attrs) { + if (!mLayoutlibCallback.shouldUseCustomInflater()) { + return null; + } if (mCustomInflater == null) { Context context = getContext(); context = getBaseContext(context); -- cgit v1.2.3 From 1cb93bced2afc95be8401ddcc646db4e4780c278 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Thu, 23 Nov 2023 16:10:11 +0000 Subject: Ensure accessibility works with dialogs Dialogs normally display in a different window, but in layoutlib they are simply added to the current view hierarchy. That causes a problem for accessibility, as the root view for dialogs is a DecorView, which is automatically considered to be the root for accessibility. This confuses the accessibility node info creation, resulting in a cycle. To prevent that, we set the decor view to be the root view as far as ViewRootImpl is concerned, which is enough to solve the accessibility cycle issue. But we need to make sure that Layout, which is the actual root of the hierarchy still considers itself visible (which requires overriding getChildVisibleRect and getGlobalVisibleRect, as those normally query ViewRootImpl which is not the parent of Layout anymore when there is a Dialog). Bug: 312418057 Test: test added (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:69e377a789407277ebb748f2c4e01216f2e9a92d) Merged-In: I0742c0bc9469fdf114853e686f9cf213ef676f2d Change-Id: I0742c0bc9469fdf114853e686f9cf213ef676f2d --- bridge/src/android/view/AttachInfo_Accessor.java | 2 + bridge/src/android/view/ViewRootImpl_Accessor.java | 10 ++-- bridge/src/android/view/WindowManagerImpl.java | 18 ++++++++ .../com/android/layoutlib/bridge/impl/Layout.java | 21 +++++++++ .../layoutlib/bridge/impl/RenderSessionImpl.java | 7 --- .../bridge/android/AccessibilityTest.java | 54 ++++++++++++++++++++++ 6 files changed, 102 insertions(+), 10 deletions(-) diff --git a/bridge/src/android/view/AttachInfo_Accessor.java b/bridge/src/android/view/AttachInfo_Accessor.java index 2e38b31793..b8c8f0e060 100644 --- a/bridge/src/android/view/AttachInfo_Accessor.java +++ b/bridge/src/android/view/AttachInfo_Accessor.java @@ -37,6 +37,8 @@ public class AttachInfo_Accessor { info.mInTouchMode = false; // this is so that we can display selections. info.mHardwareAccelerated = false; info.mApplicationScale = 1.0f; + ViewRootImpl_Accessor.setChild(root, view); + view.assignParent(root); view.dispatchAttachedToWindow(info, 0); } diff --git a/bridge/src/android/view/ViewRootImpl_Accessor.java b/bridge/src/android/view/ViewRootImpl_Accessor.java index 691f59ae46..d15952ad3d 100644 --- a/bridge/src/android/view/ViewRootImpl_Accessor.java +++ b/bridge/src/android/view/ViewRootImpl_Accessor.java @@ -26,9 +26,13 @@ public class ViewRootImpl_Accessor { public static void setChild(ViewRootImpl viewRoot, View child) { viewRoot.mView = child; - child.assignParent(viewRoot); - viewRoot.mWidth = child.getWidth(); - viewRoot.mHeight = child.getHeight(); + if (child != null) { + viewRoot.mWidth = child.getWidth(); + viewRoot.mHeight = child.getHeight(); + } else { + viewRoot.mWidth = -1; + viewRoot.mHeight = -1; + } } public static void detachFromWindow(ViewRootImpl viewRoot) { diff --git a/bridge/src/android/view/WindowManagerImpl.java b/bridge/src/android/view/WindowManagerImpl.java index eb1e22c736..285ca9e5e4 100644 --- a/bridge/src/android/view/WindowManagerImpl.java +++ b/bridge/src/android/view/WindowManagerImpl.java @@ -41,6 +41,8 @@ import com.android.internal.R; import com.android.internal.policy.DecorView; import com.android.layoutlib.bridge.Bridge; +import java.util.ArrayList; + public class WindowManagerImpl implements WindowManager { private final Context mContext; @@ -179,10 +181,12 @@ public class WindowManagerImpl implements WindowManager { } } mCurrentRootView.addView(arg0, frameLayoutParams); + ViewRootImpl_Accessor.setChild(mBaseRootView.getViewRootImpl(), arg0); } @Override public void removeView(View arg0) { + ViewRootImpl viewRootImpl = arg0.getViewRootImpl(); if (mCurrentRootView != null) { mCurrentRootView.removeView(arg0); if (mBaseRootView != null && mCurrentRootView.getChildCount() == 0) { @@ -190,6 +194,20 @@ public class WindowManagerImpl implements WindowManager { mCurrentRootView = null; } } + if (viewRootImpl != null && viewRootImpl.getView() == arg0) { + View newRoot = null; + if (mCurrentRootView != null && mCurrentRootView.getChildCount() > 0) { + ArrayList childrenList = mCurrentRootView.buildOrderedChildList(); + newRoot = childrenList.get(childrenList.size() - 1); + } else if (mBaseRootView != null) { + View root = mBaseRootView; + while (root.getParent() instanceof View) { + root = (View)root.getParent(); + } + newRoot = root; + } + ViewRootImpl_Accessor.setChild(viewRootImpl, newRoot); + } } @Override diff --git a/bridge/src/com/android/layoutlib/bridge/impl/Layout.java b/bridge/src/com/android/layoutlib/bridge/impl/Layout.java index c8e5009888..1ca3b9c2cc 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/Layout.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/Layout.java @@ -38,6 +38,8 @@ import com.android.resources.ScreenOrientation; import android.R.id; import android.annotation.NonNull; import android.graphics.Color; +import android.graphics.Point; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.DisplayMetrics; import android.util.TypedValue; @@ -196,6 +198,25 @@ class Layout extends FrameLayout { mBuilder = null; } + @Override + public boolean getChildVisibleRect(View child, Rect r, Point offset, boolean forceParentCheck) { + return r.intersect(0, 0, getWidth(), getHeight()); + } + + @Override + public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { + int width = mRight - mLeft; + int height = mBottom - mTop; + if (width > 0 && height > 0) { + r.set(0, 0, width, height); + if (globalOffset != null) { + globalOffset.set(-mScrollX, -mScrollY); + } + return true; + } + return false; + } + @NonNull private static View createSysUiOverlay(@NonNull BridgeContext context) { SysUiOverlay overlay = new SysUiOverlay(context, 20, 10, 50, 40, 60); diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index de7f651bab..034a92df75 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -72,8 +72,6 @@ import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewGroup.MarginLayoutParams; import android.view.ViewParent; -import android.view.ViewRootImpl; -import android.view.ViewRootImpl_Accessor; import android.view.WindowManagerImpl; import android.widget.ActionMenuView; import android.widget.FrameLayout; @@ -375,11 +373,6 @@ public class RenderSessionImpl extends RenderAction { mViewRoot.getViewRootImpl().mTmpFrames.displayFrame.set(mViewRoot.getLeft(), mViewRoot.getTop(), mViewRoot.getRight(), mViewRoot.getBottom()); - ViewRootImpl rootImpl = AttachInfo_Accessor.getRootView(mViewRoot); - if (rootImpl != null) { - ViewRootImpl_Accessor.setChild(rootImpl, mViewRoot); - } - mSystemViewInfoList = visitAllChildren(mViewRoot, 0, 0, params, false); diff --git a/bridge/tests/src/com/android/layoutlib/bridge/android/AccessibilityTest.java b/bridge/tests/src/com/android/layoutlib/bridge/android/AccessibilityTest.java index 149680868e..dc24d845ca 100644 --- a/bridge/tests/src/com/android/layoutlib/bridge/android/AccessibilityTest.java +++ b/bridge/tests/src/com/android/layoutlib/bridge/android/AccessibilityTest.java @@ -19,6 +19,7 @@ package com.android.layoutlib.bridge.android; import com.android.ide.common.rendering.api.RenderSession; import com.android.ide.common.rendering.api.Result; import com.android.ide.common.rendering.api.SessionParams; +import com.android.ide.common.rendering.api.SessionParams.RenderingMode; import com.android.ide.common.rendering.api.ViewInfo; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.intensive.LayoutLibTestCallback; @@ -117,4 +118,57 @@ public class AccessibilityTest extends RenderTestBase { session.dispose(); } } + + @Test + public void testDialogAccessibility() throws Exception { + String layout = + "\n" + + " \n" + + "\n"; + LayoutPullParser parser = LayoutPullParser.createFromString(layout); + // Create LayoutLibCallback. + LayoutLibTestCallback layoutLibCallback = + new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); + layoutLibCallback.initResources(); + SessionParams params = getSessionParamsBuilder() + .setParser(parser) + .setCallback(layoutLibCallback) + .setTheme("Theme.Material.Light.NoActionBar.Fullscreen", false) + .setRenderingMode(RenderingMode.V_SCROLL) + .disableDecoration() + .build(); + RenderSession session = sBridge.createSession(params); + session.setElapsedFrameTimeNanos(1); + try { + Result renderResult = session.render(50000); + assertTrue(renderResult.isSuccess()); + View rootView = + (View)((View) session.getSystemRootViews().get(1).getViewObject()).getParent(); + int[] counter = {0}; + session.execute(() -> { + AccessibilityNodeInfo rootNode = rootView.createAccessibilityNodeInfo(); + assertNotNull(rootNode); + rootNode.setQueryFromAppProcessEnabled(rootView, true); + traverseAccessibilityTree(rootNode, counter); + }); + assertEquals(17, counter[0]); + } finally { + session.dispose(); + } + } + + private void traverseAccessibilityTree(AccessibilityNodeInfo node, int[] counter) { + int childrenSize = node.getChildCount(); + for (int i = 0; i < childrenSize; i++) { + AccessibilityNodeInfo child = node.getChild(i); + counter[0]++; + traverseAccessibilityTree(child, counter); + } + } } -- cgit v1.2.3 From b2ba3bf14ca96ec852d581c511412cca3920b6f2 Mon Sep 17 00:00:00 2001 From: Jerome Gaillard Date: Wed, 29 Nov 2023 15:31:28 +0000 Subject: Clear Accessibility caches once not needed This ensures that caches in AccessibilityInteractionClient are cleared as soon as they are not needed, without having to wait for the render session to be disposed. Bug: 312996644 Test: tests updated (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:aae8dd05cf194f568350253fa49b88dde39b4990) Merged-In: I1280faa5a983a395099e7549da82448a46540108 Change-Id: I1280faa5a983a395099e7549da82448a46540108 --- .../AccessibilityInteractionClient_Accessor.java | 27 ++++++++++++++++++++++ .../layoutlib/bridge/impl/RenderAction.java | 2 ++ .../layoutlib/bridge/impl/RenderSessionImpl.java | 15 ++++++++++++ .../bridge/android/AccessibilityTest.java | 4 ++++ .../android/tools/layoutlib/create/CreateInfo.java | 5 ++++ 5 files changed, 53 insertions(+) create mode 100644 bridge/src/android/view/accessibility/AccessibilityInteractionClient_Accessor.java diff --git a/bridge/src/android/view/accessibility/AccessibilityInteractionClient_Accessor.java b/bridge/src/android/view/accessibility/AccessibilityInteractionClient_Accessor.java new file mode 100644 index 0000000000..8c87c22e88 --- /dev/null +++ b/bridge/src/android/view/accessibility/AccessibilityInteractionClient_Accessor.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2023 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.accessibility; + +public class AccessibilityInteractionClient_Accessor { + public static void clearCaches() { + AccessibilityInteractionClient.sCaches.clear(); + AccessibilityInteractionClient.sClients.clear(); + AccessibilityInteractionClient.sConnectionCache.clear(); + AccessibilityInteractionClient.sScrollingWindows.clear(); + AccessibilityInteractionClient.sDirectConnectionCount = 0; + } +} diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java index 8048ff1e1a..98b59565f7 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java @@ -43,6 +43,7 @@ import android.view.IWindowManagerImpl; import android.view.Surface; import android.view.ViewConfiguration_Accessor; import android.view.WindowManagerGlobal_Delegate; +import android.view.accessibility.AccessibilityInteractionClient_Accessor; import android.view.inputmethod.InputMethodManager_Accessor; import java.util.Collections; @@ -313,6 +314,7 @@ public abstract class RenderAction { ParserFactory.setParserFactory(null); PropertyValuesHolder_Accessor.clearClassCaches(); + AccessibilityInteractionClient_Accessor.clearCaches(); } public static BridgeContext getCurrentContext() { diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index 034a92df75..9ed5d17531 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -72,6 +72,8 @@ import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewGroup.MarginLayoutParams; import android.view.ViewParent; +import android.view.ViewRootImpl; +import android.view.ViewRootImpl_Accessor; import android.view.WindowManagerImpl; import android.widget.ActionMenuView; import android.widget.FrameLayout; @@ -1206,6 +1208,19 @@ public class RenderSessionImpl extends RenderAction { } } + @Override + public void release() { + super.release(); + if (mViewRoot == null) { + return; + } + ViewRootImpl viewRootImpl = mViewRoot.getViewRootImpl(); + if (viewRootImpl == null) { + return; + } + ViewRootImpl_Accessor.detachFromWindow(viewRootImpl); + } + private void disposeImageSurface() { if (mCanvas != null) { mCanvas.release(); diff --git a/bridge/tests/src/com/android/layoutlib/bridge/android/AccessibilityTest.java b/bridge/tests/src/com/android/layoutlib/bridge/android/AccessibilityTest.java index dc24d845ca..e1cad4ee2d 100644 --- a/bridge/tests/src/com/android/layoutlib/bridge/android/AccessibilityTest.java +++ b/bridge/tests/src/com/android/layoutlib/bridge/android/AccessibilityTest.java @@ -31,6 +31,7 @@ import org.junit.Test; import android.view.View; import android.view.ViewGroup; +import android.view.accessibility.AccessibilityInteractionClient; import android.view.accessibility.AccessibilityNodeInfo; import java.io.FileNotFoundException; @@ -63,6 +64,7 @@ public class AccessibilityTest extends RenderTestBase { try { Result renderResult = session.render(50000); assertTrue(renderResult.isSuccess()); + assertEquals(0, AccessibilityInteractionClient.sConnectionCache.size()); View rootView = (View)session.getSystemRootViews().get(0).getViewObject(); AccessibilityNodeInfo rootNode = rootView.createAccessibilityNodeInfo(); assertNotNull(rootNode); @@ -148,6 +150,7 @@ public class AccessibilityTest extends RenderTestBase { try { Result renderResult = session.render(50000); assertTrue(renderResult.isSuccess()); + assertEquals(0, AccessibilityInteractionClient.sConnectionCache.size()); View rootView = (View)((View) session.getSystemRootViews().get(1).getViewObject()).getParent(); int[] counter = {0}; @@ -157,6 +160,7 @@ public class AccessibilityTest extends RenderTestBase { rootNode.setQueryFromAppProcessEnabled(rootView, true); traverseAccessibilityTree(rootNode, counter); }); + assertEquals(0, AccessibilityInteractionClient.sConnectionCache.size()); assertEquals(17, counter[0]); } finally { session.dispose(); diff --git a/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/create/src/com/android/tools/layoutlib/create/CreateInfo.java index b2b7e7084b..fbfd66895f 100644 --- a/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -336,6 +336,11 @@ public final class CreateInfo implements ICreateInfo { "android.view.Choreographer#mCallbackQueues", // required for tests only "android.view.Choreographer$CallbackQueue#mHead", // required for tests only "android.view.ViewRootImpl#mTmpFrames", + "android.view.accessibility.AccessibilityInteractionClient#sCaches", + "android.view.accessibility.AccessibilityInteractionClient#sClients", + "android.view.accessibility.AccessibilityInteractionClient#sConnectionCache", + "android.view.accessibility.AccessibilityInteractionClient#sDirectConnectionCount", + "android.view.accessibility.AccessibilityInteractionClient#sScrollingWindows", "com.android.internal.util.ArrayUtils#sCache", }; -- cgit v1.2.3