diff options
author | 2016-11-14 17:23:59 +0000 | |
---|---|---|
committer | 2016-11-17 11:09:02 +0000 | |
commit | b076ee1a83099f1394b3fc4850513fcee1ca8bde (patch) | |
tree | 0dd6879ddf41bd244d7ade390cca677d7ae4af4b | |
parent | 1a625911a22a5b4a0e42bb21c2dbf4c8df16e77a (diff) |
Call onApplyWindowInsets after requestApplyWindowInsets
On layoutlib, requestApplyWindowInsets wasn't being passed up to
ViewRootImpl so onApplyWindowInsets wasn't being called.
Test: Added new test testApplyWindowInsets
Bug: http://b.android.com/169308
Change-Id: I8f3174dc2879a7e6c3db1628a1bfb1c023d88efc
6 files changed, 132 insertions, 0 deletions
diff --git a/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java b/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java index 85584d3ed2cc..4445a2238538 100644 --- a/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java +++ b/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java @@ -51,4 +51,8 @@ public class AttachInfo_Accessor { view.dispatchDetachedFromWindow(); } } + + public static ViewRootImpl getRootView(View view) { + return view.mAttachInfo != null ? view.mAttachInfo.mViewRootImpl : null; + } } diff --git a/tools/layoutlib/bridge/src/android/view/ViewRootImpl_Accessor.java b/tools/layoutlib/bridge/src/android/view/ViewRootImpl_Accessor.java new file mode 100644 index 000000000000..0e15b97243b0 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/view/ViewRootImpl_Accessor.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +/** + * Accessor to allow layoutlib to call {@link ViewRootImpl#dispatchApplyInsets} directly. + */ +public class ViewRootImpl_Accessor { + public static void dispatchApplyInsets(ViewRootImpl viewRoot, View host) { + viewRoot.dispatchApplyInsets(host); + } +} diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java index 97698df0f22a..c92d35af64b8 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java @@ -38,7 +38,10 @@ import android.annotation.NonNull; import android.graphics.drawable.Drawable; import android.util.DisplayMetrics; import android.util.TypedValue; +import android.view.AttachInfo_Accessor; import android.view.View; +import android.view.ViewRootImpl; +import android.view.ViewRootImpl_Accessor; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.RelativeLayout; @@ -302,6 +305,17 @@ class Layout extends RelativeLayout { return Bridge.getResourceId(ResourceType.ID, ID_PREFIX + name); } + @Override + public void requestFitSystemWindows() { + // The framework call would usually bubble up to ViewRootImpl but, in layoutlib, Layout will + // act as view root for most purposes. That way, we can also save going through the Handler + // to dispatch the new applied insets. + ViewRootImpl root = AttachInfo_Accessor.getRootView(this); + if (root != null) { + ViewRootImpl_Accessor.dispatchApplyInsets(root, this); + } + } + /** * A helper class to help initialize the Layout. */ diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/InsetsWidget.java b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/InsetsWidget.java new file mode 100644 index 000000000000..36e5c2646420 --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/myapplication.widgets/InsetsWidget.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.layoutlib.test.myapplication.widgets; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.WindowInsets; +import android.widget.TextView; + +public class InsetsWidget extends TextView { + public static boolean sApplyInsetsCalled = false; + + public InsetsWidget(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + + requestApplyInsets(); + } + + @Override + public WindowInsets onApplyWindowInsets(WindowInsets insets) { + sApplyInsetsCalled = true; + return super.onApplyWindowInsets(insets); + } +} diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/insets.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/insets.xml new file mode 100644 index 000000000000..ff06d79dd00a --- /dev/null +++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/insets.xml @@ -0,0 +1,12 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:padding="16dp" + android:orientation="horizontal" + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + + <com.android.layoutlib.test.myapplication.widgets.InsetsWidget + android:text="Hello world" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/text1"/> +</LinearLayout> diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java index 5423e876e23f..7e9193f38154 100644 --- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java @@ -62,6 +62,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; +import java.lang.reflect.Field; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; @@ -86,6 +87,7 @@ import java.util.zip.ZipFile; import com.google.android.collect.Lists; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -408,6 +410,37 @@ public class Main { renderAndVerify(params, "simple_activity.png"); } + @Test + public void testOnApplyInsetsCall() + throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { + // We get the widget via reflection to avoid IntelliJ complaining about the class being + // located in the wrong package. (From the Bridge tests point of view, it is) + Class insetsWidgetClass = Class.forName("com.android.layoutlib.test.myapplication.widgets" + + ".InsetsWidget"); + Field field = insetsWidgetClass.getDeclaredField("sApplyInsetsCalled"); + assertFalse((Boolean)field.get(null)); + + LayoutPullParser parser = createLayoutPullParser("insets.xml"); + LayoutLibTestCallback layoutLibCallback = + new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); + layoutLibCallback.initResources(); + SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5, + layoutLibCallback, "Theme.Material.Light.NoActionBar", false, + RenderingMode.NORMAL, 22); + try { + renderAndVerify(params, "scrolled.png"); + } catch(AssertionError e) { + // In this particular test we do not care about the image similarity. + // TODO: Create new render method that allows to not compare images. + if (!e.getLocalizedMessage().startsWith("Images differ")) { + throw e; + } + } + + assertTrue((Boolean)field.get(null)); + field.set(null, false); + } + @AfterClass public static void tearDown() { sLayoutLibLog = null; |