Make spacer update layout params successfully during diff-updating
Bug: 330230902
Test: updated existed tests to verify
Change-Id: I3e6879637dee01cdbe0dde514b6047b42276f306
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflater.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflater.java
index ca14d6b..0751da3 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflater.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflater.java
@@ -69,6 +69,7 @@
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewOutlineProvider;
@@ -2481,16 +2482,7 @@
if (spacer.getWidth().hasLinearDimension()) {
handleProp(
spacer.getWidth().getLinearDimension(),
- width -> {
- LayoutParams lp = view.getLayoutParams();
- if (lp == null) {
- Log.e(TAG, "LayoutParams was null when updating spacer width");
- return;
- }
-
- lp.width = safeDpToPx(width);
- view.requestLayout();
- },
+ widthDp -> updateLayoutWidthParam(view, widthDp),
posId,
pipelineMaker);
}
@@ -2498,16 +2490,7 @@
if (spacer.getHeight().hasLinearDimension()) {
handleProp(
spacer.getHeight().getLinearDimension(),
- height -> {
- LayoutParams lp = view.getLayoutParams();
- if (lp == null) {
- Log.e(TAG, "LayoutParams was null when updating spacer height");
- return;
- }
-
- lp.height = safeDpToPx(height);
- view.requestLayout();
- },
+ heightDp -> updateLayoutHeightParam(view, heightDp),
posId,
pipelineMaker);
}
@@ -2517,45 +2500,14 @@
if (spacer.getWidth().hasLinearDimension()) {
handleProp(
spacer.getWidth().getLinearDimension(),
- width -> {
- // Update minimum width first, because LayoutParams could be null.
- // This calls requestLayout.
- int widthPx = safeDpToPx(width);
- view.setMinimumWidth(widthPx);
-
- // We still need to update layout params in case other dimension is
- // expand, so 0 could
- // be miss interpreted.
- LayoutParams lp = view.getLayoutParams();
- if (lp == null) {
- Log.e(TAG, "LayoutParams was null when updating spacer width");
- return;
- }
-
- lp.width = widthPx;
- },
+ widthDp -> updateLayoutWidthParam(view, widthDp),
posId,
pipelineMaker);
}
if (spacer.getHeight().hasLinearDimension()) {
handleProp(
spacer.getHeight().getLinearDimension(),
- height -> {
- // Update minimum height first, because LayoutParams could be null.
- // This calls requestLayout.
- int heightPx = safeDpToPx(height);
- view.setMinimumHeight(heightPx);
-
- // We still need to update layout params in case other dimension is
- // expand, so 0 could be miss interpreted.
- LayoutParams lp = view.getLayoutParams();
- if (lp == null) {
- Log.e(TAG, "LayoutParams was null when updating spacer height");
- return;
- }
-
- lp.height = heightPx;
- },
+ heightDp -> updateLayoutHeightParam(view, heightDp),
posId,
pipelineMaker);
}
@@ -2576,6 +2528,49 @@
}
}
+ private void updateLayoutWidthParam(@NonNull View view, float widthDp) {
+ scheduleLayoutParamsUpdate(
+ view,
+ () -> {
+ checkNotNull(view.getLayoutParams()).width = safeDpToPx(widthDp);
+ view.requestLayout();
+ });
+ }
+
+ private void updateLayoutHeightParam(@NonNull View view, float heightDp) {
+ scheduleLayoutParamsUpdate(
+ view,
+ () -> {
+ checkNotNull(view.getLayoutParams()).height = safeDpToPx(heightDp);
+ view.requestLayout();
+ });
+ }
+
+ private void scheduleLayoutParamsUpdate(@NonNull View view, Runnable layoutParamsUpdater) {
+ if (view.getLayoutParams() != null) {
+ layoutParamsUpdater.run();
+ return;
+ }
+
+ // View#getLayoutParams() returns null if this view is not attached to a parent ViewGroup.
+ // And once the view is attached to a parent ViewGroup, it guarantees a non-null return
+ // value. Thus, we use the listener to do the update of the layout param the moment that the
+ // view is attached to window.
+ view.addOnAttachStateChangeListener(
+ new View.OnAttachStateChangeListener() {
+
+ @Override
+ public void onViewAttachedToWindow(@NonNull View v) {
+ layoutParamsUpdater.run();
+ v.removeOnAttachStateChangeListener(this);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(@NonNull View v) {
+ }
+ });
+ }
+
@Nullable
private InflatedView inflateArcSpacer(
ParentViewWrapper parentViewWrapper,
diff --git a/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflaterTest.java b/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflaterTest.java
index 04e3f2b..d0fb91c 100644
--- a/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflaterTest.java
+++ b/wear/protolayout/protolayout-renderer/src/test/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflaterTest.java
@@ -708,7 +708,7 @@
// This tests that minimum dimension is correctly set.
// Dimensions are in DP, but the density is currently 1 in the tests, so this is fine.
- expect.that(tv.getMinimumWidth()).isEqualTo(width);
+ expect.that(tv.getMeasuredWidth()).isEqualTo(width);
expect.that(tv.getMeasuredHeight()).isEqualTo(height);
}
@@ -741,13 +741,9 @@
ViewGroup boxAfterMutation = (ViewGroup) inflatedViewParent.getChildAt(0);
View spacerAfterMutation = boxAfterMutation.getChildAt(0);
- // Dimensions are in DP, but the density is currently 1 in the tests, so this is fine.
- expect.that(spacerAfterMutation.getMeasuredWidth()).isEqualTo(0);
- expect.that(spacerAfterMutation.getMeasuredHeight()).isEqualTo(0);
-
- // This tests that minimum dimension is correctly set.
- expect.that(spacerAfterMutation.getMinimumWidth()).isEqualTo(newWidth);
- expect.that(spacerAfterMutation.getMinimumHeight()).isEqualTo(newHeight);
+ // This tests that the layout dimension is correctly set.
+ expect.that(spacerAfterMutation.getMeasuredWidth()).isEqualTo(newWidth);
+ expect.that(spacerAfterMutation.getMeasuredHeight()).isEqualTo(newHeight);
}
@Test
@@ -799,7 +795,7 @@
Renderer renderer = renderer(layout1);
ViewGroup inflatedViewParent = renderer.inflate();
- Layout layout2 = layoutBoxWithSpacer(newHeight, newWidth, modifiers);
+ Layout layout2 = layoutBoxWithSpacer(newWidth, newHeight, modifiers);
// Compute the mutation.
ViewGroupMutation mutation =
@@ -815,8 +811,8 @@
View spacerAfterMutation = boxAfterMutation.getChildAt(0);
// Dimensions are in DP, but the density is currently 1 in the tests, so this is fine.
- expect.that(spacerAfterMutation.getMeasuredWidth()).isEqualTo(0);
- expect.that(spacerAfterMutation.getMeasuredHeight()).isEqualTo(0);
+ expect.that(spacerAfterMutation.getMeasuredWidth()).isEqualTo(newWidth);
+ expect.that(spacerAfterMutation.getMeasuredHeight()).isEqualTo(newHeight);
}
@Test