diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-12-01 00:17:23 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-12-01 00:17:23 +0000 |
commit | 3b42f824de3a7d01d02f635fd17fcd400cb32f01 (patch) | |
tree | 5e67a9cd2b723f1346e2300012f6ad208bf814c6 | |
parent | f4b2f6950e0784b4a34e70fb0b13318a65d796f0 (diff) | |
parent | b2ba3bf14ca96ec852d581c511412cca3920b6f2 (diff) | |
download | layoutlib-3b42f824de3a7d01d02f635fd17fcd400cb32f01.tar.gz |
Snap for 11162593 from b2ba3bf14ca96ec852d581c511412cca3920b6f2 to 24Q1-release
Change-Id: Ia1b0ef3284278fc7f8a2f152b7283405605220af
9 files changed, 153 insertions, 8 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<View> 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/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/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/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<T extends RenderParams> { 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 de7f651bab..9ed5d17531 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -375,11 +375,6 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { 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); @@ -1213,6 +1208,19 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { } } + @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 149680868e..e1cad4ee2d 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; @@ -30,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; @@ -62,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); @@ -117,4 +120,59 @@ public class AccessibilityTest extends RenderTestBase { session.dispose(); } } + + @Test + public void testDialogAccessibility() throws Exception { + String layout = + "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + + " android:padding=\"16dp\"\n" + + " android:orientation=\"horizontal\"\n" + + " android:layout_width=\"fill_parent\"\n" + + " android:layout_height=\"fill_parent\">\n" + + " <com.android.layoutlib.test.myapplication.widgets.DialogView\n" + + " android:layout_height=\"wrap_content\"\n" + + " android:layout_width=\"wrap_content\" />\n" + + "</LinearLayout>\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()); + assertEquals(0, AccessibilityInteractionClient.sConnectionCache.size()); + 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(0, AccessibilityInteractionClient.sConnectionCache.size()); + 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); + } + } } 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", }; |