@Override public float getCurrentState(PropertyHandle propertyHandle) { final LayoutOutput root = mLayoutState.getMountableOutputAt(0); return mAnimatedProperty.get(root); }
/** @return a {@link LayoutOutput} for a given {@param layoutOutputId} */ @Nullable LayoutOutput getLayoutOutput(long layoutOutputId) { final int position = getLayoutOutputPositionForId(layoutOutputId); return position < 0 ? null : getMountableOutputAt(position); }
private boolean shouldSkipMounting(LayoutState layoutState, int index) { if (!ComponentsConfiguration.createPhantomLayoutOutputsForTransitions) { return false; } final LayoutOutput layoutOutput = layoutState.getMountableOutputAt(index); final boolean isPhantom = (layoutOutput.getFlags() & MountItem.LAYOUT_FLAG_PHANTOM) != 0; final boolean isAnimating = mAnimatingTransitionIds.contains(layoutOutput.getTransitionId()); return isPhantom && !isAnimating; }
private int findLastDescendantIndex(LayoutState layoutState, int index) { final LayoutOutput host = layoutState.getMountableOutputAt(index); final long hostId = host.getId(); for (int i = index + 1, size = layoutState.getMountableOutputCount(); i < size; i++) { final LayoutOutput layoutOutput = layoutState.getMountableOutputAt(i); // Walk up the parents looking for the host's id: if we find it, it's a descendant. If we // reach the root, then it's not a descendant and we can stop. long curentHostId = layoutOutput.getHostMarker(); while (curentHostId != hostId) { if (curentHostId == ROOT_HOST_ID) { return i - 1; } final int parentIndex = layoutState.getLayoutOutputPositionForId(curentHostId); final LayoutOutput parent = layoutState.getMountableOutputAt(parentIndex); curentHostId = parent.getHostMarker(); } } return layoutState.getMountableOutputCount() - 1; }
private static ComponentLifecycle getComponentAt(final LayoutState layoutState, final int index) { return layoutState.getMountableOutputAt(index).getComponent(); }
/** * Determine whether to apply disappear animation to the given {@link MountItem} */ private boolean isItemDisappearing(LayoutState layoutState, int index) { if (!shouldAnimateTransitions(layoutState) || !hasTransitionsToAnimate()) { return false; } if (mTransitionManager == null || mLastMountedLayoutState == null) { return false; } final LayoutOutput layoutOutput = mLastMountedLayoutState.getMountableOutputAt(index); final TransitionId transitionId = layoutOutput.getTransitionId(); if (transitionId == null) { return false; } return mTransitionManager.isDisappearing(transitionId); }
private static void assertOutputsState( LayoutState layoutState, @LayoutOutput.UpdateState int state) { assertThat(STATE_DIRTY).isEqualTo(layoutState.getMountableOutputAt(0).getUpdateState()); for (int i = 1; i < layoutState.getMountableOutputCount(); i++) { LayoutOutput output = layoutState.getMountableOutputAt(i); assertThat(state).isEqualTo(output.getUpdateState()); } }
private static CharSequence getTextFromTextComponent(final LayoutState layoutState, final int index) { return Whitebox.getInternalState(layoutState.getMountableOutputAt(index).getComponent(), "text"); }
@Test public void testLayoutOutputForRootNestedTreeComponentWithAspectRatio() { final Component component = new InlineLayoutSpec() { @Override protected Component onCreateLayout(final ComponentContext c) { return create(c) .child(TestSizeDependentComponent.create(c).widthPx(100).aspectRatio(1)) .build(); } }; final LayoutState layoutState = calculateLayoutState( application, component, -1, makeSizeSpec(0, UNSPECIFIED), makeSizeSpec(0, UNSPECIFIED)); final Rect mountBounds = new Rect(); layoutState.getMountableOutputAt(0).getMountBounds(mountBounds); assertThat(mountBounds).isEqualTo(new Rect(0, 0, 100, 100)); }
@Test public void testLayoutOutputsForEnabledFalseDoesntWrap() { final Component component = new InlineLayoutSpec() { @Override protected Component onCreateLayout(final ComponentContext c) { return create(c) .child(create(c).child(TestDrawableComponent.create(c).enabled(false))) .build(); } }; final LayoutState layoutState = calculateLayoutState( application, component, -1, makeSizeSpec(100, EXACTLY), makeSizeSpec(100, EXACTLY)); assertThat(layoutState.getMountableOutputCount()).isEqualTo(2); assertThat(layoutState.getMountableOutputAt(0).getNodeInfo()).isNull(); assertThat(layoutState.getMountableOutputAt(0).getComponent().getSimpleName()) .isEqualTo("HostComponent"); assertThat(layoutState.getMountableOutputAt(1).getComponent().getSimpleName()) .isEqualTo("TestDrawableComponent"); assertThat(MountItem.isTouchableDisabled(layoutState.getMountableOutputAt(1).getFlags())) .isTrue(); }
@Test public void testLayoutComponentForNestedTreeChildWithNullLayout() { final Component component = new InlineLayoutSpec() { @Override protected Component onCreateLayout(final ComponentContext c) { return create(c).paddingPx(ALL, 2).child(new TestNullLayoutComponent()).build(); } }; final LayoutState layoutState = calculateLayoutState( application, component, -1, makeSizeSpec(350, EXACTLY), makeSizeSpec(200, EXACTLY)); assertThat(layoutState.getMountableOutputCount()).isEqualTo(1); final Rect mountBounds = new Rect(); assertThat(isHostComponent(getComponentAt(layoutState, 0))).isTrue(); layoutState.getMountableOutputAt(0).getMountBounds(mountBounds); assertThat(mountBounds).isEqualTo(new Rect(0, 0, 350, 200)); }
@Test public void testCollectRootBoundsTransitionsExtractAppearFrom() { Transition transition = Transition.create(Transition.TransitionKeyType.GLOBAL, "rootKey").animate(AnimatedProperties.HEIGHT).appearFrom(10); TransitionId rootTransitionId = new TransitionId(TransitionId.Type.GLOBAL, "rootKey", null); Transition.RootBoundsTransition rootHeightTransition = new Transition.RootBoundsTransition(); TransitionUtils.collectRootBoundsTransitions( rootTransitionId, transition, AnimatedProperties.HEIGHT, rootHeightTransition); assertThat(rootHeightTransition.hasTransition).isTrue(); assertThat(rootHeightTransition.appearTransition).isNotNull(); LayoutState layoutState = mock(LayoutState.class); LayoutOutput rootLayout = new LayoutOutput(); rootLayout.setBounds(0, 0, 300, 100); when(layoutState.getMountableOutputAt(0)).thenReturn(rootLayout); int animateFrom = (int) Transition.getRootAppearFromValue( rootHeightTransition.appearTransition, layoutState, AnimatedProperties.HEIGHT); assertThat(animateFrom).isEqualTo(10); }
@Test public void testLayoutOutputsForSelectedOnRoot() { final Component component = new InlineLayoutSpec() { @Override protected Component onCreateLayout(final ComponentContext c) { return create(c).child(TestDrawableComponent.create(c)).selected(true).build(); } }; final LayoutState layoutState = calculateLayoutState( application, component, -1, makeSizeSpec(100, EXACTLY), makeSizeSpec(100, EXACTLY)); assertThat(layoutState.getMountableOutputCount()).isEqualTo(2); final long hostMarkerZero = layoutState.getMountableOutputAt(0).getHostMarker(); assertThat(layoutState.getMountableOutputAt(1).getHostMarker()).isEqualTo(hostMarkerZero); assertThat(isHostComponent(getComponentAt(layoutState, 0))).isTrue(); assertThat(getComponentAt(layoutState, 1)).isInstanceOf(TestDrawableComponent.class); assertThat(layoutState.getMountableOutputAt(0).getNodeInfo().getSelectedState()) .isEqualTo(SELECTED_SET_TRUE); }
@Test public void testLayoutOutputsForFocusableOnRoot() { final Component component = new InlineLayoutSpec() { @Override protected Component onCreateLayout(final ComponentContext c) { return create(c).child(TestDrawableComponent.create(c)).focusable(true).build(); } }; final LayoutState layoutState = calculateLayoutState( application, component, -1, makeSizeSpec(100, EXACTLY), makeSizeSpec(100, EXACTLY)); assertThat(layoutState.getMountableOutputCount()).isEqualTo(2); final long hostMarkerZero = layoutState.getMountableOutputAt(0).getHostMarker(); assertThat(layoutState.getMountableOutputAt(1).getHostMarker()).isEqualTo(hostMarkerZero); assertThat(isHostComponent(getComponentAt(layoutState, 0))).isTrue(); assertThat(getComponentAt(layoutState, 1)).isInstanceOf(TestDrawableComponent.class); assertThat(layoutState.getMountableOutputAt(0).getNodeInfo().getFocusState()).isEqualTo(FOCUS_SET_TRUE); }
@Test public void testLayoutOutputsForEnabledFalseInInnerComponentView() { final Component component = new InlineLayoutSpec() { @Override protected Component onCreateLayout(final ComponentContext c) { return create(c) .child(create(c).child(TestViewComponent.create(c).enabled(false))) .build(); } }; final LayoutState layoutState = calculateLayoutState( application, component, -1, makeSizeSpec(100, EXACTLY), makeSizeSpec(100, EXACTLY)); assertThat(layoutState.getMountableOutputCount()).isEqualTo(2); assertThat(layoutState.getMountableOutputAt(0).getNodeInfo()).isNull(); assertThat(layoutState.getMountableOutputAt(0).getComponent()) .isInstanceOf(HostComponent.class); assertThat(layoutState.getMountableOutputAt(1).getComponent()) .isInstanceOf(TestViewComponent.class); assertThat(layoutState.getMountableOutputAt(1).getNodeInfo().getEnabledState()) .isEqualTo(ENABLED_SET_FALSE); }
@Test public void testLayoutOutputsForSelected() { final Component component = new InlineLayoutSpec() { @Override protected Component onCreateLayout(final ComponentContext c) { return create(c) .child( create(c).child(TestDrawableComponent.create(c)).focusable(true).selected(true)) .build(); } }; final LayoutState layoutState = calculateLayoutState( application, component, -1, makeSizeSpec(100, EXACTLY), makeSizeSpec(100, EXACTLY)); assertThat(layoutState.getMountableOutputCount()).isEqualTo(3); assertThat(layoutState.getMountableOutputAt(0).getNodeInfo()).isNull(); assertThat(layoutState.getMountableOutputAt(1).getNodeInfo().getSelectedState()) .isEqualTo(SELECTED_SET_TRUE); }
@Test public void testCollectRootBoundsTransitionsExtractAppearFromDimensionValue() { Transition transition = Transition.create(Transition.TransitionKeyType.GLOBAL, "rootKey") .animate(AnimatedProperties.HEIGHT) .appearFrom(DimensionValue.heightPercentageOffset(50)); TransitionId rootTransitionId = new TransitionId(TransitionId.Type.GLOBAL, "rootKey", null); Transition.RootBoundsTransition rootHeightTransition = new Transition.RootBoundsTransition(); TransitionUtils.collectRootBoundsTransitions( rootTransitionId, transition, AnimatedProperties.HEIGHT, rootHeightTransition); assertThat(rootHeightTransition.hasTransition).isTrue(); assertThat(rootHeightTransition.appearTransition).isNotNull(); LayoutState layoutState = mock(LayoutState.class); LayoutOutput rootLayout = new LayoutOutput(); rootLayout.setBounds(0, 0, 300, 100); when(layoutState.getMountableOutputAt(0)).thenReturn(rootLayout); int animateFrom = (int) Transition.getRootAppearFromValue( rootHeightTransition.appearTransition, layoutState, AnimatedProperties.HEIGHT); float expectedAppearFrom = rootLayout.getBounds().height() * 1.5f; assertThat(animateFrom).isEqualTo((int) expectedAppearFrom); } }
@Test public void testLayoutOutputsForFocusable() { final Component component = new InlineLayoutSpec() { @Override protected Component onCreateLayout(final ComponentContext c) { return create(c) .child(create(c).child(TestDrawableComponent.create(c)).focusable(true)) .build(); } }; final LayoutState layoutState = calculateLayoutState( application, component, -1, makeSizeSpec(100, EXACTLY), makeSizeSpec(100, EXACTLY)); assertThat(layoutState.getMountableOutputCount()).isEqualTo(3); assertThat(layoutState.getMountableOutputAt(0).getNodeInfo()).isNull(); assertThat(layoutState.getMountableOutputAt(1).getNodeInfo().getFocusState()).isEqualTo(FOCUS_SET_TRUE); }
@Test @TargetApi(Build.VERSION_CODES.LOLLIPOP) public void testLayoutOutputsWithStateListAnimator() { final StateListAnimator stateListAnimator = new StateListAnimator(); final Component component = new InlineLayoutSpec() { @Override protected Component onCreateLayout(final ComponentContext c) { return create(c) .child( create(c) .child(TestDrawableComponent.create(c)) .stateListAnimator(stateListAnimator)) .build(); } }; final LayoutState layoutState = calculateLayoutState( application, component, -1, makeSizeSpec(100, EXACTLY), makeSizeSpec(100, EXACTLY)); assertThat(layoutState.getMountableOutputCount()).isEqualTo(3); assertThat(layoutState.getMountableOutputAt(1).getComponent()) .isExactlyInstanceOf(HostComponent.class); assertThat(layoutState.getMountableOutputAt(1).getViewNodeInfo().getStateListAnimator()) .isSameAs(stateListAnimator); assertThat(layoutState.getMountableOutputAt(2).getComponent()) .isExactlyInstanceOf(TestDrawableComponent.class); }
@Test public void testCachedMeasuresForNestedTreeComponentDelegateWithUndefinedSize() { final Component component1 = new TestNestedTreeDelegateWithUndefinedSizeLayout(); final Component component2 = new TestNestedTreeDelegateWithUndefinedSizeLayout(); LayoutState prevLayoutState = calculateLayoutStateWithDiffing( mContext, component1, makeSizeSpec(350, SizeSpec.EXACTLY), makeSizeSpec(200, SizeSpec.EXACTLY), null); LayoutState layoutState = calculateLayoutStateWithDiffing( mContext, component2, makeSizeSpec(350, SizeSpec.EXACTLY), makeSizeSpec(200, SizeSpec.EXACTLY), prevLayoutState); // The nested root measure() was called in the first layout calculation. TestComponent prevNestedRoot = (TestComponent) prevLayoutState.getMountableOutputAt(2).getComponent(); assertThat(prevNestedRoot.wasMeasureCalled()).isTrue(); TestComponent nestedRoot = (TestComponent) layoutState.getMountableOutputAt(2).getComponent(); assertThat(nestedRoot.wasMeasureCalled()).isFalse(); }