summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOscar Adame Vázquez <oscarad@google.com>2018-06-07 21:14:07 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2018-06-07 21:14:07 +0000
commitdb7542da7aec8e442a8f2fc5c4ff40bd86086837 (patch)
treeb5ec52ad4bef55bc67fa5d020f78dad3e9dc360d
parentaaddafb4b7aedd31ae4b87d30fe43e09df77c5a6 (diff)
parentad720ed1bde5c5621701a3dc764699adf899bcde (diff)
downloadsherpa-db7542da7aec8e442a8f2fc5c4ff40bd86086837.tar.gz
Merge "Cleaning up Chains related code" into studio-master-dev
-rw-r--r--solver/src/main/java/android/support/constraint/solver/widgets/Chain.java60
-rw-r--r--solver/src/main/java/android/support/constraint/solver/widgets/ChainHead.java111
-rw-r--r--solver/src/main/java/android/support/constraint/solver/widgets/ConstraintWidget.java10
-rw-r--r--solver/src/main/java/android/support/constraint/solver/widgets/ConstraintWidgetContainer.java32
-rw-r--r--solver/src/main/java/android/support/constraint/solver/widgets/Optimizer.java53
-rw-r--r--solver/src/test/java/android/support/constraint/solver/ChainHeadTest.java129
6 files changed, 272 insertions, 123 deletions
diff --git a/solver/src/main/java/android/support/constraint/solver/widgets/Chain.java b/solver/src/main/java/android/support/constraint/solver/widgets/Chain.java
index e51fbaa..6d6f12b 100644
--- a/solver/src/main/java/android/support/constraint/solver/widgets/Chain.java
+++ b/solver/src/main/java/android/support/constraint/solver/widgets/Chain.java
@@ -43,7 +43,7 @@ class Chain {
// Don't skip things. Either the element is GONE or not.
int offset = 0;
int chainsSize = 0;
- ConstraintWidget[] chainsArray = null;
+ ChainHead[] chainsArray = null;
if (orientation == ConstraintWidget.HORIZONTAL) {
offset = 0;
chainsSize = constraintWidgetContainer.mHorizontalChainsSize;
@@ -54,7 +54,7 @@ class Chain {
chainsArray = constraintWidgetContainer.mVerticalChainsArray;
}
for (int i = 0; i < chainsSize; i++) {
- ConstraintWidget first = chainsArray[i];
+ ChainHead first = chainsArray[i];
if (constraintWidgetContainer.optimizeFor(Optimizer.OPTIMIZATION_CHAIN)) {
if (!Optimizer.applyChainOptimized(constraintWidgetContainer, system, orientation, offset, first)) {
applyChainConstraints(constraintWidgetContainer, system, orientation, offset, first);
@@ -73,14 +73,19 @@ class Chain {
* @param system the linear system we add the equations to
* @param orientation HORIZONTAL or VERTICAL
* @param offset 0 or 2 to accomodate for HORIZONTAL / VERTICAL
- * @param first first widget of the chain
+ * @param chainHead a chain represented by its main elements
*/
static void applyChainConstraints(ConstraintWidgetContainer container, LinearSystem system,
- int orientation, int offset, ConstraintWidget first) {
+ int orientation, int offset, ChainHead chainHead) {
+ ConstraintWidget first = chainHead.mFirst;
+ ConstraintWidget last = chainHead.mLast;
+ ConstraintWidget firstVisibleWidget = chainHead.mFirstVisibleWidget;
+ ConstraintWidget lastVisibleWidget = chainHead.mLastVisibleWidget;
+ ConstraintWidget head = chainHead.mHead;
+
ConstraintWidget widget = first;
ConstraintWidget next = null;
- ConstraintWidget firstVisibleWidget = null;
- ConstraintWidget lastVisibleWidget = null;
+
boolean done = false;
int numMatchConstraints = 0;
float totalWeights = 0;
@@ -92,33 +97,6 @@ class Chain {
boolean isChainSpreadInside = false;
boolean isChainPacked = false;
- ConstraintWidget head = first;
- if (orientation == ConstraintWidget.HORIZONTAL && container.isRtl()) {
- // find the last widget
- while (!done) {
- // go to the next widget
- ConstraintAnchor nextAnchor = widget.mListAnchors[offset + 1].mTarget;
- if (nextAnchor != null) {
- next = nextAnchor.mOwner;
- if (next.mListAnchors[offset].mTarget == null
- || next.mListAnchors[offset].mTarget.mOwner != widget) {
- next = null;
- }
- } else {
- next = null;
- }
- if (next != null) {
- widget = next;
- } else {
- done = true;
- }
- }
- head = widget;
- widget = first;
- next = null;
- done = false;
- }
-
if (orientation == ConstraintWidget.HORIZONTAL) {
isChainSpread = head.mHorizontalChainStyle == ConstraintWidget.CHAIN_SPREAD;
isChainSpreadInside = head.mHorizontalChainStyle == ConstraintWidget.CHAIN_SPREAD_INSIDE;
@@ -131,24 +109,9 @@ class Chain {
// The first traversal will:
// - set up some basic ordering constraints
- // - build a linked list of visible widgets
// - build a linked list of matched constraints widgets
while (!done) {
- // apply ordering on the current widget
-
- // First, let's maintain a linked list of visible widgets for the chain
- widget.mListNextVisibleWidget[orientation] = null;
- if (widget.getVisibility() != ConstraintWidget.GONE) {
- if (lastVisibleWidget != null) {
- lastVisibleWidget.mListNextVisibleWidget[orientation] = widget;
- }
- if (firstVisibleWidget == null) {
- firstVisibleWidget = widget;
- }
- lastVisibleWidget = widget;
- }
-
ConstraintAnchor begin = widget.mListAnchors[offset];
int strength = SolverVariable.STRENGTH_HIGHEST;
if (isWrapContent || isChainPacked) {
@@ -221,7 +184,6 @@ class Chain {
done = true;
}
}
- ConstraintWidget last = widget;
// Make sure we have constraints for the last anchors / targets
if (lastVisibleWidget != null && last.mListAnchors[offset + 1].mTarget != null) {
diff --git a/solver/src/main/java/android/support/constraint/solver/widgets/ChainHead.java b/solver/src/main/java/android/support/constraint/solver/widgets/ChainHead.java
new file mode 100644
index 0000000..ee56b7a
--- /dev/null
+++ b/solver/src/main/java/android/support/constraint/solver/widgets/ChainHead.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2018 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.support.constraint.solver.widgets;
+
+/**
+ * Class to represent a chain by its main elements.
+ */
+public class ChainHead {
+
+ protected ConstraintWidget mFirst;
+ protected ConstraintWidget mFirstVisibleWidget;
+ protected ConstraintWidget mLast;
+ protected ConstraintWidget mLastVisibleWidget;
+ protected ConstraintWidget mHead;
+ private int mOrientation;
+ private boolean mIsRtl = false;
+ // TODO: Apply linked list of matched constraint widgets.
+
+ /**
+ * Initialize variables, then determine visible widgets and head.
+ *
+ * @param first first widget in a chain
+ * @param orientation orientation of the chain (either Horizontal or Vertical)
+ * @param isRtl Right-to-left layout flag to determine the actual head of the chain
+ */
+ public ChainHead(ConstraintWidget first, int orientation, boolean isRtl){
+ mFirst = first;
+ mOrientation = orientation;
+ mIsRtl = isRtl;
+ defineChainProperties();
+ }
+
+ private void defineChainProperties(){
+ int offset = mOrientation * 2;
+
+ // TraverseChain
+ ConstraintWidget widget = mFirst;
+ ConstraintWidget next = mFirst;
+ boolean done = false;
+ widget.mListNextVisibleWidget[mOrientation] = null;
+
+ while (!done) {
+ // go to the next widget
+ ConstraintAnchor nextAnchor = widget.mListAnchors[offset + 1].mTarget;
+ if (nextAnchor != null) {
+ next = nextAnchor.mOwner;
+ if (next.mListAnchors[offset].mTarget == null
+ || next.mListAnchors[offset].mTarget.mOwner != widget) {
+ next = null;
+ }
+ } else {
+ next = null;
+ }
+ if(widget.getVisibility() != ConstraintWidget.GONE) {
+ if (mFirstVisibleWidget == null) {
+ mFirstVisibleWidget = widget;
+ }
+ if(mLastVisibleWidget != null){
+ mLastVisibleWidget.mListNextVisibleWidget[mOrientation] = widget;
+ }
+ mLastVisibleWidget = widget;
+ }
+ if (next != null) {
+ widget = next;
+ } else {
+ done = true;
+ }
+ }
+ mLast = widget;
+
+ if(mOrientation == ConstraintWidget.HORIZONTAL && mIsRtl) {
+ mHead = mLast;
+ }else{
+ mHead = mFirst;
+ }
+ }
+
+ public ConstraintWidget getFirst() {
+ return mFirst;
+ }
+
+ public ConstraintWidget getFirstVisibleWidget() {
+ return mFirstVisibleWidget;
+ }
+
+ public ConstraintWidget getLast() {
+ return mLast;
+ }
+
+ public ConstraintWidget getLastVisibleWidget() {
+ return mLastVisibleWidget;
+ }
+
+ public ConstraintWidget getHead() {
+ return mHead;
+ }
+}
diff --git a/solver/src/main/java/android/support/constraint/solver/widgets/ConstraintWidget.java b/solver/src/main/java/android/support/constraint/solver/widgets/ConstraintWidget.java
index a5e143d..ed8bd32 100644
--- a/solver/src/main/java/android/support/constraint/solver/widgets/ConstraintWidget.java
+++ b/solver/src/main/java/android/support/constraint/solver/widgets/ConstraintWidget.java
@@ -2194,15 +2194,21 @@ public class ConstraintWidget {
verticalParentWrapContent = mParent != null ? mParent.mListDimensionBehaviors[DIMENSION_VERTICAL] == WRAP_CONTENT : false;
// Add this widget to an horizontal chain if dual connections are found
+ if((mLeft.mTarget != null && mLeft.mTarget.mTarget != mLeft) &&
+ mRight.mTarget != null && mRight.mTarget.mTarget == mRight){
+ ((ConstraintWidgetContainer) mParent).addChain(this, HORIZONTAL);
+ }
if ((mLeft.mTarget != null && mLeft.mTarget.mTarget == mLeft)
|| (mRight.mTarget != null && mRight.mTarget.mTarget == mRight)) {
- ((ConstraintWidgetContainer) mParent).addChain(this, HORIZONTAL);
inHorizontalChain = true;
}
// Add this widget to an vertical chain if dual connections are found
+ if((mTop.mTarget != null && mTop.mTarget.mTarget != mTop) &&
+ mBottom.mTarget != null && mBottom.mTarget.mTarget == mBottom){
+ ((ConstraintWidgetContainer) mParent).addChain(this, VERTICAL);
+ }
if ((mTop.mTarget != null && mTop.mTarget.mTarget == mTop)
|| (mBottom.mTarget != null && mBottom.mTarget.mTarget == mBottom)) {
- ((ConstraintWidgetContainer) mParent).addChain(this, VERTICAL);
inVerticalChain = true;
}
diff --git a/solver/src/main/java/android/support/constraint/solver/widgets/ConstraintWidgetContainer.java b/solver/src/main/java/android/support/constraint/solver/widgets/ConstraintWidgetContainer.java
index 15a2ce2..322aef9 100644
--- a/solver/src/main/java/android/support/constraint/solver/widgets/ConstraintWidgetContainer.java
+++ b/solver/src/main/java/android/support/constraint/solver/widgets/ConstraintWidgetContainer.java
@@ -55,8 +55,8 @@ public class ConstraintWidgetContainer extends WidgetContainer {
int mHorizontalChainsSize = 0;
int mVerticalChainsSize = 0;
- ConstraintWidget[] mVerticalChainsArray = new ConstraintWidget[4];
- ConstraintWidget[] mHorizontalChainsArray = new ConstraintWidget[4];
+ ChainHead[] mVerticalChainsArray = new ChainHead[4];
+ ChainHead[] mHorizontalChainsArray = new ChainHead[4];
private int mOptimizationLevel = Optimizer.OPTIMIZATION_STANDARD;
@@ -664,22 +664,8 @@ public class ConstraintWidgetContainer extends WidgetContainer {
void addChain(ConstraintWidget constraintWidget, int type) {
ConstraintWidget widget = constraintWidget;
if (type == HORIZONTAL) {
- // find the left most widget that doesn't have a dual connection (i.e., start of chain)
- while (widget.mLeft.mTarget != null
- && widget.mLeft.mTarget.mOwner.mRight.mTarget != null
- && widget.mLeft.mTarget.mOwner.mRight.mTarget == widget.mLeft
- && widget.mLeft.mTarget.mOwner != widget) {
- widget = widget.mLeft.mTarget.mOwner;
- }
addHorizontalChain(widget);
} else if (type == VERTICAL) {
- // find the top most widget that doesn't have a dual connection (i.e., start of chain)
- while (widget.mTop.mTarget != null
- && widget.mTop.mTarget.mOwner.mBottom.mTarget != null
- && widget.mTop.mTarget.mOwner.mBottom.mTarget == widget.mTop
- && widget.mTop.mTarget.mOwner != widget) {
- widget = widget.mTop.mTarget.mOwner;
- }
addVerticalChain(widget);
}
}
@@ -691,15 +677,10 @@ public class ConstraintWidgetContainer extends WidgetContainer {
* @param widget widget starting the chain
*/
private void addHorizontalChain(ConstraintWidget widget) {
- for (int i = 0; i < mHorizontalChainsSize; i++) {
- if (mHorizontalChainsArray[i] == widget) {
- return;
- }
- }
if (mHorizontalChainsSize + 1 >= mHorizontalChainsArray.length) {
mHorizontalChainsArray = Arrays.copyOf(mHorizontalChainsArray, mHorizontalChainsArray.length * 2);
}
- mHorizontalChainsArray[mHorizontalChainsSize] = widget;
+ mHorizontalChainsArray[mHorizontalChainsSize] = new ChainHead(widget, HORIZONTAL, isRtl());
mHorizontalChainsSize++;
}
@@ -710,15 +691,10 @@ public class ConstraintWidgetContainer extends WidgetContainer {
* @param widget widget starting the chain
*/
private void addVerticalChain(ConstraintWidget widget) {
- for (int i = 0; i < mVerticalChainsSize; i++) {
- if (mVerticalChainsArray[i] == widget) {
- return;
- }
- }
if (mVerticalChainsSize + 1 >= mVerticalChainsArray.length) {
mVerticalChainsArray = Arrays.copyOf(mVerticalChainsArray, mVerticalChainsArray.length * 2);
}
- mVerticalChainsArray[mVerticalChainsSize] = widget;
+ mVerticalChainsArray[mVerticalChainsSize] = new ChainHead(widget, VERTICAL, isRtl());
mVerticalChainsSize++;
}
diff --git a/solver/src/main/java/android/support/constraint/solver/widgets/Optimizer.java b/solver/src/main/java/android/support/constraint/solver/widgets/Optimizer.java
index d60c069..4fb16d3 100644
--- a/solver/src/main/java/android/support/constraint/solver/widgets/Optimizer.java
+++ b/solver/src/main/java/android/support/constraint/solver/widgets/Optimizer.java
@@ -372,17 +372,21 @@ public class Optimizer {
* @param system
* @param orientation
* @param offset
- * @param first
+ * @param chainHead
*
* @return true if the chain has been optimized, false otherwise
*/
static boolean applyChainOptimized(ConstraintWidgetContainer container, LinearSystem system,
- int orientation, int offset, ConstraintWidget first) {
+ int orientation, int offset, ChainHead chainHead) {
+
+ ConstraintWidget first = chainHead.mFirst;
+ ConstraintWidget last = chainHead.mLast;
+ ConstraintWidget firstVisibleWidget = chainHead.mFirstVisibleWidget;
+ ConstraintWidget lastVisibleWidget = chainHead.mLastVisibleWidget;
+ ConstraintWidget head = chainHead.mHead;
ConstraintWidget widget = first;
ConstraintWidget next = null;
- ConstraintWidget firstVisibleWidget = null;
- ConstraintWidget lastVisibleWidget = null;
boolean done = false;
@@ -396,33 +400,6 @@ public class Optimizer {
boolean isChainSpreadInside = false;
boolean isChainPacked = false;
- ConstraintWidget head = first;
- if (orientation == ConstraintWidget.HORIZONTAL && container.isRtl()) {
- // find the last widget
- while (!done) {
- // go to the next widget
- ConstraintAnchor nextAnchor = widget.mListAnchors[offset + 1].mTarget;
- if (nextAnchor != null) {
- next = nextAnchor.mOwner;
- if (next.mListAnchors[offset].mTarget == null
- || next.mListAnchors[offset].mTarget.mOwner != widget) {
- next = null;
- }
- } else {
- next = null;
- }
- if (next != null) {
- widget = next;
- } else {
- done = true;
- }
- }
- head = widget;
- widget = first;
- next = null;
- done = false;
- }
-
if (orientation == ConstraintWidget.HORIZONTAL) {
isChainSpread = head.mHorizontalChainStyle == ConstraintWidget.CHAIN_SPREAD;
isChainSpreadInside = head.mHorizontalChainStyle == ConstraintWidget.CHAIN_SPREAD_INSIDE;
@@ -435,7 +412,6 @@ public class Optimizer {
// The first traversal will:
// - set up some basic ordering constraints
- // - build a linked list of visible widgets
// - build a linked list of matched constraints widgets
float totalSize = 0;
@@ -443,18 +419,8 @@ public class Optimizer {
int numVisibleWidgets = 0;
while (!done) {
- // apply ordering on the current widget
-
- // First, let's maintain a linked list of visible widgets for the chain
- widget.mListNextVisibleWidget[orientation] = null;
+ // Measure visible widgets and add margins.
if (widget.getVisibility() != ConstraintWidget.GONE) {
- if (lastVisibleWidget != null) {
- lastVisibleWidget.mListNextVisibleWidget[orientation] = widget;
- }
- if (firstVisibleWidget == null) {
- firstVisibleWidget = widget;
- }
- lastVisibleWidget = widget;
numVisibleWidgets ++;
if (orientation == HORIZONTAL) {
totalSize += widget.getWidth();
@@ -514,7 +480,6 @@ public class Optimizer {
done = true;
}
}
- ConstraintWidget last = widget;
ResolutionAnchor firstNode = first.mListAnchors[offset].getResolutionNode();
ResolutionAnchor lastNode = last.mListAnchors[offset + 1].getResolutionNode();
diff --git a/solver/src/test/java/android/support/constraint/solver/ChainHeadTest.java b/solver/src/test/java/android/support/constraint/solver/ChainHeadTest.java
new file mode 100644
index 0000000..99bf0a2
--- /dev/null
+++ b/solver/src/test/java/android/support/constraint/solver/ChainHeadTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2018 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.support.constraint.solver;
+
+import android.support.constraint.solver.widgets.ChainHead;
+import android.support.constraint.solver.widgets.ConstraintAnchor;
+import android.support.constraint.solver.widgets.ConstraintWidget;
+import android.support.constraint.solver.widgets.ConstraintWidgetContainer;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+public class ChainHeadTest {
+
+ @Test
+ public void basicHorizontalChainHeadTest(){
+ ConstraintWidgetContainer root = new ConstraintWidgetContainer(0, 0, 600, 600);
+ ConstraintWidget A = new ConstraintWidget(100, 20);
+ ConstraintWidget B = new ConstraintWidget(100, 20);
+ ConstraintWidget C = new ConstraintWidget(100, 20);
+
+ root.setDebugName("root");
+ A.setDebugName("A");
+ B.setDebugName("B");
+ C.setDebugName("C");
+
+ root.add(A);
+ root.add(B);
+ root.add(C);
+
+ A.connect(ConstraintAnchor.Type.LEFT, root, ConstraintAnchor.Type.LEFT);
+ A.connect(ConstraintAnchor.Type.RIGHT, B, ConstraintAnchor.Type.LEFT);
+ B.connect(ConstraintAnchor.Type.LEFT, A, ConstraintAnchor.Type.RIGHT);
+ B.connect(ConstraintAnchor.Type.RIGHT, C, ConstraintAnchor.Type.LEFT);
+ C.connect(ConstraintAnchor.Type.LEFT, B, ConstraintAnchor.Type.RIGHT);
+ C.connect(ConstraintAnchor.Type.RIGHT, root, ConstraintAnchor.Type.RIGHT);
+ A.connect(ConstraintAnchor.Type.TOP, root, ConstraintAnchor.Type.TOP);
+ B.connect(ConstraintAnchor.Type.TOP, root, ConstraintAnchor.Type.TOP);
+ C.connect(ConstraintAnchor.Type.TOP, root, ConstraintAnchor.Type.TOP);
+
+ ChainHead chainHead = new ChainHead(A, ConstraintWidget.HORIZONTAL, false);
+
+ assertEquals(chainHead.getHead(), A);
+ assertEquals(chainHead.getFirst(), A);
+ assertEquals(chainHead.getFirstVisibleWidget(), A);
+ assertEquals(chainHead.getLast(), C);
+ assertEquals(chainHead.getLastVisibleWidget(), C);
+
+ A.setVisibility(ConstraintWidget.GONE);
+
+ chainHead = new ChainHead(A, ConstraintWidget.HORIZONTAL, false);
+
+ assertEquals(chainHead.getHead(), A);
+ assertEquals(chainHead.getFirst(), A);
+ assertEquals(chainHead.getFirstVisibleWidget(), B);
+
+
+ chainHead = new ChainHead(A, ConstraintWidget.HORIZONTAL, true);
+
+ assertEquals(chainHead.getHead(), C);
+ assertEquals(chainHead.getFirst(), A);
+ assertEquals(chainHead.getFirstVisibleWidget(), B);
+ }
+
+ @Test
+ public void basicVerticalChainHeadTest(){
+ ConstraintWidgetContainer root = new ConstraintWidgetContainer(0, 0, 600, 600);
+ ConstraintWidget A = new ConstraintWidget(100, 20);
+ ConstraintWidget B = new ConstraintWidget(100, 20);
+ ConstraintWidget C = new ConstraintWidget(100, 20);
+
+ root.setDebugName("root");
+ A.setDebugName("A");
+ B.setDebugName("B");
+ C.setDebugName("C");
+
+ root.add(A);
+ root.add(B);
+ root.add(C);
+
+ A.connect(ConstraintAnchor.Type.TOP, root, ConstraintAnchor.Type.TOP);
+ A.connect(ConstraintAnchor.Type.BOTTOM, B, ConstraintAnchor.Type.TOP);
+ B.connect(ConstraintAnchor.Type.TOP, A, ConstraintAnchor.Type.BOTTOM);
+ B.connect(ConstraintAnchor.Type.BOTTOM, C, ConstraintAnchor.Type.TOP);
+ C.connect(ConstraintAnchor.Type.TOP, B, ConstraintAnchor.Type.BOTTOM);
+ C.connect(ConstraintAnchor.Type.BOTTOM, root, ConstraintAnchor.Type.BOTTOM);
+ A.connect(ConstraintAnchor.Type.LEFT, root, ConstraintAnchor.Type.LEFT);
+ B.connect(ConstraintAnchor.Type.LEFT, root, ConstraintAnchor.Type.LEFT);
+ C.connect(ConstraintAnchor.Type.LEFT, root, ConstraintAnchor.Type.LEFT);
+
+ ChainHead chainHead = new ChainHead(A, ConstraintWidget.VERTICAL, false);
+
+ assertEquals(chainHead.getHead(), A);
+ assertEquals(chainHead.getFirst(), A);
+ assertEquals(chainHead.getFirstVisibleWidget(), A);
+ assertEquals(chainHead.getLast(), C);
+ assertEquals(chainHead.getLastVisibleWidget(), C);
+
+ A.setVisibility(ConstraintWidget.GONE);
+
+ chainHead = new ChainHead(A, ConstraintWidget.VERTICAL, false);
+
+ assertEquals(chainHead.getHead(), A);
+ assertEquals(chainHead.getFirst(), A);
+ assertEquals(chainHead.getFirstVisibleWidget(), B);
+
+
+ chainHead = new ChainHead(A, ConstraintWidget.VERTICAL, true);
+
+ assertEquals(chainHead.getHead(), A);
+ assertEquals(chainHead.getFirst(), A);
+ assertEquals(chainHead.getFirstVisibleWidget(), B);
+ }
+
+}