1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.constraintlayout.widget;
18 
19 import android.annotation.SuppressLint;
20 import android.content.Context;
21 import android.content.res.Resources;
22 import android.content.res.TypedArray;
23 import android.content.res.XmlResourceParser;
24 import android.graphics.Color;
25 import android.os.Build;
26 import android.os.Build.VERSION_CODES;
27 import android.util.AttributeSet;
28 import android.util.Log;
29 import android.util.SparseArray;
30 import android.util.SparseIntArray;
31 import android.util.TypedValue;
32 import android.util.Xml;
33 import android.view.LayoutInflater;
34 import android.view.View;
35 
36 import androidx.constraintlayout.core.motion.utils.Easing;
37 import androidx.constraintlayout.core.widgets.ConstraintWidget;
38 import androidx.constraintlayout.core.widgets.HelperWidget;
39 import androidx.constraintlayout.motion.widget.Debug;
40 import androidx.constraintlayout.motion.widget.MotionLayout;
41 import androidx.constraintlayout.motion.widget.MotionScene;
42 import androidx.constraintlayout.widget.ConstraintAttribute.AttributeType;
43 import androidx.constraintlayout.widget.ConstraintLayout.LayoutParams;
44 
45 import org.xmlpull.v1.XmlPullParser;
46 import org.xmlpull.v1.XmlPullParserException;
47 
48 import java.io.IOException;
49 import java.io.Writer;
50 import java.lang.reflect.Field;
51 import java.lang.reflect.Modifier;
52 import java.util.ArrayList;
53 import java.util.Arrays;
54 import java.util.HashMap;
55 import java.util.HashSet;
56 import java.util.Locale;
57 import java.util.Set;
58 
59 /**
60  * Defines a set of constraints to be used with {@link ConstraintLayout}.
61  *
62  * <p>{@code ConstraintSet} enables you create and save constraints and apply
63  * them to an existing {@code ConstraintLayout}. For details about constraint
64  * behaviour, see {@link ConstraintLayout}.</p>
65  *
66  * <p>{@code ConstraintsSet} can be created in various ways:</p>
67  * <ul>
68  *     <li>Manually &mdash;
69  *         {@code c = new ConstraintSet(); c.connect(...);}</li>
70  *     <li>From an {@code R.layout.*} object &mdash;
71  *         {@code c.clone(context, R.layout.layout1);}</li>
72  *     <li>From a {@code ConstraintLayout} &mdash;
73  *         {@code c.clone(constraintLayout);}</li>
74  * </ul>
75  *
76  * <p>Example code:</p>
77  * <pre>import android.content.Context;
78  *      import android.os.Bundle;
79  *      import android.support.constraint.ConstraintLayout;
80  *      import android.support.constraint.ConstraintSet;
81  *      import android.support.transition.TransitionManager;
82  *      import android.support.v7.app.AppCompatActivity;
83  *      import android.view.View;
84  *
85  *      public class MainActivity extends AppCompatActivity {
86  *          ConstraintSet mConstraintSet1 = new ConstraintSet(); // Create a ConstraintSet.
87  *          ConstraintSet mConstraintSet2 = new ConstraintSet(); // Create a ConstraintSet.
88  *          ConstraintLayout mConstraintLayout; // Cache the ConstraintLayout.
89  *          boolean mOld = true;
90  *
91  *
92  *          protected void onCreate(Bundle savedInstanceState) {
93  *              super.onCreate(savedInstanceState);
94  *              Context context = this;
95  *              mConstraintSet2.clone(context, R.layout.state2); // Get constraints from layout.
96  *              setContentView(R.layout.state1);
97  *              mConstraintLayout = (ConstraintLayout) findViewById(R.id.activity_main);
98  *              mConstraintSet1.clone(mConstraintLayout); // Get constraints from ConstraintSet.
99  *          }
100  *
101  *          public void foo(View view) {
102  *              TransitionManager.beginDelayedTransition(mConstraintLayout);
103  *              if (mOld = !mOld) {
104  *                  mConstraintSet1.applyTo(mConstraintLayout); // Set new constraints.
105  *              }  else {
106  *                  mConstraintSet2.applyTo(mConstraintLayout); // Set new constraints.
107  *              }
108  *          }
109  *      }</pre>
110  */
111 public class ConstraintSet {
112     private static final String TAG = "ConstraintSet";
113     private static final String ERROR_MESSAGE = "XML parser error must be within a Constraint ";
114 
115     private static final int INTERNAL_MATCH_PARENT = -1;
116     private static final int INTERNAL_WRAP_CONTENT = -2;
117     private static final int INTERNAL_MATCH_CONSTRAINT = -3;
118     private static final int INTERNAL_WRAP_CONTENT_CONSTRAINED = -4;
119 
120     private boolean mValidate;
121     public String mIdString;
122     public String derivedState = "";
123     private String [] mMatchLabels = new String[0];
124     public static final int ROTATE_NONE = 0;
125     public static final int ROTATE_PORTRATE_OF_RIGHT = 1;
126     public static final int ROTATE_PORTRATE_OF_LEFT = 2;
127     public static final int ROTATE_RIGHT_OF_PORTRATE = 3;
128     public static final int ROTATE_LEFT_OF_PORTRATE = 4;
129     public int mRotate = 0;
130     private HashMap<String, ConstraintAttribute> mSavedAttributes = new HashMap<>();
131 
132     /**
133      * require that all views have IDs to function
134      */
135     private boolean mForceId = true;
136     /**
137      * Used to indicate a parameter is cleared or not set
138      */
139     public static final int UNSET = LayoutParams.UNSET;
140 
141     /**
142      * Dimension will be controlled by constraints
143      */
144     public static final int MATCH_CONSTRAINT = ConstraintLayout.LayoutParams.MATCH_CONSTRAINT;
145 
146     /**
147      * Dimension will set by the view's content
148      */
149     public static final int WRAP_CONTENT = ConstraintLayout.LayoutParams.WRAP_CONTENT;
150 
151     /**
152      * How to calculate the size of a view in 0 dp by using its wrap_content size
153      */
154     public static final int MATCH_CONSTRAINT_WRAP =
155             ConstraintLayout.LayoutParams.MATCH_CONSTRAINT_WRAP;
156 
157     /**
158      * Calculate the size of a view in 0 dp by reducing the constrains gaps as much as possible
159      */
160     public static final int MATCH_CONSTRAINT_SPREAD =
161             ConstraintLayout.LayoutParams.MATCH_CONSTRAINT_SPREAD;
162 
163     public static final int MATCH_CONSTRAINT_PERCENT =
164             ConstraintLayout.LayoutParams.MATCH_CONSTRAINT_PERCENT;
165 
166     /**
167      * References the id of the parent.
168      * Used in:
169      * <ul>
170      * <li>{@link #connect(int, int, int, int, int)}</li>
171      * <li>{@link #center(int, int, int, int, int, int, int, float)}</li>
172      * </ul>
173      */
174     public static final int PARENT_ID = ConstraintLayout.LayoutParams.PARENT_ID;
175 
176     /**
177      * The horizontal orientation.
178      */
179     public static final int HORIZONTAL = ConstraintLayout.LayoutParams.HORIZONTAL;
180 
181     /**
182      * The vertical orientation.
183      */
184     public static final int VERTICAL = ConstraintLayout.LayoutParams.VERTICAL;
185 
186     /**
187      * Used to create a horizontal create guidelines.
188      */
189     public static final int HORIZONTAL_GUIDELINE = 0;
190 
191     /**
192      * Used to create a vertical create guidelines.
193      * see {@link #create(int, int)}
194      */
195     public static final int VERTICAL_GUIDELINE = 1;
196 
197     /**
198      * This view is visible.
199      * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
200      * android:visibility}.
201      */
202     public static final int VISIBLE = View.VISIBLE;
203 
204     /**
205      * This view is invisible, but it still takes up space for layout purposes.
206      * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
207      * android:visibility}.
208      */
209     public static final int INVISIBLE = View.INVISIBLE;
210 
211     /**
212      * This view is gone, and will not take any space for layout
213      * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
214      * android:visibility}.
215      */
216     public static final int GONE = View.GONE;
217 
218     /**
219      * The left side of a view.
220      */
221     public static final int LEFT = ConstraintLayout.LayoutParams.LEFT;
222 
223     /**
224      * The right side of a view.
225      */
226     public static final int RIGHT = ConstraintLayout.LayoutParams.RIGHT;
227 
228     /**
229      * The top of a view.
230      */
231     public static final int TOP = ConstraintLayout.LayoutParams.TOP;
232 
233     /**
234      * The bottom side of a view.
235      */
236     public static final int BOTTOM = ConstraintLayout.LayoutParams.BOTTOM;
237 
238     /**
239      * The baseline of the text in a view.
240      */
241     public static final int BASELINE = ConstraintLayout.LayoutParams.BASELINE;
242 
243     /**
244      * The left side of a view in left to right languages.
245      * In right to left languages it corresponds to the right side of the view
246      */
247     public static final int START = ConstraintLayout.LayoutParams.START;
248 
249     /**
250      * The right side of a view in left to right languages.
251      * In right to left languages it corresponds to the left side of the view
252      */
253     public static final int END = ConstraintLayout.LayoutParams.END;
254 
255     /**
256      * Circle reference from a view.
257      */
258     public static final int CIRCLE_REFERENCE = ConstraintLayout.LayoutParams.CIRCLE;
259 
260     /**
261      * Chain spread style
262      */
263     public static final int CHAIN_SPREAD = ConstraintLayout.LayoutParams.CHAIN_SPREAD;
264 
265     /**
266      * Chain spread inside style
267      */
268     public static final int CHAIN_SPREAD_INSIDE = ConstraintLayout.LayoutParams.CHAIN_SPREAD_INSIDE;
269 
270     public static final int VISIBILITY_MODE_NORMAL = 0;
271     public static final int VISIBILITY_MODE_IGNORE = 1;
272     /**
273      * Chain packed style
274      */
275     public static final int CHAIN_PACKED = ConstraintLayout.LayoutParams.CHAIN_PACKED;
276 
277     private static final boolean DEBUG = false;
278     private static final int[] VISIBILITY_FLAGS = new int[]{VISIBLE, INVISIBLE, GONE};
279     private static final int BARRIER_TYPE = 1;
280 
281     private HashMap<Integer, Constraint> mConstraints = new HashMap<Integer, Constraint>();
282 
283     private static SparseIntArray sMapToConstant = new SparseIntArray();
284     private static SparseIntArray sOverrideMapToConstant = new SparseIntArray();
285     private static final int BASELINE_TO_BASELINE = 1;
286     private static final int BOTTOM_MARGIN = 2;
287     private static final int BOTTOM_TO_BOTTOM = 3;
288     private static final int BOTTOM_TO_TOP = 4;
289     private static final int DIMENSION_RATIO = 5;
290     private static final int EDITOR_ABSOLUTE_X = 6;
291     private static final int EDITOR_ABSOLUTE_Y = 7;
292     private static final int END_MARGIN = 8;
293     private static final int END_TO_END = 9;
294     private static final int END_TO_START = 10;
295     private static final int GONE_BOTTOM_MARGIN = 11;
296     private static final int GONE_END_MARGIN = 12;
297     private static final int GONE_LEFT_MARGIN = 13;
298     private static final int GONE_RIGHT_MARGIN = 14;
299     private static final int GONE_START_MARGIN = 15;
300     private static final int GONE_TOP_MARGIN = 16;
301     private static final int GUIDE_BEGIN = 17;
302     private static final int GUIDE_END = 18;
303     private static final int GUIDE_PERCENT = 19;
304     private static final int HORIZONTAL_BIAS = 20;
305     private static final int LAYOUT_HEIGHT = 21;
306     private static final int LAYOUT_VISIBILITY = 22;
307     private static final int LAYOUT_WIDTH = 23;
308     private static final int LEFT_MARGIN = 24;
309     private static final int LEFT_TO_LEFT = 25;
310     private static final int LEFT_TO_RIGHT = 26;
311     private static final int ORIENTATION = 27;
312     private static final int RIGHT_MARGIN = 28;
313     private static final int RIGHT_TO_LEFT = 29;
314     private static final int RIGHT_TO_RIGHT = 30;
315     private static final int START_MARGIN = 31;
316     private static final int START_TO_END = 32;
317     private static final int START_TO_START = 33;
318     private static final int TOP_MARGIN = 34;
319     private static final int TOP_TO_BOTTOM = 35;
320     private static final int TOP_TO_TOP = 36;
321     private static final int VERTICAL_BIAS = 37;
322     private static final int VIEW_ID = 38;
323     private static final int HORIZONTAL_WEIGHT = 39;
324     private static final int VERTICAL_WEIGHT = 40;
325     private static final int HORIZONTAL_STYLE = 41;
326     private static final int VERTICAL_STYLE = 42;
327     private static final int ALPHA = 43;
328     private static final int ELEVATION = 44;
329     private static final int ROTATION_X = 45;
330     private static final int ROTATION_Y = 46;
331     private static final int SCALE_X = 47;
332     private static final int SCALE_Y = 48;
333     private static final int TRANSFORM_PIVOT_X = 49;
334     private static final int TRANSFORM_PIVOT_Y = 50;
335     private static final int TRANSLATION_X = 51;
336     private static final int TRANSLATION_Y = 52;
337     private static final int TRANSLATION_Z = 53;
338     private static final int WIDTH_DEFAULT = 54;
339     private static final int HEIGHT_DEFAULT = 55;
340     private static final int WIDTH_MAX = 56;
341     private static final int HEIGHT_MAX = 57;
342     private static final int WIDTH_MIN = 58;
343     private static final int HEIGHT_MIN = 59;
344     private static final int ROTATION = 60;
345     private static final int CIRCLE = 61;
346     private static final int CIRCLE_RADIUS = 62;
347     private static final int CIRCLE_ANGLE = 63;
348     private static final int ANIMATE_RELATIVE_TO = 64;
349     private static final int TRANSITION_EASING = 65;
350     private static final int DRAW_PATH = 66;
351     private static final int TRANSITION_PATH_ROTATE = 67;
352     private static final int PROGRESS = 68;
353     private static final int WIDTH_PERCENT = 69;
354     private static final int HEIGHT_PERCENT = 70;
355     private static final int CHAIN_USE_RTL = 71;
356     private static final int BARRIER_DIRECTION = 72;
357     private static final int BARRIER_MARGIN = 73;
358     private static final int CONSTRAINT_REFERENCED_IDS = 74;
359     private static final int BARRIER_ALLOWS_GONE_WIDGETS = 75;
360     private static final int PATH_MOTION_ARC = 76;
361     private static final int CONSTRAINT_TAG = 77;
362     private static final int VISIBILITY_MODE = 78;
363     private static final int MOTION_STAGGER = 79;
364     private static final int CONSTRAINED_WIDTH = 80;
365     private static final int CONSTRAINED_HEIGHT = 81;
366     private static final int ANIMATE_CIRCLE_ANGLE_TO = 82;
367     private static final int TRANSFORM_PIVOT_TARGET = 83;
368     private static final int QUANTIZE_MOTION_STEPS = 84;
369     private static final int QUANTIZE_MOTION_PHASE = 85;
370     private static final int QUANTIZE_MOTION_INTERPOLATOR = 86;
371     private static final int UNUSED = 87;
372     private static final int QUANTIZE_MOTION_INTERPOLATOR_TYPE = 88;
373     private static final int QUANTIZE_MOTION_INTERPOLATOR_ID = 89;
374     private static final int QUANTIZE_MOTION_INTERPOLATOR_STR = 90;
375     private static final int BASELINE_TO_TOP = 91;
376     private static final int BASELINE_TO_BOTTOM = 92;
377     private static final int BASELINE_MARGIN = 93;
378     private static final int GONE_BASELINE_MARGIN = 94;
379     private static final int LAYOUT_CONSTRAINT_WIDTH = 95;
380     private static final int LAYOUT_CONSTRAINT_HEIGHT = 96;
381     private static final int LAYOUT_WRAP_BEHAVIOR = 97;
382     private static final int MOTION_TARGET = 98;
383     private static final int GUIDELINE_USE_RTL = 99;
384 
385     private static final String KEY_WEIGHT = "weight";
386     private static final String KEY_RATIO = "ratio";
387     private static final String KEY_PERCENT_PARENT = "parent";
388 
389 
390     static {
sMapToConstant.append(R.styleable.Constraint_layout_constraintLeft_toLeftOf, LEFT_TO_LEFT)391         sMapToConstant.append(R.styleable.Constraint_layout_constraintLeft_toLeftOf, LEFT_TO_LEFT);
sMapToConstant.append(R.styleable.Constraint_layout_constraintLeft_toRightOf, LEFT_TO_RIGHT)392         sMapToConstant.append(R.styleable.Constraint_layout_constraintLeft_toRightOf,
393                 LEFT_TO_RIGHT);
sMapToConstant.append(R.styleable.Constraint_layout_constraintRight_toLeftOf, RIGHT_TO_LEFT)394         sMapToConstant.append(R.styleable.Constraint_layout_constraintRight_toLeftOf,
395                 RIGHT_TO_LEFT);
sMapToConstant.append( R.styleable.Constraint_layout_constraintRight_toRightOf, RIGHT_TO_RIGHT)396         sMapToConstant.append(
397                 R.styleable.Constraint_layout_constraintRight_toRightOf, RIGHT_TO_RIGHT);
sMapToConstant.append(R.styleable.Constraint_layout_constraintTop_toTopOf, TOP_TO_TOP)398         sMapToConstant.append(R.styleable.Constraint_layout_constraintTop_toTopOf, TOP_TO_TOP);
sMapToConstant.append(R.styleable.Constraint_layout_constraintTop_toBottomOf, TOP_TO_BOTTOM)399         sMapToConstant.append(R.styleable.Constraint_layout_constraintTop_toBottomOf,
400                 TOP_TO_BOTTOM);
sMapToConstant.append(R.styleable.Constraint_layout_constraintBottom_toTopOf, BOTTOM_TO_TOP)401         sMapToConstant.append(R.styleable.Constraint_layout_constraintBottom_toTopOf,
402                 BOTTOM_TO_TOP);
sMapToConstant.append( R.styleable.Constraint_layout_constraintBottom_toBottomOf, BOTTOM_TO_BOTTOM)403         sMapToConstant.append(
404                 R.styleable.Constraint_layout_constraintBottom_toBottomOf, BOTTOM_TO_BOTTOM);
sMapToConstant.append( R.styleable.Constraint_layout_constraintBaseline_toBaselineOf, BASELINE_TO_BASELINE)405         sMapToConstant.append(
406                 R.styleable.Constraint_layout_constraintBaseline_toBaselineOf,
407                 BASELINE_TO_BASELINE);
sMapToConstant.append( R.styleable.Constraint_layout_constraintBaseline_toTopOf, BASELINE_TO_TOP)408         sMapToConstant.append(
409                 R.styleable.Constraint_layout_constraintBaseline_toTopOf, BASELINE_TO_TOP);
sMapToConstant.append( R.styleable.Constraint_layout_constraintBaseline_toBottomOf, BASELINE_TO_BOTTOM)410         sMapToConstant.append(
411                 R.styleable.Constraint_layout_constraintBaseline_toBottomOf, BASELINE_TO_BOTTOM);
412 
sMapToConstant.append(R.styleable.Constraint_layout_editor_absoluteX, EDITOR_ABSOLUTE_X)413         sMapToConstant.append(R.styleable.Constraint_layout_editor_absoluteX, EDITOR_ABSOLUTE_X);
sMapToConstant.append(R.styleable.Constraint_layout_editor_absoluteY, EDITOR_ABSOLUTE_Y)414         sMapToConstant.append(R.styleable.Constraint_layout_editor_absoluteY, EDITOR_ABSOLUTE_Y);
sMapToConstant.append(R.styleable.Constraint_layout_constraintGuide_begin, GUIDE_BEGIN)415         sMapToConstant.append(R.styleable.Constraint_layout_constraintGuide_begin, GUIDE_BEGIN);
sMapToConstant.append(R.styleable.Constraint_layout_constraintGuide_end, GUIDE_END)416         sMapToConstant.append(R.styleable.Constraint_layout_constraintGuide_end, GUIDE_END);
sMapToConstant.append(R.styleable.Constraint_layout_constraintGuide_percent, GUIDE_PERCENT)417         sMapToConstant.append(R.styleable.Constraint_layout_constraintGuide_percent, GUIDE_PERCENT);
sMapToConstant.append(R.styleable.Constraint_guidelineUseRtl, GUIDELINE_USE_RTL)418         sMapToConstant.append(R.styleable.Constraint_guidelineUseRtl, GUIDELINE_USE_RTL);
419 
sMapToConstant.append(R.styleable.Constraint_android_orientation, ORIENTATION)420         sMapToConstant.append(R.styleable.Constraint_android_orientation, ORIENTATION);
sMapToConstant.append(R.styleable.Constraint_layout_constraintStart_toEndOf, START_TO_END)421         sMapToConstant.append(R.styleable.Constraint_layout_constraintStart_toEndOf, START_TO_END);
sMapToConstant.append( R.styleable.Constraint_layout_constraintStart_toStartOf, START_TO_START)422         sMapToConstant.append(
423                 R.styleable.Constraint_layout_constraintStart_toStartOf, START_TO_START);
sMapToConstant.append(R.styleable.Constraint_layout_constraintEnd_toStartOf, END_TO_START)424         sMapToConstant.append(R.styleable.Constraint_layout_constraintEnd_toStartOf, END_TO_START);
sMapToConstant.append(R.styleable.Constraint_layout_constraintEnd_toEndOf, END_TO_END)425         sMapToConstant.append(R.styleable.Constraint_layout_constraintEnd_toEndOf, END_TO_END);
sMapToConstant.append(R.styleable.Constraint_layout_goneMarginLeft, GONE_LEFT_MARGIN)426         sMapToConstant.append(R.styleable.Constraint_layout_goneMarginLeft, GONE_LEFT_MARGIN);
sMapToConstant.append(R.styleable.Constraint_layout_goneMarginTop, GONE_TOP_MARGIN)427         sMapToConstant.append(R.styleable.Constraint_layout_goneMarginTop, GONE_TOP_MARGIN);
sMapToConstant.append(R.styleable.Constraint_layout_goneMarginRight, GONE_RIGHT_MARGIN)428         sMapToConstant.append(R.styleable.Constraint_layout_goneMarginRight, GONE_RIGHT_MARGIN);
sMapToConstant.append(R.styleable.Constraint_layout_goneMarginBottom, GONE_BOTTOM_MARGIN)429         sMapToConstant.append(R.styleable.Constraint_layout_goneMarginBottom, GONE_BOTTOM_MARGIN);
sMapToConstant.append(R.styleable.Constraint_layout_goneMarginStart, GONE_START_MARGIN)430         sMapToConstant.append(R.styleable.Constraint_layout_goneMarginStart, GONE_START_MARGIN);
sMapToConstant.append(R.styleable.Constraint_layout_goneMarginEnd, GONE_END_MARGIN)431         sMapToConstant.append(R.styleable.Constraint_layout_goneMarginEnd, GONE_END_MARGIN);
sMapToConstant.append( R.styleable.Constraint_layout_constraintVertical_weight, VERTICAL_WEIGHT)432         sMapToConstant.append(
433                 R.styleable.Constraint_layout_constraintVertical_weight, VERTICAL_WEIGHT);
sMapToConstant.append( R.styleable.Constraint_layout_constraintHorizontal_weight, HORIZONTAL_WEIGHT)434         sMapToConstant.append(
435                 R.styleable.Constraint_layout_constraintHorizontal_weight, HORIZONTAL_WEIGHT);
sMapToConstant.append( R.styleable.Constraint_layout_constraintHorizontal_chainStyle, HORIZONTAL_STYLE)436         sMapToConstant.append(
437                 R.styleable.Constraint_layout_constraintHorizontal_chainStyle, HORIZONTAL_STYLE);
sMapToConstant.append( R.styleable.Constraint_layout_constraintVertical_chainStyle, VERTICAL_STYLE)438         sMapToConstant.append(
439                 R.styleable.Constraint_layout_constraintVertical_chainStyle, VERTICAL_STYLE);
440 
sMapToConstant.append( R.styleable.Constraint_layout_constraintHorizontal_bias, HORIZONTAL_BIAS)441         sMapToConstant.append(
442                 R.styleable.Constraint_layout_constraintHorizontal_bias, HORIZONTAL_BIAS);
sMapToConstant.append( R.styleable.Constraint_layout_constraintVertical_bias, VERTICAL_BIAS)443         sMapToConstant.append(
444                 R.styleable.Constraint_layout_constraintVertical_bias, VERTICAL_BIAS);
sMapToConstant.append( R.styleable.Constraint_layout_constraintDimensionRatio, DIMENSION_RATIO)445         sMapToConstant.append(
446                 R.styleable.Constraint_layout_constraintDimensionRatio, DIMENSION_RATIO);
sMapToConstant.append(R.styleable.Constraint_layout_constraintLeft_creator, UNUSED)447         sMapToConstant.append(R.styleable.Constraint_layout_constraintLeft_creator, UNUSED);
sMapToConstant.append(R.styleable.Constraint_layout_constraintTop_creator, UNUSED)448         sMapToConstant.append(R.styleable.Constraint_layout_constraintTop_creator, UNUSED);
sMapToConstant.append(R.styleable.Constraint_layout_constraintRight_creator, UNUSED)449         sMapToConstant.append(R.styleable.Constraint_layout_constraintRight_creator, UNUSED);
sMapToConstant.append(R.styleable.Constraint_layout_constraintBottom_creator, UNUSED)450         sMapToConstant.append(R.styleable.Constraint_layout_constraintBottom_creator, UNUSED);
sMapToConstant.append(R.styleable.Constraint_layout_constraintBaseline_creator, UNUSED)451         sMapToConstant.append(R.styleable.Constraint_layout_constraintBaseline_creator, UNUSED);
sMapToConstant.append(R.styleable.Constraint_android_layout_marginLeft, LEFT_MARGIN)452         sMapToConstant.append(R.styleable.Constraint_android_layout_marginLeft, LEFT_MARGIN);
sMapToConstant.append(R.styleable.Constraint_android_layout_marginRight, RIGHT_MARGIN)453         sMapToConstant.append(R.styleable.Constraint_android_layout_marginRight, RIGHT_MARGIN);
sMapToConstant.append(R.styleable.Constraint_android_layout_marginStart, START_MARGIN)454         sMapToConstant.append(R.styleable.Constraint_android_layout_marginStart, START_MARGIN);
sMapToConstant.append(R.styleable.Constraint_android_layout_marginEnd, END_MARGIN)455         sMapToConstant.append(R.styleable.Constraint_android_layout_marginEnd, END_MARGIN);
sMapToConstant.append(R.styleable.Constraint_android_layout_marginTop, TOP_MARGIN)456         sMapToConstant.append(R.styleable.Constraint_android_layout_marginTop, TOP_MARGIN);
sMapToConstant.append(R.styleable.Constraint_android_layout_marginBottom, BOTTOM_MARGIN)457         sMapToConstant.append(R.styleable.Constraint_android_layout_marginBottom, BOTTOM_MARGIN);
sMapToConstant.append(R.styleable.Constraint_android_layout_width, LAYOUT_WIDTH)458         sMapToConstant.append(R.styleable.Constraint_android_layout_width, LAYOUT_WIDTH);
sMapToConstant.append( R.styleable.Constraint_android_layout_height, LAYOUT_HEIGHT)459         sMapToConstant.append(
460                 R.styleable.Constraint_android_layout_height, LAYOUT_HEIGHT);
sMapToConstant.append( R.styleable.Constraint_layout_constraintWidth, LAYOUT_CONSTRAINT_WIDTH)461         sMapToConstant.append(
462                 R.styleable.Constraint_layout_constraintWidth, LAYOUT_CONSTRAINT_WIDTH);
sMapToConstant.append( R.styleable.Constraint_layout_constraintHeight, LAYOUT_CONSTRAINT_HEIGHT)463         sMapToConstant.append(
464                 R.styleable.Constraint_layout_constraintHeight, LAYOUT_CONSTRAINT_HEIGHT);
sMapToConstant.append(R.styleable.Constraint_android_visibility, LAYOUT_VISIBILITY)465         sMapToConstant.append(R.styleable.Constraint_android_visibility, LAYOUT_VISIBILITY);
sMapToConstant.append(R.styleable.Constraint_android_alpha, ALPHA)466         sMapToConstant.append(R.styleable.Constraint_android_alpha, ALPHA);
sMapToConstant.append(R.styleable.Constraint_android_elevation, ELEVATION)467         sMapToConstant.append(R.styleable.Constraint_android_elevation, ELEVATION);
sMapToConstant.append(R.styleable.Constraint_android_rotationX, ROTATION_X)468         sMapToConstant.append(R.styleable.Constraint_android_rotationX, ROTATION_X);
sMapToConstant.append(R.styleable.Constraint_android_rotationY, ROTATION_Y)469         sMapToConstant.append(R.styleable.Constraint_android_rotationY, ROTATION_Y);
sMapToConstant.append(R.styleable.Constraint_android_rotation, ROTATION)470         sMapToConstant.append(R.styleable.Constraint_android_rotation, ROTATION);
sMapToConstant.append(R.styleable.Constraint_android_scaleX, SCALE_X)471         sMapToConstant.append(R.styleable.Constraint_android_scaleX, SCALE_X);
sMapToConstant.append(R.styleable.Constraint_android_scaleY, SCALE_Y)472         sMapToConstant.append(R.styleable.Constraint_android_scaleY, SCALE_Y);
sMapToConstant.append(R.styleable.Constraint_android_transformPivotX, TRANSFORM_PIVOT_X)473         sMapToConstant.append(R.styleable.Constraint_android_transformPivotX, TRANSFORM_PIVOT_X);
sMapToConstant.append(R.styleable.Constraint_android_transformPivotY, TRANSFORM_PIVOT_Y)474         sMapToConstant.append(R.styleable.Constraint_android_transformPivotY, TRANSFORM_PIVOT_Y);
sMapToConstant.append(R.styleable.Constraint_android_translationX, TRANSLATION_X)475         sMapToConstant.append(R.styleable.Constraint_android_translationX, TRANSLATION_X);
sMapToConstant.append(R.styleable.Constraint_android_translationY, TRANSLATION_Y)476         sMapToConstant.append(R.styleable.Constraint_android_translationY, TRANSLATION_Y);
sMapToConstant.append(R.styleable.Constraint_android_translationZ, TRANSLATION_Z)477         sMapToConstant.append(R.styleable.Constraint_android_translationZ, TRANSLATION_Z);
sMapToConstant.append(R.styleable.Constraint_layout_constraintWidth_default, WIDTH_DEFAULT)478         sMapToConstant.append(R.styleable.Constraint_layout_constraintWidth_default, WIDTH_DEFAULT);
sMapToConstant.append( R.styleable.Constraint_layout_constraintHeight_default, HEIGHT_DEFAULT)479         sMapToConstant.append(
480                 R.styleable.Constraint_layout_constraintHeight_default, HEIGHT_DEFAULT);
sMapToConstant.append(R.styleable.Constraint_layout_constraintWidth_max, WIDTH_MAX)481         sMapToConstant.append(R.styleable.Constraint_layout_constraintWidth_max, WIDTH_MAX);
sMapToConstant.append(R.styleable.Constraint_layout_constraintHeight_max, HEIGHT_MAX)482         sMapToConstant.append(R.styleable.Constraint_layout_constraintHeight_max, HEIGHT_MAX);
sMapToConstant.append(R.styleable.Constraint_layout_constraintWidth_min, WIDTH_MIN)483         sMapToConstant.append(R.styleable.Constraint_layout_constraintWidth_min, WIDTH_MIN);
sMapToConstant.append(R.styleable.Constraint_layout_constraintHeight_min, HEIGHT_MIN)484         sMapToConstant.append(R.styleable.Constraint_layout_constraintHeight_min, HEIGHT_MIN);
sMapToConstant.append(R.styleable.Constraint_layout_constraintCircle, CIRCLE)485         sMapToConstant.append(R.styleable.Constraint_layout_constraintCircle, CIRCLE);
sMapToConstant.append(R.styleable.Constraint_layout_constraintCircleRadius, CIRCLE_RADIUS)486         sMapToConstant.append(R.styleable.Constraint_layout_constraintCircleRadius, CIRCLE_RADIUS);
sMapToConstant.append(R.styleable.Constraint_layout_constraintCircleAngle, CIRCLE_ANGLE)487         sMapToConstant.append(R.styleable.Constraint_layout_constraintCircleAngle, CIRCLE_ANGLE);
sMapToConstant.append(R.styleable.Constraint_animateRelativeTo, ANIMATE_RELATIVE_TO)488         sMapToConstant.append(R.styleable.Constraint_animateRelativeTo, ANIMATE_RELATIVE_TO);
sMapToConstant.append(R.styleable.Constraint_transitionEasing, TRANSITION_EASING)489         sMapToConstant.append(R.styleable.Constraint_transitionEasing, TRANSITION_EASING);
sMapToConstant.append(R.styleable.Constraint_drawPath, DRAW_PATH)490         sMapToConstant.append(R.styleable.Constraint_drawPath, DRAW_PATH);
sMapToConstant.append(R.styleable.Constraint_transitionPathRotate, TRANSITION_PATH_ROTATE)491         sMapToConstant.append(R.styleable.Constraint_transitionPathRotate, TRANSITION_PATH_ROTATE);
sMapToConstant.append(R.styleable.Constraint_motionStagger, MOTION_STAGGER)492         sMapToConstant.append(R.styleable.Constraint_motionStagger, MOTION_STAGGER);
sMapToConstant.append(R.styleable.Constraint_android_id, VIEW_ID)493         sMapToConstant.append(R.styleable.Constraint_android_id, VIEW_ID);
sMapToConstant.append(R.styleable.Constraint_motionProgress, PROGRESS)494         sMapToConstant.append(R.styleable.Constraint_motionProgress, PROGRESS);
sMapToConstant.append( R.styleable.Constraint_layout_constraintWidth_percent, WIDTH_PERCENT)495         sMapToConstant.append(
496                 R.styleable.Constraint_layout_constraintWidth_percent, WIDTH_PERCENT);
sMapToConstant.append( R.styleable.Constraint_layout_constraintHeight_percent, HEIGHT_PERCENT)497         sMapToConstant.append(
498                 R.styleable.Constraint_layout_constraintHeight_percent, HEIGHT_PERCENT);
sMapToConstant.append( R.styleable.Constraint_layout_wrapBehaviorInParent, LAYOUT_WRAP_BEHAVIOR)499         sMapToConstant.append(
500                 R.styleable.Constraint_layout_wrapBehaviorInParent, LAYOUT_WRAP_BEHAVIOR);
501 
sMapToConstant.append(R.styleable.Constraint_chainUseRtl, CHAIN_USE_RTL)502         sMapToConstant.append(R.styleable.Constraint_chainUseRtl, CHAIN_USE_RTL);
sMapToConstant.append(R.styleable.Constraint_barrierDirection, BARRIER_DIRECTION)503         sMapToConstant.append(R.styleable.Constraint_barrierDirection, BARRIER_DIRECTION);
sMapToConstant.append(R.styleable.Constraint_barrierMargin, BARRIER_MARGIN)504         sMapToConstant.append(R.styleable.Constraint_barrierMargin, BARRIER_MARGIN);
sMapToConstant.append( R.styleable.Constraint_constraint_referenced_ids, CONSTRAINT_REFERENCED_IDS)505         sMapToConstant.append(
506                 R.styleable.Constraint_constraint_referenced_ids, CONSTRAINT_REFERENCED_IDS);
sMapToConstant.append( R.styleable.Constraint_barrierAllowsGoneWidgets, BARRIER_ALLOWS_GONE_WIDGETS)507         sMapToConstant.append(
508                 R.styleable.Constraint_barrierAllowsGoneWidgets, BARRIER_ALLOWS_GONE_WIDGETS);
sMapToConstant.append(R.styleable.Constraint_pathMotionArc, PATH_MOTION_ARC)509         sMapToConstant.append(R.styleable.Constraint_pathMotionArc, PATH_MOTION_ARC);
sMapToConstant.append(R.styleable.Constraint_layout_constraintTag, CONSTRAINT_TAG)510         sMapToConstant.append(R.styleable.Constraint_layout_constraintTag, CONSTRAINT_TAG);
sMapToConstant.append(R.styleable.Constraint_visibilityMode, VISIBILITY_MODE)511         sMapToConstant.append(R.styleable.Constraint_visibilityMode, VISIBILITY_MODE);
sMapToConstant.append( R.styleable.Constraint_layout_constrainedWidth, CONSTRAINED_WIDTH)512         sMapToConstant.append(
513                 R.styleable.Constraint_layout_constrainedWidth, CONSTRAINED_WIDTH);
sMapToConstant.append( R.styleable.Constraint_layout_constrainedHeight, CONSTRAINED_HEIGHT)514         sMapToConstant.append(
515                 R.styleable.Constraint_layout_constrainedHeight, CONSTRAINED_HEIGHT);
sMapToConstant.append( R.styleable.Constraint_polarRelativeTo, ANIMATE_CIRCLE_ANGLE_TO)516         sMapToConstant.append(
517                 R.styleable.Constraint_polarRelativeTo, ANIMATE_CIRCLE_ANGLE_TO);
sMapToConstant.append( R.styleable.Constraint_transformPivotTarget, TRANSFORM_PIVOT_TARGET)518         sMapToConstant.append(
519                 R.styleable.Constraint_transformPivotTarget, TRANSFORM_PIVOT_TARGET);
sMapToConstant.append( R.styleable.Constraint_quantizeMotionSteps, QUANTIZE_MOTION_STEPS)520         sMapToConstant.append(
521                 R.styleable.Constraint_quantizeMotionSteps, QUANTIZE_MOTION_STEPS);
sMapToConstant.append( R.styleable.Constraint_quantizeMotionPhase, QUANTIZE_MOTION_PHASE)522         sMapToConstant.append(
523                 R.styleable.Constraint_quantizeMotionPhase, QUANTIZE_MOTION_PHASE);
sMapToConstant.append( R.styleable.Constraint_quantizeMotionInterpolator, QUANTIZE_MOTION_INTERPOLATOR)524         sMapToConstant.append(
525                 R.styleable.Constraint_quantizeMotionInterpolator, QUANTIZE_MOTION_INTERPOLATOR);
526 
527 
528         /*
529         The tags not available in constraintOverride
530         Left here to help with documentation and understanding
531         overrideMapToConstant.append(
532         R.styleable.ConstraintOverride_layout_constraintLeft_toLeftOf, LEFT_TO_LEFT);
533         overrideMapToConstant.append(
534         R.styleable.ConstraintOverride_layout_constraintLeft_toRightOf, LEFT_TO_RIGHT);
535         overrideMapToConstant.append(
536         R.styleable.ConstraintOverride_layout_constraintRight_toLeftOf, RIGHT_TO_LEFT);
537         overrideMapToConstant.append(
538         R.styleable.ConstraintOverride_layout_constraintRight_toRightOf, RIGHT_TO_RIGHT);
539         overrideMapToConstant.append(
540         R.styleable.ConstraintOverride_layout_constraintTop_toTopOf, TOP_TO_TOP);
541         overrideMapToConstant.append(
542         R.styleable.ConstraintOverride_layout_constraintTop_toBottomOf, TOP_TO_BOTTOM);
543         overrideMapToConstant.append(
544         R.styleable.ConstraintOverride_layout_constraintBottom_toTopOf, BOTTOM_TO_TOP);
545         overrideMapToConstant.append(
546         R.styleable.ConstraintOverride_layout_constraintBottom_toBottomOf, BOTTOM_TO_BOTTOM);
547         overrideMapToConstant.append(
548         R.styleable.ConstraintOverride_layout_constraintBaseline_toBaselineOf,
549         BASELINE_TO_BASELINE);
550         overrideMapToConstant.append(
551         R.styleable.ConstraintOverride_layout_constraintGuide_begin, GUIDE_BEGIN);
552         overrideMapToConstant.append(
553         R.styleable.ConstraintOverride_layout_constraintGuide_end, GUIDE_END);
554         overrideMapToConstant.append(
555         R.styleable.ConstraintOverride_layout_constraintGuide_percent, GUIDE_PERCENT);
556         overrideMapToConstant.append(
557         R.styleable.ConstraintOverride_layout_constraintStart_toEndOf, START_TO_END);
558         overrideMapToConstant.append(
559         R.styleable.ConstraintOverride_layout_constraintStart_toStartOf, START_TO_START);
560         overrideMapToConstant.append(
561         R.styleable.ConstraintOverride_layout_constraintEnd_toStartOf, END_TO_START);
562         overrideMapToConstant.append(
563         R.styleable.ConstraintOverride_layout_constraintEnd_toEndOf, END_TO_END);
564         */
sOverrideMapToConstant.append( R.styleable.ConstraintOverride_layout_editor_absoluteY, EDITOR_ABSOLUTE_X)565         sOverrideMapToConstant.append(
566                 R.styleable.ConstraintOverride_layout_editor_absoluteY, EDITOR_ABSOLUTE_X);
sOverrideMapToConstant.append( R.styleable.ConstraintOverride_layout_editor_absoluteY, EDITOR_ABSOLUTE_Y)567         sOverrideMapToConstant.append(
568                 R.styleable.ConstraintOverride_layout_editor_absoluteY, EDITOR_ABSOLUTE_Y);
sOverrideMapToConstant.append( R.styleable.ConstraintOverride_android_orientation, ORIENTATION)569         sOverrideMapToConstant.append(
570                 R.styleable.ConstraintOverride_android_orientation, ORIENTATION);
sOverrideMapToConstant.append( R.styleable.ConstraintOverride_layout_goneMarginLeft, GONE_LEFT_MARGIN)571         sOverrideMapToConstant.append(
572                 R.styleable.ConstraintOverride_layout_goneMarginLeft, GONE_LEFT_MARGIN);
sOverrideMapToConstant.append( R.styleable.ConstraintOverride_layout_goneMarginTop, GONE_TOP_MARGIN)573         sOverrideMapToConstant.append(
574                 R.styleable.ConstraintOverride_layout_goneMarginTop, GONE_TOP_MARGIN);
sOverrideMapToConstant.append( R.styleable.ConstraintOverride_layout_goneMarginRight, GONE_RIGHT_MARGIN)575         sOverrideMapToConstant.append(
576                 R.styleable.ConstraintOverride_layout_goneMarginRight, GONE_RIGHT_MARGIN);
sOverrideMapToConstant.append( R.styleable.ConstraintOverride_layout_goneMarginBottom, GONE_BOTTOM_MARGIN)577         sOverrideMapToConstant.append(
578                 R.styleable.ConstraintOverride_layout_goneMarginBottom, GONE_BOTTOM_MARGIN);
sOverrideMapToConstant.append( R.styleable.ConstraintOverride_layout_goneMarginStart, GONE_START_MARGIN)579         sOverrideMapToConstant.append(
580                 R.styleable.ConstraintOverride_layout_goneMarginStart, GONE_START_MARGIN);
sOverrideMapToConstant.append( R.styleable.ConstraintOverride_layout_goneMarginEnd, GONE_END_MARGIN)581         sOverrideMapToConstant.append(
582                 R.styleable.ConstraintOverride_layout_goneMarginEnd, GONE_END_MARGIN);
sOverrideMapToConstant.append( R.styleable.ConstraintOverride_layout_constraintVertical_weight, VERTICAL_WEIGHT)583         sOverrideMapToConstant.append(
584                 R.styleable.ConstraintOverride_layout_constraintVertical_weight,
585                 VERTICAL_WEIGHT);
sOverrideMapToConstant.append( R.styleable.ConstraintOverride_layout_constraintHorizontal_weight, HORIZONTAL_WEIGHT)586         sOverrideMapToConstant.append(
587                 R.styleable.ConstraintOverride_layout_constraintHorizontal_weight,
588                 HORIZONTAL_WEIGHT);
sOverrideMapToConstant.append( R.styleable.ConstraintOverride_layout_constraintHorizontal_chainStyle, HORIZONTAL_STYLE)589         sOverrideMapToConstant.append(
590                 R.styleable.ConstraintOverride_layout_constraintHorizontal_chainStyle,
591                 HORIZONTAL_STYLE);
sOverrideMapToConstant.append( R.styleable.ConstraintOverride_layout_constraintVertical_chainStyle, VERTICAL_STYLE)592         sOverrideMapToConstant.append(
593                 R.styleable.ConstraintOverride_layout_constraintVertical_chainStyle,
594                 VERTICAL_STYLE);
595 
sOverrideMapToConstant.append( R.styleable.ConstraintOverride_layout_constraintHorizontal_bias, HORIZONTAL_BIAS)596         sOverrideMapToConstant.append(
597                 R.styleable.ConstraintOverride_layout_constraintHorizontal_bias,
598                 HORIZONTAL_BIAS);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintVertical_bias, VERTICAL_BIAS)599         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintVertical_bias,
600                 VERTICAL_BIAS);
sOverrideMapToConstant.append( R.styleable.ConstraintOverride_layout_constraintDimensionRatio, DIMENSION_RATIO)601         sOverrideMapToConstant.append(
602                 R.styleable.ConstraintOverride_layout_constraintDimensionRatio, DIMENSION_RATIO);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintLeft_creator, UNUSED)603         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintLeft_creator,
604                 UNUSED);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintTop_creator, UNUSED)605         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintTop_creator,
606                 UNUSED);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintRight_creator, UNUSED)607         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintRight_creator,
608                 UNUSED);
sOverrideMapToConstant.append( R.styleable.ConstraintOverride_layout_constraintBottom_creator, UNUSED)609         sOverrideMapToConstant.append(
610                 R.styleable.ConstraintOverride_layout_constraintBottom_creator, UNUSED);
sOverrideMapToConstant.append( R.styleable.ConstraintOverride_layout_constraintBaseline_creator, UNUSED)611         sOverrideMapToConstant.append(
612                 R.styleable.ConstraintOverride_layout_constraintBaseline_creator,
613                 UNUSED);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginLeft, LEFT_MARGIN)614         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginLeft,
615                 LEFT_MARGIN);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginRight, RIGHT_MARGIN)616         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginRight,
617                 RIGHT_MARGIN);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginStart, START_MARGIN)618         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginStart,
619                 START_MARGIN);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginEnd, END_MARGIN)620         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginEnd,
621                 END_MARGIN);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginTop, TOP_MARGIN)622         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginTop,
623                 TOP_MARGIN);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginBottom, BOTTOM_MARGIN)624         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_marginBottom,
625                 BOTTOM_MARGIN);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_width, LAYOUT_WIDTH)626         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_width,
627                 LAYOUT_WIDTH);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_height, LAYOUT_HEIGHT)628         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_layout_height,
629                 LAYOUT_HEIGHT);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintWidth, LAYOUT_CONSTRAINT_WIDTH)630         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintWidth,
631                 LAYOUT_CONSTRAINT_WIDTH);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintHeight, LAYOUT_CONSTRAINT_HEIGHT)632         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintHeight,
633                 LAYOUT_CONSTRAINT_HEIGHT);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_visibility, LAYOUT_VISIBILITY)634         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_visibility,
635                 LAYOUT_VISIBILITY);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_alpha, ALPHA)636         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_alpha, ALPHA);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_elevation, ELEVATION)637         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_elevation, ELEVATION);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_rotationX, ROTATION_X)638         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_rotationX, ROTATION_X);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_rotationY, ROTATION_Y)639         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_rotationY, ROTATION_Y);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_rotation, ROTATION)640         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_rotation, ROTATION);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_scaleX, SCALE_X)641         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_scaleX, SCALE_X);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_scaleY, SCALE_Y)642         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_scaleY, SCALE_Y);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_transformPivotX, TRANSFORM_PIVOT_X)643         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_transformPivotX,
644                 TRANSFORM_PIVOT_X);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_transformPivotY, TRANSFORM_PIVOT_Y)645         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_transformPivotY,
646                 TRANSFORM_PIVOT_Y);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_translationX, TRANSLATION_X)647         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_translationX,
648                 TRANSLATION_X);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_translationY, TRANSLATION_Y)649         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_translationY,
650                 TRANSLATION_Y);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_translationZ, TRANSLATION_Z)651         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_translationZ,
652                 TRANSLATION_Z);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintWidth_default, WIDTH_DEFAULT)653         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintWidth_default,
654                 WIDTH_DEFAULT);
sOverrideMapToConstant.append( R.styleable.ConstraintOverride_layout_constraintHeight_default, HEIGHT_DEFAULT)655         sOverrideMapToConstant.append(
656                 R.styleable.ConstraintOverride_layout_constraintHeight_default, HEIGHT_DEFAULT);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintWidth_max, WIDTH_MAX)657         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintWidth_max,
658                 WIDTH_MAX);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintHeight_max, HEIGHT_MAX)659         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintHeight_max,
660                 HEIGHT_MAX);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintWidth_min, WIDTH_MIN)661         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintWidth_min,
662                 WIDTH_MIN);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintHeight_min, HEIGHT_MIN)663         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintHeight_min,
664                 HEIGHT_MIN);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintCircleRadius, CIRCLE_RADIUS)665         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintCircleRadius,
666                 CIRCLE_RADIUS);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintCircleAngle, CIRCLE_ANGLE)667         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintCircleAngle,
668                 CIRCLE_ANGLE);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_animateRelativeTo, ANIMATE_RELATIVE_TO)669         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_animateRelativeTo,
670                 ANIMATE_RELATIVE_TO);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_transitionEasing, TRANSITION_EASING)671         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_transitionEasing,
672                 TRANSITION_EASING);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_drawPath, DRAW_PATH)673         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_drawPath, DRAW_PATH);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_transitionPathRotate, TRANSITION_PATH_ROTATE)674         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_transitionPathRotate,
675                 TRANSITION_PATH_ROTATE);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_motionStagger, MOTION_STAGGER)676         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_motionStagger, MOTION_STAGGER);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_id, VIEW_ID)677         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_android_id, VIEW_ID);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_motionTarget, MOTION_TARGET)678         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_motionTarget, MOTION_TARGET);
679 
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_motionProgress, PROGRESS)680         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_motionProgress, PROGRESS);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintWidth_percent, WIDTH_PERCENT)681         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintWidth_percent,
682                 WIDTH_PERCENT);
sOverrideMapToConstant.append( R.styleable.ConstraintOverride_layout_constraintHeight_percent, HEIGHT_PERCENT)683         sOverrideMapToConstant.append(
684                 R.styleable.ConstraintOverride_layout_constraintHeight_percent, HEIGHT_PERCENT);
685 
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_chainUseRtl, CHAIN_USE_RTL)686         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_chainUseRtl, CHAIN_USE_RTL);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_barrierDirection, BARRIER_DIRECTION)687         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_barrierDirection,
688                 BARRIER_DIRECTION);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_barrierMargin, BARRIER_MARGIN)689         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_barrierMargin,
690                 BARRIER_MARGIN);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_constraint_referenced_ids, CONSTRAINT_REFERENCED_IDS)691         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_constraint_referenced_ids,
692                 CONSTRAINT_REFERENCED_IDS);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_barrierAllowsGoneWidgets, BARRIER_ALLOWS_GONE_WIDGETS)693         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_barrierAllowsGoneWidgets,
694                 BARRIER_ALLOWS_GONE_WIDGETS);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_pathMotionArc, PATH_MOTION_ARC)695         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_pathMotionArc,
696                 PATH_MOTION_ARC);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintTag, CONSTRAINT_TAG)697         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constraintTag,
698                 CONSTRAINT_TAG);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_visibilityMode, VISIBILITY_MODE)699         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_visibilityMode,
700                 VISIBILITY_MODE);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constrainedWidth, CONSTRAINED_WIDTH)701         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constrainedWidth,
702                 CONSTRAINED_WIDTH);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constrainedHeight, CONSTRAINED_HEIGHT)703         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_constrainedHeight,
704                 CONSTRAINED_HEIGHT);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_polarRelativeTo, ANIMATE_CIRCLE_ANGLE_TO)705         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_polarRelativeTo,
706                 ANIMATE_CIRCLE_ANGLE_TO);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_transformPivotTarget, TRANSFORM_PIVOT_TARGET)707         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_transformPivotTarget,
708                 TRANSFORM_PIVOT_TARGET);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_quantizeMotionSteps, QUANTIZE_MOTION_STEPS)709         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_quantizeMotionSteps,
710                 QUANTIZE_MOTION_STEPS);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_quantizeMotionPhase, QUANTIZE_MOTION_PHASE)711         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_quantizeMotionPhase,
712                 QUANTIZE_MOTION_PHASE);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_quantizeMotionInterpolator, QUANTIZE_MOTION_INTERPOLATOR)713         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_quantizeMotionInterpolator,
714                 QUANTIZE_MOTION_INTERPOLATOR);
sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_wrapBehaviorInParent, LAYOUT_WRAP_BEHAVIOR)715         sOverrideMapToConstant.append(R.styleable.ConstraintOverride_layout_wrapBehaviorInParent,
716                 LAYOUT_WRAP_BEHAVIOR);
717 
718     }
719 
getCustomAttributeSet()720     public HashMap<String, ConstraintAttribute> getCustomAttributeSet() {
721         return mSavedAttributes;
722     }
723 
724     // @TODO: add description
725 
726     /**
727      *
728      * @param mId
729      * @return
730      */
getParameters(int mId)731     public Constraint getParameters(int mId) {
732         return get(mId);
733     }
734 
735     /**
736      * This will copy Constraints from the ConstraintSet
737      *
738      * @param set
739      */
readFallback(ConstraintSet set)740     public void readFallback(ConstraintSet set) {
741 
742         for (Integer key : set.mConstraints.keySet()) {
743             int id = key;
744             Constraint parent = set.mConstraints.get(key);
745 
746             if (!mConstraints.containsKey(id)) {
747                 mConstraints.put(id, new Constraint());
748             }
749             Constraint constraint = mConstraints.get(id);
750             if (constraint == null) {
751                 continue;
752             }
753             if (!constraint.layout.mApply) {
754                 constraint.layout.copyFrom(parent.layout);
755             }
756             if (!constraint.propertySet.mApply) {
757                 constraint.propertySet.copyFrom(parent.propertySet);
758             }
759             if (!constraint.transform.mApply) {
760                 constraint.transform.copyFrom(parent.transform);
761             }
762             if (!constraint.motion.mApply) {
763                 constraint.motion.copyFrom(parent.motion);
764             }
765             for (String s : parent.mCustomConstraints.keySet()) {
766                 if (!constraint.mCustomConstraints.containsKey(s)) {
767                     constraint.mCustomConstraints.put(s, parent.mCustomConstraints.get(s));
768                 }
769             }
770         }
771     }
772 
773     /**
774      * This will copy Constraints from the ConstraintLayout if it does not have parameters
775      *
776      * @param constraintLayout
777      */
readFallback(ConstraintLayout constraintLayout)778     public void readFallback(ConstraintLayout constraintLayout) {
779         int count = constraintLayout.getChildCount();
780         for (int i = 0; i < count; i++) {
781             View view = constraintLayout.getChildAt(i);
782             ConstraintLayout.LayoutParams param =
783                     (ConstraintLayout.LayoutParams) view.getLayoutParams();
784 
785             int id = view.getId();
786             if (mForceId && id == -1) {
787                 throw new RuntimeException("All children of ConstraintLayout "
788                         + "must have ids to use ConstraintSet");
789             }
790             if (!mConstraints.containsKey(id)) {
791                 mConstraints.put(id, new Constraint());
792             }
793             Constraint constraint = mConstraints.get(id);
794             if (constraint == null) {
795                 continue;
796             }
797             if (!constraint.layout.mApply) {
798                 constraint.fillFrom(id, param);
799                 if (view instanceof ConstraintHelper) {
800                     constraint.layout.mReferenceIds = ((ConstraintHelper) view).getReferencedIds();
801                     if (view instanceof Barrier) {
802                         Barrier barrier = (Barrier) view;
803                         constraint.layout.mBarrierAllowsGoneWidgets = barrier.getAllowsGoneWidget();
804                         constraint.layout.mBarrierDirection = barrier.getType();
805                         constraint.layout.mBarrierMargin = barrier.getMargin();
806                     }
807                 }
808                 constraint.layout.mApply = true;
809             }
810             if (!constraint.propertySet.mApply) {
811                 constraint.propertySet.visibility = view.getVisibility();
812                 constraint.propertySet.alpha = view.getAlpha();
813                 constraint.propertySet.mApply = true;
814             }
815             if (!constraint.transform.mApply) {
816                 constraint.transform.mApply = true;
817                 constraint.transform.rotation = view.getRotation();
818                 constraint.transform.rotationX = view.getRotationX();
819                 constraint.transform.rotationY = view.getRotationY();
820                 constraint.transform.scaleX = view.getScaleX();
821                 constraint.transform.scaleY = view.getScaleY();
822 
823                 float pivotX = view.getPivotX(); // we assume it is not set if set to 0.0
824                 float pivotY = view.getPivotY(); // we assume it is not set if set to 0.0
825 
826                 if (pivotX != 0.0 || pivotY != 0.0) {
827                     constraint.transform.transformPivotX = pivotX;
828                     constraint.transform.transformPivotY = pivotY;
829                 }
830 
831                 constraint.transform.translationX = view.getTranslationX();
832                 constraint.transform.translationY = view.getTranslationY();
833                 if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
834                     constraint.transform.translationZ = view.getTranslationZ();
835                     if (constraint.transform.applyElevation) {
836                         constraint.transform.elevation = view.getElevation();
837                     }
838                 }
839             }
840         }
841 
842     }
843 
844     /**
845      * Get the delta from the ConstraintSet and apply to this
846      * @param cs
847      */
applyDeltaFrom(ConstraintSet cs)848     public void applyDeltaFrom(ConstraintSet cs) {
849         for (Constraint from : cs.mConstraints.values()) {
850             if (from.mDelta == null) {
851                 continue;
852             }
853             if (from.mTargetString == null) {
854                 Constraint constraint = getConstraint(from.mViewId);
855                 from.mDelta.applyDelta(constraint);
856                 continue;
857             }
858             for (int key : mConstraints.keySet()) {
859                 Constraint potential = getConstraint(key);
860                 if (potential.layout.mConstraintTag == null) {
861                     continue;
862                 }
863                 if (from.mTargetString.matches(potential.layout.mConstraintTag)) {
864                     from.mDelta.applyDelta(potential);
865 
866                     @SuppressWarnings("unchecked")
867                     HashMap<String, ConstraintAttribute> fromClone =
868                             (HashMap<String, ConstraintAttribute>) from.mCustomConstraints.clone();
869                     potential.mCustomConstraints.putAll(fromClone);
870                 }
871             }
872         }
873     }
874 
875     /**
876      * Parse the constraint dimension attribute
877      *
878      * @param a
879      * @param attr
880      * @param orientation
881      */
parseDimensionConstraints(Object data, TypedArray a, int attr, int orientation)882     static void parseDimensionConstraints(Object data, TypedArray a, int attr, int orientation) {
883         if (data == null) {
884             return;
885         }
886         // data can be of:
887         //
888         // ConstraintLayout.LayoutParams
889         // ConstraintSet.Layout
890         // Constraint.Delta
891 
892         TypedValue v = a.peekValue(attr);
893         int type = v.type;
894         int finalValue = 0;
895         boolean finalConstrained = false;
896         switch (type) {
897             case TypedValue.TYPE_DIMENSION: {
898                 finalValue = a.getDimensionPixelSize(attr, 0);
899             }
900             break;
901             case TypedValue.TYPE_STRING: {
902                 String value = a.getString(attr);
903                 parseDimensionConstraintsString(data, value, orientation);
904                 return;
905             }
906             default: {
907                 int value = a.getInt(attr, 0);
908                 switch (value) {
909                     case INTERNAL_WRAP_CONTENT:
910                     case INTERNAL_MATCH_PARENT: {
911                         finalValue = value;
912                     }
913                         break;
914                     case INTERNAL_MATCH_CONSTRAINT: {
915                         finalValue = MATCH_CONSTRAINT;
916                     }
917                     break;
918                     case INTERNAL_WRAP_CONTENT_CONSTRAINED: {
919                         finalValue = WRAP_CONTENT;
920                         finalConstrained = true;
921                     }
922                     break;
923                 }
924             }
925         }
926 
927         if (data instanceof ConstraintLayout.LayoutParams) {
928             ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) data;
929             if (orientation == HORIZONTAL) {
930                 params.width = finalValue;
931                 params.constrainedWidth = finalConstrained;
932             } else {
933                 params.height = finalValue;
934                 params.constrainedHeight = finalConstrained;
935             }
936         } else if (data instanceof Layout) {
937             Layout params = (Layout) data;
938             if (orientation == HORIZONTAL) {
939                 params.mWidth = finalValue;
940                 params.constrainedWidth = finalConstrained;
941             } else {
942                 params.mHeight = finalValue;
943                 params.constrainedHeight = finalConstrained;
944             }
945         } else if (data instanceof Constraint.Delta) {
946             Constraint.Delta params = (Constraint.Delta) data;
947             if (orientation == HORIZONTAL) {
948                 params.add(LAYOUT_WIDTH, finalValue);
949                 params.add(CONSTRAINED_WIDTH, finalConstrained);
950             } else {
951                 params.add(LAYOUT_HEIGHT, finalValue);
952                 params.add(CONSTRAINED_HEIGHT, finalConstrained);
953             }
954         }
955     }
956 
957     /**
958      * Parse the dimension ratio string
959      *
960      * @param value
961      */
parseDimensionRatioString(ConstraintLayout.LayoutParams params, String value)962     static void parseDimensionRatioString(ConstraintLayout.LayoutParams params, String value) {
963         String dimensionRatio = value;
964         float dimensionRatioValue = Float.NaN;
965         int dimensionRatioSide = UNSET;
966         if (dimensionRatio != null) {
967             int len = dimensionRatio.length();
968             int commaIndex = dimensionRatio.indexOf(',');
969             if (commaIndex > 0 && commaIndex < len - 1) {
970                 String dimension = dimensionRatio.substring(0, commaIndex);
971                 if (dimension.equalsIgnoreCase("W")) {
972                     dimensionRatioSide = HORIZONTAL;
973                 } else if (dimension.equalsIgnoreCase("H")) {
974                     dimensionRatioSide = VERTICAL;
975                 }
976                 commaIndex++;
977             } else {
978                 commaIndex = 0;
979             }
980             int colonIndex = dimensionRatio.indexOf(':');
981             if (colonIndex >= 0 && colonIndex < len - 1) {
982                 String nominator = dimensionRatio.substring(commaIndex, colonIndex);
983                 String denominator = dimensionRatio.substring(colonIndex + 1);
984                 if (nominator.length() > 0 && denominator.length() > 0) {
985                     try {
986                         float nominatorValue = Float.parseFloat(nominator);
987                         float denominatorValue = Float.parseFloat(denominator);
988                         if (nominatorValue > 0 && denominatorValue > 0) {
989                             if (dimensionRatioSide == VERTICAL) {
990                                 dimensionRatioValue = Math.abs(denominatorValue / nominatorValue);
991                             } else {
992                                 dimensionRatioValue = Math.abs(nominatorValue / denominatorValue);
993                             }
994                         }
995                     } catch (NumberFormatException e) {
996                         // Ignore
997                     }
998                 }
999             } else {
1000                 String r = dimensionRatio.substring(commaIndex);
1001                 if (r.length() > 0) {
1002                     try {
1003                         dimensionRatioValue = Float.parseFloat(r);
1004                     } catch (NumberFormatException e) {
1005                         // Ignore
1006                     }
1007                 }
1008             }
1009         }
1010         params.dimensionRatio = dimensionRatio;
1011         params.mDimensionRatioValue = dimensionRatioValue;
1012         params.mDimensionRatioSide = dimensionRatioSide;
1013     }
1014 
1015     /**
1016      * Parse the constraints string dimension
1017      *
1018      * @param value
1019      * @param orientation
1020      */
parseDimensionConstraintsString(Object data, String value, int orientation)1021     static void parseDimensionConstraintsString(Object data, String value, int orientation) {
1022         // data can be of:
1023         //
1024         // ConstraintLayout.LayoutParams
1025         // ConstraintSet.Layout
1026         // Constraint.Delta
1027 
1028         // String should be of the form
1029         //
1030         // "<Key>=<Value>"
1031         // supported Keys are:
1032         // "weight=<value>"
1033         // "ratio=<value>"
1034         // "parent=<value>"
1035         if (value == null) {
1036             return;
1037         }
1038 
1039         int equalIndex = value.indexOf('=');
1040         int len = value.length();
1041         if (equalIndex > 0 && equalIndex < len - 1) {
1042             String key = value.substring(0, equalIndex);
1043             String val = value.substring(equalIndex + 1);
1044             if (val.length() > 0) {
1045                 key = key.trim();
1046                 val = val.trim();
1047                 if (KEY_RATIO.equalsIgnoreCase(key)) {
1048                     if (data instanceof ConstraintLayout.LayoutParams) {
1049                         ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) data;
1050                         if (orientation == HORIZONTAL) {
1051                             params.width = MATCH_CONSTRAINT;
1052                         } else {
1053                             params.height = MATCH_CONSTRAINT;
1054                         }
1055                         parseDimensionRatioString(params, val);
1056                     } else if (data instanceof Layout) {
1057                         Layout params = (Layout) data;
1058                         params.dimensionRatio = val;
1059                     } else if (data instanceof Constraint.Delta) {
1060                         Constraint.Delta params = (Constraint.Delta) data;
1061                         params.add(DIMENSION_RATIO, val);
1062                     }
1063                 } else if (KEY_WEIGHT.equalsIgnoreCase(key)) {
1064                     try {
1065                         float weight = Float.parseFloat(val);
1066                         if (data instanceof ConstraintLayout.LayoutParams) {
1067                             ConstraintLayout.LayoutParams params =
1068                                     (ConstraintLayout.LayoutParams) data;
1069                             if (orientation == HORIZONTAL) {
1070                                 params.width = MATCH_CONSTRAINT;
1071                                 params.horizontalWeight = weight;
1072                             } else {
1073                                 params.height = MATCH_CONSTRAINT;
1074                                 params.verticalWeight = weight;
1075                             }
1076                         } else if (data instanceof Layout) {
1077                             Layout params = (Layout) data;
1078                             if (orientation == HORIZONTAL) {
1079                                 params.mWidth = MATCH_CONSTRAINT;
1080                                 params.horizontalWeight = weight;
1081                             } else {
1082                                 params.mHeight = MATCH_CONSTRAINT;
1083                                 params.verticalWeight = weight;
1084                             }
1085                         } else if (data instanceof Constraint.Delta) {
1086                             Constraint.Delta params = (Constraint.Delta) data;
1087                             if (orientation == HORIZONTAL) {
1088                                 params.add(LAYOUT_WIDTH, MATCH_CONSTRAINT);
1089                                 params.add(HORIZONTAL_WEIGHT, weight);
1090                             } else {
1091                                 params.add(LAYOUT_HEIGHT, MATCH_CONSTRAINT);
1092                                 params.add(VERTICAL_WEIGHT, weight);
1093                             }
1094                         }
1095                     } catch (NumberFormatException e) {
1096                         // nothing
1097                     }
1098                 } else if (KEY_PERCENT_PARENT.equalsIgnoreCase(key)) {
1099                     try {
1100                         float percent = Math.min(1, Float.parseFloat(val));
1101                         percent = Math.max(0, percent);
1102                         if (data instanceof ConstraintLayout.LayoutParams) {
1103                             ConstraintLayout.LayoutParams params =
1104                                     (ConstraintLayout.LayoutParams) data;
1105                             if (orientation == HORIZONTAL) {
1106                                 params.width = MATCH_CONSTRAINT;
1107                                 params.matchConstraintPercentWidth = percent;
1108                                 params.matchConstraintDefaultWidth = MATCH_CONSTRAINT_PERCENT;
1109                             } else {
1110                                 params.height = MATCH_CONSTRAINT;
1111                                 params.matchConstraintPercentHeight = percent;
1112                                 params.matchConstraintDefaultHeight = MATCH_CONSTRAINT_PERCENT;
1113                             }
1114                         } else if (data instanceof Layout) {
1115                             Layout params = (Layout) data;
1116                             if (orientation == HORIZONTAL) {
1117                                 params.mWidth = MATCH_CONSTRAINT;
1118                                 params.widthPercent = percent;
1119                                 params.widthDefault = MATCH_CONSTRAINT_PERCENT;
1120                             } else {
1121                                 params.mHeight = MATCH_CONSTRAINT;
1122                                 params.heightPercent = percent;
1123                                 params.heightDefault = MATCH_CONSTRAINT_PERCENT;
1124                             }
1125                         } else if (data instanceof Constraint.Delta) {
1126                             Constraint.Delta params = (Constraint.Delta) data;
1127                             if (orientation == HORIZONTAL) {
1128                                 params.add(LAYOUT_WIDTH, MATCH_CONSTRAINT);
1129                                 params.add(WIDTH_DEFAULT, MATCH_CONSTRAINT_PERCENT);
1130                             } else {
1131                                 params.add(LAYOUT_HEIGHT, MATCH_CONSTRAINT);
1132                                 params.add(HEIGHT_DEFAULT, MATCH_CONSTRAINT_PERCENT);
1133                             }
1134                         }
1135                     } catch (NumberFormatException e) {
1136                         // nothing
1137                     }
1138                 }
1139             }
1140         }
1141     }
1142 
1143 
1144     /**
1145      * Get the types associated with this ConstraintSet
1146      * The types mechanism allows you to tag the constraint set
1147      * with a series of string to define properties of a ConstraintSet
1148      *
1149      * @return an array of type strings
1150      */
getStateLabels()1151     public String[] getStateLabels() {
1152         return Arrays.copyOf(mMatchLabels, mMatchLabels.length);
1153     }
1154 
1155     /**
1156      * Set the types associated with this ConstraintSet
1157      * The types mechanism allows you to tag the constraint set
1158      * with a series of string to define properties of a ConstraintSet
1159      * @param types a comer separated array of strings.
1160      */
setStateLabels(String types)1161     public void setStateLabels(String types) {
1162         mMatchLabels = types.split(",");
1163         for (int i = 0; i < mMatchLabels.length; i++) {
1164             mMatchLabels[i] = mMatchLabels[i].trim();
1165         }
1166     }
1167     /**
1168      * Set the types associated with this ConstraintSet
1169      * The types mechanism allows you to tag the constraint set
1170      * with a series of string to define properties of a ConstraintSet
1171      * @param types a comer separated array of strings.
1172      */
setStateLabelsList(String... types)1173     public void setStateLabelsList(String... types) {
1174         mMatchLabels = types;
1175         for (int i = 0; i < mMatchLabels.length; i++) {
1176             mMatchLabels[i] = mMatchLabels[i].trim();
1177         }
1178     }
1179 
1180     /**
1181      * Test if the list of strings matches labels defined on this constraintSet
1182      * @param types list of types
1183      * @return true if all types are in the labels
1184      */
matchesLabels(String...types)1185     public boolean matchesLabels(String...types) {
1186         for (String type : types) {
1187             boolean match = false;
1188             for (String matchType : mMatchLabels) {
1189                 if (matchType.equals(type)) {
1190                     match = true;
1191                     break;
1192                 }
1193             }
1194             if (!match) {
1195                 return false;
1196             }
1197 
1198         }
1199         return true;
1200     }
1201 
1202     /**
1203      *
1204      */
1205     public static class Layout {
1206         public boolean mIsGuideline = false;
1207         public boolean mApply = false;
1208         public boolean mOverride = false;
1209         public int mWidth;
1210         public int mHeight;
1211         public static final int UNSET = ConstraintSet.UNSET;
1212         public static final int UNSET_GONE_MARGIN = Integer.MIN_VALUE;
1213         public int guideBegin = UNSET;
1214         public int guideEnd = UNSET;
1215         public float guidePercent = UNSET;
1216         public boolean guidelineUseRtl = true;
1217         public int leftToLeft = UNSET;
1218         public int leftToRight = UNSET;
1219         public int rightToLeft = UNSET;
1220         public int rightToRight = UNSET;
1221         public int topToTop = UNSET;
1222         public int topToBottom = UNSET;
1223         public int bottomToTop = UNSET;
1224         public int bottomToBottom = UNSET;
1225         public int baselineToBaseline = UNSET;
1226         public int baselineToTop = UNSET;
1227         public int baselineToBottom = UNSET;
1228         public int startToEnd = UNSET;
1229         public int startToStart = UNSET;
1230         public int endToStart = UNSET;
1231         public int endToEnd = UNSET;
1232         public float horizontalBias = 0.5f;
1233         public float verticalBias = 0.5f;
1234         public String dimensionRatio = null;
1235         public int circleConstraint = UNSET;
1236         public int circleRadius = 0;
1237         public float circleAngle = 0;
1238         public int editorAbsoluteX = UNSET;
1239         public int editorAbsoluteY = UNSET;
1240         public int orientation = UNSET;
1241         public int leftMargin = 0;
1242         public int rightMargin = 0;
1243         public int topMargin = 0;
1244         public int bottomMargin = 0;
1245         public int endMargin = 0;
1246         public int startMargin = 0;
1247         public int baselineMargin = 0;
1248         public int goneLeftMargin = UNSET_GONE_MARGIN;
1249         public int goneTopMargin = UNSET_GONE_MARGIN;
1250         public int goneRightMargin = UNSET_GONE_MARGIN;
1251         public int goneBottomMargin = UNSET_GONE_MARGIN;
1252         public int goneEndMargin = UNSET_GONE_MARGIN;
1253         public int goneStartMargin = UNSET_GONE_MARGIN;
1254         public int goneBaselineMargin = UNSET_GONE_MARGIN;
1255         public float verticalWeight = UNSET;
1256         public float horizontalWeight = UNSET;
1257         public int horizontalChainStyle = CHAIN_SPREAD;
1258         public int verticalChainStyle = CHAIN_SPREAD;
1259         public int widthDefault = ConstraintWidget.MATCH_CONSTRAINT_SPREAD;
1260         public int heightDefault = ConstraintWidget.MATCH_CONSTRAINT_SPREAD;
1261         public int widthMax = 0;
1262         public int heightMax = 0;
1263         public int widthMin = 0;
1264         public int heightMin = 0;
1265         public float widthPercent = 1;
1266         public float heightPercent = 1;
1267         public int mBarrierDirection = UNSET;
1268         public int mBarrierMargin = 0;
1269         public int mHelperType = UNSET;
1270         public int[] mReferenceIds;
1271         public String mReferenceIdString;
1272         public String mConstraintTag;
1273         public boolean constrainedWidth = false;
1274         public boolean constrainedHeight = false;
1275         // TODO public boolean mChainUseRtl = false;
1276         public boolean mBarrierAllowsGoneWidgets = true;
1277         public int mWrapBehavior = ConstraintWidget.WRAP_BEHAVIOR_INCLUDED;
1278 
1279         /**
1280          * Copy from Layout
1281          * @param src
1282          */
copyFrom(Layout src)1283         public void copyFrom(Layout src) {
1284             mIsGuideline = src.mIsGuideline;
1285             mWidth = src.mWidth;
1286             mApply = src.mApply;
1287             mHeight = src.mHeight;
1288             guideBegin = src.guideBegin;
1289             guideEnd = src.guideEnd;
1290             guidePercent = src.guidePercent;
1291             guidelineUseRtl = src.guidelineUseRtl;
1292             leftToLeft = src.leftToLeft;
1293             leftToRight = src.leftToRight;
1294             rightToLeft = src.rightToLeft;
1295             rightToRight = src.rightToRight;
1296             topToTop = src.topToTop;
1297             topToBottom = src.topToBottom;
1298             bottomToTop = src.bottomToTop;
1299             bottomToBottom = src.bottomToBottom;
1300             baselineToBaseline = src.baselineToBaseline;
1301             baselineToTop = src.baselineToTop;
1302             baselineToBottom = src.baselineToBottom;
1303             startToEnd = src.startToEnd;
1304             startToStart = src.startToStart;
1305             endToStart = src.endToStart;
1306             endToEnd = src.endToEnd;
1307             horizontalBias = src.horizontalBias;
1308             verticalBias = src.verticalBias;
1309             dimensionRatio = src.dimensionRatio;
1310             circleConstraint = src.circleConstraint;
1311             circleRadius = src.circleRadius;
1312             circleAngle = src.circleAngle;
1313             editorAbsoluteX = src.editorAbsoluteX;
1314             editorAbsoluteY = src.editorAbsoluteY;
1315             orientation = src.orientation;
1316             leftMargin = src.leftMargin;
1317             rightMargin = src.rightMargin;
1318             topMargin = src.topMargin;
1319             bottomMargin = src.bottomMargin;
1320             endMargin = src.endMargin;
1321             startMargin = src.startMargin;
1322             baselineMargin = src.baselineMargin;
1323             goneLeftMargin = src.goneLeftMargin;
1324             goneTopMargin = src.goneTopMargin;
1325             goneRightMargin = src.goneRightMargin;
1326             goneBottomMargin = src.goneBottomMargin;
1327             goneEndMargin = src.goneEndMargin;
1328             goneStartMargin = src.goneStartMargin;
1329             goneBaselineMargin = src.goneBaselineMargin;
1330             verticalWeight = src.verticalWeight;
1331             horizontalWeight = src.horizontalWeight;
1332             horizontalChainStyle = src.horizontalChainStyle;
1333             verticalChainStyle = src.verticalChainStyle;
1334             widthDefault = src.widthDefault;
1335             heightDefault = src.heightDefault;
1336             widthMax = src.widthMax;
1337             heightMax = src.heightMax;
1338             widthMin = src.widthMin;
1339             heightMin = src.heightMin;
1340             widthPercent = src.widthPercent;
1341             heightPercent = src.heightPercent;
1342             mBarrierDirection = src.mBarrierDirection;
1343             mBarrierMargin = src.mBarrierMargin;
1344             mHelperType = src.mHelperType;
1345             mConstraintTag = src.mConstraintTag;
1346 
1347             if (src.mReferenceIds != null && src.mReferenceIdString == null) {
1348                 mReferenceIds = Arrays.copyOf(src.mReferenceIds, src.mReferenceIds.length);
1349             } else {
1350                 mReferenceIds = null;
1351             }
1352             mReferenceIdString = src.mReferenceIdString;
1353             constrainedWidth = src.constrainedWidth;
1354             constrainedHeight = src.constrainedHeight;
1355             // TODO mChainUseRtl = t.mChainUseRtl;
1356             mBarrierAllowsGoneWidgets = src.mBarrierAllowsGoneWidgets;
1357             mWrapBehavior = src.mWrapBehavior;
1358         }
1359 
1360         private static SparseIntArray sMapToConstant = new SparseIntArray();
1361         private static final int BASELINE_TO_BASELINE = 1;
1362         private static final int BOTTOM_MARGIN = 2;
1363         private static final int BOTTOM_TO_BOTTOM = 3;
1364         private static final int BOTTOM_TO_TOP = 4;
1365         private static final int DIMENSION_RATIO = 5;
1366         private static final int EDITOR_ABSOLUTE_X = 6;
1367         private static final int EDITOR_ABSOLUTE_Y = 7;
1368         private static final int END_MARGIN = 8;
1369         private static final int END_TO_END = 9;
1370         private static final int END_TO_START = 10;
1371         private static final int GONE_BOTTOM_MARGIN = 11;
1372         private static final int GONE_END_MARGIN = 12;
1373         private static final int GONE_LEFT_MARGIN = 13;
1374         private static final int GONE_RIGHT_MARGIN = 14;
1375         private static final int GONE_START_MARGIN = 15;
1376         private static final int GONE_TOP_MARGIN = 16;
1377         private static final int GUIDE_BEGIN = 17;
1378         private static final int GUIDE_END = 18;
1379         private static final int GUIDE_PERCENT = 19;
1380         private static final int HORIZONTAL_BIAS = 20;
1381         private static final int LAYOUT_HEIGHT = 21;
1382         private static final int LAYOUT_WIDTH = 22;
1383         private static final int LEFT_MARGIN = 23;
1384         private static final int LEFT_TO_LEFT = 24;
1385         private static final int LEFT_TO_RIGHT = 25;
1386         private static final int ORIENTATION = 26;
1387         private static final int RIGHT_MARGIN = 27;
1388         private static final int RIGHT_TO_LEFT = 28;
1389         private static final int RIGHT_TO_RIGHT = 29;
1390         private static final int START_MARGIN = 30;
1391         private static final int START_TO_END = 31;
1392         private static final int START_TO_START = 32;
1393         private static final int TOP_MARGIN = 33;
1394         private static final int TOP_TO_BOTTOM = 34;
1395         private static final int TOP_TO_TOP = 35;
1396         private static final int VERTICAL_BIAS = 36;
1397         private static final int HORIZONTAL_WEIGHT = 37;
1398         private static final int VERTICAL_WEIGHT = 38;
1399         private static final int HORIZONTAL_STYLE = 39;
1400         private static final int VERTICAL_STYLE = 40;
1401         private static final int LAYOUT_CONSTRAINT_WIDTH = 41;
1402         private static final int LAYOUT_CONSTRAINT_HEIGHT = 42;
1403 
1404         private static final int CIRCLE = 61;
1405         private static final int CIRCLE_RADIUS = 62;
1406         private static final int CIRCLE_ANGLE = 63;
1407         private static final int WIDTH_PERCENT = 69;
1408         private static final int HEIGHT_PERCENT = 70;
1409         private static final int CHAIN_USE_RTL = 71;
1410         private static final int BARRIER_DIRECTION = 72;
1411         private static final int BARRIER_MARGIN = 73;
1412         private static final int CONSTRAINT_REFERENCED_IDS = 74;
1413         private static final int BARRIER_ALLOWS_GONE_WIDGETS = 75;
1414 
1415         private static final int LAYOUT_WRAP_BEHAVIOR = 76;
1416         private static final int BASELINE_TO_TOP = 77;
1417         private static final int BASELINE_TO_BOTTOM = 78;
1418         private static final int GONE_BASELINE_MARGIN = 79;
1419         private static final int BASELINE_MARGIN = 80;
1420         private static final int WIDTH_DEFAULT = 81;
1421         private static final int HEIGHT_DEFAULT = 82;
1422         private static final int HEIGHT_MAX = 83;
1423         private static final int WIDTH_MAX = 84;
1424         private static final int HEIGHT_MIN = 85;
1425         private static final int WIDTH_MIN = 86;
1426         private static final int CONSTRAINED_WIDTH = 87;
1427         private static final int CONSTRAINED_HEIGHT = 88;
1428         private static final int CONSTRAINT_TAG = 89;
1429         private static final int GUIDE_USE_RTL = 90;
1430 
1431         private static final int UNUSED = 91;
1432 
1433         static {
sMapToConstant.append(R.styleable.Layout_layout_constraintLeft_toLeftOf, LEFT_TO_LEFT)1434             sMapToConstant.append(R.styleable.Layout_layout_constraintLeft_toLeftOf, LEFT_TO_LEFT);
sMapToConstant.append(R.styleable.Layout_layout_constraintLeft_toRightOf, LEFT_TO_RIGHT)1435             sMapToConstant.append(R.styleable.Layout_layout_constraintLeft_toRightOf,
1436                     LEFT_TO_RIGHT);
sMapToConstant.append(R.styleable.Layout_layout_constraintRight_toLeftOf, RIGHT_TO_LEFT)1437             sMapToConstant.append(R.styleable.Layout_layout_constraintRight_toLeftOf,
1438                     RIGHT_TO_LEFT);
sMapToConstant.append(R.styleable.Layout_layout_constraintRight_toRightOf, RIGHT_TO_RIGHT)1439             sMapToConstant.append(R.styleable.Layout_layout_constraintRight_toRightOf,
1440                     RIGHT_TO_RIGHT);
sMapToConstant.append(R.styleable.Layout_layout_constraintTop_toTopOf, TOP_TO_TOP)1441             sMapToConstant.append(R.styleable.Layout_layout_constraintTop_toTopOf, TOP_TO_TOP);
sMapToConstant.append(R.styleable.Layout_layout_constraintTop_toBottomOf, TOP_TO_BOTTOM)1442             sMapToConstant.append(R.styleable.Layout_layout_constraintTop_toBottomOf,
1443                     TOP_TO_BOTTOM);
sMapToConstant.append(R.styleable.Layout_layout_constraintBottom_toTopOf, BOTTOM_TO_TOP)1444             sMapToConstant.append(R.styleable.Layout_layout_constraintBottom_toTopOf,
1445                     BOTTOM_TO_TOP);
sMapToConstant.append(R.styleable.Layout_layout_constraintBottom_toBottomOf, BOTTOM_TO_BOTTOM)1446             sMapToConstant.append(R.styleable.Layout_layout_constraintBottom_toBottomOf,
1447                     BOTTOM_TO_BOTTOM);
sMapToConstant.append(R.styleable.Layout_layout_constraintBaseline_toBaselineOf, BASELINE_TO_BASELINE)1448             sMapToConstant.append(R.styleable.Layout_layout_constraintBaseline_toBaselineOf,
1449                     BASELINE_TO_BASELINE);
1450 
sMapToConstant.append(R.styleable.Layout_layout_editor_absoluteX, EDITOR_ABSOLUTE_X)1451             sMapToConstant.append(R.styleable.Layout_layout_editor_absoluteX, EDITOR_ABSOLUTE_X);
sMapToConstant.append(R.styleable.Layout_layout_editor_absoluteY, EDITOR_ABSOLUTE_Y)1452             sMapToConstant.append(R.styleable.Layout_layout_editor_absoluteY, EDITOR_ABSOLUTE_Y);
sMapToConstant.append(R.styleable.Layout_layout_constraintGuide_begin, GUIDE_BEGIN)1453             sMapToConstant.append(R.styleable.Layout_layout_constraintGuide_begin, GUIDE_BEGIN);
sMapToConstant.append(R.styleable.Layout_layout_constraintGuide_end, GUIDE_END)1454             sMapToConstant.append(R.styleable.Layout_layout_constraintGuide_end, GUIDE_END);
sMapToConstant.append(R.styleable.Layout_layout_constraintGuide_percent, GUIDE_PERCENT)1455             sMapToConstant.append(R.styleable.Layout_layout_constraintGuide_percent, GUIDE_PERCENT);
sMapToConstant.append(R.styleable.Layout_guidelineUseRtl, GUIDE_USE_RTL)1456             sMapToConstant.append(R.styleable.Layout_guidelineUseRtl, GUIDE_USE_RTL);
sMapToConstant.append(R.styleable.Layout_android_orientation, ORIENTATION)1457             sMapToConstant.append(R.styleable.Layout_android_orientation, ORIENTATION);
sMapToConstant.append(R.styleable.Layout_layout_constraintStart_toEndOf, START_TO_END)1458             sMapToConstant.append(R.styleable.Layout_layout_constraintStart_toEndOf, START_TO_END);
sMapToConstant.append(R.styleable.Layout_layout_constraintStart_toStartOf, START_TO_START)1459             sMapToConstant.append(R.styleable.Layout_layout_constraintStart_toStartOf,
1460                     START_TO_START);
sMapToConstant.append(R.styleable.Layout_layout_constraintEnd_toStartOf, END_TO_START)1461             sMapToConstant.append(R.styleable.Layout_layout_constraintEnd_toStartOf, END_TO_START);
sMapToConstant.append(R.styleable.Layout_layout_constraintEnd_toEndOf, END_TO_END)1462             sMapToConstant.append(R.styleable.Layout_layout_constraintEnd_toEndOf, END_TO_END);
sMapToConstant.append(R.styleable.Layout_layout_goneMarginLeft, GONE_LEFT_MARGIN)1463             sMapToConstant.append(R.styleable.Layout_layout_goneMarginLeft, GONE_LEFT_MARGIN);
sMapToConstant.append(R.styleable.Layout_layout_goneMarginTop, GONE_TOP_MARGIN)1464             sMapToConstant.append(R.styleable.Layout_layout_goneMarginTop, GONE_TOP_MARGIN);
sMapToConstant.append(R.styleable.Layout_layout_goneMarginRight, GONE_RIGHT_MARGIN)1465             sMapToConstant.append(R.styleable.Layout_layout_goneMarginRight, GONE_RIGHT_MARGIN);
sMapToConstant.append(R.styleable.Layout_layout_goneMarginBottom, GONE_BOTTOM_MARGIN)1466             sMapToConstant.append(R.styleable.Layout_layout_goneMarginBottom, GONE_BOTTOM_MARGIN);
sMapToConstant.append(R.styleable.Layout_layout_goneMarginStart, GONE_START_MARGIN)1467             sMapToConstant.append(R.styleable.Layout_layout_goneMarginStart, GONE_START_MARGIN);
sMapToConstant.append(R.styleable.Layout_layout_goneMarginEnd, GONE_END_MARGIN)1468             sMapToConstant.append(R.styleable.Layout_layout_goneMarginEnd, GONE_END_MARGIN);
sMapToConstant.append(R.styleable.Layout_layout_constraintVertical_weight, VERTICAL_WEIGHT)1469             sMapToConstant.append(R.styleable.Layout_layout_constraintVertical_weight,
1470                     VERTICAL_WEIGHT);
sMapToConstant.append(R.styleable.Layout_layout_constraintHorizontal_weight, HORIZONTAL_WEIGHT)1471             sMapToConstant.append(R.styleable.Layout_layout_constraintHorizontal_weight,
1472                     HORIZONTAL_WEIGHT);
sMapToConstant.append(R.styleable.Layout_layout_constraintHorizontal_chainStyle, HORIZONTAL_STYLE)1473             sMapToConstant.append(R.styleable.Layout_layout_constraintHorizontal_chainStyle,
1474                     HORIZONTAL_STYLE);
sMapToConstant.append(R.styleable.Layout_layout_constraintVertical_chainStyle, VERTICAL_STYLE)1475             sMapToConstant.append(R.styleable.Layout_layout_constraintVertical_chainStyle,
1476                     VERTICAL_STYLE);
1477 
sMapToConstant.append(R.styleable.Layout_layout_constraintHorizontal_bias, HORIZONTAL_BIAS)1478             sMapToConstant.append(R.styleable.Layout_layout_constraintHorizontal_bias,
1479                     HORIZONTAL_BIAS);
sMapToConstant.append(R.styleable.Layout_layout_constraintVertical_bias, VERTICAL_BIAS)1480             sMapToConstant.append(R.styleable.Layout_layout_constraintVertical_bias,
1481                     VERTICAL_BIAS);
sMapToConstant.append(R.styleable.Layout_layout_constraintDimensionRatio, DIMENSION_RATIO)1482             sMapToConstant.append(R.styleable.Layout_layout_constraintDimensionRatio,
1483                     DIMENSION_RATIO);
sMapToConstant.append(R.styleable.Layout_layout_constraintLeft_creator, UNUSED)1484             sMapToConstant.append(R.styleable.Layout_layout_constraintLeft_creator, UNUSED);
sMapToConstant.append(R.styleable.Layout_layout_constraintTop_creator, UNUSED)1485             sMapToConstant.append(R.styleable.Layout_layout_constraintTop_creator, UNUSED);
sMapToConstant.append(R.styleable.Layout_layout_constraintRight_creator, UNUSED)1486             sMapToConstant.append(R.styleable.Layout_layout_constraintRight_creator, UNUSED);
sMapToConstant.append(R.styleable.Layout_layout_constraintBottom_creator, UNUSED)1487             sMapToConstant.append(R.styleable.Layout_layout_constraintBottom_creator, UNUSED);
sMapToConstant.append(R.styleable.Layout_layout_constraintBaseline_creator, UNUSED)1488             sMapToConstant.append(R.styleable.Layout_layout_constraintBaseline_creator, UNUSED);
sMapToConstant.append(R.styleable.Layout_android_layout_marginLeft, LEFT_MARGIN)1489             sMapToConstant.append(R.styleable.Layout_android_layout_marginLeft, LEFT_MARGIN);
sMapToConstant.append(R.styleable.Layout_android_layout_marginRight, RIGHT_MARGIN)1490             sMapToConstant.append(R.styleable.Layout_android_layout_marginRight, RIGHT_MARGIN);
sMapToConstant.append(R.styleable.Layout_android_layout_marginStart, START_MARGIN)1491             sMapToConstant.append(R.styleable.Layout_android_layout_marginStart, START_MARGIN);
sMapToConstant.append(R.styleable.Layout_android_layout_marginEnd, END_MARGIN)1492             sMapToConstant.append(R.styleable.Layout_android_layout_marginEnd, END_MARGIN);
sMapToConstant.append(R.styleable.Layout_android_layout_marginTop, TOP_MARGIN)1493             sMapToConstant.append(R.styleable.Layout_android_layout_marginTop, TOP_MARGIN);
sMapToConstant.append(R.styleable.Layout_android_layout_marginBottom, BOTTOM_MARGIN)1494             sMapToConstant.append(R.styleable.Layout_android_layout_marginBottom, BOTTOM_MARGIN);
sMapToConstant.append(R.styleable.Layout_android_layout_width, LAYOUT_WIDTH)1495             sMapToConstant.append(R.styleable.Layout_android_layout_width, LAYOUT_WIDTH);
sMapToConstant.append(R.styleable.Layout_android_layout_height, LAYOUT_HEIGHT)1496             sMapToConstant.append(R.styleable.Layout_android_layout_height, LAYOUT_HEIGHT);
sMapToConstant.append(R.styleable.Layout_layout_constraintWidth, LAYOUT_CONSTRAINT_WIDTH)1497             sMapToConstant.append(R.styleable.Layout_layout_constraintWidth,
1498                     LAYOUT_CONSTRAINT_WIDTH);
sMapToConstant.append(R.styleable.Layout_layout_constraintHeight, LAYOUT_CONSTRAINT_HEIGHT)1499             sMapToConstant.append(R.styleable.Layout_layout_constraintHeight,
1500                     LAYOUT_CONSTRAINT_HEIGHT);
sMapToConstant.append(R.styleable.Layout_layout_constrainedWidth, CONSTRAINED_WIDTH)1501             sMapToConstant.append(R.styleable.Layout_layout_constrainedWidth,
1502                     CONSTRAINED_WIDTH);
sMapToConstant.append(R.styleable.Layout_layout_constrainedHeight, CONSTRAINED_HEIGHT)1503             sMapToConstant.append(R.styleable.Layout_layout_constrainedHeight,
1504                     CONSTRAINED_HEIGHT);
sMapToConstant.append(R.styleable.Layout_layout_wrapBehaviorInParent, LAYOUT_WRAP_BEHAVIOR)1505             sMapToConstant.append(R.styleable.Layout_layout_wrapBehaviorInParent,
1506                     LAYOUT_WRAP_BEHAVIOR);
1507 
sMapToConstant.append(R.styleable.Layout_layout_constraintCircle, CIRCLE)1508             sMapToConstant.append(R.styleable.Layout_layout_constraintCircle, CIRCLE);
sMapToConstant.append(R.styleable.Layout_layout_constraintCircleRadius, CIRCLE_RADIUS)1509             sMapToConstant.append(R.styleable.Layout_layout_constraintCircleRadius, CIRCLE_RADIUS);
sMapToConstant.append(R.styleable.Layout_layout_constraintCircleAngle, CIRCLE_ANGLE)1510             sMapToConstant.append(R.styleable.Layout_layout_constraintCircleAngle, CIRCLE_ANGLE);
sMapToConstant.append(R.styleable.Layout_layout_constraintWidth_percent, WIDTH_PERCENT)1511             sMapToConstant.append(R.styleable.Layout_layout_constraintWidth_percent, WIDTH_PERCENT);
sMapToConstant.append(R.styleable.Layout_layout_constraintHeight_percent, HEIGHT_PERCENT)1512             sMapToConstant.append(R.styleable.Layout_layout_constraintHeight_percent,
1513                     HEIGHT_PERCENT);
1514 
sMapToConstant.append(R.styleable.Layout_chainUseRtl, CHAIN_USE_RTL)1515             sMapToConstant.append(R.styleable.Layout_chainUseRtl, CHAIN_USE_RTL);
sMapToConstant.append(R.styleable.Layout_barrierDirection, BARRIER_DIRECTION)1516             sMapToConstant.append(R.styleable.Layout_barrierDirection, BARRIER_DIRECTION);
sMapToConstant.append(R.styleable.Layout_barrierMargin, BARRIER_MARGIN)1517             sMapToConstant.append(R.styleable.Layout_barrierMargin, BARRIER_MARGIN);
sMapToConstant.append(R.styleable.Layout_constraint_referenced_ids, CONSTRAINT_REFERENCED_IDS)1518             sMapToConstant.append(R.styleable.Layout_constraint_referenced_ids,
1519                     CONSTRAINT_REFERENCED_IDS);
sMapToConstant.append(R.styleable.Layout_barrierAllowsGoneWidgets, BARRIER_ALLOWS_GONE_WIDGETS)1520             sMapToConstant.append(R.styleable.Layout_barrierAllowsGoneWidgets,
1521                     BARRIER_ALLOWS_GONE_WIDGETS);
sMapToConstant.append(R.styleable.Layout_layout_constraintWidth_max, WIDTH_MAX)1522             sMapToConstant.append(R.styleable.Layout_layout_constraintWidth_max,
1523                     WIDTH_MAX);
sMapToConstant.append(R.styleable.Layout_layout_constraintWidth_min, WIDTH_MIN)1524             sMapToConstant.append(R.styleable.Layout_layout_constraintWidth_min,
1525                     WIDTH_MIN);
sMapToConstant.append(R.styleable.Layout_layout_constraintWidth_max, HEIGHT_MAX)1526             sMapToConstant.append(R.styleable.Layout_layout_constraintWidth_max,
1527                     HEIGHT_MAX);
sMapToConstant.append(R.styleable.Layout_layout_constraintHeight_min, HEIGHT_MIN)1528             sMapToConstant.append(R.styleable.Layout_layout_constraintHeight_min,
1529                     HEIGHT_MIN);
1530 
sMapToConstant.append(R.styleable.Layout_layout_constraintWidth, CONSTRAINED_WIDTH)1531             sMapToConstant.append(R.styleable.Layout_layout_constraintWidth, CONSTRAINED_WIDTH);
sMapToConstant.append(R.styleable.Layout_layout_constraintHeight, CONSTRAINED_HEIGHT)1532             sMapToConstant.append(R.styleable.Layout_layout_constraintHeight, CONSTRAINED_HEIGHT);
sMapToConstant.append(R.styleable.ConstraintLayout_Layout_layout_constraintTag, CONSTRAINT_TAG)1533             sMapToConstant.append(R.styleable.ConstraintLayout_Layout_layout_constraintTag,
1534                     CONSTRAINT_TAG);
sMapToConstant.append(R.styleable.Layout_guidelineUseRtl, GUIDE_USE_RTL)1535             sMapToConstant.append(R.styleable.Layout_guidelineUseRtl, GUIDE_USE_RTL);
1536 
1537         }
1538 
fillFromAttributeList(Context context, AttributeSet attrs)1539         void fillFromAttributeList(Context context, AttributeSet attrs) {
1540             TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Layout);
1541             mApply = true;
1542             final int count = a.getIndexCount();
1543             for (int i = 0; i < count; i++) {
1544                 int attr = a.getIndex(i);
1545 
1546                 switch (sMapToConstant.get(attr)) {
1547                     case LEFT_TO_LEFT:
1548                         leftToLeft = lookupID(a, attr, leftToLeft);
1549                         break;
1550                     case LEFT_TO_RIGHT:
1551                         leftToRight = lookupID(a, attr, leftToRight);
1552                         break;
1553                     case RIGHT_TO_LEFT:
1554                         rightToLeft = lookupID(a, attr, rightToLeft);
1555                         break;
1556                     case RIGHT_TO_RIGHT:
1557                         rightToRight = lookupID(a, attr, rightToRight);
1558                         break;
1559                     case TOP_TO_TOP:
1560                         topToTop = lookupID(a, attr, topToTop);
1561                         break;
1562                     case TOP_TO_BOTTOM:
1563                         topToBottom = lookupID(a, attr, topToBottom);
1564                         break;
1565                     case BOTTOM_TO_TOP:
1566                         bottomToTop = lookupID(a, attr, bottomToTop);
1567                         break;
1568                     case BOTTOM_TO_BOTTOM:
1569                         bottomToBottom = lookupID(a, attr, bottomToBottom);
1570                         break;
1571                     case BASELINE_TO_BASELINE:
1572                         baselineToBaseline = lookupID(a, attr, baselineToBaseline);
1573                         break;
1574                     case BASELINE_TO_TOP:
1575                         baselineToTop = lookupID(a, attr, baselineToTop);
1576                         break;
1577                     case BASELINE_TO_BOTTOM:
1578                         baselineToBottom = lookupID(a, attr, baselineToBottom);
1579                         break;
1580                     case EDITOR_ABSOLUTE_X:
1581                         editorAbsoluteX = a.getDimensionPixelOffset(attr, editorAbsoluteX);
1582                         break;
1583                     case EDITOR_ABSOLUTE_Y:
1584                         editorAbsoluteY = a.getDimensionPixelOffset(attr, editorAbsoluteY);
1585                         break;
1586                     case GUIDE_BEGIN:
1587                         guideBegin = a.getDimensionPixelOffset(attr, guideBegin);
1588                         break;
1589                     case GUIDE_END:
1590                         guideEnd = a.getDimensionPixelOffset(attr, guideEnd);
1591                         break;
1592                     case GUIDE_PERCENT:
1593                         guidePercent = a.getFloat(attr, guidePercent);
1594                         break;
1595                     case GUIDE_USE_RTL:
1596                         guidelineUseRtl = a.getBoolean(attr, guidelineUseRtl);
1597                         break;
1598 
1599                     case ORIENTATION:
1600                         orientation = a.getInt(attr, orientation);
1601                         break;
1602                     case START_TO_END:
1603                         startToEnd = lookupID(a, attr, startToEnd);
1604                         break;
1605                     case START_TO_START:
1606                         startToStart = lookupID(a, attr, startToStart);
1607                         break;
1608                     case END_TO_START:
1609                         endToStart = lookupID(a, attr, endToStart);
1610                         break;
1611                     case END_TO_END:
1612                         endToEnd = lookupID(a, attr, endToEnd);
1613                         break;
1614                     case CIRCLE:
1615                         circleConstraint = lookupID(a, attr, circleConstraint);
1616                         break;
1617                     case CIRCLE_RADIUS:
1618                         circleRadius = a.getDimensionPixelSize(attr, circleRadius);
1619                         break;
1620                     case CIRCLE_ANGLE:
1621                         circleAngle = a.getFloat(attr, circleAngle);
1622                         break;
1623                     case GONE_LEFT_MARGIN:
1624                         goneLeftMargin = a.getDimensionPixelSize(attr, goneLeftMargin);
1625                         break;
1626                     case GONE_TOP_MARGIN:
1627                         goneTopMargin = a.getDimensionPixelSize(attr, goneTopMargin);
1628                         break;
1629                     case GONE_RIGHT_MARGIN:
1630                         goneRightMargin = a.getDimensionPixelSize(attr, goneRightMargin);
1631                         break;
1632                     case GONE_BOTTOM_MARGIN:
1633                         goneBottomMargin = a.getDimensionPixelSize(attr, goneBottomMargin);
1634                         break;
1635                     case GONE_START_MARGIN:
1636                         goneStartMargin = a.getDimensionPixelSize(attr, goneStartMargin);
1637                         break;
1638                     case GONE_END_MARGIN:
1639                         goneEndMargin = a.getDimensionPixelSize(attr, goneEndMargin);
1640                         break;
1641                     case GONE_BASELINE_MARGIN:
1642                         goneBaselineMargin = a.getDimensionPixelSize(attr, goneBaselineMargin);
1643                         break;
1644                     case HORIZONTAL_BIAS:
1645                         horizontalBias = a.getFloat(attr, horizontalBias);
1646                         break;
1647                     case VERTICAL_BIAS:
1648                         verticalBias = a.getFloat(attr, verticalBias);
1649                         break;
1650                     case LEFT_MARGIN:
1651                         leftMargin = a.getDimensionPixelSize(attr, leftMargin);
1652                         break;
1653                     case RIGHT_MARGIN:
1654                         rightMargin = a.getDimensionPixelSize(attr, rightMargin);
1655                         break;
1656                     case START_MARGIN:
1657                         startMargin = a.getDimensionPixelSize(attr, startMargin);
1658                         break;
1659                     case END_MARGIN:
1660                         endMargin = a.getDimensionPixelSize(attr, endMargin);
1661                         break;
1662                     case TOP_MARGIN:
1663                         topMargin = a.getDimensionPixelSize(attr, topMargin);
1664                         break;
1665                     case BOTTOM_MARGIN:
1666                         bottomMargin = a.getDimensionPixelSize(attr, bottomMargin);
1667                         break;
1668                     case BASELINE_MARGIN:
1669                         baselineMargin = a.getDimensionPixelSize(attr, baselineMargin);
1670                         break;
1671                     case LAYOUT_WIDTH:
1672                         mWidth = a.getLayoutDimension(attr, mWidth);
1673                         break;
1674                     case LAYOUT_HEIGHT:
1675                         mHeight = a.getLayoutDimension(attr, mHeight);
1676                         break;
1677                     case LAYOUT_CONSTRAINT_WIDTH:
1678                         ConstraintSet.parseDimensionConstraints(this, a, attr, HORIZONTAL);
1679                         break;
1680                     case LAYOUT_CONSTRAINT_HEIGHT:
1681                         ConstraintSet.parseDimensionConstraints(this, a, attr, VERTICAL);
1682                         break;
1683                     case WIDTH_DEFAULT:
1684                         widthDefault = a.getInt(attr, widthDefault);
1685                         break;
1686                     case HEIGHT_DEFAULT:
1687                         heightDefault = a.getInt(attr, heightDefault);
1688                         break;
1689                     case VERTICAL_WEIGHT:
1690                         verticalWeight = a.getFloat(attr, verticalWeight);
1691                         break;
1692                     case HORIZONTAL_WEIGHT:
1693                         horizontalWeight = a.getFloat(attr, horizontalWeight);
1694                         break;
1695                     case VERTICAL_STYLE:
1696                         verticalChainStyle = a.getInt(attr, verticalChainStyle);
1697                         break;
1698                     case HORIZONTAL_STYLE:
1699                         horizontalChainStyle = a.getInt(attr, horizontalChainStyle);
1700                         break;
1701                     case DIMENSION_RATIO:
1702                         dimensionRatio = a.getString(attr);
1703                         break;
1704                     case HEIGHT_MAX:
1705                         heightMax = a.getDimensionPixelSize(attr, heightMax);
1706                         break;
1707                     case WIDTH_MAX:
1708                         widthMax = a.getDimensionPixelSize(attr, widthMax);
1709                         break;
1710                     case HEIGHT_MIN:
1711                         heightMin = a.getDimensionPixelSize(attr, heightMin);
1712                         break;
1713                     case WIDTH_MIN:
1714                         widthMin = a.getDimensionPixelSize(attr, widthMin);
1715                         break;
1716                     case WIDTH_PERCENT:
1717                         widthPercent = a.getFloat(attr, 1);
1718                         break;
1719                     case HEIGHT_PERCENT:
1720                         heightPercent = a.getFloat(attr, 1);
1721                         break;
1722                     case CONSTRAINED_WIDTH:
1723                         constrainedWidth = a.getBoolean(attr, constrainedWidth);
1724                         break;
1725                     case CONSTRAINED_HEIGHT:
1726                         constrainedHeight = a.getBoolean(attr, constrainedHeight);
1727                         break;
1728                     case CHAIN_USE_RTL:
1729                         Log.e(TAG, "CURRENTLY UNSUPPORTED"); // TODO add support or remove
1730                         //  TODO add support or remove  c.mChainUseRtl
1731                         //   = a.getBoolean(attr,c.mChainUseRtl);
1732                         break;
1733                     case BARRIER_DIRECTION:
1734                         mBarrierDirection = a.getInt(attr, mBarrierDirection);
1735                         break;
1736                     case LAYOUT_WRAP_BEHAVIOR:
1737                         mWrapBehavior = a.getInt(attr, mWrapBehavior);
1738                         break;
1739                     case BARRIER_MARGIN:
1740                         mBarrierMargin = a.getDimensionPixelSize(attr, mBarrierMargin);
1741                         break;
1742                     case CONSTRAINT_REFERENCED_IDS:
1743                         mReferenceIdString = a.getString(attr);
1744                         break;
1745                     case BARRIER_ALLOWS_GONE_WIDGETS:
1746                         mBarrierAllowsGoneWidgets = a.getBoolean(attr, mBarrierAllowsGoneWidgets);
1747                         break;
1748                     case CONSTRAINT_TAG:
1749                         mConstraintTag = a.getString(attr);
1750                         break;
1751                     case UNUSED:
1752                         Log.w(TAG,
1753                                 "unused attribute 0x" + Integer.toHexString(attr)
1754                                         + "   " + sMapToConstant.get(attr));
1755                         break;
1756                     default:
1757                         Log.w(TAG,
1758                                 "Unknown attribute 0x" + Integer.toHexString(attr)
1759                                         + "   " + sMapToConstant.get(attr));
1760 
1761                 }
1762             }
1763             a.recycle();
1764         }
1765 
1766         /**
1767          * Print the content to a string
1768          * @param scene
1769          * @param stringBuilder
1770          */
dump(MotionScene scene, StringBuilder stringBuilder)1771         public void dump(MotionScene scene, StringBuilder stringBuilder) {
1772             Field[] fields = this.getClass().getDeclaredFields();
1773             stringBuilder.append("\n");
1774             for (int i = 0; i < fields.length; i++) {
1775                 Field field = fields[i];
1776                 String name = field.getName();
1777                 if (Modifier.isStatic(field.getModifiers())) {
1778                     continue;
1779                 }
1780 
1781                 try {
1782                     Object value = field.get(this);
1783                     Class<?> type = field.getType();
1784                     if (type == Integer.TYPE) {
1785                         Integer iValue = (Integer) value;
1786                         if (iValue != UNSET) {
1787                             String stringId = scene.lookUpConstraintName(iValue);
1788                             stringBuilder.append("    ");
1789                             stringBuilder.append(name);
1790                             stringBuilder.append(" = \"");
1791                             stringBuilder.append((stringId == null) ? iValue : stringId);
1792                             stringBuilder.append("\"\n");
1793                         }
1794                     } else if (type == Float.TYPE) {
1795                         Float fValue = (Float) value;
1796                         if (fValue != UNSET) {
1797                             stringBuilder.append("    ");
1798                             stringBuilder.append(name);
1799                             stringBuilder.append(" = \"");
1800                             stringBuilder.append(fValue);
1801                             stringBuilder.append("\"\n");
1802                         }
1803                     }
1804                 } catch (IllegalAccessException e) {
1805                     Log.e(TAG, "Error accessing ConstraintSet field", e);
1806                 }
1807             }
1808         }
1809     }
1810 
1811     /**
1812      *
1813      */
1814     public static class Transform {
1815         public boolean mApply = false;
1816         public float rotation = 0;
1817         public float rotationX = 0;
1818         public float rotationY = 0;
1819         public float scaleX = 1;
1820         public float scaleY = 1;
1821         public float transformPivotX = Float.NaN;
1822         public float transformPivotY = Float.NaN;
1823         public int transformPivotTarget = UNSET;
1824         public float translationX = 0;
1825         public float translationY = 0;
1826         public float translationZ = 0;
1827         public boolean applyElevation = false;
1828         public float elevation = 0;
1829 
1830         /**
1831          * Copy Transform from src
1832          * @param src
1833          */
copyFrom(Transform src)1834         public void copyFrom(Transform src) {
1835             mApply = src.mApply;
1836             rotation = src.rotation;
1837             rotationX = src.rotationX;
1838             rotationY = src.rotationY;
1839             scaleX = src.scaleX;
1840             scaleY = src.scaleY;
1841             transformPivotX = src.transformPivotX;
1842             transformPivotY = src.transformPivotY;
1843             transformPivotTarget = src.transformPivotTarget;
1844             translationX = src.translationX;
1845             translationY = src.translationY;
1846             translationZ = src.translationZ;
1847             applyElevation = src.applyElevation;
1848             elevation = src.elevation;
1849         }
1850 
1851         private static SparseIntArray sMapToConstant = new SparseIntArray();
1852         private static final int ROTATION = 1;
1853         private static final int ROTATION_X = 2;
1854         private static final int ROTATION_Y = 3;
1855         private static final int SCALE_X = 4;
1856         private static final int SCALE_Y = 5;
1857         private static final int TRANSFORM_PIVOT_X = 6;
1858         private static final int TRANSFORM_PIVOT_Y = 7;
1859         private static final int TRANSLATION_X = 8;
1860         private static final int TRANSLATION_Y = 9;
1861         private static final int TRANSLATION_Z = 10;
1862         private static final int ELEVATION = 11;
1863         private static final int TRANSFORM_PIVOT_TARGET = 12;
1864 
1865 
1866         static {
sMapToConstant.append(R.styleable.Transform_android_rotation, ROTATION)1867             sMapToConstant.append(R.styleable.Transform_android_rotation, ROTATION);
sMapToConstant.append(R.styleable.Transform_android_rotationX, ROTATION_X)1868             sMapToConstant.append(R.styleable.Transform_android_rotationX, ROTATION_X);
sMapToConstant.append(R.styleable.Transform_android_rotationY, ROTATION_Y)1869             sMapToConstant.append(R.styleable.Transform_android_rotationY, ROTATION_Y);
sMapToConstant.append(R.styleable.Transform_android_scaleX, SCALE_X)1870             sMapToConstant.append(R.styleable.Transform_android_scaleX, SCALE_X);
sMapToConstant.append(R.styleable.Transform_android_scaleY, SCALE_Y)1871             sMapToConstant.append(R.styleable.Transform_android_scaleY, SCALE_Y);
sMapToConstant.append(R.styleable.Transform_android_transformPivotX, TRANSFORM_PIVOT_X)1872             sMapToConstant.append(R.styleable.Transform_android_transformPivotX, TRANSFORM_PIVOT_X);
sMapToConstant.append(R.styleable.Transform_android_transformPivotY, TRANSFORM_PIVOT_Y)1873             sMapToConstant.append(R.styleable.Transform_android_transformPivotY, TRANSFORM_PIVOT_Y);
sMapToConstant.append(R.styleable.Transform_android_translationX, TRANSLATION_X)1874             sMapToConstant.append(R.styleable.Transform_android_translationX, TRANSLATION_X);
sMapToConstant.append(R.styleable.Transform_android_translationY, TRANSLATION_Y)1875             sMapToConstant.append(R.styleable.Transform_android_translationY, TRANSLATION_Y);
sMapToConstant.append(R.styleable.Transform_android_translationZ, TRANSLATION_Z)1876             sMapToConstant.append(R.styleable.Transform_android_translationZ, TRANSLATION_Z);
sMapToConstant.append(R.styleable.Transform_android_elevation, ELEVATION)1877             sMapToConstant.append(R.styleable.Transform_android_elevation, ELEVATION);
sMapToConstant.append(R.styleable.Transform_transformPivotTarget, TRANSFORM_PIVOT_TARGET)1878             sMapToConstant.append(R.styleable.Transform_transformPivotTarget,
1879                     TRANSFORM_PIVOT_TARGET);
1880 
1881         }
1882 
fillFromAttributeList(Context context, AttributeSet attrs)1883         void fillFromAttributeList(Context context, AttributeSet attrs) {
1884             TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Transform);
1885             mApply = true;
1886             final int count = a.getIndexCount();
1887             for (int i = 0; i < count; i++) {
1888                 int attr = a.getIndex(i);
1889 
1890                 switch (sMapToConstant.get(attr)) {
1891                     case ROTATION:
1892                         rotation = a.getFloat(attr, rotation);
1893                         break;
1894                     case ROTATION_X:
1895                         rotationX = a.getFloat(attr, rotationX);
1896                         break;
1897                     case ROTATION_Y:
1898                         rotationY = a.getFloat(attr, rotationY);
1899                         break;
1900                     case SCALE_X:
1901                         scaleX = a.getFloat(attr, scaleX);
1902                         break;
1903                     case SCALE_Y:
1904                         scaleY = a.getFloat(attr, scaleY);
1905                         break;
1906                     case TRANSFORM_PIVOT_X:
1907                         transformPivotX = a.getDimension(attr, transformPivotX);
1908                         break;
1909                     case TRANSFORM_PIVOT_Y:
1910                         transformPivotY = a.getDimension(attr, transformPivotY);
1911                         break;
1912                     case TRANSFORM_PIVOT_TARGET:
1913                         transformPivotTarget = lookupID(a, attr, transformPivotTarget);
1914                         break;
1915                     case TRANSLATION_X:
1916                         translationX = a.getDimension(attr, translationX);
1917                         break;
1918                     case TRANSLATION_Y:
1919                         translationY = a.getDimension(attr, translationY);
1920                         break;
1921                     case TRANSLATION_Z:
1922                         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
1923                             translationZ = a.getDimension(attr, translationZ);
1924                         }
1925                         break;
1926                     case ELEVATION:
1927                         if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
1928                             applyElevation = true;
1929                             elevation = a.getDimension(attr, elevation);
1930                         }
1931                         break;
1932                 }
1933             }
1934             a.recycle();
1935         }
1936     }
1937 
1938     /**
1939      *
1940      */
1941     public static class PropertySet {
1942         public boolean mApply = false;
1943         public int visibility = View.VISIBLE;
1944         public int mVisibilityMode = VISIBILITY_MODE_NORMAL;
1945         public float alpha = 1;
1946         public float mProgress = Float.NaN;
1947 
1948         // @TODO: add description
1949 
1950         /**
1951          *
1952          * @param src
1953          */
copyFrom(PropertySet src)1954         public void copyFrom(PropertySet src) {
1955             mApply = src.mApply;
1956             visibility = src.visibility;
1957             alpha = src.alpha;
1958             mProgress = src.mProgress;
1959             mVisibilityMode = src.mVisibilityMode;
1960         }
1961 
fillFromAttributeList(Context context, AttributeSet attrs)1962         void fillFromAttributeList(Context context, AttributeSet attrs) {
1963             TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PropertySet);
1964             mApply = true;
1965             final int count = a.getIndexCount();
1966             for (int i = 0; i < count; i++) {
1967                 int attr = a.getIndex(i);
1968 
1969                 if (attr == R.styleable.PropertySet_android_alpha) {
1970                     alpha = a.getFloat(attr, alpha);
1971                 } else if (attr == R.styleable.PropertySet_android_visibility) {
1972                     visibility = a.getInt(attr, visibility);
1973                     visibility = VISIBILITY_FLAGS[visibility];
1974                 } else if (attr == R.styleable.PropertySet_visibilityMode) {
1975                     mVisibilityMode = a.getInt(attr, mVisibilityMode);
1976                 } else if (attr == R.styleable.PropertySet_motionProgress) {
1977                     mProgress = a.getFloat(attr, mProgress);
1978                 }
1979             }
1980             a.recycle();
1981         }
1982     }
1983 
1984     /**
1985      *
1986      */
1987     public static class Motion {
1988         public boolean mApply = false;
1989         public int mAnimateRelativeTo = Layout.UNSET;
1990         public int mAnimateCircleAngleTo = 0;
1991         public String mTransitionEasing = null;
1992         public int mPathMotionArc = Layout.UNSET;
1993         public int mDrawPath = 0;
1994         public float mMotionStagger = Float.NaN;
1995         public int mPolarRelativeTo = Layout.UNSET;
1996         public float mPathRotate = Float.NaN;
1997         public float mQuantizeMotionPhase = Float.NaN;
1998         public int mQuantizeMotionSteps = Layout.UNSET;
1999         public String mQuantizeInterpolatorString = null;
2000         public int mQuantizeInterpolatorType = INTERPOLATOR_UNDEFINED; // undefined
2001         public int mQuantizeInterpolatorID = -1;
2002         private static final int INTERPOLATOR_REFERENCE_ID = -2;
2003         private static final int SPLINE_STRING = -1;
2004         private static final int INTERPOLATOR_UNDEFINED = -3;
2005 
2006         // @TODO: add description
2007 
2008         /**
2009          *
2010          * @param src
2011          */
copyFrom(Motion src)2012         public void copyFrom(Motion src) {
2013             mApply = src.mApply;
2014             mAnimateRelativeTo = src.mAnimateRelativeTo;
2015             mTransitionEasing = src.mTransitionEasing;
2016             mPathMotionArc = src.mPathMotionArc;
2017             mDrawPath = src.mDrawPath;
2018             mPathRotate = src.mPathRotate;
2019             mMotionStagger = src.mMotionStagger;
2020             mPolarRelativeTo = src.mPolarRelativeTo;
2021         }
2022 
2023         private static SparseIntArray sMapToConstant = new SparseIntArray();
2024         private static final int TRANSITION_PATH_ROTATE = 1;
2025         private static final int PATH_MOTION_ARC = 2;
2026         private static final int TRANSITION_EASING = 3;
2027         private static final int MOTION_DRAW_PATH = 4;
2028         private static final int ANIMATE_RELATIVE_TO = 5;
2029         private static final int ANIMATE_CIRCLE_ANGLE_TO = 6;
2030         private static final int MOTION_STAGGER = 7;
2031         private static final int QUANTIZE_MOTION_STEPS = 8;
2032         private static final int QUANTIZE_MOTION_PHASE = 9;
2033         private static final int QUANTIZE_MOTION_INTERPOLATOR = 10;
2034 
2035 
2036         static {
sMapToConstant.append(R.styleable.Motion_motionPathRotate, TRANSITION_PATH_ROTATE)2037             sMapToConstant.append(R.styleable.Motion_motionPathRotate, TRANSITION_PATH_ROTATE);
sMapToConstant.append(R.styleable.Motion_pathMotionArc, PATH_MOTION_ARC)2038             sMapToConstant.append(R.styleable.Motion_pathMotionArc, PATH_MOTION_ARC);
sMapToConstant.append(R.styleable.Motion_transitionEasing, TRANSITION_EASING)2039             sMapToConstant.append(R.styleable.Motion_transitionEasing, TRANSITION_EASING);
sMapToConstant.append(R.styleable.Motion_drawPath, MOTION_DRAW_PATH)2040             sMapToConstant.append(R.styleable.Motion_drawPath, MOTION_DRAW_PATH);
sMapToConstant.append(R.styleable.Motion_animateRelativeTo, ANIMATE_RELATIVE_TO)2041             sMapToConstant.append(R.styleable.Motion_animateRelativeTo, ANIMATE_RELATIVE_TO);
sMapToConstant.append(R.styleable.Motion_animateCircleAngleTo, ANIMATE_CIRCLE_ANGLE_TO)2042             sMapToConstant.append(R.styleable.Motion_animateCircleAngleTo, ANIMATE_CIRCLE_ANGLE_TO);
sMapToConstant.append(R.styleable.Motion_motionStagger, MOTION_STAGGER)2043             sMapToConstant.append(R.styleable.Motion_motionStagger, MOTION_STAGGER);
sMapToConstant.append(R.styleable.Motion_quantizeMotionSteps, QUANTIZE_MOTION_STEPS)2044             sMapToConstant.append(R.styleable.Motion_quantizeMotionSteps, QUANTIZE_MOTION_STEPS);
sMapToConstant.append(R.styleable.Motion_quantizeMotionPhase, QUANTIZE_MOTION_PHASE)2045             sMapToConstant.append(R.styleable.Motion_quantizeMotionPhase, QUANTIZE_MOTION_PHASE);
sMapToConstant.append(R.styleable.Motion_quantizeMotionInterpolator, QUANTIZE_MOTION_INTERPOLATOR)2046             sMapToConstant.append(R.styleable.Motion_quantizeMotionInterpolator,
2047                     QUANTIZE_MOTION_INTERPOLATOR);
2048         }
2049 
fillFromAttributeList(Context context, AttributeSet attrs)2050         void fillFromAttributeList(Context context, AttributeSet attrs) {
2051             TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Motion);
2052             mApply = true;
2053             final int count = a.getIndexCount();
2054             for (int i = 0; i < count; i++) {
2055                 int attr = a.getIndex(i);
2056 
2057                 switch (sMapToConstant.get(attr)) {
2058                     case TRANSITION_PATH_ROTATE:
2059                         mPathRotate = a.getFloat(attr, mPathRotate);
2060                         break;
2061                     case PATH_MOTION_ARC:
2062                         mPathMotionArc = a.getInt(attr, mPathMotionArc);
2063                         break;
2064                     case TRANSITION_EASING:
2065                         TypedValue type = a.peekValue(attr);
2066                         if (type.type == TypedValue.TYPE_STRING) {
2067                             mTransitionEasing = a.getString(attr);
2068                         } else {
2069                             mTransitionEasing = Easing.NAMED_EASING[a.getInteger(attr, 0)];
2070                         }
2071                         break;
2072                     case MOTION_DRAW_PATH:
2073                         mDrawPath = a.getInt(attr, 0);
2074                         break;
2075                     case ANIMATE_RELATIVE_TO:
2076                         mAnimateRelativeTo = lookupID(a, attr, mAnimateRelativeTo);
2077                         break;
2078                     case ANIMATE_CIRCLE_ANGLE_TO:
2079                         mAnimateCircleAngleTo = a.getInteger(attr, mAnimateCircleAngleTo);
2080                         break;
2081                     case MOTION_STAGGER:
2082                         mMotionStagger = a.getFloat(attr, mMotionStagger);
2083                         break;
2084                     case QUANTIZE_MOTION_STEPS:
2085                         mQuantizeMotionSteps = a.getInteger(attr, mQuantizeMotionSteps);
2086                         break;
2087                     case QUANTIZE_MOTION_PHASE:
2088                         mQuantizeMotionPhase = a.getFloat(attr, mQuantizeMotionPhase);
2089                         break;
2090                     case QUANTIZE_MOTION_INTERPOLATOR:
2091                         type = a.peekValue(attr);
2092 
2093                         if (type.type == TypedValue.TYPE_REFERENCE) {
2094                             mQuantizeInterpolatorID = a.getResourceId(attr, -1);
2095                             if (mQuantizeInterpolatorID != -1) {
2096                                 mQuantizeInterpolatorType = INTERPOLATOR_REFERENCE_ID;
2097                             }
2098                         } else if (type.type == TypedValue.TYPE_STRING) {
2099                             mQuantizeInterpolatorString = a.getString(attr);
2100                             if (mQuantizeInterpolatorString.indexOf("/") > 0) {
2101                                 mQuantizeInterpolatorID = a.getResourceId(attr, -1);
2102                                 mQuantizeInterpolatorType = INTERPOLATOR_REFERENCE_ID;
2103                             } else {
2104                                 mQuantizeInterpolatorType = SPLINE_STRING;
2105                             }
2106                         } else {
2107                             mQuantizeInterpolatorType = a.getInteger(attr, mQuantizeInterpolatorID);
2108                         }
2109 
2110                         break;
2111                 }
2112             }
2113             a.recycle();
2114         }
2115     }
2116 
2117     /**
2118      *
2119      */
2120     public static class Constraint {
2121         int mViewId;
2122         String mTargetString;
2123         public final PropertySet propertySet = new PropertySet();
2124         public final Motion motion = new Motion();
2125         public final Layout layout = new Layout();
2126         public final Transform transform = new Transform();
2127         public HashMap<String, ConstraintAttribute> mCustomConstraints = new HashMap<>();
2128         Delta mDelta;
2129 
2130         static class Delta {
2131             private static final int INITIAL_BOOLEAN = 4;
2132             private static final int INITIAL_INT = 10;
2133             private static final int INITIAL_FLOAT = 10;
2134             private static final int INITIAL_STRING = 5;
2135             int[] mTypeInt = new int[INITIAL_INT];
2136             int[] mValueInt = new int[INITIAL_INT];
2137             int mCountInt = 0;
2138 
add(int type, int value)2139             void add(int type, int value) {
2140                 if (mCountInt >= mTypeInt.length) {
2141                     mTypeInt = Arrays.copyOf(mTypeInt, mTypeInt.length * 2);
2142                     mValueInt = Arrays.copyOf(mValueInt, mValueInt.length * 2);
2143                 }
2144                 mTypeInt[mCountInt] = type;
2145                 mValueInt[mCountInt++] = value;
2146             }
2147 
2148             int[] mTypeFloat = new int[INITIAL_FLOAT];
2149             float[] mValueFloat = new float[INITIAL_FLOAT];
2150             int mCountFloat = 0;
2151 
add(int type, float value)2152             void add(int type, float value) {
2153                 if (mCountFloat >= mTypeFloat.length) {
2154                     mTypeFloat = Arrays.copyOf(mTypeFloat, mTypeFloat.length * 2);
2155                     mValueFloat = Arrays.copyOf(mValueFloat, mValueFloat.length * 2);
2156                 }
2157                 mTypeFloat[mCountFloat] = type;
2158                 mValueFloat[mCountFloat++] = value;
2159             }
2160 
2161             int[] mTypeString = new int[INITIAL_STRING];
2162             String[] mValueString = new String[INITIAL_STRING];
2163             int mCountString = 0;
2164 
add(int type, String value)2165             void add(int type, String value) {
2166                 if (mCountString >= mTypeString.length) {
2167                     mTypeString = Arrays.copyOf(mTypeString, mTypeString.length * 2);
2168                     mValueString = Arrays.copyOf(mValueString, mValueString.length * 2);
2169                 }
2170                 mTypeString[mCountString] = type;
2171                 mValueString[mCountString++] = value;
2172             }
2173 
2174             int[] mTypeBoolean = new int[INITIAL_BOOLEAN];
2175             boolean[] mValueBoolean = new boolean[INITIAL_BOOLEAN];
2176             int mCountBoolean = 0;
2177 
add(int type, boolean value)2178             void add(int type, boolean value) {
2179                 if (mCountBoolean >= mTypeBoolean.length) {
2180                     mTypeBoolean = Arrays.copyOf(mTypeBoolean, mTypeBoolean.length * 2);
2181                     mValueBoolean = Arrays.copyOf(mValueBoolean, mValueBoolean.length * 2);
2182                 }
2183                 mTypeBoolean[mCountBoolean] = type;
2184                 mValueBoolean[mCountBoolean++] = value;
2185             }
2186 
applyDelta(Constraint c)2187             void applyDelta(Constraint c) {
2188                 for (int i = 0; i < mCountInt; i++) {
2189                     setDeltaValue(c, mTypeInt[i], mValueInt[i]);
2190                 }
2191                 for (int i = 0; i < mCountFloat; i++) {
2192                     setDeltaValue(c, mTypeFloat[i], mValueFloat[i]);
2193                 }
2194                 for (int i = 0; i < mCountString; i++) {
2195                     setDeltaValue(c, mTypeString[i], mValueString[i]);
2196                 }
2197                 for (int i = 0; i < mCountBoolean; i++) {
2198                     setDeltaValue(c, mTypeBoolean[i], mValueBoolean[i]);
2199                 }
2200             }
2201 
2202             @SuppressLint("LogConditional")
printDelta(String tag)2203             void printDelta(String tag) {
2204                 Log.v(tag, "int");
2205 
2206                 for (int i = 0; i < mCountInt; i++) {
2207                     Log.v(tag, mTypeInt[i] + " = " + mValueInt[i]);
2208                 }
2209                 Log.v(tag, "float");
2210 
2211                 for (int i = 0; i < mCountFloat; i++) {
2212                     Log.v(tag, mTypeFloat[i] + " = " + mValueFloat[i]);
2213                 }
2214                 Log.v(tag, "strings");
2215 
2216                 for (int i = 0; i < mCountString; i++) {
2217                     Log.v(tag, mTypeString[i] + " = " + mValueString[i]);
2218                 }
2219                 Log.v(tag, "boolean");
2220                 for (int i = 0; i < mCountBoolean; i++) {
2221                     Log.v(tag, mTypeBoolean[i] + " = " + mValueBoolean[i]);
2222                 }
2223             }
2224         }
2225 
2226         /**
2227          * Apply a delta to a constraint
2228          * @param c
2229          */
applyDelta(Constraint c)2230         public void applyDelta(Constraint c) {
2231             if (mDelta != null) {
2232                 mDelta.applyDelta(c);
2233             }
2234         }
2235 
2236         /**
2237          * Apply a delta file
2238          * @param tag
2239          */
printDelta(String tag)2240         public void printDelta(String tag) {
2241             if (mDelta != null) {
2242                 mDelta.printDelta(tag);
2243             } else {
2244                 Log.v(tag, "DELTA IS NULL");
2245             }
2246         }
2247 
get(String attributeName, AttributeType attributeType)2248         private ConstraintAttribute get(String attributeName, AttributeType attributeType) {
2249             ConstraintAttribute ret;
2250             if (mCustomConstraints.containsKey(attributeName)) {
2251                 ret = mCustomConstraints.get(attributeName);
2252                 if (ret.getType() != attributeType) {
2253                     throw new IllegalArgumentException(
2254                             "ConstraintAttribute is already a " + ret.getType().name());
2255                 }
2256             } else {
2257                 ret = new ConstraintAttribute(attributeName, attributeType);
2258                 mCustomConstraints.put(attributeName, ret);
2259             }
2260             return ret;
2261         }
2262 
setStringValue(String attributeName, String value)2263         private void setStringValue(String attributeName, String value) {
2264             get(attributeName, AttributeType.STRING_TYPE).setStringValue(value);
2265         }
2266 
setFloatValue(String attributeName, float value)2267         private void setFloatValue(String attributeName, float value) {
2268             get(attributeName, AttributeType.FLOAT_TYPE).setFloatValue(value);
2269         }
2270 
setIntValue(String attributeName, int value)2271         private void setIntValue(String attributeName, int value) {
2272             get(attributeName, AttributeType.INT_TYPE).setIntValue(value);
2273         }
2274 
setColorValue(String attributeName, int value)2275         private void setColorValue(String attributeName, int value) {
2276             get(attributeName, AttributeType.COLOR_TYPE).setColorValue(value);
2277         }
2278 
2279         /**
2280          * Return a copy of the Constraint
2281          * @return
2282          */
2283         @Override
clone()2284         public Constraint clone() {
2285             Constraint clone = new Constraint();
2286             clone.layout.copyFrom(layout);
2287             clone.motion.copyFrom(motion);
2288             clone.propertySet.copyFrom(propertySet);
2289             clone.transform.copyFrom(transform);
2290             clone.mViewId = mViewId;
2291             clone.mDelta = mDelta;
2292             return clone;
2293         }
2294 
fillFromConstraints(ConstraintHelper helper, int viewId, Constraints.LayoutParams param)2295         private void fillFromConstraints(ConstraintHelper helper,
2296                                          int viewId,
2297                                          Constraints.LayoutParams param) {
2298             fillFromConstraints(viewId, param);
2299             if (helper instanceof Barrier) {
2300                 layout.mHelperType = BARRIER_TYPE;
2301                 Barrier barrier = (Barrier) helper;
2302                 layout.mBarrierDirection = barrier.getType();
2303                 layout.mReferenceIds = barrier.getReferencedIds();
2304                 layout.mBarrierMargin = barrier.getMargin();
2305             }
2306         }
2307 
fillFromConstraints(int viewId, Constraints.LayoutParams param)2308         private void fillFromConstraints(int viewId, Constraints.LayoutParams param) {
2309             fillFrom(viewId, param);
2310             propertySet.alpha = param.alpha;
2311             transform.rotation = param.rotation;
2312             transform.rotationX = param.rotationX;
2313             transform.rotationY = param.rotationY;
2314             transform.scaleX = param.scaleX;
2315             transform.scaleY = param.scaleY;
2316             transform.transformPivotX = param.transformPivotX;
2317             transform.transformPivotY = param.transformPivotY;
2318             transform.translationX = param.translationX;
2319             transform.translationY = param.translationY;
2320             transform.translationZ = param.translationZ;
2321             transform.elevation = param.elevation;
2322             transform.applyElevation = param.applyElevation;
2323         }
2324 
fillFrom(int viewId, ConstraintLayout.LayoutParams param)2325         private void fillFrom(int viewId, ConstraintLayout.LayoutParams param) {
2326             mViewId = viewId;
2327             layout.leftToLeft = param.leftToLeft;
2328             layout.leftToRight = param.leftToRight;
2329             layout.rightToLeft = param.rightToLeft;
2330             layout.rightToRight = param.rightToRight;
2331             layout.topToTop = param.topToTop;
2332             layout.topToBottom = param.topToBottom;
2333             layout.bottomToTop = param.bottomToTop;
2334             layout.bottomToBottom = param.bottomToBottom;
2335             layout.baselineToBaseline = param.baselineToBaseline;
2336             layout.baselineToTop = param.baselineToTop;
2337             layout.baselineToBottom = param.baselineToBottom;
2338             layout.startToEnd = param.startToEnd;
2339             layout.startToStart = param.startToStart;
2340             layout.endToStart = param.endToStart;
2341             layout.endToEnd = param.endToEnd;
2342 
2343             layout.horizontalBias = param.horizontalBias;
2344             layout.verticalBias = param.verticalBias;
2345             layout.dimensionRatio = param.dimensionRatio;
2346 
2347             layout.circleConstraint = param.circleConstraint;
2348             layout.circleRadius = param.circleRadius;
2349             layout.circleAngle = param.circleAngle;
2350 
2351             layout.editorAbsoluteX = param.editorAbsoluteX;
2352             layout.editorAbsoluteY = param.editorAbsoluteY;
2353             layout.orientation = param.orientation;
2354             layout.guidePercent = param.guidePercent;
2355             layout.guideBegin = param.guideBegin;
2356             layout.guideEnd = param.guideEnd;
2357             layout.mWidth = param.width;
2358             layout.mHeight = param.height;
2359             layout.leftMargin = param.leftMargin;
2360             layout.rightMargin = param.rightMargin;
2361             layout.topMargin = param.topMargin;
2362             layout.bottomMargin = param.bottomMargin;
2363             layout.baselineMargin = param.baselineMargin;
2364             layout.verticalWeight = param.verticalWeight;
2365             layout.horizontalWeight = param.horizontalWeight;
2366             layout.verticalChainStyle = param.verticalChainStyle;
2367             layout.horizontalChainStyle = param.horizontalChainStyle;
2368             layout.constrainedWidth = param.constrainedWidth;
2369             layout.constrainedHeight = param.constrainedHeight;
2370             layout.widthDefault = param.matchConstraintDefaultWidth;
2371             layout.heightDefault = param.matchConstraintDefaultHeight;
2372             layout.widthMax = param.matchConstraintMaxWidth;
2373             layout.heightMax = param.matchConstraintMaxHeight;
2374             layout.widthMin = param.matchConstraintMinWidth;
2375             layout.heightMin = param.matchConstraintMinHeight;
2376             layout.widthPercent = param.matchConstraintPercentWidth;
2377             layout.heightPercent = param.matchConstraintPercentHeight;
2378             layout.mConstraintTag = param.constraintTag;
2379             layout.goneTopMargin = param.goneTopMargin;
2380             layout.goneBottomMargin = param.goneBottomMargin;
2381             layout.goneLeftMargin = param.goneLeftMargin;
2382             layout.goneRightMargin = param.goneRightMargin;
2383             layout.goneStartMargin = param.goneStartMargin;
2384             layout.goneEndMargin = param.goneEndMargin;
2385             layout.goneBaselineMargin = param.goneBaselineMargin;
2386             layout.mWrapBehavior = param.wrapBehaviorInParent;
2387             layout.endMargin = param.getMarginEnd();
2388             layout.startMargin = param.getMarginStart();
2389         }
2390 
2391         /**
2392          * apply ConstraintSet to the layout params
2393          * @param param
2394          */
applyTo(ConstraintLayout.LayoutParams param)2395         public void applyTo(ConstraintLayout.LayoutParams param) {
2396             param.leftToLeft = layout.leftToLeft;
2397             param.leftToRight = layout.leftToRight;
2398             param.rightToLeft = layout.rightToLeft;
2399             param.rightToRight = layout.rightToRight;
2400 
2401             param.topToTop = layout.topToTop;
2402             param.topToBottom = layout.topToBottom;
2403             param.bottomToTop = layout.bottomToTop;
2404             param.bottomToBottom = layout.bottomToBottom;
2405 
2406             param.baselineToBaseline = layout.baselineToBaseline;
2407             param.baselineToTop = layout.baselineToTop;
2408             param.baselineToBottom = layout.baselineToBottom;
2409 
2410             param.startToEnd = layout.startToEnd;
2411             param.startToStart = layout.startToStart;
2412             param.endToStart = layout.endToStart;
2413             param.endToEnd = layout.endToEnd;
2414 
2415             param.leftMargin = layout.leftMargin;
2416             param.rightMargin = layout.rightMargin;
2417             param.topMargin = layout.topMargin;
2418             param.bottomMargin = layout.bottomMargin;
2419             param.goneStartMargin = layout.goneStartMargin;
2420             param.goneEndMargin = layout.goneEndMargin;
2421             param.goneTopMargin = layout.goneTopMargin;
2422             param.goneBottomMargin = layout.goneBottomMargin;
2423 
2424             param.horizontalBias = layout.horizontalBias;
2425             param.verticalBias = layout.verticalBias;
2426 
2427             param.circleConstraint = layout.circleConstraint;
2428             param.circleRadius = layout.circleRadius;
2429             param.circleAngle = layout.circleAngle;
2430 
2431             param.dimensionRatio = layout.dimensionRatio;
2432             param.editorAbsoluteX = layout.editorAbsoluteX;
2433             param.editorAbsoluteY = layout.editorAbsoluteY;
2434             param.verticalWeight = layout.verticalWeight;
2435             param.horizontalWeight = layout.horizontalWeight;
2436             param.verticalChainStyle = layout.verticalChainStyle;
2437             param.horizontalChainStyle = layout.horizontalChainStyle;
2438             param.constrainedWidth = layout.constrainedWidth;
2439             param.constrainedHeight = layout.constrainedHeight;
2440             param.matchConstraintDefaultWidth = layout.widthDefault;
2441             param.matchConstraintDefaultHeight = layout.heightDefault;
2442             param.matchConstraintMaxWidth = layout.widthMax;
2443             param.matchConstraintMaxHeight = layout.heightMax;
2444             param.matchConstraintMinWidth = layout.widthMin;
2445             param.matchConstraintMinHeight = layout.heightMin;
2446             param.matchConstraintPercentWidth = layout.widthPercent;
2447             param.matchConstraintPercentHeight = layout.heightPercent;
2448             param.orientation = layout.orientation;
2449             param.guidePercent = layout.guidePercent;
2450             param.guideBegin = layout.guideBegin;
2451             param.guideEnd = layout.guideEnd;
2452             param.width = layout.mWidth;
2453             param.height = layout.mHeight;
2454             if (layout.mConstraintTag != null) {
2455                 param.constraintTag = layout.mConstraintTag;
2456             }
2457             param.wrapBehaviorInParent = layout.mWrapBehavior;
2458 
2459             param.setMarginStart(layout.startMargin);
2460             param.setMarginEnd(layout.endMargin);
2461 
2462             param.validate();
2463         }
2464 
2465     }
2466 
2467     /**
2468      * Copy the constraints from a layout.
2469      *
2470      * @param context            the context for the layout inflation
2471      * @param constraintLayoutId the id of the layout file
2472      */
clone(Context context, int constraintLayoutId)2473     public void clone(Context context, int constraintLayoutId) {
2474         clone((ConstraintLayout) LayoutInflater.from(context).inflate(constraintLayoutId, null));
2475     }
2476 
2477     /**
2478      * Copy the constraints from a layout.
2479      *
2480      * @param set constraint set to copy
2481      */
clone(ConstraintSet set)2482     public void clone(ConstraintSet set) {
2483         mConstraints.clear();
2484         for (Integer key : set.mConstraints.keySet()) {
2485             Constraint constraint = set.mConstraints.get(key);
2486             if (constraint == null) {
2487                 continue;
2488             }
2489             mConstraints.put(key, constraint.clone());
2490         }
2491     }
2492 
2493     /**
2494      * Copy the layout parameters of a ConstraintLayout.
2495      *
2496      * @param constraintLayout The ConstraintLayout to be copied
2497      */
clone(ConstraintLayout constraintLayout)2498     public void clone(ConstraintLayout constraintLayout) {
2499         int count = constraintLayout.getChildCount();
2500         mConstraints.clear();
2501         for (int i = 0; i < count; i++) {
2502             View view = constraintLayout.getChildAt(i);
2503             ConstraintLayout.LayoutParams param =
2504                     (ConstraintLayout.LayoutParams) view.getLayoutParams();
2505 
2506             int id = view.getId();
2507             if (mForceId && id == -1) {
2508                 throw new RuntimeException("All children of ConstraintLayout must "
2509                         + "have ids to use ConstraintSet");
2510             }
2511             if (!mConstraints.containsKey(id)) {
2512                 mConstraints.put(id, new Constraint());
2513             }
2514             Constraint constraint = mConstraints.get(id);
2515             if (constraint == null) {
2516                 continue;
2517             }
2518             constraint.mCustomConstraints =
2519                     ConstraintAttribute.extractAttributes(mSavedAttributes, view);
2520             constraint.fillFrom(id, param);
2521             constraint.propertySet.visibility = view.getVisibility();
2522             constraint.propertySet.alpha = view.getAlpha();
2523             constraint.transform.rotation = view.getRotation();
2524             constraint.transform.rotationX = view.getRotationX();
2525             constraint.transform.rotationY = view.getRotationY();
2526             constraint.transform.scaleX = view.getScaleX();
2527             constraint.transform.scaleY = view.getScaleY();
2528 
2529             float pivotX = view.getPivotX(); // we assume it is not set if set to 0.0
2530             float pivotY = view.getPivotY(); // we assume it is not set if set to 0.0
2531 
2532             if (pivotX != 0.0 || pivotY != 0.0) {
2533                 constraint.transform.transformPivotX = pivotX;
2534                 constraint.transform.transformPivotY = pivotY;
2535             }
2536 
2537             constraint.transform.translationX = view.getTranslationX();
2538             constraint.transform.translationY = view.getTranslationY();
2539             if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
2540                 constraint.transform.translationZ = view.getTranslationZ();
2541                 if (constraint.transform.applyElevation) {
2542                     constraint.transform.elevation = view.getElevation();
2543                 }
2544             }
2545             if (view instanceof Barrier) {
2546                 Barrier barrier = ((Barrier) view);
2547                 constraint.layout.mBarrierAllowsGoneWidgets = barrier.getAllowsGoneWidget();
2548                 constraint.layout.mReferenceIds = barrier.getReferencedIds();
2549                 constraint.layout.mBarrierDirection = barrier.getType();
2550                 constraint.layout.mBarrierMargin = barrier.getMargin();
2551             }
2552         }
2553     }
2554 
2555     /**
2556      * Copy the layout parameters of a ConstraintLayout.
2557      *
2558      * @param constraints The ConstraintLayout to be copied
2559      */
clone(Constraints constraints)2560     public void clone(Constraints constraints) {
2561         int count = constraints.getChildCount();
2562         mConstraints.clear();
2563         for (int i = 0; i < count; i++) {
2564             View view = constraints.getChildAt(i);
2565             Constraints.LayoutParams param = (Constraints.LayoutParams) view.getLayoutParams();
2566 
2567             int id = view.getId();
2568             if (mForceId && id == -1) {
2569                 throw new RuntimeException("All children of ConstraintLayout "
2570                         + "must have ids to use ConstraintSet");
2571             }
2572             if (!mConstraints.containsKey(id)) {
2573                 mConstraints.put(id, new Constraint());
2574             }
2575             Constraint constraint = mConstraints.get(id);
2576             if (constraint == null) {
2577                 continue;
2578             }
2579             if (view instanceof ConstraintHelper) {
2580                 ConstraintHelper helper = (ConstraintHelper) view;
2581                 constraint.fillFromConstraints(helper, id, param);
2582             }
2583             constraint.fillFromConstraints(id, param);
2584         }
2585     }
2586 
2587     /**
2588      * Apply the constraints to a ConstraintLayout.
2589      *
2590      * @param constraintLayout to be modified
2591      */
applyTo(ConstraintLayout constraintLayout)2592     public void applyTo(ConstraintLayout constraintLayout) {
2593         applyToInternal(constraintLayout, true);
2594         constraintLayout.setConstraintSet(null);
2595         constraintLayout.requestLayout();
2596     }
2597 
2598 
2599     /**
2600      * Apply the constraints to a ConstraintLayout.
2601      *
2602      * @param constraintLayout to be modified
2603      */
applyToWithoutCustom(ConstraintLayout constraintLayout)2604     public void applyToWithoutCustom(ConstraintLayout constraintLayout) {
2605         applyToInternal(constraintLayout, false);
2606         constraintLayout.setConstraintSet(null);
2607     }
2608 
2609     /**
2610      * Apply custom attributes alone
2611      *
2612      * @param constraintLayout
2613      */
applyCustomAttributes(ConstraintLayout constraintLayout)2614     public void applyCustomAttributes(ConstraintLayout constraintLayout) {
2615         int count = constraintLayout.getChildCount();
2616         for (int i = 0; i < count; i++) {
2617             View view = constraintLayout.getChildAt(i);
2618             int id = view.getId();
2619             if (!mConstraints.containsKey(id)) {
2620                 Log.w(TAG, "id unknown " + Debug.getName(view));
2621                 continue;
2622             }
2623             if (mForceId && id == -1) {
2624                 throw new RuntimeException("All children of ConstraintLayout "
2625                         + "must have ids to use ConstraintSet");
2626             }
2627 
2628             if (mConstraints.containsKey(id)) {
2629                 Constraint constraint = mConstraints.get(id);
2630                 if (constraint == null) {
2631                     continue;
2632                 }
2633                 ConstraintAttribute.setAttributes(view, constraint.mCustomConstraints);
2634             }
2635         }
2636     }
2637 
2638     /**
2639      * Apply Layout to Helper widget
2640      *
2641      * @param helper
2642      * @param child
2643      * @param layoutParams
2644      * @param mapIdToWidget
2645      */
applyToHelper(ConstraintHelper helper, ConstraintWidget child, LayoutParams layoutParams, SparseArray<ConstraintWidget> mapIdToWidget)2646     public void applyToHelper(ConstraintHelper helper, ConstraintWidget child,
2647                               LayoutParams layoutParams,
2648                               SparseArray<ConstraintWidget> mapIdToWidget) {
2649         int id = helper.getId();
2650         if (mConstraints.containsKey(id)) {
2651             Constraint constraint = mConstraints.get(id);
2652             if (constraint != null && child instanceof HelperWidget) {
2653                 HelperWidget helperWidget = (HelperWidget) child;
2654                 helper.loadParameters(constraint, helperWidget, layoutParams, mapIdToWidget);
2655             }
2656         }
2657     }
2658 
2659     /**
2660      * Fill in a ConstraintLayout LayoutParam based on the id.
2661      *
2662      * @param id           Id of the view
2663      * @param layoutParams LayoutParams to be filled
2664      */
applyToLayoutParams(int id, ConstraintLayout.LayoutParams layoutParams)2665     public void applyToLayoutParams(int id, ConstraintLayout.LayoutParams layoutParams) {
2666         if (mConstraints.containsKey(id)) {
2667             Constraint constraint = mConstraints.get(id);
2668             if (constraint != null) {
2669                 constraint.applyTo(layoutParams);
2670             }
2671         }
2672     }
2673 
2674     /**
2675      * Used to set constraints when used by constraint layout
2676      */
applyToInternal(ConstraintLayout constraintLayout, boolean applyPostLayout)2677     void applyToInternal(ConstraintLayout constraintLayout, boolean applyPostLayout) {
2678         int count = constraintLayout.getChildCount();
2679         HashSet<Integer> used = new HashSet<Integer>(mConstraints.keySet());
2680         for (int i = 0; i < count; i++) {
2681             View view = constraintLayout.getChildAt(i);
2682             int id = view.getId();
2683             if (!mConstraints.containsKey(id)) {
2684                 Log.w(TAG, "id unknown " + Debug.getName(view));
2685                 continue;
2686             }
2687 
2688             if (mForceId && id == -1) {
2689                 throw new RuntimeException("All children of ConstraintLayout "
2690                         + "must have ids to use ConstraintSet");
2691             }
2692             if (id == -1) {
2693                 continue;
2694             }
2695 
2696             if (mConstraints.containsKey(id)) {
2697                 used.remove(id);
2698                 Constraint constraint = mConstraints.get(id);
2699                 if (constraint == null) {
2700                     continue;
2701                 }
2702                 if (view instanceof Barrier) {
2703                     constraint.layout.mHelperType = BARRIER_TYPE;
2704                     Barrier barrier = (Barrier) view;
2705                     barrier.setId(id);
2706                     barrier.setType(constraint.layout.mBarrierDirection);
2707                     barrier.setMargin(constraint.layout.mBarrierMargin);
2708 
2709                     barrier.setAllowsGoneWidget(constraint.layout.mBarrierAllowsGoneWidgets);
2710                     if (constraint.layout.mReferenceIds != null) {
2711                         barrier.setReferencedIds(constraint.layout.mReferenceIds);
2712                     } else if (constraint.layout.mReferenceIdString != null) {
2713                         constraint.layout.mReferenceIds = convertReferenceString(barrier,
2714                                 constraint.layout.mReferenceIdString);
2715                         barrier.setReferencedIds(constraint.layout.mReferenceIds);
2716                     }
2717                 }
2718                 ConstraintLayout.LayoutParams param = (ConstraintLayout.LayoutParams) view
2719                         .getLayoutParams();
2720                 param.validate();
2721                 constraint.applyTo(param);
2722 
2723                 if (applyPostLayout) {
2724                     ConstraintAttribute.setAttributes(view, constraint.mCustomConstraints);
2725                 }
2726                 view.setLayoutParams(param);
2727                 if (constraint.propertySet.mVisibilityMode == VISIBILITY_MODE_NORMAL) {
2728                     view.setVisibility(constraint.propertySet.visibility);
2729                 }
2730                 view.setAlpha(constraint.propertySet.alpha);
2731                 view.setRotation(constraint.transform.rotation);
2732                 view.setRotationX(constraint.transform.rotationX);
2733                 view.setRotationY(constraint.transform.rotationY);
2734                 view.setScaleX(constraint.transform.scaleX);
2735                 view.setScaleY(constraint.transform.scaleY);
2736                 if (constraint.transform.transformPivotTarget != UNSET) {
2737                     View layout = (View) view.getParent();
2738                     View center = layout.findViewById(
2739                             constraint.transform.transformPivotTarget);
2740                     if (center != null) {
2741                         float cy = (center.getTop() + center.getBottom()) / 2.0f;
2742                         float cx = (center.getLeft() + center.getRight()) / 2.0f;
2743                         if (view.getRight() - view.getLeft() > 0
2744                                 && view.getBottom() - view.getTop() > 0) {
2745                             float px = (cx - view.getLeft());
2746                             float py = (cy - view.getTop());
2747                             view.setPivotX(px);
2748                             view.setPivotY(py);
2749                         }
2750                     }
2751                 } else {
2752                     if (!Float.isNaN(constraint.transform.transformPivotX)) {
2753                         view.setPivotX(constraint.transform.transformPivotX);
2754                     }
2755                     if (!Float.isNaN(constraint.transform.transformPivotY)) {
2756                         view.setPivotY(constraint.transform.transformPivotY);
2757                     }
2758                 }
2759                 view.setTranslationX(constraint.transform.translationX);
2760                 view.setTranslationY(constraint.transform.translationY);
2761                 if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
2762                     view.setTranslationZ(constraint.transform.translationZ);
2763                     if (constraint.transform.applyElevation) {
2764                         view.setElevation(constraint.transform.elevation);
2765                     }
2766                 }
2767             } else {
2768                 Log.v(TAG, "WARNING NO CONSTRAINTS for view " + id);
2769             }
2770         }
2771         for (Integer id : used) {
2772             Constraint constraint = mConstraints.get(id);
2773             if (constraint == null) {
2774                 continue;
2775             }
2776             if (constraint.layout.mHelperType == BARRIER_TYPE) {
2777                 Barrier barrier = new Barrier(constraintLayout.getContext());
2778                 barrier.setId(id);
2779                 if (constraint.layout.mReferenceIds != null) {
2780                     barrier.setReferencedIds(constraint.layout.mReferenceIds);
2781                 } else if (constraint.layout.mReferenceIdString != null) {
2782                     constraint.layout.mReferenceIds = convertReferenceString(barrier,
2783                             constraint.layout.mReferenceIdString);
2784                     barrier.setReferencedIds(constraint.layout.mReferenceIds);
2785                 }
2786                 barrier.setType(constraint.layout.mBarrierDirection);
2787                 barrier.setMargin(constraint.layout.mBarrierMargin);
2788                 LayoutParams param = constraintLayout
2789                         .generateDefaultLayoutParams();
2790                 barrier.validateParams();
2791                 constraint.applyTo(param);
2792                 constraintLayout.addView(barrier, param);
2793             }
2794             if (constraint.layout.mIsGuideline) {
2795                 Guideline g = new Guideline(constraintLayout.getContext());
2796                 g.setId(id);
2797                 ConstraintLayout.LayoutParams param =
2798                         constraintLayout.generateDefaultLayoutParams();
2799                 constraint.applyTo(param);
2800                 constraintLayout.addView(g, param);
2801             }
2802         }
2803         for (int i = 0; i < count; i++) {
2804             View view = constraintLayout.getChildAt(i);
2805             if (view instanceof ConstraintHelper) {
2806                 ConstraintHelper constraintHelper = (ConstraintHelper) view;
2807                 constraintHelper.applyLayoutFeaturesInConstraintSet(constraintLayout);
2808             }
2809         }
2810     }
2811 
2812     /**
2813      * Center widget between the other two widgets.
2814      * (for sides see: {@link #TOP}, {@link #BOTTOM}, {@link #START},
2815      * {@link #END}, {@link #LEFT}, {@link #RIGHT})
2816      * Note, sides must be all vertical or horizontal sides.
2817      *
2818      * @param centerID     ID of the widget to be centered
2819      * @param firstID      ID of the first widget to connect the left or top of the widget to
2820      * @param firstSide    the side of the widget to connect to
2821      * @param firstMargin  the connection margin
2822      * @param secondId     the ID of the second widget to connect to right or top of the widget to
2823      * @param secondSide   the side of the widget to connect to
2824      * @param secondMargin the connection margin
2825      * @param bias         the ratio between two connections
2826      */
center(int centerID, int firstID, int firstSide, int firstMargin, int secondId, int secondSide, int secondMargin, float bias)2827     public void center(int centerID,
2828                        int firstID, int firstSide, int firstMargin,
2829                        int secondId, int secondSide, int secondMargin,
2830                        float bias) {
2831         // Error checking
2832 
2833         if (firstMargin < 0) {
2834             throw new IllegalArgumentException("margin must be > 0");
2835         }
2836         if (secondMargin < 0) {
2837             throw new IllegalArgumentException("margin must be > 0");
2838         }
2839         if (bias <= 0 || bias > 1) {
2840             throw new IllegalArgumentException("bias must be between 0 and 1 inclusive");
2841         }
2842 
2843         if (firstSide == LEFT || firstSide == RIGHT) {
2844             connect(centerID, LEFT, firstID, firstSide, firstMargin);
2845             connect(centerID, RIGHT, secondId, secondSide, secondMargin);
2846             Constraint constraint = mConstraints.get(centerID);
2847             if (constraint != null) {
2848                 constraint.layout.horizontalBias = bias;
2849             }
2850         } else if (firstSide == START || firstSide == END) {
2851             connect(centerID, START, firstID, firstSide, firstMargin);
2852             connect(centerID, END, secondId, secondSide, secondMargin);
2853             Constraint constraint = mConstraints.get(centerID);
2854             if (constraint != null) {
2855                 constraint.layout.horizontalBias = bias;
2856             }
2857         } else {
2858             connect(centerID, TOP, firstID, firstSide, firstMargin);
2859             connect(centerID, BOTTOM, secondId, secondSide, secondMargin);
2860             Constraint constraint = mConstraints.get(centerID);
2861             if (constraint != null) {
2862                 constraint.layout.verticalBias = bias;
2863             }
2864         }
2865     }
2866 
2867     /**
2868      * Centers the widget horizontally to the left and right side on another widgets sides.
2869      * (for sides see: {@link #START}, {@link #END}, {@link #LEFT}, {@link #RIGHT})
2870      *
2871      * @param centerID    ID of widget to be centered
2872      * @param leftId      The Id of the widget on the left side
2873      * @param leftSide    The side of the leftId widget to connect to
2874      * @param leftMargin  The margin on the left side
2875      * @param rightId     The Id of the widget on the right side
2876      * @param rightSide   The side  of the rightId widget to connect to
2877      * @param rightMargin The margin on the right side
2878      * @param bias        The ratio of the space on the left vs.
2879      * right sides 0.5 is centered (default)
2880      */
centerHorizontally(int centerID, int leftId, int leftSide, int leftMargin, int rightId, int rightSide, int rightMargin, float bias)2881     public void centerHorizontally(int centerID,
2882                                    int leftId,
2883                                    int leftSide,
2884                                    int leftMargin,
2885                                    int rightId,
2886                                    int rightSide,
2887                                    int rightMargin,
2888                                    float bias) {
2889         connect(centerID, LEFT, leftId, leftSide, leftMargin);
2890         connect(centerID, RIGHT, rightId, rightSide, rightMargin);
2891         Constraint constraint = mConstraints.get(centerID);
2892         if (constraint != null) {
2893             constraint.layout.horizontalBias = bias;
2894         }
2895     }
2896 
2897     /**
2898      * Centers the widgets horizontally to the left and right side on another widgets sides.
2899      * (for sides see: {@link #START}, {@link #END},
2900      * {@link #LEFT}, {@link #RIGHT})
2901      *
2902      * @param centerID    ID of widget to be centered
2903      * @param startId     The Id of the widget on the start side (left in non rtl languages)
2904      * @param startSide   The side of the startId widget to connect to
2905      * @param startMargin The margin on the start side
2906      * @param endId       The Id of the widget on the start side (left in non rtl languages)
2907      * @param endSide     The side of the endId widget to connect to
2908      * @param endMargin   The margin on the end side
2909      * @param bias        The ratio of the space on the start vs end side 0.5 is centered (default)
2910      */
centerHorizontallyRtl(int centerID, int startId, int startSide, int startMargin, int endId, int endSide, int endMargin, float bias)2911     public void centerHorizontallyRtl(int centerID, int startId, int startSide, int startMargin,
2912                                       int endId, int endSide, int endMargin, float bias) {
2913         connect(centerID, START, startId, startSide, startMargin);
2914         connect(centerID, END, endId, endSide, endMargin);
2915         Constraint constraint = mConstraints.get(centerID);
2916         if (constraint != null) {
2917             constraint.layout.horizontalBias = bias;
2918         }
2919     }
2920 
2921     /**
2922      * Centers the widgets vertically to the top and bottom side on another widgets sides.
2923      * (for sides see: {@link #TOP}, {@link #BOTTOM})
2924      *
2925      * @param centerID     ID of widget to be centered
2926      * @param topId        The Id of the widget on the top side
2927      * @param topSide      The side of the leftId widget to connect to
2928      * @param topMargin    The margin on the top side
2929      * @param bottomId     The Id of the widget on the bottom side
2930      * @param bottomSide   The side of the bottomId widget to connect to
2931      * @param bottomMargin The margin on the bottom side
2932      * @param bias         The ratio of the space on the top vs.
2933      * bottom sides 0.5 is centered (default)
2934      */
centerVertically(int centerID, int topId, int topSide, int topMargin, int bottomId, int bottomSide, int bottomMargin, float bias)2935     public void centerVertically(int centerID, int topId, int topSide, int topMargin, int bottomId,
2936                                  int bottomSide, int bottomMargin, float bias) {
2937         connect(centerID, TOP, topId, topSide, topMargin);
2938         connect(centerID, BOTTOM, bottomId, bottomSide, bottomMargin);
2939         Constraint constraint = mConstraints.get(centerID);
2940         if (constraint != null) {
2941             constraint.layout.verticalBias = bias;
2942         }
2943     }
2944 
2945     /**
2946      * Spaces a set of widgets vertically between the view topId and bottomId.
2947      * Widgets can be spaced with weights.
2948      * This operation sets all the related margins to 0.
2949      * <p>
2950      * (for sides see: {@link #TOP}, {@link #BOTTOM})
2951      *
2952      * @param topId      The id of the widget to connect to or PARENT_ID
2953      * @param topSide    the side of the start to connect to
2954      * @param bottomId   The id of the widget to connect to or PARENT_ID
2955      * @param bottomSide the side of the right to connect to
2956      * @param chainIds   widgets to use as a chain
2957      * @param weights    can be null
2958      * @param style      set the style of the chain
2959      */
createVerticalChain(int topId, int topSide, int bottomId, int bottomSide, int[] chainIds, float[] weights, int style)2960     public void createVerticalChain(int topId,
2961                                     int topSide,
2962                                     int bottomId,
2963                                     int bottomSide,
2964                                     int[] chainIds,
2965                                     float[] weights,
2966                                     int style) {
2967         if (chainIds.length < 2) {
2968             throw new IllegalArgumentException("must have 2 or more widgets in a chain");
2969         }
2970         if (weights != null && weights.length != chainIds.length) {
2971             throw new IllegalArgumentException("must have 2 or more widgets in a chain");
2972         }
2973         if (weights != null) {
2974             get(chainIds[0]).layout.verticalWeight = weights[0];
2975         }
2976         get(chainIds[0]).layout.verticalChainStyle = style;
2977 
2978         connect(chainIds[0], TOP, topId, topSide, 0);
2979         for (int i = 1; i < chainIds.length; i++) {
2980             connect(chainIds[i], TOP, chainIds[i - 1], BOTTOM, 0);
2981             connect(chainIds[i - 1], BOTTOM, chainIds[i], TOP, 0);
2982             if (weights != null) {
2983                 get(chainIds[i]).layout.verticalWeight = weights[i];
2984             }
2985         }
2986         connect(chainIds[chainIds.length - 1], BOTTOM, bottomId, bottomSide, 0);
2987     }
2988 
2989     /**
2990      * Spaces a set of widgets horizontally between the view startID and endId.
2991      * Widgets can be spaced with weights.
2992      * This operation sets all the related margins to 0.
2993      * <p>
2994      * (for sides see: {@link #START}, {@link #END},
2995      * {@link #LEFT}, {@link #RIGHT})
2996      *
2997      * @param leftId    The id of the widget to connect to or PARENT_ID
2998      * @param leftSide  the side of the start to connect to
2999      * @param rightId   The id of the widget to connect to or PARENT_ID
3000      * @param rightSide the side of the right to connect to
3001      * @param chainIds  The widgets in the chain
3002      * @param weights   The weight to assign to each element in the chain or null
3003      * @param style     The type of chain
3004      */
createHorizontalChain(int leftId, int leftSide, int rightId, int rightSide, int[] chainIds, float[] weights, int style)3005     public void createHorizontalChain(int leftId,
3006                                       int leftSide,
3007                                       int rightId,
3008                                       int rightSide,
3009                                       int[] chainIds,
3010                                       float[] weights,
3011                                       int style) {
3012         createHorizontalChain(leftId, leftSide, rightId, rightSide,
3013                 chainIds, weights, style, LEFT, RIGHT);
3014     }
3015 
3016     /**
3017      * Spaces a set of widgets horizontal between the view startID and endId.
3018      * Widgets can be spaced with weights.
3019      * (for sides see: {@link #START}, {@link #END},
3020      * {@link #LEFT}, {@link #RIGHT})
3021      *
3022      * @param startId   The id of the widget to connect to or PARENT_ID
3023      * @param startSide the side of the start to connect to
3024      * @param endId     The id of the widget to connect to or PARENT_ID
3025      * @param endSide   the side of the end to connect to
3026      * @param chainIds  The widgets in the chain
3027      * @param weights   The weight to assign to each element in the chain or null
3028      * @param style     The type of chain
3029      */
createHorizontalChainRtl(int startId, int startSide, int endId, int endSide, int[] chainIds, float[] weights, int style)3030     public void createHorizontalChainRtl(int startId,
3031                                          int startSide,
3032                                          int endId,
3033                                          int endSide,
3034                                          int[] chainIds,
3035                                          float[] weights,
3036                                          int style) {
3037         createHorizontalChain(startId, startSide, endId, endSide,
3038                 chainIds, weights, style, START, END);
3039     }
3040 
createHorizontalChain(int leftId, int leftSide, int rightId, int rightSide, int[] chainIds, float[] weights, int style, int left, int right)3041     private void createHorizontalChain(int leftId,
3042                                        int leftSide,
3043                                        int rightId,
3044                                        int rightSide,
3045                                        int[] chainIds,
3046                                        float[] weights,
3047                                        int style, int left, int right) {
3048 
3049         if (chainIds.length < 2) {
3050             throw new IllegalArgumentException("must have 2 or more widgets in a chain");
3051         }
3052         if (weights != null && weights.length != chainIds.length) {
3053             throw new IllegalArgumentException("must have 2 or more widgets in a chain");
3054         }
3055         if (weights != null) {
3056             get(chainIds[0]).layout.horizontalWeight = weights[0];
3057         }
3058         get(chainIds[0]).layout.horizontalChainStyle = style;
3059         connect(chainIds[0], left, leftId, leftSide, UNSET);
3060         for (int i = 1; i < chainIds.length; i++) {
3061             connect(chainIds[i], left, chainIds[i - 1], right, UNSET);
3062             connect(chainIds[i - 1], right, chainIds[i], left, UNSET);
3063             if (weights != null) {
3064                 get(chainIds[i]).layout.horizontalWeight = weights[i];
3065             }
3066         }
3067 
3068         connect(chainIds[chainIds.length - 1], right, rightId, rightSide,
3069                 UNSET);
3070 
3071     }
3072 
3073     /**
3074      * Create a constraint between two widgets.
3075      * (for sides see: {@link #TOP}, {@link #BOTTOM}, {@link #START}, {@link #END},
3076      * {@link #LEFT}, {@link #RIGHT}, {@link #BASELINE})
3077      *
3078      * @param startID   the ID of the widget to be constrained
3079      * @param startSide the side of the widget to constrain
3080      * @param endID     the id of the widget to constrain to
3081      * @param endSide   the side of widget to constrain to
3082      * @param margin    the margin to constrain (margin must be positive)
3083      */
connect(int startID, int startSide, int endID, int endSide, int margin)3084     public void connect(int startID, int startSide, int endID, int endSide, int margin) {
3085         if (!mConstraints.containsKey(startID)) {
3086             mConstraints.put(startID, new Constraint());
3087         }
3088         Constraint constraint = mConstraints.get(startID);
3089         if (constraint == null) {
3090             return;
3091         }
3092         switch (startSide) {
3093             case LEFT:
3094                 if (endSide == LEFT) {
3095                     constraint.layout.leftToLeft = endID;
3096                     constraint.layout.leftToRight = Layout.UNSET;
3097                 } else if (endSide == RIGHT) {
3098                     constraint.layout.leftToRight = endID;
3099                     constraint.layout.leftToLeft = Layout.UNSET;
3100 
3101                 } else {
3102                     throw new IllegalArgumentException("Left to "
3103                             + sideToString(endSide) + " undefined");
3104                 }
3105                 constraint.layout.leftMargin = margin;
3106                 break;
3107             case RIGHT:
3108                 if (endSide == LEFT) {
3109                     constraint.layout.rightToLeft = endID;
3110                     constraint.layout.rightToRight = Layout.UNSET;
3111 
3112                 } else if (endSide == RIGHT) {
3113                     constraint.layout.rightToRight = endID;
3114                     constraint.layout.rightToLeft = Layout.UNSET;
3115 
3116                 } else {
3117                     throw new IllegalArgumentException("right to "
3118                             + sideToString(endSide) + " undefined");
3119                 }
3120                 constraint.layout.rightMargin = margin;
3121                 break;
3122             case TOP:
3123                 if (endSide == TOP) {
3124                     constraint.layout.topToTop = endID;
3125                     constraint.layout.topToBottom = Layout.UNSET;
3126                     constraint.layout.baselineToBaseline = Layout.UNSET;
3127                     constraint.layout.baselineToTop = Layout.UNSET;
3128                     constraint.layout.baselineToBottom = Layout.UNSET;
3129                 } else if (endSide == BOTTOM) {
3130                     constraint.layout.topToBottom = endID;
3131                     constraint.layout.topToTop = Layout.UNSET;
3132                     constraint.layout.baselineToBaseline = Layout.UNSET;
3133                     constraint.layout.baselineToTop = Layout.UNSET;
3134                     constraint.layout.baselineToBottom = Layout.UNSET;
3135                 } else {
3136                     throw new IllegalArgumentException("right to "
3137                             + sideToString(endSide) + " undefined");
3138                 }
3139                 constraint.layout.topMargin = margin;
3140                 break;
3141             case BOTTOM:
3142                 if (endSide == BOTTOM) {
3143                     constraint.layout.bottomToBottom = endID;
3144                     constraint.layout.bottomToTop = Layout.UNSET;
3145                     constraint.layout.baselineToBaseline = Layout.UNSET;
3146                     constraint.layout.baselineToTop = Layout.UNSET;
3147                     constraint.layout.baselineToBottom = Layout.UNSET;
3148                 } else if (endSide == TOP) {
3149                     constraint.layout.bottomToTop = endID;
3150                     constraint.layout.bottomToBottom = Layout.UNSET;
3151                     constraint.layout.baselineToBaseline = Layout.UNSET;
3152                     constraint.layout.baselineToTop = Layout.UNSET;
3153                     constraint.layout.baselineToBottom = Layout.UNSET;
3154                 } else {
3155                     throw new IllegalArgumentException("right to "
3156                             + sideToString(endSide) + " undefined");
3157                 }
3158                 constraint.layout.bottomMargin = margin;
3159                 break;
3160             case BASELINE:
3161                 if (endSide == BASELINE) {
3162                     constraint.layout.baselineToBaseline = endID;
3163                     constraint.layout.bottomToBottom = Layout.UNSET;
3164                     constraint.layout.bottomToTop = Layout.UNSET;
3165                     constraint.layout.topToTop = Layout.UNSET;
3166                     constraint.layout.topToBottom = Layout.UNSET;
3167                 } else if (endSide == TOP) {
3168                     constraint.layout.baselineToTop = endID;
3169                     constraint.layout.bottomToBottom = Layout.UNSET;
3170                     constraint.layout.bottomToTop = Layout.UNSET;
3171                     constraint.layout.topToTop = Layout.UNSET;
3172                     constraint.layout.topToBottom = Layout.UNSET;
3173                 } else if (endSide == BOTTOM) {
3174                     constraint.layout.baselineToBottom = endID;
3175                     constraint.layout.bottomToBottom = Layout.UNSET;
3176                     constraint.layout.bottomToTop = Layout.UNSET;
3177                     constraint.layout.topToTop = Layout.UNSET;
3178                     constraint.layout.topToBottom = Layout.UNSET;
3179                 } else {
3180                     throw new IllegalArgumentException("right to "
3181                             + sideToString(endSide) + " undefined");
3182                 }
3183                 break;
3184             case START:
3185                 if (endSide == START) {
3186                     constraint.layout.startToStart = endID;
3187                     constraint.layout.startToEnd = Layout.UNSET;
3188                 } else if (endSide == END) {
3189                     constraint.layout.startToEnd = endID;
3190                     constraint.layout.startToStart = Layout.UNSET;
3191                 } else {
3192                     throw new IllegalArgumentException("right to "
3193                             + sideToString(endSide) + " undefined");
3194                 }
3195                 constraint.layout.startMargin = margin;
3196                 break;
3197             case END:
3198                 if (endSide == END) {
3199                     constraint.layout.endToEnd = endID;
3200                     constraint.layout.endToStart = Layout.UNSET;
3201                 } else if (endSide == START) {
3202                     constraint.layout.endToStart = endID;
3203                     constraint.layout.endToEnd = Layout.UNSET;
3204                 } else {
3205                     throw new IllegalArgumentException("right to "
3206                             + sideToString(endSide) + " undefined");
3207                 }
3208                 constraint.layout.endMargin = margin;
3209                 break;
3210             default:
3211                 throw new IllegalArgumentException(
3212                         sideToString(startSide) + " to " + sideToString(endSide) + " unknown");
3213         }
3214     }
3215 
3216     /**
3217      * Create a constraint between two widgets.
3218      * (for sides see: {@link #TOP}, {@link #BOTTOM}, {@link #START},
3219      * {@link #END}, {@link #LEFT}, {@link #RIGHT}, {@link #BASELINE})
3220      *
3221      * @param startID   the ID of the widget to be constrained
3222      * @param startSide the side of the widget to constrain
3223      * @param endID     the id of the widget to constrain to
3224      * @param endSide   the side of widget to constrain to
3225      */
connect(int startID, int startSide, int endID, int endSide)3226     public void connect(int startID, int startSide, int endID, int endSide) {
3227         if (!mConstraints.containsKey(startID)) {
3228             mConstraints.put(startID, new Constraint());
3229         }
3230         Constraint constraint = mConstraints.get(startID);
3231         if (constraint == null) {
3232             return;
3233         }
3234         switch (startSide) {
3235             case LEFT:
3236                 if (endSide == LEFT) {
3237                     constraint.layout.leftToLeft = endID;
3238                     constraint.layout.leftToRight = Layout.UNSET;
3239                 } else if (endSide == RIGHT) {
3240                     constraint.layout.leftToRight = endID;
3241                     constraint.layout.leftToLeft = Layout.UNSET;
3242                 } else {
3243                     throw new IllegalArgumentException("left to "
3244                             + sideToString(endSide) + " undefined");
3245                 }
3246                 break;
3247             case RIGHT:
3248                 if (endSide == LEFT) {
3249                     constraint.layout.rightToLeft = endID;
3250                     constraint.layout.rightToRight = Layout.UNSET;
3251 
3252                 } else if (endSide == RIGHT) {
3253                     constraint.layout.rightToRight = endID;
3254                     constraint.layout.rightToLeft = Layout.UNSET;
3255                 } else {
3256                     throw new IllegalArgumentException("right to "
3257                             + sideToString(endSide) + " undefined");
3258                 }
3259                 break;
3260             case TOP:
3261                 if (endSide == TOP) {
3262                     constraint.layout.topToTop = endID;
3263                     constraint.layout.topToBottom = Layout.UNSET;
3264                     constraint.layout.baselineToBaseline = Layout.UNSET;
3265                     constraint.layout.baselineToTop = Layout.UNSET;
3266                     constraint.layout.baselineToBottom = Layout.UNSET;
3267                 } else if (endSide == BOTTOM) {
3268                     constraint.layout.topToBottom = endID;
3269                     constraint.layout.topToTop = Layout.UNSET;
3270                     constraint.layout.baselineToBaseline = Layout.UNSET;
3271                     constraint.layout.baselineToTop = Layout.UNSET;
3272                     constraint.layout.baselineToBottom = Layout.UNSET;
3273                 } else {
3274                     throw new IllegalArgumentException("right to "
3275                             + sideToString(endSide) + " undefined");
3276                 }
3277                 break;
3278             case BOTTOM:
3279                 if (endSide == BOTTOM) {
3280                     constraint.layout.bottomToBottom = endID;
3281                     constraint.layout.bottomToTop = Layout.UNSET;
3282                     constraint.layout.baselineToBaseline = Layout.UNSET;
3283                     constraint.layout.baselineToTop = Layout.UNSET;
3284                     constraint.layout.baselineToBottom = Layout.UNSET;
3285                 } else if (endSide == TOP) {
3286                     constraint.layout.bottomToTop = endID;
3287                     constraint.layout.bottomToBottom = Layout.UNSET;
3288                     constraint.layout.baselineToBaseline = Layout.UNSET;
3289                     constraint.layout.baselineToTop = Layout.UNSET;
3290                     constraint.layout.baselineToBottom = Layout.UNSET;
3291                 } else {
3292                     throw new IllegalArgumentException("right to "
3293                             + sideToString(endSide) + " undefined");
3294                 }
3295                 break;
3296             case BASELINE:
3297                 if (endSide == BASELINE) {
3298                     constraint.layout.baselineToBaseline = endID;
3299                     constraint.layout.bottomToBottom = Layout.UNSET;
3300                     constraint.layout.bottomToTop = Layout.UNSET;
3301                     constraint.layout.topToTop = Layout.UNSET;
3302                     constraint.layout.topToBottom = Layout.UNSET;
3303                 } else if (endSide == TOP) {
3304                     constraint.layout.baselineToTop = endID;
3305                     constraint.layout.bottomToBottom = Layout.UNSET;
3306                     constraint.layout.bottomToTop = Layout.UNSET;
3307                     constraint.layout.topToTop = Layout.UNSET;
3308                     constraint.layout.topToBottom = Layout.UNSET;
3309                 } else if (endSide == BOTTOM) {
3310                     constraint.layout.baselineToBottom = endID;
3311                     constraint.layout.bottomToBottom = Layout.UNSET;
3312                     constraint.layout.bottomToTop = Layout.UNSET;
3313                     constraint.layout.topToTop = Layout.UNSET;
3314                     constraint.layout.topToBottom = Layout.UNSET;
3315                 } else {
3316                     throw new IllegalArgumentException("right to "
3317                             + sideToString(endSide) + " undefined");
3318                 }
3319                 break;
3320             case START:
3321                 if (endSide == START) {
3322                     constraint.layout.startToStart = endID;
3323                     constraint.layout.startToEnd = Layout.UNSET;
3324                 } else if (endSide == END) {
3325                     constraint.layout.startToEnd = endID;
3326                     constraint.layout.startToStart = Layout.UNSET;
3327                 } else {
3328                     throw new IllegalArgumentException("right to "
3329                             + sideToString(endSide) + " undefined");
3330                 }
3331                 break;
3332             case END:
3333                 if (endSide == END) {
3334                     constraint.layout.endToEnd = endID;
3335                     constraint.layout.endToStart = Layout.UNSET;
3336                 } else if (endSide == START) {
3337                     constraint.layout.endToStart = endID;
3338                     constraint.layout.endToEnd = Layout.UNSET;
3339                 } else {
3340                     throw new IllegalArgumentException("right to "
3341                             + sideToString(endSide) + " undefined");
3342                 }
3343                 break;
3344             default:
3345                 throw new IllegalArgumentException(
3346                         sideToString(startSide) + " to " + sideToString(endSide) + " unknown");
3347         }
3348     }
3349 
3350     /**
3351      * Centers the view horizontally relative to toView's position.
3352      *
3353      * @param viewId ID of view to center Horizontally
3354      * @param toView ID of view to center on (or in)
3355      */
centerHorizontally(int viewId, int toView)3356     public void centerHorizontally(int viewId, int toView) {
3357         if (toView == PARENT_ID) {
3358             center(viewId, PARENT_ID, ConstraintSet.LEFT, 0, PARENT_ID,
3359                     ConstraintSet.RIGHT, 0, 0.5f);
3360         } else {
3361             center(viewId, toView, ConstraintSet.RIGHT, 0, toView,
3362                     ConstraintSet.LEFT, 0, 0.5f);
3363         }
3364     }
3365 
3366     /**
3367      * Centers the view horizontally relative to toView's position.
3368      *
3369      * @param viewId ID of view to center Horizontally
3370      * @param toView ID of view to center on (or in)
3371      */
centerHorizontallyRtl(int viewId, int toView)3372     public void centerHorizontallyRtl(int viewId, int toView) {
3373         if (toView == PARENT_ID) {
3374             center(viewId, PARENT_ID, ConstraintSet.START, 0, PARENT_ID,
3375                     ConstraintSet.END, 0, 0.5f);
3376         } else {
3377             center(viewId, toView, ConstraintSet.END, 0, toView,
3378                     ConstraintSet.START, 0, 0.5f);
3379         }
3380     }
3381 
3382     /**
3383      * Centers the view vertically relative to toView's position.
3384      *
3385      * @param viewId ID of view to center Horizontally
3386      * @param toView ID of view to center on (or in)
3387      */
centerVertically(int viewId, int toView)3388     public void centerVertically(int viewId, int toView) {
3389         if (toView == PARENT_ID) {
3390             center(viewId, PARENT_ID, ConstraintSet.TOP, 0, PARENT_ID,
3391                     ConstraintSet.BOTTOM, 0, 0.5f);
3392         } else {
3393             center(viewId, toView, ConstraintSet.BOTTOM, 0, toView, ConstraintSet.TOP,
3394                     0, 0.5f);
3395         }
3396     }
3397 
3398     /**
3399      * Remove all constraints from this view.
3400      *
3401      * @param viewId ID of view to remove all connections to
3402      */
clear(int viewId)3403     public void clear(int viewId) {
3404         mConstraints.remove(viewId);
3405     }
3406 
3407     /**
3408      * Remove a constraint from this view.
3409      *
3410      * @param viewId ID of view to center on (or in)
3411      * @param anchor the Anchor to remove constraint from
3412      */
clear(int viewId, int anchor)3413     public void clear(int viewId, int anchor) {
3414         if (mConstraints.containsKey(viewId)) {
3415             Constraint constraint = mConstraints.get(viewId);
3416             if (constraint == null) {
3417                 return;
3418             }
3419             switch (anchor) {
3420                 case LEFT:
3421                     constraint.layout.leftToRight = Layout.UNSET;
3422                     constraint.layout.leftToLeft = Layout.UNSET;
3423                     constraint.layout.leftMargin = Layout.UNSET;
3424                     constraint.layout.goneLeftMargin = Layout.UNSET_GONE_MARGIN;
3425                     break;
3426                 case RIGHT:
3427                     constraint.layout.rightToRight = Layout.UNSET;
3428                     constraint.layout.rightToLeft = Layout.UNSET;
3429                     constraint.layout.rightMargin = Layout.UNSET;
3430                     constraint.layout.goneRightMargin = Layout.UNSET_GONE_MARGIN;
3431                     break;
3432                 case TOP:
3433                     constraint.layout.topToBottom = Layout.UNSET;
3434                     constraint.layout.topToTop = Layout.UNSET;
3435                     constraint.layout.topMargin = 0;
3436                     constraint.layout.goneTopMargin = Layout.UNSET_GONE_MARGIN;
3437                     break;
3438                 case BOTTOM:
3439                     constraint.layout.bottomToTop = Layout.UNSET;
3440                     constraint.layout.bottomToBottom = Layout.UNSET;
3441                     constraint.layout.bottomMargin = 0;
3442                     constraint.layout.goneBottomMargin = Layout.UNSET_GONE_MARGIN;
3443                     break;
3444                 case BASELINE:
3445                     constraint.layout.baselineToBaseline = Layout.UNSET;
3446                     constraint.layout.baselineToTop = Layout.UNSET;
3447                     constraint.layout.baselineToBottom = Layout.UNSET;
3448                     constraint.layout.baselineMargin = 0;
3449                     constraint.layout.goneBaselineMargin = Layout.UNSET_GONE_MARGIN;
3450                     break;
3451                 case START:
3452                     constraint.layout.startToEnd = Layout.UNSET;
3453                     constraint.layout.startToStart = Layout.UNSET;
3454                     constraint.layout.startMargin = 0;
3455                     constraint.layout.goneStartMargin = Layout.UNSET_GONE_MARGIN;
3456                     break;
3457                 case END:
3458                     constraint.layout.endToStart = Layout.UNSET;
3459                     constraint.layout.endToEnd = Layout.UNSET;
3460                     constraint.layout.endMargin = 0;
3461                     constraint.layout.goneEndMargin = Layout.UNSET_GONE_MARGIN;
3462                     break;
3463                 case CIRCLE_REFERENCE:
3464                     constraint.layout.circleAngle = Layout.UNSET;
3465                     constraint.layout.circleRadius = Layout.UNSET;
3466                     constraint.layout.circleConstraint = Layout.UNSET;
3467                     break;
3468                 default:
3469                     throw new IllegalArgumentException("unknown constraint");
3470             }
3471         }
3472     }
3473 
3474     /**
3475      * Sets the margin.
3476      *
3477      * @param viewId ID of view to adjust the margin on
3478      * @param anchor The side to adjust the margin on
3479      * @param value  The new value for the margin
3480      */
setMargin(int viewId, int anchor, int value)3481     public void setMargin(int viewId, int anchor, int value) {
3482         Constraint constraint = get(viewId);
3483         switch (anchor) {
3484             case LEFT:
3485                 constraint.layout.leftMargin = value;
3486                 break;
3487             case RIGHT:
3488                 constraint.layout.rightMargin = value;
3489                 break;
3490             case TOP:
3491                 constraint.layout.topMargin = value;
3492                 break;
3493             case BOTTOM:
3494                 constraint.layout.bottomMargin = value;
3495                 break;
3496             case BASELINE:
3497                 constraint.layout.baselineMargin = value;
3498                 break;
3499             case START:
3500                 constraint.layout.startMargin = value;
3501                 break;
3502             case END:
3503                 constraint.layout.endMargin = value;
3504                 break;
3505             default:
3506                 throw new IllegalArgumentException("unknown constraint");
3507         }
3508     }
3509 
3510     /**
3511      * Sets the gone margin.
3512      *
3513      * @param viewId ID of view to adjust the margin on
3514      * @param anchor The side to adjust the margin on
3515      * @param value  The new value for the margin
3516      */
setGoneMargin(int viewId, int anchor, int value)3517     public void setGoneMargin(int viewId, int anchor, int value) {
3518         Constraint constraint = get(viewId);
3519         switch (anchor) {
3520             case LEFT:
3521                 constraint.layout.goneLeftMargin = value;
3522                 break;
3523             case RIGHT:
3524                 constraint.layout.goneRightMargin = value;
3525                 break;
3526             case TOP:
3527                 constraint.layout.goneTopMargin = value;
3528                 break;
3529             case BOTTOM:
3530                 constraint.layout.goneBottomMargin = value;
3531                 break;
3532             case BASELINE:
3533                 constraint.layout.goneBaselineMargin = value;
3534                 break;
3535             case START:
3536                 constraint.layout.goneStartMargin = value;
3537                 break;
3538             case END:
3539                 constraint.layout.goneEndMargin = value;
3540                 break;
3541             default:
3542                 throw new IllegalArgumentException("unknown constraint");
3543         }
3544     }
3545 
3546     /**
3547      * Adjust the horizontal bias of the view (used with views constrained on left and right).
3548      *
3549      * @param viewId ID of view to adjust the horizontal
3550      * @param bias   the new bias 0.5 is in the middle
3551      */
setHorizontalBias(int viewId, float bias)3552     public void setHorizontalBias(int viewId, float bias) {
3553         get(viewId).layout.horizontalBias = bias;
3554     }
3555 
3556     /**
3557      * Adjust the vertical bias of the view (used with views constrained on left and right).
3558      *
3559      * @param viewId ID of view to adjust the vertical
3560      * @param bias   the new bias 0.5 is in the middle
3561      */
setVerticalBias(int viewId, float bias)3562     public void setVerticalBias(int viewId, float bias) {
3563         get(viewId).layout.verticalBias = bias;
3564     }
3565 
3566     /**
3567      * Constrains the views aspect ratio.
3568      * For Example a HD screen is 16 by 9 = 16/(float)9 = 1.777f.
3569      *
3570      * @param viewId ID of view to constrain
3571      * @param ratio  The ratio of the width to height (width / height)
3572      */
setDimensionRatio(int viewId, String ratio)3573     public void setDimensionRatio(int viewId, String ratio) {
3574         get(viewId).layout.dimensionRatio = ratio;
3575     }
3576 
3577     /**
3578      * Adjust the visibility of a view.
3579      *
3580      * @param viewId     ID of view to adjust the vertical
3581      * @param visibility the visibility
3582      */
setVisibility(int viewId, int visibility)3583     public void setVisibility(int viewId, int visibility) {
3584         get(viewId).propertySet.visibility = visibility;
3585     }
3586 
3587     /**
3588      * ConstraintSet will not setVisibility. {@link #VISIBILITY_MODE_IGNORE} or {@link
3589      * #VISIBILITY_MODE_NORMAL}.
3590      *
3591      * @param viewId         ID of view
3592      * @param visibilityMode
3593      */
setVisibilityMode(int viewId, int visibilityMode)3594     public void setVisibilityMode(int viewId, int visibilityMode) {
3595         get(viewId).propertySet.mVisibilityMode = visibilityMode;
3596     }
3597 
3598     /**
3599      * ConstraintSet will not setVisibility. {@link #VISIBILITY_MODE_IGNORE} or {@link
3600      * #VISIBILITY_MODE_NORMAL}.
3601      *
3602      * @param viewId ID of view
3603      */
getVisibilityMode(int viewId)3604     public int getVisibilityMode(int viewId) {
3605         return get(viewId).propertySet.mVisibilityMode;
3606     }
3607 
3608     /**
3609      * Get the visibility flag set in this view
3610      *
3611      * @param viewId the id of the view
3612      * @return the visibility constraint for the view
3613      */
getVisibility(int viewId)3614     public int getVisibility(int viewId) {
3615         return get(viewId).propertySet.visibility;
3616     }
3617 
3618     /**
3619      * Get the height set in the view
3620      *
3621      * @param viewId the id of the view
3622      * @return return the height constraint of the view
3623      */
getHeight(int viewId)3624     public int getHeight(int viewId) {
3625         return get(viewId).layout.mHeight;
3626     }
3627 
3628     /**
3629      * Get the width set in the view
3630      *
3631      * @param viewId the id of the view
3632      * @return return the width constraint of the view
3633      */
getWidth(int viewId)3634     public int getWidth(int viewId) {
3635         return get(viewId).layout.mWidth;
3636     }
3637 
3638     /**
3639      * Adjust the alpha of a view.
3640      *
3641      * @param viewId ID of view to adjust the vertical
3642      * @param alpha  the alpha
3643      */
setAlpha(int viewId, float alpha)3644     public void setAlpha(int viewId, float alpha) {
3645         get(viewId).propertySet.alpha = alpha;
3646     }
3647 
3648     /**
3649      * return with the constraint set will apply elevation for the specified view.
3650      *
3651      * @return true if the elevation will be set on this view (default is false)
3652      */
getApplyElevation(int viewId)3653     public boolean getApplyElevation(int viewId) {
3654         return get(viewId).transform.applyElevation;
3655     }
3656 
3657     /**
3658      * set if elevation will be applied to the view.
3659      * Elevation logic is based on style and animation. By default it is not used because it would
3660      * lead to unexpected results.
3661      *
3662      * @param viewId ID of view to adjust the elevation
3663      * @param apply  true if this constraint set applies elevation to this view
3664      */
setApplyElevation(int viewId, boolean apply)3665     public void setApplyElevation(int viewId, boolean apply) {
3666         if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
3667             get(viewId).transform.applyElevation = apply;
3668         }
3669     }
3670 
3671     /**
3672      * Adjust the elevation of a view.
3673      *
3674      * @param viewId    ID of view to adjust the elevation
3675      * @param elevation the elevation
3676      */
setElevation(int viewId, float elevation)3677     public void setElevation(int viewId, float elevation) {
3678         if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
3679             get(viewId).transform.elevation = elevation;
3680             get(viewId).transform.applyElevation = true;
3681         }
3682     }
3683 
3684     /**
3685      * Adjust the post-layout rotation about the Z axis of a view.
3686      *
3687      * @param viewId   ID of view to adjust th Z rotation
3688      * @param rotation the rotation about the X axis
3689      */
setRotation(int viewId, float rotation)3690     public void setRotation(int viewId, float rotation) {
3691         get(viewId).transform.rotation = rotation;
3692     }
3693 
3694     /**
3695      * Adjust the post-layout rotation about the X axis of a view.
3696      *
3697      * @param viewId    ID of view to adjust th X rotation
3698      * @param rotationX the rotation about the X axis
3699      */
setRotationX(int viewId, float rotationX)3700     public void setRotationX(int viewId, float rotationX) {
3701         get(viewId).transform.rotationX = rotationX;
3702     }
3703 
3704     /**
3705      * Adjust the post-layout rotation about the Y axis of a view.
3706      *
3707      * @param viewId    ID of view to adjust the Y rotation
3708      * @param rotationY the rotationY
3709      */
setRotationY(int viewId, float rotationY)3710     public void setRotationY(int viewId, float rotationY) {
3711         get(viewId).transform.rotationY = rotationY;
3712     }
3713 
3714     /**
3715      * Adjust the post-layout scale in X of a view.
3716      *
3717      * @param viewId ID of view to adjust the scale in X
3718      * @param scaleX the scale in X
3719      */
setScaleX(int viewId, float scaleX)3720     public void setScaleX(int viewId, float scaleX) {
3721         get(viewId).transform.scaleX = scaleX;
3722     }
3723 
3724     /**
3725      * Adjust the post-layout scale in Y of a view.
3726      *
3727      * @param viewId ID of view to adjust the scale in Y
3728      * @param scaleY the scale in Y
3729      */
setScaleY(int viewId, float scaleY)3730     public void setScaleY(int viewId, float scaleY) {
3731         get(viewId).transform.scaleY = scaleY;
3732     }
3733 
3734     /**
3735      * Set X location of the pivot point around which the view will rotate and scale.
3736      * use Float.NaN to clear the pivot value.
3737      * Note: once an actual View has had its pivot set it cannot be cleared.
3738      *
3739      * @param viewId          ID of view to adjust the transforms pivot point about X
3740      * @param transformPivotX X location of the pivot point.
3741      */
setTransformPivotX(int viewId, float transformPivotX)3742     public void setTransformPivotX(int viewId, float transformPivotX) {
3743         get(viewId).transform.transformPivotX = transformPivotX;
3744     }
3745 
3746     /**
3747      * Set Y location of the pivot point around which the view will rotate and scale.
3748      * use Float.NaN to clear the pivot value.
3749      * Note: once an actual View has had its pivot set it cannot be cleared.
3750      *
3751      * @param viewId          ID of view to adjust the transforms pivot point about Y
3752      * @param transformPivotY Y location of the pivot point.
3753      */
setTransformPivotY(int viewId, float transformPivotY)3754     public void setTransformPivotY(int viewId, float transformPivotY) {
3755         get(viewId).transform.transformPivotY = transformPivotY;
3756     }
3757 
3758     /**
3759      * Set X,Y location of the pivot point around which the view will rotate and scale.
3760      * use Float.NaN to clear the pivot value.
3761      * Note: once an actual View has had its pivot set it cannot be cleared.
3762      *
3763      * @param viewId          ID of view to adjust the transforms pivot point
3764      * @param transformPivotX X location of the pivot point.
3765      * @param transformPivotY Y location of the pivot point.
3766      */
setTransformPivot(int viewId, float transformPivotX, float transformPivotY)3767     public void setTransformPivot(int viewId, float transformPivotX, float transformPivotY) {
3768         Constraint constraint = get(viewId);
3769         constraint.transform.transformPivotY = transformPivotY;
3770         constraint.transform.transformPivotX = transformPivotX;
3771     }
3772 
3773     /**
3774      * Adjust the post-layout X translation of a view.
3775      *
3776      * @param viewId       ID of view to translate in X
3777      * @param translationX the translation in X
3778      */
setTranslationX(int viewId, float translationX)3779     public void setTranslationX(int viewId, float translationX) {
3780         get(viewId).transform.translationX = translationX;
3781     }
3782 
3783     /**
3784      * Adjust the  post-layout Y translation of a view.
3785      *
3786      * @param viewId       ID of view to to translate in Y
3787      * @param translationY the translation in Y
3788      */
setTranslationY(int viewId, float translationY)3789     public void setTranslationY(int viewId, float translationY) {
3790         get(viewId).transform.translationY = translationY;
3791     }
3792 
3793     /**
3794      * Adjust the post-layout translation of a view.
3795      *
3796      * @param viewId       ID of view to adjust its translation in X & Y
3797      * @param translationX the translation in X
3798      * @param translationY the translation in Y
3799      */
setTranslation(int viewId, float translationX, float translationY)3800     public void setTranslation(int viewId, float translationX, float translationY) {
3801         Constraint constraint = get(viewId);
3802         constraint.transform.translationX = translationX;
3803         constraint.transform.translationY = translationY;
3804     }
3805 
3806     /**
3807      * Adjust the translation in Z of a view.
3808      *
3809      * @param viewId       ID of view to adjust
3810      * @param translationZ the translationZ
3811      */
setTranslationZ(int viewId, float translationZ)3812     public void setTranslationZ(int viewId, float translationZ) {
3813         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
3814             get(viewId).transform.translationZ = translationZ;
3815         }
3816     }
3817 
3818     /**
3819      *
3820      */
setEditorAbsoluteX(int viewId, int position)3821     public void setEditorAbsoluteX(int viewId, int position) {
3822         get(viewId).layout.editorAbsoluteX = position;
3823     }
3824 
3825     /**
3826      *
3827      */
setEditorAbsoluteY(int viewId, int position)3828     public void setEditorAbsoluteY(int viewId, int position) {
3829         get(viewId).layout.editorAbsoluteY = position;
3830     }
3831 
3832     /**
3833      * Sets the wrap behavior of the widget in the parent's wrap computation
3834      */
setLayoutWrapBehavior(int viewId, int behavior)3835     public void setLayoutWrapBehavior(int viewId, int behavior) {
3836         if (behavior >= 0 && behavior <= ConstraintWidget.WRAP_BEHAVIOR_SKIPPED) {
3837             get(viewId).layout.mWrapBehavior = behavior;
3838         }
3839     }
3840 
3841     /**
3842      * Sets the height of the view. It can be a dimension, {@link #WRAP_CONTENT} or {@link
3843      * #MATCH_CONSTRAINT}.
3844      *
3845      * @param viewId ID of view to adjust its height
3846      * @param height the height of the view
3847      */
constrainHeight(int viewId, int height)3848     public void constrainHeight(int viewId, int height) {
3849         get(viewId).layout.mHeight = height;
3850     }
3851 
3852     /**
3853      * Sets the width of the view. It can be a dimension, {@link #WRAP_CONTENT} or {@link
3854      * #MATCH_CONSTRAINT}.
3855      *
3856      * @param viewId ID of view to adjust its width
3857      * @param width  the width of the view
3858      */
constrainWidth(int viewId, int width)3859     public void constrainWidth(int viewId, int width) {
3860         get(viewId).layout.mWidth = width;
3861     }
3862 
3863     /**
3864      * Constrain the view on a circle constraint
3865      *
3866      * @param viewId ID of the view we constrain
3867      * @param id     ID of the view we constrain relative to
3868      * @param radius the radius of the circle in degrees
3869      * @param angle  the angle
3870      */
constrainCircle(int viewId, int id, int radius, float angle)3871     public void constrainCircle(int viewId, int id, int radius, float angle) {
3872         Constraint constraint = get(viewId);
3873         constraint.layout.circleConstraint = id;
3874         constraint.layout.circleRadius = radius;
3875         constraint.layout.circleAngle = angle;
3876     }
3877 
3878     /**
3879      * Sets the maximum height of the view. It is a dimension, It is only applicable if height is
3880      * #MATCH_CONSTRAINT}.
3881      *
3882      * @param viewId ID of view to adjust it height
3883      * @param height the maximum height of the constraint
3884      */
constrainMaxHeight(int viewId, int height)3885     public void constrainMaxHeight(int viewId, int height) {
3886         get(viewId).layout.heightMax = height;
3887     }
3888 
3889     /**
3890      * Sets the maximum width of the view. It is a dimension, It is only applicable if width is
3891      * #MATCH_CONSTRAINT}.
3892      *
3893      * @param viewId ID of view to adjust its max height
3894      * @param width  the maximum width of the view
3895      */
constrainMaxWidth(int viewId, int width)3896     public void constrainMaxWidth(int viewId, int width) {
3897         get(viewId).layout.widthMax = width;
3898     }
3899 
3900     /**
3901      * Sets the height of the view. It is a dimension, It is only applicable if height is
3902      * #MATCH_CONSTRAINT}.
3903      *
3904      * @param viewId ID of view to adjust its min height
3905      * @param height the minimum height of the view
3906      */
constrainMinHeight(int viewId, int height)3907     public void constrainMinHeight(int viewId, int height) {
3908         get(viewId).layout.heightMin = height;
3909     }
3910 
3911     /**
3912      * Sets the width of the view.  It is a dimension, It is only applicable if width is
3913      * #MATCH_CONSTRAINT}.
3914      *
3915      * @param viewId ID of view to adjust its min height
3916      * @param width  the minimum width of the view
3917      */
constrainMinWidth(int viewId, int width)3918     public void constrainMinWidth(int viewId, int width) {
3919         get(viewId).layout.widthMin = width;
3920     }
3921 
3922     /**
3923      * Sets the width of the view as a percentage of the parent.
3924      *
3925      * @param viewId
3926      * @param percent
3927      */
constrainPercentWidth(int viewId, float percent)3928     public void constrainPercentWidth(int viewId, float percent) {
3929         get(viewId).layout.widthPercent = percent;
3930     }
3931 
3932     /**
3933      * Sets the height of the view as a percentage of the parent.
3934      *
3935      * @param viewId
3936      * @param percent
3937      */
constrainPercentHeight(int viewId, float percent)3938     public void constrainPercentHeight(int viewId, float percent) {
3939         get(viewId).layout.heightPercent = percent;
3940     }
3941 
3942     /**
3943      * Sets how the height is calculated ether MATCH_CONSTRAINT_WRAP or MATCH_CONSTRAINT_SPREAD.
3944      * Default is spread.
3945      *
3946      * @param viewId ID of view to adjust its matchConstraintDefaultHeight
3947      * @param height MATCH_CONSTRAINT_WRAP or MATCH_CONSTRAINT_SPREAD
3948      */
constrainDefaultHeight(int viewId, int height)3949     public void constrainDefaultHeight(int viewId, int height) {
3950         get(viewId).layout.heightDefault = height;
3951     }
3952 
3953     /**
3954      * Sets how the width is calculated ether MATCH_CONSTRAINT_WRAP or MATCH_CONSTRAINT_SPREAD.
3955      * Default is spread.
3956      *
3957      * @param viewId      ID of view to adjust its matchConstraintDefaultWidth
3958      * @param constrained if true with will be constrained
3959      */
constrainedWidth(int viewId, boolean constrained)3960     public void constrainedWidth(int viewId, boolean constrained) {
3961         get(viewId).layout.constrainedWidth = constrained;
3962     }
3963 
3964     /**
3965      * Sets how the height is calculated ether MATCH_CONSTRAINT_WRAP or MATCH_CONSTRAINT_SPREAD.
3966      * Default is spread.
3967      *
3968      * @param viewId      ID of view to adjust its matchConstraintDefaultHeight
3969      * @param constrained if true height will be constrained
3970      */
constrainedHeight(int viewId, boolean constrained)3971     public void constrainedHeight(int viewId, boolean constrained) {
3972         get(viewId).layout.constrainedHeight = constrained;
3973     }
3974 
3975     /**
3976      * Sets how the width is calculated ether MATCH_CONSTRAINT_WRAP or MATCH_CONSTRAINT_SPREAD.
3977      * Default is spread.
3978      *
3979      * @param viewId ID of view to adjust its matchConstraintDefaultWidth
3980      * @param width  SPREAD or WRAP
3981      */
constrainDefaultWidth(int viewId, int width)3982     public void constrainDefaultWidth(int viewId, int width) {
3983         get(viewId).layout.widthDefault = width;
3984     }
3985 
3986     /**
3987      * The child's weight that we can use to distribute the available horizontal space
3988      * in a chain, if the dimension behaviour is set to MATCH_CONSTRAINT
3989      *
3990      * @param viewId ID of view to adjust its HorizontalWeight
3991      * @param weight the weight that we can use to distribute the horizontal space
3992      */
setHorizontalWeight(int viewId, float weight)3993     public void setHorizontalWeight(int viewId, float weight) {
3994         get(viewId).layout.horizontalWeight = weight;
3995     }
3996 
3997     /**
3998      * The child's weight that we can use to distribute the available vertical space
3999      * in a chain, if the dimension behaviour is set to MATCH_CONSTRAINT
4000      *
4001      * @param viewId ID of view to adjust its VerticalWeight
4002      * @param weight the weight that we can use to distribute the vertical space
4003      */
setVerticalWeight(int viewId, float weight)4004     public void setVerticalWeight(int viewId, float weight) {
4005         get(viewId).layout.verticalWeight = weight;
4006     }
4007 
4008     /**
4009      * How the elements of the horizontal chain will be positioned. if the dimension
4010      * behaviour is set to MATCH_CONSTRAINT. The possible values are:
4011      *
4012      * <ul>
4013      * <li>{@link #CHAIN_SPREAD} -- the elements will be spread out</li>
4014      * <li>{@link #CHAIN_SPREAD_INSIDE} -- similar, but the endpoints of the chain will not
4015      * be spread out</li>
4016      * <li>{@link #CHAIN_PACKED} -- the elements of the chain will be packed together. The
4017      * horizontal bias attribute of the child will then affect the positioning of the packed
4018      * elements</li>
4019      * </ul>
4020      *
4021      * @param viewId     ID of view to adjust its HorizontalChainStyle
4022      * @param chainStyle the weight that we can use to distribute the horizontal space
4023      */
setHorizontalChainStyle(int viewId, int chainStyle)4024     public void setHorizontalChainStyle(int viewId, int chainStyle) {
4025         get(viewId).layout.horizontalChainStyle = chainStyle;
4026     }
4027 
4028     /**
4029      * How the elements of the vertical chain will be positioned. in a chain, if the dimension
4030      * behaviour is set to MATCH_CONSTRAINT
4031      *
4032      * <ul>
4033      * <li>{@link #CHAIN_SPREAD} -- the elements will be spread out</li>
4034      * <li>{@link #CHAIN_SPREAD_INSIDE} -- similar, but the endpoints of the chain will not
4035      * be spread out</li>
4036      * <li>{@link #CHAIN_PACKED} -- the elements of the chain will be packed together. The
4037      * vertical bias attribute of the child will then affect the positioning of the packed
4038      * elements</li>
4039      * </ul>
4040      *
4041      * @param viewId     ID of view to adjust its VerticalChainStyle
4042      * @param chainStyle the weight that we can use to distribute the horizontal space
4043      */
setVerticalChainStyle(int viewId, int chainStyle)4044     public void setVerticalChainStyle(int viewId, int chainStyle) {
4045         get(viewId).layout.verticalChainStyle = chainStyle;
4046     }
4047 
4048     /**
4049      * Adds a view to a horizontal chain.
4050      *
4051      * @param viewId  view to add
4052      * @param leftId  view in chain to the left
4053      * @param rightId view in chain to the right
4054      */
addToHorizontalChain(int viewId, int leftId, int rightId)4055     public void addToHorizontalChain(int viewId, int leftId, int rightId) {
4056         connect(viewId, LEFT, leftId, (leftId == PARENT_ID) ? LEFT : RIGHT, 0);
4057         connect(viewId, RIGHT, rightId, (rightId == PARENT_ID) ? RIGHT : LEFT, 0);
4058         if (leftId != PARENT_ID) {
4059             connect(leftId, RIGHT, viewId, LEFT, 0);
4060         }
4061         if (rightId != PARENT_ID) {
4062             connect(rightId, LEFT, viewId, RIGHT, 0);
4063         }
4064     }
4065 
4066     /**
4067      * Adds a view to a horizontal chain.
4068      *
4069      * @param viewId  view to add
4070      * @param leftId  view to the start side
4071      * @param rightId view to the end side
4072      */
addToHorizontalChainRTL(int viewId, int leftId, int rightId)4073     public void addToHorizontalChainRTL(int viewId, int leftId, int rightId) {
4074         connect(viewId, START, leftId, (leftId == PARENT_ID) ? START : END, 0);
4075         connect(viewId, END, rightId, (rightId == PARENT_ID) ? END : START, 0);
4076         if (leftId != PARENT_ID) {
4077             connect(leftId, END, viewId, START, 0);
4078         }
4079         if (rightId != PARENT_ID) {
4080             connect(rightId, START, viewId, END, 0);
4081         }
4082     }
4083 
4084     /**
4085      * Adds a view to a vertical chain.
4086      *
4087      * @param viewId   view to add to a vertical chain
4088      * @param topId    view above.
4089      * @param bottomId view below
4090      */
addToVerticalChain(int viewId, int topId, int bottomId)4091     public void addToVerticalChain(int viewId, int topId, int bottomId) {
4092         connect(viewId, TOP, topId, (topId == PARENT_ID) ? TOP : BOTTOM, 0);
4093         connect(viewId, BOTTOM, bottomId, (bottomId == PARENT_ID) ? BOTTOM : TOP, 0);
4094         if (topId != PARENT_ID) {
4095             connect(topId, BOTTOM, viewId, TOP, 0);
4096         }
4097         if (bottomId != PARENT_ID) {
4098             connect(bottomId, TOP, viewId, BOTTOM, 0);
4099         }
4100     }
4101 
4102     /**
4103      * Removes a view from a vertical chain.
4104      * This assumes the view is connected to a vertical chain.
4105      * Its behaviour is undefined if not part of a vertical chain.
4106      *
4107      * @param viewId the view to be removed
4108      */
removeFromVerticalChain(int viewId)4109     public void removeFromVerticalChain(int viewId) {
4110         if (mConstraints.containsKey(viewId)) {
4111             Constraint constraint = mConstraints.get(viewId);
4112             if (constraint == null) {
4113                 return;
4114             }
4115             int topId = constraint.layout.topToBottom;
4116             int bottomId = constraint.layout.bottomToTop;
4117             if (topId != Layout.UNSET || bottomId != Layout.UNSET) {
4118                 if (topId != Layout.UNSET && bottomId != Layout.UNSET) {
4119                     // top and bottom connected to views
4120                     connect(topId, BOTTOM, bottomId, TOP, 0);
4121                     connect(bottomId, TOP, topId, BOTTOM, 0);
4122                 } else if (constraint.layout.bottomToBottom != Layout.UNSET) {
4123                     // top connected to view. Bottom connected to parent
4124                     connect(topId, BOTTOM, constraint.layout.bottomToBottom, BOTTOM, 0);
4125                 } else if (constraint.layout.topToTop != Layout.UNSET) {
4126                     // bottom connected to view. Top connected to parent
4127                     connect(bottomId, TOP, constraint.layout.topToTop, TOP, 0);
4128                 }
4129             }
4130         }
4131         clear(viewId, TOP);
4132         clear(viewId, BOTTOM);
4133     }
4134 
4135     /**
4136      * Removes a view from a horizontal chain.
4137      * This assumes the view is connected to a horizontal chain.
4138      * Its behaviour is undefined if not part of a horizontal chain.
4139      *
4140      * @param viewId the view to be removed
4141      */
removeFromHorizontalChain(int viewId)4142     public void removeFromHorizontalChain(int viewId) {
4143         if (mConstraints.containsKey(viewId)) {
4144             Constraint constraint = mConstraints.get(viewId);
4145             if (constraint == null) {
4146                 return;
4147             }
4148             int leftId = constraint.layout.leftToRight;
4149             int rightId = constraint.layout.rightToLeft;
4150             if (leftId != Layout.UNSET || rightId != Layout.UNSET) {
4151                 if (leftId != Layout.UNSET && rightId != Layout.UNSET) {
4152                     // left and right connected to views
4153                     connect(leftId, RIGHT, rightId, LEFT, 0);
4154                     connect(rightId, LEFT, leftId, RIGHT, 0);
4155                 } else if (constraint.layout.rightToRight != Layout.UNSET) {
4156                     // left connected to view. right connected to parent
4157                     connect(leftId, RIGHT, constraint.layout.rightToRight, RIGHT, 0);
4158                 } else if (constraint.layout.leftToLeft != Layout.UNSET) {
4159                     // right connected to view. left connected to parent
4160                     connect(rightId, LEFT, constraint.layout.leftToLeft, LEFT, 0);
4161                 }
4162                 clear(viewId, LEFT);
4163                 clear(viewId, RIGHT);
4164             } else {
4165 
4166                 int startId = constraint.layout.startToEnd;
4167                 int endId = constraint.layout.endToStart;
4168                 if (startId != Layout.UNSET || endId != Layout.UNSET) {
4169                     if (startId != Layout.UNSET && endId != Layout.UNSET) {
4170                         // start and end connected to views
4171                         connect(startId, END, endId, START, 0);
4172                         connect(endId, START, leftId, END, 0);
4173                     } else if (endId != Layout.UNSET) {
4174                         if (constraint.layout.rightToRight != Layout.UNSET) {
4175                             // left connected to view. right connected to parent
4176                             connect(leftId, END, constraint.layout.rightToRight, END, 0);
4177                         } else if (constraint.layout.leftToLeft != Layout.UNSET) {
4178                             // right connected to view. left connected to parent
4179                             connect(endId, START, constraint.layout.leftToLeft, START, 0);
4180                         }
4181                     }
4182                 }
4183                 clear(viewId, START);
4184                 clear(viewId, END);
4185             }
4186         }
4187     }
4188 
4189     /**
4190      * Creates a ConstraintLayout virtual object. Currently only horizontal or vertical GuideLines.
4191      *
4192      * @param guidelineID ID of guideline to create
4193      * @param orientation the Orientation of the guideline
4194      */
create(int guidelineID, int orientation)4195     public void create(int guidelineID, int orientation) {
4196         Constraint constraint = get(guidelineID);
4197         constraint.layout.mIsGuideline = true;
4198         constraint.layout.orientation = orientation;
4199     }
4200 
4201     /**
4202      * Creates a ConstraintLayout Barrier object.
4203      *
4204      * @param id         the id of the constraint to create or partially overwrite.
4205      * @param direction  Barrier.{LEFT,RIGHT,TOP,BOTTOM,START,END}
4206      * @param margin     the barrierMargin of the Barrier object
4207      * @param referenced the referenceIds of the Barrier object
4208      */
createBarrier(int id, int direction, int margin, int... referenced)4209     public void createBarrier(int id, int direction, int margin, int... referenced) {
4210         Constraint constraint = get(id);
4211         constraint.layout.mHelperType = BARRIER_TYPE;
4212         constraint.layout.mBarrierDirection = direction;
4213         constraint.layout.mBarrierMargin = margin;
4214         constraint.layout.mIsGuideline = false;
4215         constraint.layout.mReferenceIds = referenced;
4216     }
4217 
4218     /**
4219      * Set the guideline's distance from the top or left edge.
4220      *
4221      * @param guidelineID ID of the guideline
4222      * @param margin      the distance to the top or left edge
4223      */
setGuidelineBegin(int guidelineID, int margin)4224     public void setGuidelineBegin(int guidelineID, int margin) {
4225         get(guidelineID).layout.guideBegin = margin;
4226         get(guidelineID).layout.guideEnd = Layout.UNSET;
4227         get(guidelineID).layout.guidePercent = Layout.UNSET;
4228 
4229     }
4230 
4231     /**
4232      * Set a guideline's distance to end.
4233      *
4234      * @param guidelineID ID of the guideline
4235      * @param margin      the margin to the right or bottom side of container
4236      */
setGuidelineEnd(int guidelineID, int margin)4237     public void setGuidelineEnd(int guidelineID, int margin) {
4238         get(guidelineID).layout.guideEnd = margin;
4239         get(guidelineID).layout.guideBegin = Layout.UNSET;
4240         get(guidelineID).layout.guidePercent = Layout.UNSET;
4241     }
4242 
4243     /**
4244      * Set a Guideline's percent.
4245      *
4246      * @param guidelineID ID of the guideline
4247      * @param ratio       the ratio between the gap on the left and right
4248      *                   0.0 is top/left 0.5 is middle
4249      */
setGuidelinePercent(int guidelineID, float ratio)4250     public void setGuidelinePercent(int guidelineID, float ratio) {
4251         get(guidelineID).layout.guidePercent = ratio;
4252         get(guidelineID).layout.guideEnd = Layout.UNSET;
4253         get(guidelineID).layout.guideBegin = Layout.UNSET;
4254     }
4255 
4256     /**
4257      * get the reference id's of a helper.
4258      *
4259      * @param id
4260      * @return array of id's
4261      */
getReferencedIds(int id)4262     public int[] getReferencedIds(int id) {
4263         Constraint constraint = get(id);
4264         if (constraint.layout.mReferenceIds == null) {
4265             return new int[0];
4266         }
4267         return Arrays.copyOf(constraint.layout.mReferenceIds,
4268                 constraint.layout.mReferenceIds.length);
4269     }
4270 
4271     /**
4272      * sets the reference id's of a barrier.
4273      *
4274      * @param id
4275      * @param referenced
4276      */
setReferencedIds(int id, int... referenced)4277     public void setReferencedIds(int id, int... referenced) {
4278         Constraint constraint = get(id);
4279         constraint.layout.mReferenceIds = referenced;
4280     }
4281 
4282     /**
4283      * SEt tye type of barier
4284      * @param id
4285      * @param type
4286      */
setBarrierType(int id, int type)4287     public void setBarrierType(int id, int type) {
4288         Constraint constraint = get(id);
4289         constraint.layout.mHelperType = type;
4290     }
4291 
4292     /**
4293      * Remove the attribute
4294      * @param attributeName
4295      */
removeAttribute(String attributeName)4296     public void removeAttribute(String attributeName) {
4297         mSavedAttributes.remove(attributeName);
4298     }
4299 
4300     /**
4301      * Set the value of an attribute of type int
4302      * @param viewId
4303      * @param attributeName
4304      * @param value
4305      */
setIntValue(int viewId, String attributeName, int value)4306     public void setIntValue(int viewId, String attributeName, int value) {
4307         get(viewId).setIntValue(attributeName, value);
4308     }
4309 
4310     /**
4311      * Set the value of an attribute of type color
4312      * @param viewId
4313      * @param attributeName
4314      * @param value
4315      */
setColorValue(int viewId, String attributeName, int value)4316     public void setColorValue(int viewId, String attributeName, int value) {
4317         get(viewId).setColorValue(attributeName, value);
4318     }
4319 
4320     /**
4321      * Set the value of an attribute of type float
4322      * @param viewId
4323      * @param attributeName
4324      * @param value
4325      */
setFloatValue(int viewId, String attributeName, float value)4326     public void setFloatValue(int viewId, String attributeName, float value) {
4327         get(viewId).setFloatValue(attributeName, value);
4328     }
4329 
4330     /**
4331      * Set the value of an attribute of type string
4332      * @param viewId
4333      * @param attributeName
4334      * @param value
4335      */
setStringValue(int viewId, String attributeName, String value)4336     public void setStringValue(int viewId, String attributeName, String value) {
4337         get(viewId).setStringValue(attributeName, value);
4338     }
4339 
addAttributes(AttributeType attributeType, String... attributeName)4340     private void addAttributes(AttributeType attributeType, String... attributeName) {
4341         ConstraintAttribute constraintAttribute = null;
4342         for (int i = 0; i < attributeName.length; i++) {
4343             if (mSavedAttributes.containsKey(attributeName[i])) {
4344                 constraintAttribute = mSavedAttributes.get(attributeName[i]);
4345                 if (constraintAttribute == null) {
4346                     continue;
4347                 }
4348                 if (constraintAttribute.getType() != attributeType) {
4349                     throw new IllegalArgumentException(
4350                             "ConstraintAttribute is already a "
4351                                     + constraintAttribute.getType().name());
4352                 }
4353             } else {
4354                 constraintAttribute = new ConstraintAttribute(attributeName[i], attributeType);
4355                 mSavedAttributes.put(attributeName[i], constraintAttribute);
4356             }
4357         }
4358     }
4359 
4360     /**
4361      * Parse int
4362      * @param set
4363      * @param attributes
4364      */
parseIntAttributes(Constraint set, String attributes)4365     public void parseIntAttributes(Constraint set, String attributes) {
4366         String[] sp = attributes.split(",");
4367         for (int i = 0; i < sp.length; i++) {
4368             String[] attr = sp[i].split("=");
4369             if (attr.length != 2) {
4370                 Log.w(TAG, " Unable to parse " + sp[i]);
4371             } else {
4372                 set.setFloatValue(attr[0], Integer.decode(attr[1]));
4373             }
4374         }
4375     }
4376 
4377     /**
4378      * Parse color
4379      * @param set
4380      * @param attributes
4381      */
parseColorAttributes(Constraint set, String attributes)4382     public void parseColorAttributes(Constraint set, String attributes) {
4383         String[] sp = attributes.split(",");
4384         for (int i = 0; i < sp.length; i++) {
4385             String[] attr = sp[i].split("=");
4386             if (attr.length != 2) {
4387                 Log.w(TAG, " Unable to parse " + sp[i]);
4388             } else {
4389                 set.setColorValue(attr[0], Color.parseColor(attr[1]));
4390             }
4391         }
4392     }
4393 
4394     /**
4395      * Parse floats
4396      * @param set
4397      * @param attributes
4398      */
parseFloatAttributes(Constraint set, String attributes)4399     public void parseFloatAttributes(Constraint set, String attributes) {
4400         String[] sp = attributes.split(",");
4401         for (int i = 0; i < sp.length; i++) {
4402             String[] attr = sp[i].split("=");
4403             if (attr.length != 2) {
4404                 Log.w(TAG, " Unable to parse " + sp[i]);
4405             } else {
4406                 set.setFloatValue(attr[0], Float.parseFloat(attr[1]));
4407             }
4408         }
4409     }
4410 
4411     /**
4412      * Parse string
4413      * @param set
4414      * @param attributes
4415      */
parseStringAttributes(Constraint set, String attributes)4416     public void parseStringAttributes(Constraint set, String attributes) {
4417         String[] sp = splitString(attributes);
4418         for (int i = 0; i < sp.length; i++) {
4419             String[] attr = sp[i].split("=");
4420             Log.w(TAG, " Unable to parse " + sp[i]);
4421             set.setStringValue(attr[0], attr[1]);
4422         }
4423     }
4424 
splitString(String str)4425     private static String[] splitString(String str) {
4426         char[] chars = str.toCharArray();
4427         ArrayList<String> list = new ArrayList<>();
4428         boolean inDouble = false;
4429         int start = 0;
4430         for (int i = 0; i < chars.length; i++) {
4431             if (chars[i] == ',' && !inDouble) {
4432                 list.add(new String(chars, start, i - start));
4433                 start = i + 1;
4434             } else if (chars[i] == '"') {
4435                 inDouble = !inDouble;
4436             }
4437         }
4438         list.add(new String(chars, start, chars.length - start));
4439         return list.toArray(new String[list.size()]);
4440     }
4441 
4442     /**
4443      * Add attribute of type Int
4444      * @param attributeName
4445      */
addIntAttributes(String... attributeName)4446     public void addIntAttributes(String... attributeName) {
4447         addAttributes(AttributeType.INT_TYPE, attributeName);
4448     }
4449 
4450     /**
4451      * Add attribute of type Color
4452      * @param attributeName
4453      */
addColorAttributes(String... attributeName)4454     public void addColorAttributes(String... attributeName) {
4455         addAttributes(AttributeType.COLOR_TYPE, attributeName);
4456     }
4457 
4458     /**
4459      * Add attribute of type float
4460      * @param attributeName
4461      */
addFloatAttributes(String... attributeName)4462     public void addFloatAttributes(String... attributeName) {
4463         addAttributes(AttributeType.FLOAT_TYPE, attributeName);
4464     }
4465 
4466     /**
4467      * Add attribute of type string
4468      * @param attributeName
4469      */
addStringAttributes(String... attributeName)4470     public void addStringAttributes(String... attributeName) {
4471         addAttributes(AttributeType.STRING_TYPE, attributeName);
4472     }
4473 
get(int id)4474     private Constraint get(int id) {
4475         if (!mConstraints.containsKey(id)) {
4476             mConstraints.put(id, new Constraint());
4477         }
4478         return mConstraints.get(id);
4479     }
4480 
sideToString(int side)4481     private String sideToString(int side) {
4482         switch (side) {
4483             case LEFT:
4484                 return "left";
4485             case RIGHT:
4486                 return "right";
4487             case TOP:
4488                 return "top";
4489             case BOTTOM:
4490                 return "bottom";
4491             case BASELINE:
4492                 return "baseline";
4493             case START:
4494                 return "start";
4495             case END:
4496                 return "end";
4497         }
4498         return "undefined";
4499     }
4500 
4501     /**
4502      * Load a constraint set from a constraintSet.xml file.
4503      * Note. Do NOT use this to load a layout file.
4504      * It will fail silently as there is no efficient way to differentiate.
4505      *
4506      * @param context    the context for the inflation
4507      * @param resourceId id of xml file in res/xml/
4508      */
load(Context context, int resourceId)4509     public void load(Context context, int resourceId) {
4510         Resources res = context.getResources();
4511         XmlPullParser parser = res.getXml(resourceId);
4512         try {
4513             for (int eventType = parser.getEventType();
4514                     eventType != XmlResourceParser.END_DOCUMENT;
4515                     eventType = parser.next()) {
4516                 switch (eventType) {
4517                     case XmlResourceParser.START_DOCUMENT:
4518                     case XmlResourceParser.END_TAG:
4519                     case XmlResourceParser.TEXT:
4520                         break;
4521                     case XmlResourceParser.START_TAG:
4522                         String tagName = parser.getName();
4523                         Constraint constraint = fillFromAttributeList(context,
4524                                 Xml.asAttributeSet(parser), false);
4525                         if (tagName.equalsIgnoreCase("Guideline")) {
4526                             constraint.layout.mIsGuideline = true;
4527                         }
4528                         if (DEBUG) {
4529                             Log.v(TAG, Debug.getLoc()
4530                                     + " cache " + Debug.getName(context, constraint.mViewId)
4531                                     + " " + constraint.mViewId);
4532                         }
4533                         mConstraints.put(constraint.mViewId, constraint);
4534                         break;
4535                 }
4536             }
4537         } catch (XmlPullParserException e) {
4538             Log.e(TAG, "Error parsing resource: " + resourceId, e);
4539         } catch (IOException e) {
4540             Log.e(TAG, "Error parsing resource: " + resourceId, e);
4541         }
4542     }
4543 
4544     /**
4545      * Load a constraint set from a constraintSet.xml file
4546      *
4547      * @param context the context for the inflation
4548      * @param parser  id of xml file in res/xml/
4549      */
load(Context context, XmlPullParser parser)4550     public void load(Context context, XmlPullParser parser) {
4551         String tagName = null;
4552         try {
4553             Constraint constraint = null;
4554             for (int eventType = parser.getEventType();
4555                     eventType != XmlResourceParser.END_DOCUMENT;
4556                     eventType = parser.next()) {
4557                 switch (eventType) {
4558                     case XmlResourceParser.START_DOCUMENT:
4559                         String document = parser.getName();
4560                         break;
4561                     case XmlResourceParser.START_TAG:
4562                         tagName = parser.getName();
4563                         if (DEBUG) {
4564                             Log.v(TAG, Debug.getLoc() + " " + document + " tagName=" + tagName);
4565                         }
4566                         switch (tagName) {
4567                             case "Constraint":
4568                                 constraint = fillFromAttributeList(context,
4569                                         Xml.asAttributeSet(parser), false);
4570                                 break;
4571                             case "ConstraintOverride":
4572                                 constraint = fillFromAttributeList(context,
4573                                         Xml.asAttributeSet(parser), true);
4574                                 break;
4575                             case "Guideline":
4576                                 constraint = fillFromAttributeList(context,
4577                                         Xml.asAttributeSet(parser), false);
4578                                 constraint.layout.mIsGuideline = true;
4579                                 constraint.layout.mApply = true;
4580                                 break;
4581                             case "Barrier":
4582                                 constraint = fillFromAttributeList(context,
4583                                         Xml.asAttributeSet(parser), false);
4584                                 constraint.layout.mHelperType = BARRIER_TYPE;
4585                                 break;
4586                             case "PropertySet":
4587                                 if (constraint == null) {
4588                                     throw new RuntimeException(ERROR_MESSAGE
4589                                             + parser.getLineNumber());
4590                                 }
4591                                 constraint.propertySet.fillFromAttributeList(context,
4592                                         Xml.asAttributeSet(parser));
4593                                 break;
4594                             case "Transform":
4595                                 if (constraint == null) {
4596                                     throw new RuntimeException(ERROR_MESSAGE
4597                                             + parser.getLineNumber());
4598                                 }
4599                                 constraint.transform.fillFromAttributeList(context,
4600                                         Xml.asAttributeSet(parser));
4601                                 break;
4602                             case "Layout":
4603                                 if (constraint == null) {
4604                                     throw new RuntimeException(ERROR_MESSAGE
4605                                             + parser.getLineNumber());
4606                                 }
4607                                 constraint.layout.fillFromAttributeList(context,
4608                                         Xml.asAttributeSet(parser));
4609                                 break;
4610                             case "Motion":
4611                                 if (constraint == null) {
4612                                     throw new RuntimeException(ERROR_MESSAGE
4613                                             + parser.getLineNumber());
4614                                 }
4615                                 constraint.motion.fillFromAttributeList(context,
4616                                         Xml.asAttributeSet(parser));
4617                                 break;
4618                             case "CustomAttribute":
4619                             case "CustomMethod":
4620                                 if (constraint == null) {
4621                                     throw new RuntimeException(ERROR_MESSAGE
4622                                             + parser.getLineNumber());
4623                                 }
4624                                 ConstraintAttribute.parse(context, parser,
4625                                         constraint.mCustomConstraints);
4626                                 break;
4627                         }
4628 //                        if (tagName.equalsIgnoreCase("Constraint")) {
4629 //                            constraint = fillFromAttributeList(context,
4630 //                            Xml.asAttributeSet(parser));
4631 //                        } else if (tagName.equalsIgnoreCase("Guideline")) {
4632 //                            constraint = fillFromAttributeList(context,
4633 //                            Xml.asAttributeSet(parser));
4634 //                            constraint.layout.mIsGuideline = true;
4635 //                        } else if (tagName.equalsIgnoreCase("CustomAttribute")) {
4636 //                            ConstraintAttribute.parse(context, parser,
4637 //                            constraint.mCustomConstraints);
4638 //                        }
4639                         break;
4640                     case XmlResourceParser.END_TAG:
4641                         tagName = parser.getName();
4642                         switch (tagName.toLowerCase(Locale.ROOT)) {
4643                             case "constraintset":
4644                                 return;
4645                             case "constraint":
4646                             case "constraintoverride":
4647                             case "guideline":
4648                                 mConstraints.put(constraint.mViewId, constraint);
4649                                 constraint = null;
4650                         }
4651                         tagName = null;
4652                         break;
4653                     case XmlResourceParser.TEXT:
4654                         break;
4655                 }
4656             }
4657         } catch (XmlPullParserException e) {
4658             Log.e(TAG, "Error parsing XML resource", e);
4659         } catch (IOException e) {
4660             Log.e(TAG, "Error parsing XML resource", e);
4661         }
4662     }
4663 
lookupID(TypedArray a, int index, int def)4664     private static int lookupID(TypedArray a, int index, int def) {
4665         int ret = a.getResourceId(index, def);
4666         if (ret == Layout.UNSET) {
4667             ret = a.getInt(index, Layout.UNSET);
4668         }
4669         return ret;
4670     }
4671 
fillFromAttributeList(Context context, AttributeSet attrs, boolean override)4672     private Constraint fillFromAttributeList(Context context,
4673                                              AttributeSet attrs,
4674                                              boolean override) {
4675         Constraint c = new Constraint();
4676         TypedArray a = context.obtainStyledAttributes(attrs,
4677                 override ? R.styleable.ConstraintOverride : R.styleable.Constraint);
4678         populateConstraint(c, a, override);
4679         a.recycle();
4680         return c;
4681     }
4682 
4683     /**
4684      * Used to read a ConstraintDelta
4685      *
4686      * @param context
4687      * @param parser
4688      * @return
4689      */
buildDelta(Context context, XmlPullParser parser)4690     public static Constraint buildDelta(Context context, XmlPullParser parser) {
4691         AttributeSet attrs = Xml.asAttributeSet(parser);
4692         Constraint c = new Constraint();
4693         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ConstraintOverride);
4694         populateOverride(c, a);
4695         a.recycle();
4696         return c;
4697     }
4698 
populateOverride(Constraint c, TypedArray a)4699     private static void populateOverride(Constraint c, TypedArray a) {
4700 
4701         final int count = a.getIndexCount();
4702         TypedValue type;
4703         Constraint.Delta delta = new Constraint.Delta();
4704         c.mDelta = delta;
4705         c.motion.mApply = false;
4706         c.layout.mApply = false;
4707         c.propertySet.mApply = false;
4708         c.transform.mApply = false;
4709         for (int i = 0; i < count; i++) {
4710             int attr = a.getIndex(i);
4711 
4712 
4713             int attrType = sOverrideMapToConstant.get(attr);
4714             if (DEBUG) {
4715                 Log.v(TAG, Debug.getLoc() + " > " + attrType + " " + getDebugName(attrType));
4716             }
4717 
4718             switch (attrType) {
4719 
4720                 case EDITOR_ABSOLUTE_X:
4721                     delta.add(EDITOR_ABSOLUTE_X,
4722                             a.getDimensionPixelOffset(attr, c.layout.editorAbsoluteX));
4723                     break;
4724                 case EDITOR_ABSOLUTE_Y:
4725                     delta.add(EDITOR_ABSOLUTE_Y,
4726                             a.getDimensionPixelOffset(attr, c.layout.editorAbsoluteY));
4727                     break;
4728                 case GUIDE_BEGIN:
4729                     delta.add(GUIDE_BEGIN, a.getDimensionPixelOffset(attr, c.layout.guideBegin));
4730                     break;
4731                 case GUIDE_END:
4732                     delta.add(GUIDE_END, a.getDimensionPixelOffset(attr, c.layout.guideEnd));
4733                     break;
4734                 case GUIDE_PERCENT:
4735                     delta.add(GUIDE_PERCENT, a.getFloat(attr, c.layout.guidePercent));
4736                     break;
4737                 case GUIDELINE_USE_RTL:
4738                     delta.add(GUIDELINE_USE_RTL, a.getBoolean(attr, c.layout.guidelineUseRtl));
4739                     break;
4740                 case ORIENTATION:
4741                     delta.add(ORIENTATION, a.getInt(attr, c.layout.orientation));
4742                     break;
4743                 case CIRCLE_RADIUS:
4744                     delta.add(CIRCLE_RADIUS, a.getDimensionPixelSize(attr, c.layout.circleRadius));
4745                     break;
4746                 case CIRCLE_ANGLE:
4747                     delta.add(CIRCLE_ANGLE, a.getFloat(attr, c.layout.circleAngle));
4748                     break;
4749                 case GONE_LEFT_MARGIN:
4750                     delta.add(GONE_LEFT_MARGIN,
4751                             a.getDimensionPixelSize(attr, c.layout.goneLeftMargin));
4752                     break;
4753                 case GONE_TOP_MARGIN:
4754                     delta.add(GONE_TOP_MARGIN,
4755                             a.getDimensionPixelSize(attr, c.layout.goneTopMargin));
4756                     break;
4757                 case GONE_RIGHT_MARGIN:
4758                     delta.add(GONE_RIGHT_MARGIN,
4759                             a.getDimensionPixelSize(attr, c.layout.goneRightMargin));
4760                     break;
4761                 case GONE_BOTTOM_MARGIN:
4762                     delta.add(GONE_BOTTOM_MARGIN,
4763                             a.getDimensionPixelSize(attr, c.layout.goneBottomMargin));
4764                     break;
4765                 case GONE_START_MARGIN:
4766                     delta.add(GONE_START_MARGIN,
4767                             a.getDimensionPixelSize(attr, c.layout.goneStartMargin));
4768                     break;
4769                 case GONE_END_MARGIN:
4770                     delta.add(GONE_END_MARGIN,
4771                             a.getDimensionPixelSize(attr, c.layout.goneEndMargin));
4772                     break;
4773                 case GONE_BASELINE_MARGIN:
4774                     delta.add(GONE_BASELINE_MARGIN,
4775                             a.getDimensionPixelSize(attr, c.layout.goneBaselineMargin));
4776                     break;
4777                 case HORIZONTAL_BIAS:
4778                     delta.add(HORIZONTAL_BIAS, a.getFloat(attr, c.layout.horizontalBias));
4779                     break;
4780                 case VERTICAL_BIAS:
4781                     delta.add(VERTICAL_BIAS, a.getFloat(attr, c.layout.verticalBias));
4782                     break;
4783                 case LEFT_MARGIN:
4784                     delta.add(LEFT_MARGIN, a.getDimensionPixelSize(attr, c.layout.leftMargin));
4785                     break;
4786                 case RIGHT_MARGIN:
4787                     delta.add(RIGHT_MARGIN, a.getDimensionPixelSize(attr, c.layout.rightMargin));
4788                     break;
4789                 case START_MARGIN:
4790                     delta.add(START_MARGIN,
4791                             a.getDimensionPixelSize(attr, c.layout.startMargin));
4792                     break;
4793                 case END_MARGIN:
4794                     delta.add(END_MARGIN, a.getDimensionPixelSize(attr, c.layout.endMargin));
4795                     break;
4796                 case TOP_MARGIN:
4797                     delta.add(TOP_MARGIN, a.getDimensionPixelSize(attr, c.layout.topMargin));
4798                     break;
4799                 case BOTTOM_MARGIN:
4800                     delta.add(BOTTOM_MARGIN, a.getDimensionPixelSize(attr, c.layout.bottomMargin));
4801                     break;
4802                 case BASELINE_MARGIN:
4803                     delta.add(BASELINE_MARGIN,
4804                             a.getDimensionPixelSize(attr, c.layout.baselineMargin));
4805                     break;
4806                 case LAYOUT_WIDTH:
4807                     delta.add(LAYOUT_WIDTH, a.getLayoutDimension(attr, c.layout.mWidth));
4808                     break;
4809                 case LAYOUT_HEIGHT:
4810                     delta.add(LAYOUT_HEIGHT, a.getLayoutDimension(attr, c.layout.mHeight));
4811                     break;
4812                 case LAYOUT_CONSTRAINT_WIDTH:
4813                     ConstraintSet.parseDimensionConstraints(delta, a, attr, HORIZONTAL);
4814                     break;
4815                 case LAYOUT_CONSTRAINT_HEIGHT:
4816                     ConstraintSet.parseDimensionConstraints(delta, a, attr, VERTICAL);
4817                     break;
4818                 case LAYOUT_WRAP_BEHAVIOR:
4819                     delta.add(LAYOUT_WRAP_BEHAVIOR, a.getInt(attr, c.layout.mWrapBehavior));
4820                     break;
4821                 case WIDTH_DEFAULT:
4822                     delta.add(WIDTH_DEFAULT, a.getInt(attr, c.layout.widthDefault));
4823                     break;
4824                 case HEIGHT_DEFAULT:
4825                     delta.add(HEIGHT_DEFAULT, a.getInt(attr, c.layout.heightDefault));
4826                     break;
4827                 case HEIGHT_MAX:
4828                     delta.add(HEIGHT_MAX, a.getDimensionPixelSize(attr, c.layout.heightMax));
4829                     break;
4830                 case WIDTH_MAX:
4831                     delta.add(WIDTH_MAX, a.getDimensionPixelSize(attr, c.layout.widthMax));
4832                     break;
4833                 case HEIGHT_MIN:
4834                     delta.add(HEIGHT_MIN, a.getDimensionPixelSize(attr, c.layout.heightMin));
4835                     break;
4836                 case WIDTH_MIN:
4837                     delta.add(WIDTH_MIN, a.getDimensionPixelSize(attr, c.layout.widthMin));
4838                     break;
4839                 case CONSTRAINED_WIDTH:
4840                     delta.add(CONSTRAINED_WIDTH, a.getBoolean(attr, c.layout.constrainedWidth));
4841                     break;
4842                 case CONSTRAINED_HEIGHT:
4843                     delta.add(CONSTRAINED_HEIGHT, a.getBoolean(attr, c.layout.constrainedHeight));
4844                     break;
4845                 case LAYOUT_VISIBILITY:
4846                     delta.add(LAYOUT_VISIBILITY,
4847                             VISIBILITY_FLAGS[a.getInt(attr, c.propertySet.visibility)]);
4848                     break;
4849                 case VISIBILITY_MODE:
4850                     delta.add(VISIBILITY_MODE, a.getInt(attr, c.propertySet.mVisibilityMode));
4851                     break;
4852                 case ALPHA:
4853                     delta.add(ALPHA, a.getFloat(attr, c.propertySet.alpha));
4854                     break;
4855                 case ELEVATION:
4856                     if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
4857                         delta.add(ELEVATION, true);
4858                         delta.add(ELEVATION, a.getDimension(attr, c.transform.elevation));
4859                     }
4860                     break;
4861                 case ROTATION:
4862                     delta.add(ROTATION, a.getFloat(attr, c.transform.rotation));
4863                     break;
4864                 case ROTATION_X:
4865                     delta.add(ROTATION_X, a.getFloat(attr, c.transform.rotationX));
4866                     break;
4867                 case ROTATION_Y:
4868                     delta.add(ROTATION_Y, a.getFloat(attr, c.transform.rotationY));
4869                     break;
4870                 case SCALE_X:
4871                     delta.add(SCALE_X, a.getFloat(attr, c.transform.scaleX));
4872                     break;
4873                 case SCALE_Y:
4874                     delta.add(SCALE_Y, a.getFloat(attr, c.transform.scaleY));
4875                     break;
4876                 case TRANSFORM_PIVOT_X:
4877                     delta.add(TRANSFORM_PIVOT_X, a.getDimension(attr, c.transform.transformPivotX));
4878                     break;
4879                 case TRANSFORM_PIVOT_Y:
4880                     delta.add(TRANSFORM_PIVOT_Y, a.getDimension(attr, c.transform.transformPivotY));
4881                     break;
4882                 case TRANSLATION_X:
4883                     delta.add(TRANSLATION_X, a.getDimension(attr, c.transform.translationX));
4884                     break;
4885                 case TRANSLATION_Y:
4886                     delta.add(TRANSLATION_Y, a.getDimension(attr, c.transform.translationY));
4887                     break;
4888                 case TRANSLATION_Z:
4889                     if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
4890                         delta.add(TRANSLATION_Z, a.getDimension(attr, c.transform.translationZ));
4891                     }
4892                     break;
4893                 case TRANSFORM_PIVOT_TARGET:
4894                     delta.add(TRANSFORM_PIVOT_TARGET,
4895                             lookupID(a, attr, c.transform.transformPivotTarget));
4896                     break;
4897                 case VERTICAL_WEIGHT:
4898                     delta.add(VERTICAL_WEIGHT, a.getFloat(attr, c.layout.verticalWeight));
4899                     break;
4900                 case HORIZONTAL_WEIGHT:
4901                     delta.add(HORIZONTAL_WEIGHT, a.getFloat(attr, c.layout.horizontalWeight));
4902                     break;
4903                 case VERTICAL_STYLE:
4904                     delta.add(VERTICAL_STYLE, a.getInt(attr, c.layout.verticalChainStyle));
4905                     break;
4906                 case HORIZONTAL_STYLE:
4907                     delta.add(HORIZONTAL_STYLE, a.getInt(attr, c.layout.horizontalChainStyle));
4908                     break;
4909                 case VIEW_ID:
4910                     c.mViewId = a.getResourceId(attr, c.mViewId);
4911                     delta.add(VIEW_ID, c.mViewId);
4912                     break;
4913                 case MOTION_TARGET:
4914                     if (MotionLayout.IS_IN_EDIT_MODE) {
4915                         c.mViewId = a.getResourceId(attr, c.mViewId);
4916                         if (c.mViewId == -1) {
4917                             c.mTargetString = a.getString(attr);
4918                         }
4919                     } else {
4920                         if (a.peekValue(attr).type == TypedValue.TYPE_STRING) {
4921                             c.mTargetString = a.getString(attr);
4922                         } else {
4923                             c.mViewId = a.getResourceId(attr, c.mViewId);
4924                         }
4925                     }
4926                     break;
4927                 case DIMENSION_RATIO:
4928                     delta.add(DIMENSION_RATIO, a.getString(attr));
4929                     break;
4930                 case WIDTH_PERCENT:
4931                     delta.add(WIDTH_PERCENT, a.getFloat(attr, 1));
4932                     break;
4933                 case HEIGHT_PERCENT:
4934                     delta.add(HEIGHT_PERCENT, a.getFloat(attr, 1));
4935                     break;
4936                 case PROGRESS:
4937                     delta.add(PROGRESS, a.getFloat(attr, c.propertySet.mProgress));
4938                     break;
4939                 case ANIMATE_RELATIVE_TO:
4940                     delta.add(ANIMATE_RELATIVE_TO,
4941                             lookupID(a, attr, c.motion.mAnimateRelativeTo));
4942                     break;
4943                 case ANIMATE_CIRCLE_ANGLE_TO:
4944                     delta.add(ANIMATE_CIRCLE_ANGLE_TO,
4945                             a.getInteger(attr, c.motion.mAnimateCircleAngleTo));
4946                     break;
4947                 case TRANSITION_EASING:
4948                     type = a.peekValue(attr);
4949                     if (type.type == TypedValue.TYPE_STRING) {
4950                         delta.add(TRANSITION_EASING, a.getString(attr));
4951                     } else {
4952                         delta.add(TRANSITION_EASING,
4953                                 Easing.NAMED_EASING[a.getInteger(attr, 0)]);
4954                     }
4955                     break;
4956                 case PATH_MOTION_ARC:
4957                     delta.add(PATH_MOTION_ARC, a.getInt(attr, c.motion.mPathMotionArc));
4958                     break;
4959                 case TRANSITION_PATH_ROTATE:
4960                     delta.add(TRANSITION_PATH_ROTATE, a.getFloat(attr, c.motion.mPathRotate));
4961                     break;
4962                 case MOTION_STAGGER:
4963                     delta.add(MOTION_STAGGER, a.getFloat(attr, c.motion.mMotionStagger));
4964                     break;
4965 
4966                 case QUANTIZE_MOTION_STEPS:
4967                     delta.add(QUANTIZE_MOTION_STEPS, a.getInteger(attr,
4968                             c.motion.mQuantizeMotionSteps));
4969                     break;
4970                 case QUANTIZE_MOTION_PHASE:
4971                     delta.add(QUANTIZE_MOTION_PHASE, a.getFloat(attr,
4972                             c.motion.mQuantizeMotionPhase));
4973                     break;
4974                 case QUANTIZE_MOTION_INTERPOLATOR:
4975                     type = a.peekValue(attr);
4976                     if (type.type == TypedValue.TYPE_REFERENCE) {
4977                         c.motion.mQuantizeInterpolatorID = a.getResourceId(attr, -1);
4978                         delta.add(QUANTIZE_MOTION_INTERPOLATOR_ID,
4979                                 c.motion.mQuantizeInterpolatorID);
4980                         if (c.motion.mQuantizeInterpolatorID != -1) {
4981                             c.motion.mQuantizeInterpolatorType = Motion.INTERPOLATOR_REFERENCE_ID;
4982                             delta.add(QUANTIZE_MOTION_INTERPOLATOR_TYPE,
4983                                     c.motion.mQuantizeInterpolatorType);
4984                         }
4985                     } else if (type.type == TypedValue.TYPE_STRING) {
4986                         c.motion.mQuantizeInterpolatorString = a.getString(attr);
4987                         delta.add(QUANTIZE_MOTION_INTERPOLATOR_STR,
4988                                 c.motion.mQuantizeInterpolatorString);
4989 
4990                         if (c.motion.mQuantizeInterpolatorString.indexOf("/") > 0) {
4991                             c.motion.mQuantizeInterpolatorID = a.getResourceId(attr, -1);
4992                             delta.add(QUANTIZE_MOTION_INTERPOLATOR_ID,
4993                                     c.motion.mQuantizeInterpolatorID);
4994 
4995                             c.motion.mQuantizeInterpolatorType = Motion.INTERPOLATOR_REFERENCE_ID;
4996                             delta.add(QUANTIZE_MOTION_INTERPOLATOR_TYPE,
4997                                     c.motion.mQuantizeInterpolatorType);
4998 
4999                         } else {
5000                             c.motion.mQuantizeInterpolatorType = Motion.SPLINE_STRING;
5001                             delta.add(QUANTIZE_MOTION_INTERPOLATOR_TYPE,
5002                                     c.motion.mQuantizeInterpolatorType);
5003                         }
5004                     } else {
5005                         c.motion.mQuantizeInterpolatorType =
5006                                 a.getInteger(attr, c.motion.mQuantizeInterpolatorID);
5007                         delta.add(QUANTIZE_MOTION_INTERPOLATOR_TYPE,
5008                                 c.motion.mQuantizeInterpolatorType);
5009                     }
5010                     break;
5011                 case DRAW_PATH:
5012                     delta.add(DRAW_PATH, a.getInt(attr, 0));
5013                     break;
5014                 case CHAIN_USE_RTL:
5015                     Log.e(TAG, "CURRENTLY UNSUPPORTED"); // TODO add support or remove
5016                     //  TODO add support or remove
5017                     //   c.mChainUseRtl = a.getBoolean(attr,c.mChainUseRtl);
5018                     break;
5019                 case BARRIER_DIRECTION:
5020                     delta.add(BARRIER_DIRECTION, a.getInt(attr, c.layout.mBarrierDirection));
5021                     break;
5022                 case BARRIER_MARGIN:
5023                     delta.add(BARRIER_MARGIN, a.getDimensionPixelSize(attr,
5024                             c.layout.mBarrierMargin));
5025                     break;
5026                 case CONSTRAINT_REFERENCED_IDS:
5027                     delta.add(CONSTRAINT_REFERENCED_IDS, a.getString(attr));
5028                     break;
5029                 case CONSTRAINT_TAG:
5030                     delta.add(CONSTRAINT_TAG, a.getString(attr));
5031                     break;
5032                 case BARRIER_ALLOWS_GONE_WIDGETS:
5033                     delta.add(BARRIER_ALLOWS_GONE_WIDGETS, a.getBoolean(attr,
5034                             c.layout.mBarrierAllowsGoneWidgets));
5035                     break;
5036                 case UNUSED:
5037                     Log.w(TAG,
5038                             "unused attribute 0x" + Integer.toHexString(attr)
5039                                     + "   " + sMapToConstant.get(attr));
5040                     break;
5041                 default:
5042                     Log.w(TAG,
5043                             "Unknown attribute 0x" + Integer.toHexString(attr)
5044                                     + "   " + sMapToConstant.get(attr));
5045             }
5046         }
5047     }
5048 
setDeltaValue(Constraint c, int type, float value)5049     private static void setDeltaValue(Constraint c, int type, float value) {
5050         switch (type) {
5051             case GUIDE_PERCENT:
5052                 c.layout.guidePercent = value;
5053                 break;
5054             case CIRCLE_ANGLE:
5055                 c.layout.circleAngle = value;
5056                 break;
5057             case HORIZONTAL_BIAS:
5058                 c.layout.horizontalBias = value;
5059                 break;
5060             case VERTICAL_BIAS:
5061                 c.layout.verticalBias = value;
5062                 break;
5063             case ALPHA:
5064                 c.propertySet.alpha = value;
5065                 break;
5066             case ELEVATION:
5067                 c.transform.elevation = value;
5068                 c.transform.applyElevation = true;
5069                 break;
5070             case ROTATION:
5071                 c.transform.rotation = value;
5072                 break;
5073             case ROTATION_X:
5074                 c.transform.rotationX = value;
5075                 break;
5076             case ROTATION_Y:
5077                 c.transform.rotationY = value;
5078                 break;
5079             case SCALE_X:
5080                 c.transform.scaleX = value;
5081                 break;
5082             case SCALE_Y:
5083                 c.transform.scaleY = value;
5084                 break;
5085             case TRANSFORM_PIVOT_X:
5086                 c.transform.transformPivotX = value;
5087                 break;
5088             case TRANSFORM_PIVOT_Y:
5089                 c.transform.transformPivotY = value;
5090                 break;
5091             case TRANSLATION_X:
5092                 c.transform.translationX = value;
5093                 break;
5094             case TRANSLATION_Y:
5095                 c.transform.translationY = value;
5096                 break;
5097             case TRANSLATION_Z:
5098                 c.transform.translationZ = value;
5099                 break;
5100             case VERTICAL_WEIGHT:
5101                 c.layout.verticalWeight = value;
5102                 break;
5103             case HORIZONTAL_WEIGHT:
5104                 c.layout.horizontalWeight = value;
5105                 break;
5106             case WIDTH_PERCENT:
5107                 c.layout.widthPercent = value;
5108                 break;
5109             case HEIGHT_PERCENT:
5110                 c.layout.heightPercent = value;
5111                 break;
5112             case PROGRESS:
5113                 c.propertySet.mProgress = value;
5114                 break;
5115             case TRANSITION_PATH_ROTATE:
5116                 c.motion.mPathRotate = value;
5117                 break;
5118             case MOTION_STAGGER:
5119                 c.motion.mMotionStagger = value;
5120                 break;
5121             case QUANTIZE_MOTION_PHASE:
5122                 c.motion.mQuantizeMotionPhase = value;
5123                 break;
5124             case UNUSED:
5125                 break;
5126             default:
5127                 Log.w(TAG,
5128                         "Unknown attribute 0x");
5129         }
5130     }
5131 
setDeltaValue(Constraint c, int type, int value)5132     private static void setDeltaValue(Constraint c, int type, int value) {
5133         switch (type) {
5134             case EDITOR_ABSOLUTE_X:
5135                 c.layout.editorAbsoluteX = value;
5136                 break;
5137             case EDITOR_ABSOLUTE_Y:
5138                 c.layout.editorAbsoluteY = value;
5139                 break;
5140             case LAYOUT_WRAP_BEHAVIOR:
5141                 c.layout.mWrapBehavior = value;
5142                 break;
5143             case GUIDE_BEGIN:
5144                 c.layout.guideBegin = value;
5145                 break;
5146             case GUIDE_END:
5147                 c.layout.guideEnd = value;
5148                 break;
5149             case ORIENTATION:
5150                 c.layout.orientation = value;
5151                 break;
5152             case CIRCLE:
5153                 c.layout.circleConstraint = value;
5154                 break;
5155             case CIRCLE_RADIUS:
5156                 c.layout.circleRadius = value;
5157                 break;
5158             case GONE_LEFT_MARGIN:
5159                 c.layout.goneLeftMargin = value;
5160                 break;
5161             case GONE_TOP_MARGIN:
5162                 c.layout.goneTopMargin = value;
5163                 break;
5164             case GONE_RIGHT_MARGIN:
5165                 c.layout.goneRightMargin = value;
5166                 break;
5167             case GONE_BOTTOM_MARGIN:
5168                 c.layout.goneBottomMargin = value;
5169                 break;
5170             case GONE_START_MARGIN:
5171                 c.layout.goneStartMargin = value;
5172                 break;
5173             case GONE_END_MARGIN:
5174                 c.layout.goneEndMargin = value;
5175                 break;
5176             case GONE_BASELINE_MARGIN:
5177                 c.layout.goneBaselineMargin = value;
5178                 break;
5179             case LEFT_MARGIN:
5180                 c.layout.leftMargin = value;
5181                 break;
5182             case RIGHT_MARGIN:
5183                 c.layout.rightMargin = value;
5184                 break;
5185             case START_MARGIN:
5186                 c.layout.startMargin = value;
5187                 break;
5188             case END_MARGIN:
5189                 c.layout.endMargin = value;
5190                 break;
5191             case TOP_MARGIN:
5192                 c.layout.topMargin = value;
5193                 break;
5194             case BOTTOM_MARGIN:
5195                 c.layout.bottomMargin = value;
5196                 break;
5197             case BASELINE_MARGIN:
5198                 c.layout.baselineMargin = value;
5199                 break;
5200             case LAYOUT_WIDTH:
5201                 c.layout.mWidth = value;
5202                 break;
5203             case LAYOUT_HEIGHT:
5204                 c.layout.mHeight = value;
5205                 break;
5206             case WIDTH_DEFAULT:
5207                 c.layout.widthDefault = value;
5208                 break;
5209             case HEIGHT_DEFAULT:
5210                 c.layout.heightDefault = value;
5211                 break;
5212             case HEIGHT_MAX:
5213                 c.layout.heightMax = value;
5214                 break;
5215             case WIDTH_MAX:
5216                 c.layout.widthMax = value;
5217                 break;
5218             case HEIGHT_MIN:
5219                 c.layout.heightMin = value;
5220                 break;
5221             case WIDTH_MIN:
5222                 c.layout.widthMin = value;
5223                 break;
5224             case LAYOUT_VISIBILITY:
5225                 c.propertySet.visibility = value;
5226                 break;
5227             case VISIBILITY_MODE:
5228                 c.propertySet.mVisibilityMode = value;
5229                 break;
5230             case TRANSFORM_PIVOT_TARGET:
5231                 c.transform.transformPivotTarget = value;
5232                 break;
5233             case VERTICAL_STYLE:
5234                 c.layout.verticalChainStyle = value;
5235                 break;
5236             case HORIZONTAL_STYLE:
5237                 c.layout.horizontalChainStyle = value;
5238                 break;
5239             case VIEW_ID:
5240                 c.mViewId = value;
5241                 break;
5242             case ANIMATE_RELATIVE_TO:
5243                 c.motion.mAnimateRelativeTo = value;
5244                 break;
5245             case ANIMATE_CIRCLE_ANGLE_TO:
5246                 c.motion.mAnimateCircleAngleTo = value;
5247                 break;
5248             case PATH_MOTION_ARC:
5249                 c.motion.mPathMotionArc = value;
5250                 break;
5251             case QUANTIZE_MOTION_STEPS:
5252                 c.motion.mQuantizeMotionSteps = value;
5253                 break;
5254             case QUANTIZE_MOTION_INTERPOLATOR_TYPE:
5255                 c.motion.mQuantizeInterpolatorType = value;
5256                 break;
5257             case QUANTIZE_MOTION_INTERPOLATOR_ID:
5258                 c.motion.mQuantizeInterpolatorID = value;
5259                 break;
5260             case DRAW_PATH:
5261                 c.motion.mDrawPath = value;
5262                 break;
5263             case BARRIER_DIRECTION:
5264                 c.layout.mBarrierDirection = value;
5265                 break;
5266             case BARRIER_MARGIN:
5267                 c.layout.mBarrierMargin = value;
5268                 break;
5269             case UNUSED:
5270                 break;
5271             default:
5272                 Log.w(TAG,
5273                         "Unknown attribute 0x");
5274         }
5275     }
5276 
setDeltaValue(Constraint c, int type, String value)5277     private static void setDeltaValue(Constraint c, int type, String value) {
5278         switch (type) {
5279             case DIMENSION_RATIO:
5280                 c.layout.dimensionRatio = value;
5281                 break;
5282             case TRANSITION_EASING:
5283                 c.motion.mTransitionEasing = value;
5284                 break;
5285             case QUANTIZE_MOTION_INTERPOLATOR_STR:
5286                 c.motion.mQuantizeInterpolatorString = value;
5287                 break;
5288             case CONSTRAINT_REFERENCED_IDS:
5289                 c.layout.mReferenceIdString = value;
5290                 // If a string is defined, clear up the reference ids array
5291                 c.layout.mReferenceIds = null;
5292                 break;
5293             case CONSTRAINT_TAG:
5294                 c.layout.mConstraintTag = value;
5295                 break;
5296             case UNUSED:
5297                 break;
5298             default:
5299                 Log.w(TAG,
5300                         "Unknown attribute 0x");
5301         }
5302     }
5303 
setDeltaValue(Constraint c, int type, boolean value)5304     private static void setDeltaValue(Constraint c, int type, boolean value) {
5305         switch (type) {
5306             case CONSTRAINED_WIDTH:
5307                 c.layout.constrainedWidth = value;
5308                 break;
5309             case CONSTRAINED_HEIGHT:
5310                 c.layout.constrainedHeight = value;
5311                 break;
5312             case ELEVATION:
5313                 c.transform.applyElevation = value;
5314                 break;
5315             case BARRIER_ALLOWS_GONE_WIDGETS:
5316                 c.layout.mBarrierAllowsGoneWidgets = value;
5317                 break;
5318             case UNUSED:
5319                 break;
5320             default:
5321                 Log.w(TAG, "Unknown attribute 0x");
5322         }
5323     }
5324 
populateConstraint(Constraint c, TypedArray a, boolean override)5325     private void populateConstraint(Constraint c, TypedArray a, boolean override) {
5326         if (override) {
5327             populateOverride(c, a);
5328             return;
5329         }
5330         final int count = a.getIndexCount();
5331         for (int i = 0; i < count; i++) {
5332             int attr = a.getIndex(i);
5333             if (DEBUG) { // USEFUL when adding features to track tags being parsed
5334                 try {
5335                     Field[] campos = R.styleable.class.getFields();
5336                     boolean found = false;
5337                     for (Field f : campos) {
5338                         try {
5339                             if (f.getType().isPrimitive()
5340                                     && attr == f.getInt(null) && f.getName()
5341                                     .contains("Constraint_")) {
5342                                 found = true;
5343                                 if (DEBUG) {
5344                                     Log.v(TAG, "L id " + f.getName() + " #" + attr);
5345                                 }
5346                                 break;
5347                             }
5348                         } catch (Exception e) {
5349 
5350                         }
5351                     }
5352                     if (!found) {
5353                         campos = android.R.attr.class.getFields();
5354                         for (Field f : campos) {
5355                             try {
5356                                 if (f.getType().isPrimitive() && attr == f.getInt(null)
5357                                         && f.getName()
5358                                         .contains("Constraint_")) {
5359                                     found = false;
5360                                     if (DEBUG) {
5361                                         Log.v(TAG, "x id " + f.getName());
5362                                     }
5363                                     break;
5364                                 }
5365                             } catch (Exception e) {
5366 
5367                             }
5368                         }
5369                     }
5370                     if (!found) {
5371                         Log.v(TAG, " ? " + attr);
5372                     }
5373                 } catch (Exception e) {
5374                     Log.v(TAG, " " + e.toString());
5375                 }
5376             }
5377 
5378 
5379             if (attr != R.styleable.Constraint_android_id
5380                     && R.styleable.Constraint_android_layout_marginStart != attr
5381                     && R.styleable.Constraint_android_layout_marginEnd != attr) {
5382                 c.motion.mApply = true;
5383                 c.layout.mApply = true;
5384                 c.propertySet.mApply = true;
5385                 c.transform.mApply = true;
5386             }
5387 
5388             switch (sMapToConstant.get(attr)) {
5389                 case LEFT_TO_LEFT:
5390                     c.layout.leftToLeft = lookupID(a, attr, c.layout.leftToLeft);
5391                     break;
5392                 case LEFT_TO_RIGHT:
5393                     c.layout.leftToRight = lookupID(a, attr, c.layout.leftToRight);
5394                     break;
5395                 case RIGHT_TO_LEFT:
5396                     c.layout.rightToLeft = lookupID(a, attr, c.layout.rightToLeft);
5397                     break;
5398                 case RIGHT_TO_RIGHT:
5399                     c.layout.rightToRight = lookupID(a, attr, c.layout.rightToRight);
5400                     break;
5401                 case TOP_TO_TOP:
5402                     c.layout.topToTop = lookupID(a, attr, c.layout.topToTop);
5403                     break;
5404                 case TOP_TO_BOTTOM:
5405                     c.layout.topToBottom = lookupID(a, attr, c.layout.topToBottom);
5406                     break;
5407                 case BOTTOM_TO_TOP:
5408                     c.layout.bottomToTop = lookupID(a, attr, c.layout.bottomToTop);
5409                     break;
5410                 case BOTTOM_TO_BOTTOM:
5411                     c.layout.bottomToBottom = lookupID(a, attr, c.layout.bottomToBottom);
5412                     break;
5413                 case BASELINE_TO_BASELINE:
5414                     c.layout.baselineToBaseline = lookupID(a, attr, c.layout.baselineToBaseline);
5415                     break;
5416                 case BASELINE_TO_TOP:
5417                     c.layout.baselineToTop = lookupID(a, attr, c.layout.baselineToTop);
5418                     break;
5419                 case BASELINE_TO_BOTTOM:
5420                     c.layout.baselineToBottom = lookupID(a, attr, c.layout.baselineToBottom);
5421                     break;
5422                 case EDITOR_ABSOLUTE_X:
5423                     c.layout.editorAbsoluteX = a.getDimensionPixelOffset(attr,
5424                             c.layout.editorAbsoluteX);
5425                     break;
5426                 case EDITOR_ABSOLUTE_Y:
5427                     c.layout.editorAbsoluteY = a.getDimensionPixelOffset(attr,
5428                             c.layout.editorAbsoluteY);
5429                     break;
5430                 case GUIDE_BEGIN:
5431                     c.layout.guideBegin = a.getDimensionPixelOffset(attr, c.layout.guideBegin);
5432                     break;
5433                 case GUIDE_END:
5434                     c.layout.guideEnd = a.getDimensionPixelOffset(attr, c.layout.guideEnd);
5435                     break;
5436                 case GUIDE_PERCENT:
5437                     c.layout.guidePercent = a.getFloat(attr, c.layout.guidePercent);
5438                     break;
5439                 case ORIENTATION:
5440                     c.layout.orientation = a.getInt(attr, c.layout.orientation);
5441                     break;
5442                 case START_TO_END:
5443                     c.layout.startToEnd = lookupID(a, attr, c.layout.startToEnd);
5444                     break;
5445                 case START_TO_START:
5446                     c.layout.startToStart = lookupID(a, attr, c.layout.startToStart);
5447                     break;
5448                 case END_TO_START:
5449                     c.layout.endToStart = lookupID(a, attr, c.layout.endToStart);
5450                     break;
5451                 case END_TO_END:
5452                     c.layout.endToEnd = lookupID(a, attr, c.layout.endToEnd);
5453                     break;
5454                 case CIRCLE:
5455                     c.layout.circleConstraint = lookupID(a, attr, c.layout.circleConstraint);
5456                     break;
5457                 case CIRCLE_RADIUS:
5458                     c.layout.circleRadius = a.getDimensionPixelSize(attr, c.layout.circleRadius);
5459                     break;
5460                 case CIRCLE_ANGLE:
5461                     c.layout.circleAngle = a.getFloat(attr, c.layout.circleAngle);
5462                     break;
5463                 case GONE_LEFT_MARGIN:
5464                     c.layout.goneLeftMargin = a.getDimensionPixelSize(attr,
5465                             c.layout.goneLeftMargin);
5466                     break;
5467                 case GONE_TOP_MARGIN:
5468                     c.layout.goneTopMargin = a.getDimensionPixelSize(attr, c.layout.goneTopMargin);
5469                     break;
5470                 case GONE_RIGHT_MARGIN:
5471                     c.layout.goneRightMargin = a.getDimensionPixelSize(attr,
5472                             c.layout.goneRightMargin);
5473                     break;
5474                 case GONE_BOTTOM_MARGIN:
5475                     c.layout.goneBottomMargin = a.getDimensionPixelSize(attr,
5476                             c.layout.goneBottomMargin);
5477                     break;
5478                 case GONE_START_MARGIN:
5479                     c.layout.goneStartMargin =
5480                             a.getDimensionPixelSize(attr, c.layout.goneStartMargin);
5481                     break;
5482                 case GONE_END_MARGIN:
5483                     c.layout.goneEndMargin = a.getDimensionPixelSize(attr, c.layout.goneEndMargin);
5484                     break;
5485                 case GONE_BASELINE_MARGIN:
5486                     c.layout.goneBaselineMargin = a.getDimensionPixelSize(attr,
5487                             c.layout.goneBaselineMargin);
5488                     break;
5489                 case HORIZONTAL_BIAS:
5490                     c.layout.horizontalBias = a.getFloat(attr, c.layout.horizontalBias);
5491                     break;
5492                 case VERTICAL_BIAS:
5493                     c.layout.verticalBias = a.getFloat(attr, c.layout.verticalBias);
5494                     break;
5495                 case LEFT_MARGIN:
5496                     c.layout.leftMargin = a.getDimensionPixelSize(attr, c.layout.leftMargin);
5497                     break;
5498                 case RIGHT_MARGIN:
5499                     c.layout.rightMargin = a.getDimensionPixelSize(attr, c.layout.rightMargin);
5500                     break;
5501                 case START_MARGIN:
5502                     c.layout.startMargin = a.getDimensionPixelSize(attr, c.layout.startMargin);
5503                     break;
5504                 case END_MARGIN:
5505                     c.layout.endMargin = a.getDimensionPixelSize(attr, c.layout.endMargin);
5506                     break;
5507                 case TOP_MARGIN:
5508                     c.layout.topMargin = a.getDimensionPixelSize(attr, c.layout.topMargin);
5509                     break;
5510                 case BOTTOM_MARGIN:
5511                     c.layout.bottomMargin = a.getDimensionPixelSize(attr, c.layout.bottomMargin);
5512                     break;
5513                 case BASELINE_MARGIN:
5514                     c.layout.baselineMargin = a.getDimensionPixelSize(attr,
5515                             c.layout.baselineMargin);
5516                     break;
5517                 case LAYOUT_WIDTH:
5518                     c.layout.mWidth = a.getLayoutDimension(attr, c.layout.mWidth);
5519                     break;
5520                 case LAYOUT_HEIGHT:
5521                     c.layout.mHeight = a.getLayoutDimension(attr, c.layout.mHeight);
5522                     break;
5523                 case LAYOUT_CONSTRAINT_WIDTH:
5524                     ConstraintSet.parseDimensionConstraints(c.layout, a, attr, HORIZONTAL);
5525                     break;
5526                 case LAYOUT_CONSTRAINT_HEIGHT:
5527                     ConstraintSet.parseDimensionConstraints(c.layout, a, attr, VERTICAL);
5528                     break;
5529                 case LAYOUT_WRAP_BEHAVIOR:
5530                     c.layout.mWrapBehavior = a.getInt(attr, c.layout.mWrapBehavior);
5531                     break;
5532                 case WIDTH_DEFAULT:
5533                     c.layout.widthDefault = a.getInt(attr, c.layout.widthDefault);
5534                     break;
5535                 case HEIGHT_DEFAULT:
5536                     c.layout.heightDefault = a.getInt(attr, c.layout.heightDefault);
5537                     break;
5538                 case HEIGHT_MAX:
5539                     c.layout.heightMax = a.getDimensionPixelSize(attr, c.layout.heightMax);
5540                     break;
5541                 case WIDTH_MAX:
5542                     c.layout.widthMax = a.getDimensionPixelSize(attr, c.layout.widthMax);
5543                     break;
5544                 case HEIGHT_MIN:
5545                     c.layout.heightMin = a.getDimensionPixelSize(attr, c.layout.heightMin);
5546                     break;
5547                 case WIDTH_MIN:
5548                     c.layout.widthMin = a.getDimensionPixelSize(attr, c.layout.widthMin);
5549                     break;
5550                 case CONSTRAINED_WIDTH:
5551                     c.layout.constrainedWidth = a.getBoolean(attr, c.layout.constrainedWidth);
5552                     break;
5553                 case CONSTRAINED_HEIGHT:
5554                     c.layout.constrainedHeight = a.getBoolean(attr, c.layout.constrainedHeight);
5555                     break;
5556                 case LAYOUT_VISIBILITY:
5557                     c.propertySet.visibility = a.getInt(attr, c.propertySet.visibility);
5558                     c.propertySet.visibility = VISIBILITY_FLAGS[c.propertySet.visibility];
5559                     break;
5560                 case VISIBILITY_MODE:
5561                     c.propertySet.mVisibilityMode = a.getInt(attr, c.propertySet.mVisibilityMode);
5562                     break;
5563                 case ALPHA:
5564                     c.propertySet.alpha = a.getFloat(attr, c.propertySet.alpha);
5565                     break;
5566                 case ELEVATION:
5567                     if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
5568                         c.transform.applyElevation = true;
5569                         c.transform.elevation = a.getDimension(attr, c.transform.elevation);
5570                     }
5571                     break;
5572                 case ROTATION:
5573                     c.transform.rotation = a.getFloat(attr, c.transform.rotation);
5574                     break;
5575                 case ROTATION_X:
5576                     c.transform.rotationX = a.getFloat(attr, c.transform.rotationX);
5577                     break;
5578                 case ROTATION_Y:
5579                     c.transform.rotationY = a.getFloat(attr, c.transform.rotationY);
5580                     break;
5581                 case SCALE_X:
5582                     c.transform.scaleX = a.getFloat(attr, c.transform.scaleX);
5583                     break;
5584                 case SCALE_Y:
5585                     c.transform.scaleY = a.getFloat(attr, c.transform.scaleY);
5586                     break;
5587                 case TRANSFORM_PIVOT_X:
5588                     c.transform.transformPivotX = a.getDimension(attr, c.transform.transformPivotX);
5589                     break;
5590                 case TRANSFORM_PIVOT_Y:
5591                     c.transform.transformPivotY = a.getDimension(attr, c.transform.transformPivotY);
5592                     break;
5593                 case TRANSLATION_X:
5594                     c.transform.translationX = a.getDimension(attr, c.transform.translationX);
5595                     break;
5596                 case TRANSLATION_Y:
5597                     c.transform.translationY = a.getDimension(attr, c.transform.translationY);
5598                     break;
5599                 case TRANSLATION_Z:
5600                     if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
5601                         c.transform.translationZ = a.getDimension(attr, c.transform.translationZ);
5602                     }
5603                     break;
5604                 case TRANSFORM_PIVOT_TARGET:
5605                     c.transform.transformPivotTarget =
5606                             lookupID(a, attr, c.transform.transformPivotTarget);
5607                     break;
5608                 case VERTICAL_WEIGHT:
5609                     c.layout.verticalWeight = a.getFloat(attr, c.layout.verticalWeight);
5610                     break;
5611                 case HORIZONTAL_WEIGHT:
5612                     c.layout.horizontalWeight = a.getFloat(attr, c.layout.horizontalWeight);
5613                     break;
5614                 case VERTICAL_STYLE:
5615                     c.layout.verticalChainStyle = a.getInt(attr, c.layout.verticalChainStyle);
5616                     break;
5617                 case HORIZONTAL_STYLE:
5618                     c.layout.horizontalChainStyle = a.getInt(attr, c.layout.horizontalChainStyle);
5619                     break;
5620                 case VIEW_ID:
5621                     c.mViewId = a.getResourceId(attr, c.mViewId);
5622                     break;
5623                 case DIMENSION_RATIO:
5624                     c.layout.dimensionRatio = a.getString(attr);
5625                     break;
5626                 case WIDTH_PERCENT:
5627                     c.layout.widthPercent = a.getFloat(attr, 1);
5628                     break;
5629                 case HEIGHT_PERCENT:
5630                     c.layout.heightPercent = a.getFloat(attr, 1);
5631                     break;
5632                 case PROGRESS:
5633                     c.propertySet.mProgress = a.getFloat(attr, c.propertySet.mProgress);
5634                     break;
5635                 case ANIMATE_RELATIVE_TO:
5636                     c.motion.mAnimateRelativeTo = lookupID(a, attr, c.motion.mAnimateRelativeTo);
5637                     break;
5638                 case ANIMATE_CIRCLE_ANGLE_TO:
5639                     c.motion.mAnimateCircleAngleTo =
5640                             a.getInteger(attr, c.motion.mAnimateCircleAngleTo);
5641                     break;
5642                 case TRANSITION_EASING:
5643                     TypedValue type = a.peekValue(attr);
5644                     if (type.type == TypedValue.TYPE_STRING) {
5645                         c.motion.mTransitionEasing = a.getString(attr);
5646                     } else {
5647                         c.motion.mTransitionEasing =
5648                                 Easing.NAMED_EASING[a.getInteger(attr, 0)];
5649                     }
5650                     break;
5651                 case PATH_MOTION_ARC:
5652                     c.motion.mPathMotionArc = a.getInt(attr, c.motion.mPathMotionArc);
5653                     break;
5654                 case TRANSITION_PATH_ROTATE:
5655                     c.motion.mPathRotate = a.getFloat(attr, c.motion.mPathRotate);
5656                     break;
5657                 case MOTION_STAGGER:
5658                     c.motion.mMotionStagger = a.getFloat(attr, c.motion.mMotionStagger);
5659                     break;
5660 
5661                 case QUANTIZE_MOTION_STEPS:
5662                     c.motion.mQuantizeMotionSteps = a.getInteger(attr,
5663                             c.motion.mQuantizeMotionSteps);
5664                     break;
5665                 case QUANTIZE_MOTION_PHASE:
5666                     c.motion.mQuantizeMotionPhase = a.getFloat(attr, c.motion.mQuantizeMotionPhase);
5667                     break;
5668                 case QUANTIZE_MOTION_INTERPOLATOR:
5669                     type = a.peekValue(attr);
5670 
5671                     if (type.type == TypedValue.TYPE_REFERENCE) {
5672                         c.motion.mQuantizeInterpolatorID = a.getResourceId(attr, -1);
5673                         if (c.motion.mQuantizeInterpolatorID != -1) {
5674                             c.motion.mQuantizeInterpolatorType = Motion.INTERPOLATOR_REFERENCE_ID;
5675                         }
5676                     } else if (type.type == TypedValue.TYPE_STRING) {
5677                         c.motion.mQuantizeInterpolatorString = a.getString(attr);
5678                         if (c.motion.mQuantizeInterpolatorString.indexOf("/") > 0) {
5679                             c.motion.mQuantizeInterpolatorID = a.getResourceId(attr, -1);
5680                             c.motion.mQuantizeInterpolatorType = Motion.INTERPOLATOR_REFERENCE_ID;
5681                         } else {
5682                             c.motion.mQuantizeInterpolatorType = Motion.SPLINE_STRING;
5683                         }
5684                     } else {
5685                         c.motion.mQuantizeInterpolatorType = a.getInteger(attr,
5686                                 c.motion.mQuantizeInterpolatorID);
5687                     }
5688 
5689                     break;
5690 
5691 
5692                 case DRAW_PATH:
5693                     c.motion.mDrawPath = a.getInt(attr, 0);
5694                     break;
5695                 case CHAIN_USE_RTL:
5696                     Log.e(TAG, "CURRENTLY UNSUPPORTED"); // TODO add support or remove
5697                     //  TODO add support or remove  c.mChainUseRtl =
5698                     //   a.getBoolean(attr,c.mChainUseRtl);
5699                     break;
5700                 case BARRIER_DIRECTION:
5701                     c.layout.mBarrierDirection = a.getInt(attr, c.layout.mBarrierDirection);
5702                     break;
5703                 case BARRIER_MARGIN:
5704                     c.layout.mBarrierMargin = a.getDimensionPixelSize(attr,
5705                             c.layout.mBarrierMargin);
5706                     break;
5707                 case CONSTRAINT_REFERENCED_IDS:
5708                     c.layout.mReferenceIdString = a.getString(attr);
5709                     break;
5710                 case CONSTRAINT_TAG:
5711                     c.layout.mConstraintTag = a.getString(attr);
5712                     break;
5713                 case BARRIER_ALLOWS_GONE_WIDGETS:
5714                     c.layout.mBarrierAllowsGoneWidgets = a.getBoolean(attr,
5715                             c.layout.mBarrierAllowsGoneWidgets);
5716                     break;
5717                 case UNUSED:
5718                     Log.w(TAG,
5719                             "unused attribute 0x" + Integer.toHexString(attr)
5720                                     + "   " + sMapToConstant.get(attr));
5721                     break;
5722                 default:
5723                     Log.w(TAG,
5724                             "Unknown attribute 0x" + Integer.toHexString(attr)
5725                                     + "   " + sMapToConstant.get(attr));
5726             }
5727         }
5728         if (c.layout.mReferenceIdString != null) {
5729             // in case the strings are set, make sure to clear up the cached ids
5730             c.layout.mReferenceIds = null;
5731         }
5732     }
5733 
convertReferenceString(View view, String referenceIdString)5734     private int[] convertReferenceString(View view, String referenceIdString) {
5735         String[] split = referenceIdString.split(",");
5736         Context context = view.getContext();
5737         int[] tags = new int[split.length];
5738         int count = 0;
5739         for (int i = 0; i < split.length; i++) {
5740             String idString = split[i];
5741             idString = idString.trim();
5742             int tag = 0;
5743             try {
5744                 Class res = R.id.class;
5745                 Field field = res.getField(idString);
5746                 tag = field.getInt(null);
5747             } catch (Exception e) {
5748                 // Do nothing
5749             }
5750             if (tag == 0) {
5751                 tag = context.getResources().getIdentifier(idString, "id",
5752                         context.getPackageName());
5753             }
5754 
5755             if (tag == 0 && view.isInEditMode() && view.getParent() instanceof ConstraintLayout) {
5756                 ConstraintLayout constraintLayout = (ConstraintLayout) view.getParent();
5757                 Object value = constraintLayout.getDesignInformation(0, idString);
5758                 if (value != null && value instanceof Integer) {
5759                     tag = (Integer) value;
5760                 }
5761             }
5762             tags[count++] = tag;
5763         }
5764         if (count != split.length) {
5765             tags = Arrays.copyOf(tags, count);
5766         }
5767         return tags;
5768     }
5769 
5770     /**
5771      *
5772      */
getConstraint(int id)5773     public Constraint getConstraint(int id) {
5774         if (mConstraints.containsKey(id)) {
5775             return mConstraints.get(id);
5776         }
5777         return null;
5778     }
5779 
5780     /**
5781      *
5782      */
getKnownIds()5783     public int[] getKnownIds() {
5784         Integer[] arr = mConstraints.keySet().toArray(new Integer[0]);
5785         int[] array = new int[arr.length];
5786         for (int i = 0; i < array.length; i++) {
5787             array[i] = arr[i];
5788         }
5789         return array;
5790     }
5791 
5792     /**
5793      * Enforce id are required for all ConstraintLayout children to use ConstraintSet.
5794      * default = true;
5795      */
isForceId()5796     public boolean isForceId() {
5797         return mForceId;
5798     }
5799 
5800     /**
5801      * Enforce id are required for all ConstraintLayout children to use ConstraintSet.
5802      * default = true;
5803      *
5804      * @param forceId
5805      */
setForceId(boolean forceId)5806     public void setForceId(boolean forceId) {
5807         this.mForceId = forceId;
5808     }
5809 
5810     /**
5811      * If true perform validation checks when parsing ConstraintSets
5812      * This will slow down parsing and should only be used for debugging
5813      *
5814      * @param validate
5815      */
setValidateOnParse(boolean validate)5816     public void setValidateOnParse(boolean validate) {
5817         mValidate = validate;
5818     }
5819 
5820     /**
5821      * If true perform validation checks when parsing ConstraintSets
5822      * This will slow down parsing and should only be used for debugging
5823      *
5824      * @return validate
5825      */
isValidateOnParse()5826     public boolean isValidateOnParse() {
5827         return mValidate;
5828     }
5829 
5830     /**
5831      * Dump the contents
5832      *
5833      * @param scene
5834      * @param ids
5835      */
dump(MotionScene scene, int... ids)5836     public void dump(MotionScene scene, int... ids) {
5837         Set<Integer> keys = mConstraints.keySet();
5838         HashSet<Integer> set;
5839         if (ids.length != 0) {
5840             set = new HashSet<Integer>();
5841             for (int id : ids) {
5842                 set.add(id);
5843             }
5844         } else {
5845             set = new HashSet<>(keys);
5846         }
5847         System.out.println(set.size() + " constraints");
5848         StringBuilder stringBuilder = new StringBuilder();
5849 
5850         for (Integer id : set.toArray(new Integer[0])) {
5851             Constraint constraint = mConstraints.get(id);
5852             if (constraint == null) {
5853                 continue;
5854             }
5855 
5856             stringBuilder.append("<Constraint id=");
5857             stringBuilder.append(id);
5858             stringBuilder.append(" \n");
5859             constraint.layout.dump(scene, stringBuilder);
5860             stringBuilder.append("/>\n");
5861         }
5862         System.out.println(stringBuilder.toString());
5863 
5864     }
5865 
5866     /**
5867      * Construct a user friendly error string
5868      *
5869      * @param context    the context
5870      * @param resourceId the xml being parsed
5871      * @param pullParser the XML parser
5872      * @return
5873      */
getLine(Context context, int resourceId, XmlPullParser pullParser)5874     static String getLine(Context context, int resourceId, XmlPullParser pullParser) {
5875         return ".(" + Debug.getName(context, resourceId)
5876                 + ".xml:" + pullParser.getLineNumber()
5877                 + ") \"" + pullParser.getName() + "\"";
5878     }
5879 
getDebugName(int v)5880     static String getDebugName(int v) {
5881         for (Field field : ConstraintSet.class.getDeclaredFields()) {
5882             if (field.getName().contains("_")
5883                     && field.getType() == int.class
5884                     && java.lang.reflect.Modifier.isStatic(field.getModifiers())
5885                     && java.lang.reflect.Modifier.isFinal(field.getModifiers())) {
5886                 int val = 0;
5887                 try {
5888                     val = field.getInt(null);
5889                     if (val == v) {
5890                         return field.getName();
5891                     }
5892                 } catch (IllegalAccessException e) {
5893                     Log.e(TAG, "Error accessing ConstraintSet field", e);
5894                 }
5895 
5896             }
5897         }
5898         return "UNKNOWN";
5899     }
5900 
5901     /**
5902      * Write the state to a Writer
5903      * @param writer
5904      * @param layout
5905      * @param flags
5906      * @throws IOException
5907      */
writeState(Writer writer, ConstraintLayout layout, int flags)5908     public void writeState(Writer writer, ConstraintLayout layout, int flags) throws IOException {
5909         writer.write("\n---------------------------------------------\n");
5910         if ((flags & 1) == 1) {
5911             new WriteXmlEngine(writer, layout, flags).writeLayout();
5912         } else {
5913             new WriteJsonEngine(writer, layout, flags).writeLayout();
5914         }
5915         writer.write("\n---------------------------------------------\n");
5916 
5917     }
5918 
5919     class WriteXmlEngine {
5920         Writer mWriter;
5921         ConstraintLayout mLayout;
5922         Context mContext;
5923         int mFlags;
5924         int mUnknownCount = 0;
5925         final String mLEFT = "'left'";
5926         final String mRIGHT = "'right'";
5927         final String mBASELINE = "'baseline'";
5928         final String mBOTTOM = "'bottom'";
5929         final String mTOP = "'top'";
5930         final String mSTART = "'start'";
5931         final String mEND = "'end'";
5932 
WriteXmlEngine(Writer writer, ConstraintLayout layout, int flags)5933         WriteXmlEngine(Writer writer, ConstraintLayout layout, int flags) throws IOException {
5934             this.mWriter = writer;
5935             this.mLayout = layout;
5936             this.mContext = layout.getContext();
5937             this.mFlags = flags;
5938         }
5939 
writeLayout()5940         void writeLayout() throws IOException {
5941             mWriter.write("\n<ConstraintSet>\n");
5942             for (Integer id : mConstraints.keySet()) {
5943                 Constraint c = mConstraints.get(id);
5944                 String idName = getName(id);
5945                 mWriter.write("  <Constraint");
5946                 mWriter.write(SPACE + "android:id" + "=\"" + idName + "\"");
5947                 Layout l = c.layout;
5948                 writeBaseDimension("android:layout_width", l.mWidth, -5);
5949                 writeBaseDimension("android:layout_height", l.mHeight, -5);
5950 
5951                 writeVariable("app:layout_constraintGuide_begin", l.guideBegin, UNSET);
5952                 writeVariable("app:layout_constraintGuide_end", l.guideEnd, UNSET);
5953                 writeVariable("app:layout_constraintGuide_percent", l.guidePercent, UNSET);
5954 
5955                 writeVariable("app:layout_constraintHorizontal_bias",
5956                         l.horizontalBias, 0.5f);
5957                 writeVariable("app:layout_constraintVertical_bias",
5958                         l.verticalBias, 0.5f);
5959                 writeVariable("app:layout_constraintDimensionRatio",
5960                         l.dimensionRatio, null);
5961                 writeXmlConstraint("app:layout_constraintCircle", l.circleConstraint);
5962                 writeVariable("app:layout_constraintCircleRadius", l.circleRadius, 0);
5963                 writeVariable("app:layout_constraintCircleAngle", l.circleAngle, 0);
5964 
5965                 writeVariable("android:orientation", l.orientation, UNSET);
5966 
5967                 writeVariable("app:layout_constraintVertical_weight",
5968                         l.verticalWeight, UNSET);
5969                 writeVariable("app:layout_constraintHorizontal_weight",
5970                         l.horizontalWeight, UNSET);
5971                 writeVariable("app:layout_constraintHorizontal_chainStyle",
5972                         l.horizontalChainStyle, CHAIN_SPREAD);
5973                 writeVariable("app:layout_constraintVertical_chainStyle",
5974                         l.verticalChainStyle, CHAIN_SPREAD);
5975 
5976                 writeVariable("app:barrierDirection", l.mBarrierDirection, UNSET);
5977                 writeVariable("app:barrierMargin", l.mBarrierMargin, 0);
5978 
5979                 writeDimension("app:layout_marginLeft", l.leftMargin, 0);
5980                 writeDimension("app:layout_goneMarginLeft",
5981                         l.goneLeftMargin, Layout.UNSET_GONE_MARGIN);
5982                 writeDimension("app:layout_marginRight", l.rightMargin, 0);
5983                 writeDimension("app:layout_goneMarginRight",
5984                         l.goneRightMargin, Layout.UNSET_GONE_MARGIN);
5985                 writeDimension("app:layout_marginStart", l.startMargin, 0);
5986                 writeDimension("app:layout_goneMarginStart",
5987                         l.goneStartMargin, Layout.UNSET_GONE_MARGIN);
5988                 writeDimension("app:layout_marginEnd", l.endMargin, 0);
5989                 writeDimension("app:layout_goneMarginEnd",
5990                         l.goneEndMargin, Layout.UNSET_GONE_MARGIN);
5991                 writeDimension("app:layout_marginTop", l.topMargin, 0);
5992                 writeDimension("app:layout_goneMarginTop",
5993                         l.goneTopMargin, Layout.UNSET_GONE_MARGIN);
5994                 writeDimension("app:layout_marginBottom", l.bottomMargin, 0);
5995                 writeDimension("app:layout_goneMarginBottom",
5996                         l.goneBottomMargin, Layout.UNSET_GONE_MARGIN);
5997                 writeDimension("app:goneBaselineMargin",
5998                         l.goneBaselineMargin, Layout.UNSET_GONE_MARGIN);
5999                 writeDimension("app:baselineMargin", l.baselineMargin, 0);
6000 
6001                 writeBoolen("app:layout_constrainedWidth", l.constrainedWidth, false);
6002                 writeBoolen("app:layout_constrainedHeight",
6003                         l.constrainedHeight, false);
6004                 writeBoolen("app:barrierAllowsGoneWidgets",
6005                         l.mBarrierAllowsGoneWidgets, true);
6006                 writeVariable("app:layout_wrapBehaviorInParent", l.mWrapBehavior,
6007                         ConstraintWidget.WRAP_BEHAVIOR_INCLUDED);
6008 
6009                 writeXmlConstraint("app:baselineToBaseline", l.baselineToBaseline);
6010                 writeXmlConstraint("app:baselineToBottom", l.baselineToBottom);
6011                 writeXmlConstraint("app:baselineToTop", l.baselineToTop);
6012                 writeXmlConstraint("app:layout_constraintBottom_toBottomOf", l.bottomToBottom);
6013                 writeXmlConstraint("app:layout_constraintBottom_toTopOf", l.bottomToTop);
6014                 writeXmlConstraint("app:layout_constraintEnd_toEndOf", l.endToEnd);
6015                 writeXmlConstraint("app:layout_constraintEnd_toStartOf", l.endToStart);
6016                 writeXmlConstraint("app:layout_constraintLeft_toLeftOf", l.leftToLeft);
6017                 writeXmlConstraint("app:layout_constraintLeft_toRightOf", l.leftToRight);
6018                 writeXmlConstraint("app:layout_constraintRight_toLeftOf", l.rightToLeft);
6019                 writeXmlConstraint("app:layout_constraintRight_toRightOf", l.rightToRight);
6020                 writeXmlConstraint("app:layout_constraintStart_toEndOf", l.startToEnd);
6021                 writeXmlConstraint("app:layout_constraintStart_toStartOf", l.startToStart);
6022                 writeXmlConstraint("app:layout_constraintTop_toBottomOf", l.topToBottom);
6023                 writeXmlConstraint("app:layout_constraintTop_toTopOf", l.topToTop);
6024 
6025                 String[] typesConstraintDefault = {"spread", "wrap", "percent"};
6026                 writeEnum("app:layout_constraintHeight_default", l.heightDefault,
6027                         typesConstraintDefault, ConstraintWidget.MATCH_CONSTRAINT_SPREAD);
6028                 writeVariable("app:layout_constraintHeight_percent", l.heightPercent, 1);
6029                 writeDimension("app:layout_constraintHeight_min", l.heightMin, 0);
6030                 writeDimension("app:layout_constraintHeight_max", l.heightMax, 0);
6031                 writeBoolen("android:layout_constrainedHeight",
6032                         l.constrainedHeight, false);
6033 
6034                 writeEnum("app:layout_constraintWidth_default",
6035                         l.widthDefault, typesConstraintDefault,
6036                         ConstraintWidget.MATCH_CONSTRAINT_SPREAD);
6037                 writeVariable("app:layout_constraintWidth_percent", l.widthPercent, 1);
6038                 writeDimension("app:layout_constraintWidth_min", l.widthMin, 0);
6039                 writeDimension("app:layout_constraintWidth_max", l.widthMax, 0);
6040                 writeBoolen("android:layout_constrainedWidth",
6041                         l.constrainedWidth, false);
6042 
6043                 writeVariable("app:layout_constraintVertical_weight",
6044                         l.verticalWeight, UNSET);
6045                 writeVariable("app:layout_constraintHorizontal_weight",
6046                         l.horizontalWeight, UNSET);
6047                 writeVariable("app:layout_constraintHorizontal_chainStyle",
6048                         l.horizontalChainStyle);
6049                 writeVariable("app:layout_constraintVertical_chainStyle",
6050                         l.verticalChainStyle);
6051                 String[] barrierDir = {"left", "right", "top", "bottom", "start", "end"};
6052                 writeEnum("app:barrierDirection", l.mBarrierDirection, barrierDir, UNSET);
6053                 writeVariable("app:layout_constraintTag", l.mConstraintTag, null);
6054 
6055                 if (l.mReferenceIds != null) {
6056                     writeVariable("'ReferenceIds'", l.mReferenceIds);
6057                 }
6058                 mWriter.write(" />\n");
6059             }
6060             mWriter.write("</ConstraintSet>\n");
6061         }
6062 
6063         private static final String SPACE = "\n       ";
6064 
writeBoolen(String dimString, boolean val, boolean def)6065         private void writeBoolen(String dimString, boolean val, boolean def) throws IOException {
6066             if (val != def) {
6067                 mWriter.write(SPACE + dimString + "=\"" + val + "dp\"");
6068             }
6069         }
6070 
writeEnum(String dimString, int val, String[] types, int def)6071         private void writeEnum(String dimString,
6072                                int val,
6073                                String[] types,
6074                                int def) throws IOException {
6075             if (val != def) {
6076                 mWriter.write(SPACE + dimString + "=\"" + types[val] + "\"");
6077             }
6078         }
6079 
writeDimension(String dimString, int dim, int def)6080         private void writeDimension(String dimString, int dim, int def) throws IOException {
6081             if (dim != def) {
6082                 mWriter.write(SPACE + dimString + "=\"" + dim + "dp\"");
6083             }
6084         }
6085 
writeBaseDimension(String dimString, int dim, int def)6086         private void writeBaseDimension(String dimString, int dim, int def) throws IOException {
6087             if (dim != def) {
6088                 if (dim == -2) {
6089                     mWriter.write(SPACE + dimString + "=\"wrap_content\"");
6090 
6091                 } else if (dim == -1) {
6092                     mWriter.write(SPACE + dimString + "=\"match_parent\"");
6093 
6094                 } else {
6095                     mWriter.write(SPACE + dimString + "=\"" + dim + "dp\"");
6096                 }
6097             }
6098         }
6099 
6100         HashMap<Integer, String> mIdMap = new HashMap<>();
6101 
getName(int id)6102         String getName(int id) {
6103             if (mIdMap.containsKey(id)) {
6104                 return "@+id/" + mIdMap.get(id) + "";
6105             }
6106             if (id == 0) {
6107                 return "parent";
6108             }
6109             String name = lookup(id);
6110             mIdMap.put(id, name);
6111             return "@+id/" + name + "";
6112         }
6113 
lookup(int id)6114         String lookup(int id) {
6115             try {
6116                 if (id != -1) {
6117                     return mContext.getResources().getResourceEntryName(id);
6118                 } else {
6119                     return "unknown" + ++mUnknownCount;
6120                 }
6121             } catch (Exception ex) {
6122                 return "unknown" + ++mUnknownCount;
6123             }
6124         }
6125 
writeXmlConstraint(String str, int leftToLeft)6126         void writeXmlConstraint(String str, int leftToLeft) throws IOException {
6127             if (leftToLeft == UNSET) {
6128                 return;
6129             }
6130             mWriter.write(SPACE + str);
6131             mWriter.write("=\"" + getName(leftToLeft) + "\"");
6132 
6133         }
6134 
writeConstraint(String my, int leftToLeft, String other, int margin, int goneMargin)6135         void writeConstraint(String my, int leftToLeft,
6136                              String other,
6137                              int margin,
6138                              int goneMargin) throws IOException {
6139             if (leftToLeft == UNSET) {
6140                 return;
6141             }
6142             mWriter.write(SPACE + my);
6143             mWriter.write(":[");
6144             mWriter.write(getName(leftToLeft));
6145             mWriter.write(" , ");
6146             mWriter.write(other);
6147             if (margin != 0) {
6148                 mWriter.write(" , " + margin);
6149             }
6150             mWriter.write("],\n");
6151 
6152         }
6153 
writeCircle(int circleConstraint, float circleAngle, int circleRadius)6154         void writeCircle(int circleConstraint,
6155                          float circleAngle,
6156                          int circleRadius) throws IOException {
6157             if (circleConstraint == UNSET) {
6158                 return;
6159             }
6160             mWriter.write("circle");
6161             mWriter.write(":[");
6162             mWriter.write(getName(circleConstraint));
6163             mWriter.write(", " + circleAngle);
6164             mWriter.write(circleRadius + "]");
6165         }
6166 
writeVariable(String name, int value)6167         void writeVariable(String name, int value) throws IOException {
6168             if (value == 0 || value == -1) {
6169                 return;
6170             }
6171             mWriter.write(SPACE + name + "=\"" + value + "\"\n");
6172         }
6173 
writeVariable(String name, float value, float def)6174         void writeVariable(String name, float value, float def) throws IOException {
6175             if (value == def) {
6176                 return;
6177             }
6178             mWriter.write(SPACE + name);
6179             mWriter.write("=\"" + value + "\"");
6180 
6181         }
6182 
writeVariable(String name, String value, String def)6183         void writeVariable(String name, String value, String def) throws IOException {
6184             if (value == null || value.equals(def)) {
6185                 return;
6186             }
6187             mWriter.write(SPACE + name);
6188             mWriter.write("=\"" + value + "\"");
6189 
6190         }
6191 
writeVariable(String name, int[] value)6192         void writeVariable(String name, int[] value) throws IOException {
6193             if (value == null) {
6194                 return;
6195             }
6196             mWriter.write(SPACE + name);
6197             mWriter.write(":");
6198             for (int i = 0; i < value.length; i++) {
6199                 mWriter.write(((i == 0) ? "[" : ", ") + getName(value[i]));
6200             }
6201             mWriter.write("],\n");
6202         }
6203 
writeVariable(String name, String value)6204         void writeVariable(String name, String value) throws IOException {
6205             if (value == null) {
6206                 return;
6207             }
6208             mWriter.write(name);
6209             mWriter.write(":");
6210             mWriter.write(", " + value);
6211             mWriter.write("\n");
6212 
6213         }
6214     }
6215 
6216     // ================================== JSON ===============================================
6217     class WriteJsonEngine {
6218         Writer mWriter;
6219         ConstraintLayout mLayout;
6220         Context mContext;
6221         int mFlags;
6222         int mUnknownCount = 0;
6223         final String mLEFT = "'left'";
6224         final String mRIGHT = "'right'";
6225         final String mBASELINE = "'baseline'";
6226         final String mBOTTOM = "'bottom'";
6227         final String mTOP = "'top'";
6228         final String mSTART = "'start'";
6229         final String mEND = "'end'";
6230         private static final String SPACE = "       ";
6231 
WriteJsonEngine(Writer writer, ConstraintLayout layout, int flags)6232         WriteJsonEngine(Writer writer, ConstraintLayout layout, int flags) throws IOException {
6233             this.mWriter = writer;
6234             this.mLayout = layout;
6235             this.mContext = layout.getContext();
6236             this.mFlags = flags;
6237         }
6238 
writeLayout()6239         void writeLayout() throws IOException {
6240             mWriter.write("\n\'ConstraintSet\':{\n");
6241             for (Integer id : mConstraints.keySet()) {
6242                 Constraint c = mConstraints.get(id);
6243                 String idName = getName(id);
6244                 mWriter.write(idName + ":{\n");
6245                 Layout l = c.layout;
6246 
6247                 writeDimension("height", l.mHeight, l.heightDefault, l.heightPercent,
6248                         l.heightMin, l.heightMax, l.constrainedHeight);
6249                 writeDimension("width", l.mWidth, l.widthDefault, l.widthPercent,
6250                         l.widthMin, l.widthMax, l.constrainedWidth);
6251 
6252                 writeConstraint(mLEFT, l.leftToLeft, mLEFT, l.leftMargin, l.goneLeftMargin);
6253                 writeConstraint(mLEFT, l.leftToRight, mRIGHT, l.leftMargin, l.goneLeftMargin);
6254                 writeConstraint(mRIGHT, l.rightToLeft, mLEFT, l.rightMargin, l.goneRightMargin);
6255                 writeConstraint(mRIGHT, l.rightToRight, mRIGHT, l.rightMargin, l.goneRightMargin);
6256                 writeConstraint(mBASELINE, l.baselineToBaseline, mBASELINE, UNSET,
6257                         l.goneBaselineMargin);
6258                 writeConstraint(mBASELINE, l.baselineToTop, mTOP, UNSET, l.goneBaselineMargin);
6259                 writeConstraint(mBASELINE, l.baselineToBottom,
6260                         mBOTTOM, UNSET, l.goneBaselineMargin);
6261 
6262                 writeConstraint(mTOP, l.topToBottom, mBOTTOM, l.topMargin, l.goneTopMargin);
6263                 writeConstraint(mTOP, l.topToTop, mTOP, l.topMargin, l.goneTopMargin);
6264                 writeConstraint(mBOTTOM, l.bottomToBottom, mBOTTOM, l.bottomMargin,
6265                         l.goneBottomMargin);
6266                 writeConstraint(mBOTTOM, l.bottomToTop, mTOP, l.bottomMargin, l.goneBottomMargin);
6267                 writeConstraint(mSTART, l.startToStart, mSTART, l.startMargin, l.goneStartMargin);
6268                 writeConstraint(mSTART, l.startToEnd, mEND, l.startMargin, l.goneStartMargin);
6269                 writeConstraint(mEND, l.endToStart, mSTART, l.endMargin, l.goneEndMargin);
6270                 writeConstraint(mEND, l.endToEnd, mEND, l.endMargin, l.goneEndMargin);
6271                 writeVariable("'horizontalBias'", l.horizontalBias, 0.5f);
6272                 writeVariable("'verticalBias'", l.verticalBias, 0.5f);
6273 
6274                 writeCircle(l.circleConstraint, l.circleAngle, l.circleRadius);
6275 
6276                 writeGuideline(l.orientation, l.guideBegin, l.guideEnd, l.guidePercent);
6277                 writeVariable("'dimensionRatio'", l.dimensionRatio);
6278                 writeVariable("'barrierMargin'", l.mBarrierMargin);
6279                 writeVariable("'type'", l.mHelperType);
6280                 writeVariable("'ReferenceId'", l.mReferenceIdString);
6281                 writeVariable("'mBarrierAllowsGoneWidgets'",
6282                         l.mBarrierAllowsGoneWidgets, true);
6283                 writeVariable("'WrapBehavior'", l.mWrapBehavior);
6284 
6285                 writeVariable("'verticalWeight'", l.verticalWeight);
6286                 writeVariable("'horizontalWeight'", l.horizontalWeight);
6287                 writeVariable("'horizontalChainStyle'", l.horizontalChainStyle);
6288                 writeVariable("'verticalChainStyle'", l.verticalChainStyle);
6289                 writeVariable("'barrierDirection'", l.mBarrierDirection);
6290                 if (l.mReferenceIds != null) {
6291                     writeVariable("'ReferenceIds'", l.mReferenceIds);
6292                 }
6293                 mWriter.write("}\n");
6294             }
6295             mWriter.write("}\n");
6296         }
6297 
writeGuideline(int orientation, int guideBegin, int guideEnd, float guidePercent)6298         private void writeGuideline(int orientation,
6299                                     int guideBegin,
6300                                     int guideEnd,
6301                                     float guidePercent) throws IOException {
6302             writeVariable("'orientation'", orientation);
6303             writeVariable("'guideBegin'", guideBegin);
6304             writeVariable("'guideEnd'", guideEnd);
6305             writeVariable("'guidePercent'", guidePercent);
6306 
6307         }
6308 
6309 
writeDimension(String dimString, int dim, int dimDefault, float dimPercent, int dimMin, int dimMax, boolean unusedConstrainedDim)6310         private void writeDimension(String dimString,
6311                                     int dim,
6312                                     int dimDefault,
6313                                     float dimPercent,
6314                                     int dimMin,
6315                                     int dimMax,
6316                                     boolean unusedConstrainedDim) throws IOException {
6317             if (dim == 0) {
6318                 if (dimMax != UNSET || dimMin != UNSET) {
6319                     switch (dimDefault) {
6320                         case 0: // spread
6321                             mWriter.write(SPACE + dimString
6322                                     + ": {'spread' ," + dimMin + ", " + dimMax + "}\n");
6323                             break;
6324                         case 1: //  wrap
6325                             mWriter.write(SPACE + dimString
6326                                     + ": {'wrap' ," + dimMin + ", " + dimMax + "}\n");
6327                             return;
6328                         case 2: // percent
6329                             mWriter.write(SPACE + dimString + ": {'" + dimPercent
6330                                     + "'% ," + dimMin + ", " + dimMax + "}\n");
6331                             return;
6332                     }
6333                     return;
6334                 }
6335 
6336                 switch (dimDefault) {
6337                     case 0: // spread is the default
6338                         break;
6339                     case 1: //  wrap
6340                         mWriter.write(SPACE + dimString + ": '???????????',\n");
6341                         return;
6342                     case 2: // percent
6343                         mWriter.write(SPACE + dimString + ": '" + dimPercent + "%',\n");
6344                         return;
6345                 }
6346 
6347             } else if (dim == -2) {
6348                 mWriter.write(SPACE + dimString + ": 'wrap'\n");
6349             } else if (dim == -1) {
6350                 mWriter.write(SPACE + dimString + ": 'parent'\n");
6351             } else {
6352                 mWriter.write(SPACE + dimString + ": " + dim + ",\n");
6353             }
6354         }
6355 
6356         HashMap<Integer, String> mIdMap = new HashMap<>();
6357 
getName(int id)6358         String getName(int id) {
6359             if (mIdMap.containsKey(id)) {
6360                 return "\'" + mIdMap.get(id) + "\'";
6361             }
6362             if (id == 0) {
6363                 return "'parent'";
6364             }
6365             String name = lookup(id);
6366             mIdMap.put(id, name);
6367             return "\'" + name + "\'";
6368         }
6369 
lookup(int id)6370         String lookup(int id) {
6371             try {
6372                 if (id != -1) {
6373                     return mContext.getResources().getResourceEntryName(id);
6374                 } else {
6375                     return "unknown" + ++mUnknownCount;
6376                 }
6377             } catch (Exception ex) {
6378                 return "unknown" + ++mUnknownCount;
6379             }
6380         }
6381 
writeConstraint(String my, int leftToLeft, String other, int margin, int goneMargin)6382         void writeConstraint(String my,
6383                              int leftToLeft,
6384                              String other,
6385                              int margin,
6386                              int goneMargin) throws IOException {
6387             if (leftToLeft == UNSET) {
6388                 return;
6389             }
6390             mWriter.write(SPACE + my);
6391             mWriter.write(":[");
6392             mWriter.write(getName(leftToLeft));
6393             mWriter.write(" , ");
6394             mWriter.write(other);
6395             if (margin != 0) {
6396                 mWriter.write(" , " + margin);
6397             }
6398             mWriter.write("],\n");
6399 
6400         }
6401 
writeCircle(int circleConstraint, float circleAngle, int circleRadius)6402         void writeCircle(int circleConstraint,
6403                          float circleAngle,
6404                          int circleRadius) throws IOException {
6405             if (circleConstraint == UNSET) {
6406                 return;
6407             }
6408             mWriter.write(SPACE + "circle");
6409             mWriter.write(":[");
6410             mWriter.write(getName(circleConstraint));
6411             mWriter.write(", " + circleAngle);
6412             mWriter.write(circleRadius + "]");
6413         }
6414 
writeVariable(String name, int value)6415         void writeVariable(String name, int value) throws IOException {
6416             if (value == 0 || value == -1) {
6417                 return;
6418             }
6419             mWriter.write(SPACE + name);
6420             mWriter.write(":");
6421 
6422             mWriter.write(", " + value);
6423             mWriter.write("\n");
6424 
6425         }
6426 
writeVariable(String name, float value)6427         void writeVariable(String name, float value) throws IOException {
6428             if (value == UNSET) {
6429                 return;
6430             }
6431             mWriter.write(SPACE + name);
6432 
6433             mWriter.write(": " + value);
6434             mWriter.write(",\n");
6435 
6436         }
6437 
writeVariable(String name, float value, float def)6438         void writeVariable(String name, float value, float def) throws IOException {
6439             if (value == def) {
6440                 return;
6441             }
6442             mWriter.write(SPACE + name);
6443 
6444             mWriter.write(": " + value);
6445             mWriter.write(",\n");
6446 
6447         }
6448 
writeVariable(String name, boolean value)6449         void writeVariable(String name, boolean value) throws IOException {
6450             if (!value) {
6451                 return;
6452             }
6453             mWriter.write(SPACE + name);
6454 
6455             mWriter.write(": " + value);
6456             mWriter.write(",\n");
6457 
6458         }
writeVariable(String name, boolean value , boolean def)6459         void writeVariable(String name, boolean value , boolean def) throws IOException {
6460             if (value == def) {
6461                 return;
6462             }
6463             mWriter.write(SPACE + name);
6464 
6465             mWriter.write(": " + value);
6466             mWriter.write(",\n");
6467 
6468         }
6469 
writeVariable(String name, int[] value)6470         void writeVariable(String name, int[] value) throws IOException {
6471             if (value == null) {
6472                 return;
6473             }
6474             mWriter.write(SPACE + name);
6475             mWriter.write(": ");
6476             for (int i = 0; i < value.length; i++) {
6477                 mWriter.write(((i == 0) ? "[" : ", ") + getName(value[i]));
6478             }
6479             mWriter.write("],\n");
6480         }
6481 
writeVariable(String name, String value)6482         void writeVariable(String name, String value) throws IOException {
6483             if (value == null) {
6484                 return;
6485             }
6486             mWriter.write(SPACE + name);
6487             mWriter.write(":");
6488             mWriter.write(", " + value);
6489             mWriter.write("\n");
6490 
6491         }
6492     }
6493 
6494 }
6495