diff --git a/android/README.md b/android/README.md deleted file mode 100644 index 9a143c8c..00000000 --- a/android/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# YogaLayout [![Platform](https://img.shields.io/badge/platforms-Android-orange.svg)](https://facebook.github.io/yoga/docs/api/android/) [![Languages](https://img.shields.io/badge/languages-Java-orange.svg)](https://facebook.github.io/yoga/docs/api/android/) [![Download](https://img.shields.io/bintray/v/facebook/maven/com.facebook.yoga.android:yoga-layout.svg)](https://bintray.com/facebook/maven/com.facebook.yoga.android%3Ayoga-layout/_latestVersion) - -## Installation - -YogaLayout is available via jcenter: - - implementation 'com.facebook.yoga.android:yoga-layout:1.16.0' - -## Getting Started - -Check out the docs [here](https://yogalayout.com/getting-started/standalone/). - -We also have a sample project. To try it, clone the repo and run (with a device attached) - - buck install -r android/sample - -## Contributing - -We welcome all pull-requests! At Facebook we sync the open source version of YogaKit daily, so we're always testing the latest changes. - -See the CONTRIBUTING file for how to help out. diff --git a/android/build.gradle b/android/build.gradle deleted file mode 100644 index 57b37499..00000000 --- a/android/build.gradle +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -plugins { - id("com.android.library") - id("publish") -} - -android { - namespace 'com.facebook.yoga.android' - - compileSdkVersion rootProject.compileSdkVersion - buildToolsVersion rootProject.buildToolsVersion - ndkVersion rootProject.ndkVersion - - defaultConfig { - minSdkVersion rootProject.minSdkVersion - targetSdkVersion rootProject.targetSdkVersion - } - - compileOptions { - targetCompatibility rootProject.targetCompatibilityVersion - sourceCompatibility rootProject.sourceCompatibilityVersion - } - - publishing { - multipleVariants { - withSourcesJar() - withJavadocJar() - includeBuildTypeValues('debug', 'release') - } - } -} - -dependencies { - api project(':yoga') -} diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml deleted file mode 100644 index 7513275a..00000000 --- a/android/src/main/AndroidManifest.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - diff --git a/android/src/main/java/com/facebook/yoga/android/VirtualYogaLayout.java b/android/src/main/java/com/facebook/yoga/android/VirtualYogaLayout.java deleted file mode 100644 index c8ad1c3c..00000000 --- a/android/src/main/java/com/facebook/yoga/android/VirtualYogaLayout.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.yoga.android; - -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.View; -import android.view.ViewGroup; - -import com.facebook.yoga.YogaNode; -import com.facebook.yoga.YogaNodeFactory; - -/** - * Much like a {@link YogaLayout}, except this class does not render itself (the container) to the - * screen. As a result, do not use this if you wish the container to have a background or - * foreground. However, all of its children will still render as expected. - * - *

- * In practice, this class never added to the View tree, and all its children become children of its - * parent. As a result, all the layout (such as the traversal of the tree) is performed by Yoga - * (and so natively) increasing performance. - */ -public class VirtualYogaLayout extends ViewGroup { - - final private List mChildren = new LinkedList<>(); - final private Map mYogaNodes = new HashMap<>(); - final private YogaNode mYogaNode = YogaNodeFactory.create(); - - public VirtualYogaLayout(Context context) { - super(context); - } - - public VirtualYogaLayout(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public VirtualYogaLayout(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - YogaLayout.LayoutParams lp = new YogaLayout.LayoutParams(context, attrs); - YogaLayout.applyLayoutParams(lp, mYogaNode, this); - } - - public YogaNode getYogaNode() { - return mYogaNode; - } - - /** - * Called to add a view, creating a new yoga node for it and adding that yoga node to the parent. - * If the child is a {@link VirtualYogaLayout}, we simply transfer all its children to this one - * in a manner that maintains the tree, and add its root to the tree. - * - * @param child the View to add - * @param index the position at which to add it (ignored) - * @param params the layout parameters to apply - */ - @Override - public void addView(View child, int index, ViewGroup.LayoutParams params) { - if (child instanceof VirtualYogaLayout) { - ((VirtualYogaLayout) child).transferChildren(this); - - final YogaNode childNode = ((VirtualYogaLayout) child).getYogaNode(); - mYogaNode.addChildAt(childNode, mYogaNode.getChildCount()); - - return; - } - - YogaNode node = YogaNodeFactory.create(); - YogaLayout.LayoutParams lp = new YogaLayout.LayoutParams(params); - YogaLayout.applyLayoutParams(lp, node, child); - node.setData(child); - node.setMeasureFunction(new YogaLayout.ViewMeasureFunction()); - - mYogaNode.addChildAt(node, mYogaNode.getChildCount()); - - addView(child, node); - } - - /** - * Called to add a view with a corresponding node, but not to change the Yoga tree in any way. - * - * @param child the View to add - * @param node the corresponding yoga node - */ - public void addView(View child, YogaNode node) { - mChildren.add(child); - mYogaNodes.put(child, node); - } - - /** - * Gives up children {@code View}s to the parent, maintaining the Yoga tree. This function calls - * {@link YogaLayout#addView(View, YogaNode)} or {@link VirtualYogaLayout#addView(View, YogaNode)} - * on the parent to add the {@code View} without generating new yoga nodes. - * - * @param parent the parent to pass children to (must be a YogaLayout or a VirtualYogaLayout) - */ - protected void transferChildren(ViewGroup parent) { - if (parent instanceof VirtualYogaLayout) { - for (View child : mChildren) { - ((VirtualYogaLayout) parent).addView(child, mYogaNodes.get(child)); - } - } else if (parent instanceof YogaLayout) { - for (View child : mChildren) { - ((YogaLayout) parent).addView(child, mYogaNodes.get(child)); - } - } else { - throw new RuntimeException("VirtualYogaLayout cannot transfer children to ViewGroup of type " - +parent.getClass().getCanonicalName()+". Must either be a VirtualYogaLayout or a " + - "YogaLayout."); - } - mChildren.clear(); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - throw new RuntimeException("Attempting to layout a VirtualYogaLayout"); - } - - @Override - public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { - return new YogaLayout.LayoutParams(getContext(), attrs); - } - - @Override - protected ViewGroup.LayoutParams generateDefaultLayoutParams() { - return new YogaLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT); - } - - @Override - protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { - return new YogaLayout.LayoutParams(p); - } - - @Override - protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { - return p instanceof YogaLayout.LayoutParams; - } -} diff --git a/android/src/main/java/com/facebook/yoga/android/YogaLayout.java b/android/src/main/java/com/facebook/yoga/android/YogaLayout.java deleted file mode 100644 index beee6a99..00000000 --- a/android/src/main/java/com/facebook/yoga/android/YogaLayout.java +++ /dev/null @@ -1,816 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.yoga.android; - -import android.content.Context; -import android.content.res.Configuration; -import android.content.res.TypedArray; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.util.AttributeSet; -import android.util.SparseArray; -import android.util.TypedValue; -import android.view.View; -import android.view.ViewGroup; -import com.facebook.yoga.YogaAlign; -import com.facebook.yoga.YogaConstants; -import com.facebook.yoga.YogaDirection; -import com.facebook.yoga.YogaDisplay; -import com.facebook.yoga.YogaEdge; -import com.facebook.yoga.YogaFlexDirection; -import com.facebook.yoga.YogaJustify; -import com.facebook.yoga.YogaMeasureFunction; -import com.facebook.yoga.YogaMeasureMode; -import com.facebook.yoga.YogaMeasureOutput; -import com.facebook.yoga.YogaNode; -import com.facebook.yoga.YogaNodeFactory; -import com.facebook.yoga.YogaOverflow; -import com.facebook.yoga.YogaPositionType; -import com.facebook.yoga.YogaWrap; -import java.util.HashMap; -import java.util.Map; - -/** - * A {@code ViewGroup} based on the Yoga layout engine. - * - *

- * This class is designed to be as "plug and play" as possible. That is, you can use it in XML - * like this (note: to use {@code YogaLayout} you need to use the {@link YogaViewLayoutFactory}): - *

- *

{@code
- * 
- *     
- * 
- * }
- * - * Under the hood, all views added to this {@code ViewGroup} are laid out using flexbox rules - * and the Yoga engine. - */ -public class YogaLayout extends ViewGroup { - private final Map mYogaNodes; - private final YogaNode mYogaNode; - - public YogaLayout(Context context) { - this(context, null, 0); - } - - public YogaLayout(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public YogaLayout(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - - mYogaNode = YogaNodeFactory.create(); - mYogaNodes = new HashMap<>(); - - mYogaNode.setData(this); - mYogaNode.setMeasureFunction(new ViewMeasureFunction()); - - LayoutParams layoutParams = null; - if (attrs != null) { - layoutParams = new LayoutParams(context, attrs); - } else { - layoutParams = (LayoutParams) generateDefaultLayoutParams(); - } - applyLayoutParams(layoutParams, mYogaNode, this); - } - - public YogaNode getYogaNode() { - return mYogaNode; - } - - public YogaNode getYogaNodeForView(View view) { - return mYogaNodes.get(view); - } - - /** - * Adds a child view with the specified layout parameters. - * - * In the typical View is added, this constructs a {@code YogaNode} for this child and applies all - * the {@code yoga:*} attributes. The Yoga node is added to the Yoga tree and the child is added - * to this ViewGroup. - * - * If the child is a {@link YogaLayout} itself, we do not construct a new Yoga node for that - * child, but use its root node instead. - * - * If the child is a {@link VirtualYogaLayout}, we also use its Yoga node, but we also instruct it - * to transfer all of its children to this {@link YogaLayout} while preserving the Yoga tree (so - * that the layout of its children is correct). The {@link VirtualYogaLayout} is then not added - * to the View hierarchy. - * - *

Note: do not invoke this method from - * {@code #draw(android.graphics.Canvas)}, {@code onDraw(android.graphics.Canvas)}, - * {@code #dispatchDraw(android.graphics.Canvas)} or any related method.

- * - * @param child the child view to add - * @param index the position at which to add the child or -1 to add last - * @param params the layout parameters to set on the child - */ - @Override - public void addView(View child, int index, ViewGroup.LayoutParams params) { - // Internal nodes (which this is now) cannot have measure functions - mYogaNode.setMeasureFunction(null); - - if (child instanceof VirtualYogaLayout) { - ((VirtualYogaLayout) child).transferChildren(this); - final YogaNode childNode = ((VirtualYogaLayout) child).getYogaNode(); - - mYogaNode.addChildAt(childNode, mYogaNode.getChildCount()); - - return; - } - - super.addView(child, index, params); - - // It is possible that addView is being called as part of a transferal of children, in which - // case we already know about the YogaNode and only need the Android View tree to be aware - // that we now own this child. If so, we don't need to do anything further - if (mYogaNodes.containsKey(child)) { - return; - } - - YogaNode childNode; - - if (child instanceof YogaLayout) { - childNode = ((YogaLayout) child).getYogaNode(); - } else { - if(mYogaNodes.containsKey(child)) { - childNode = mYogaNodes.get(child); - } else { - childNode = YogaNodeFactory.create(); - } - - childNode.setData(child); - childNode.setMeasureFunction(new ViewMeasureFunction()); - } - - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - applyLayoutParams(lp, childNode, child); - - mYogaNodes.put(child, childNode); - mYogaNode.addChildAt(childNode, mYogaNode.getChildCount()); - } - - /** - * Adds a view to this {@code ViewGroup} with an already given {@code YogaNode}. Use - * this function if you already have a Yoga node (and perhaps tree) associated with the view you - * are adding, that you would like to preserve. - * - * @param child The view to add - * @param node The Yoga node belonging to the view - */ - public void addView(View child, YogaNode node) { - mYogaNodes.put(child, node); - addView(child); - } - - @Override - public void removeView(View view) { - removeViewFromYogaTree(view, false); - super.removeView(view); - } - - @Override - public void removeViewAt(int index) { - removeViewFromYogaTree(getChildAt(index), false); - super.removeViewAt(index); - } - - @Override - public void removeViewInLayout(View view) { - removeViewFromYogaTree(view, true); - super.removeViewInLayout(view); - } - - @Override - public void removeViews(int start, int count) { - for (int i = start; i < start + count; i++) { - removeViewFromYogaTree(getChildAt(i), false); - } - super.removeViews(start, count); - } - - @Override - public void removeViewsInLayout(int start, int count) { - for (int i = start; i < start + count; i++) { - removeViewFromYogaTree(getChildAt(i), true); - } - super.removeViewsInLayout(start, count); - } - - @Override - public void removeAllViews() { - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - removeViewFromYogaTree(getChildAt(i), false); - } - super.removeAllViews(); - } - - @Override - public void removeAllViewsInLayout() { - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - removeViewFromYogaTree(getChildAt(i), true); - } - super.removeAllViewsInLayout(); - } - - /** - * Marks a particular view as "dirty" and to be relaid out. If the view is not a child of this - * {@link YogaLayout}, the entire tree is traversed to find it. - * - * @param view the view to mark as dirty - */ - public void invalidate(View view) { - if (mYogaNodes.containsKey(view)) { - mYogaNodes.get(view).dirty(); - return; - } - - final int childCount = mYogaNode.getChildCount(); - for (int i = 0; i < childCount; i++) { - final YogaNode yogaNode = mYogaNode.getChildAt(i); - if (yogaNode.getData() instanceof YogaLayout) { - ((YogaLayout) yogaNode.getData()).invalidate(view); - } - } - invalidate(); - } - - private void removeViewFromYogaTree(View view, boolean inLayout) { - final YogaNode node = mYogaNodes.get(view); - if (node == null) { - return; - } - - final YogaNode owner = node.getOwner(); - - for (int i = 0; i < owner.getChildCount(); i++) { - if (owner.getChildAt(i).equals(node)) { - owner.removeChildAt(i); - break; - } - } - - node.setData(null); - mYogaNodes.remove(view); - - if (inLayout) { - mYogaNode.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED); - } - } - - private void applyLayoutRecursive(YogaNode node, float xOffset, float yOffset) { - View view = (View) node.getData(); - - if (view != null && view != this) { - if (view.getVisibility() == GONE) { - return; - } - int left = Math.round(xOffset + node.getLayoutX()); - int top = Math.round(yOffset + node.getLayoutY()); - view.measure( - View.MeasureSpec.makeMeasureSpec( - Math.round(node.getLayoutWidth()), - View.MeasureSpec.EXACTLY), - View.MeasureSpec.makeMeasureSpec( - Math.round(node.getLayoutHeight()), - View.MeasureSpec.EXACTLY)); - view.layout(left, top, left + view.getMeasuredWidth(), top + view.getMeasuredHeight()); - } - - final int childrenCount = node.getChildCount(); - for (int i = 0; i < childrenCount; i++) { - if (this.equals(view)) { - applyLayoutRecursive(node.getChildAt(i), xOffset, yOffset); - } else if (view instanceof YogaLayout) { - continue; - } else { - applyLayoutRecursive( - node.getChildAt(i), - xOffset + node.getLayoutX(), - yOffset + node.getLayoutY()); - } - } - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - // Either we are a root of a tree, or this function is called by our owner's onLayout, in which - // case our r-l and b-t are the size of our node. - if (!(getParent() instanceof YogaLayout)) { - createLayout( - MeasureSpec.makeMeasureSpec(r - l, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(b - t, MeasureSpec.EXACTLY)); - } - - applyLayoutRecursive(mYogaNode, 0, 0); - } - - /** - * This function is mostly unneeded, because Yoga is doing the measuring. Hence we only need to - * return accurate results if we are the root. - * - * @param widthMeasureSpec the suggested specification for the width - * @param heightMeasureSpec the suggested specification for the height - */ - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - if (!(getParent() instanceof YogaLayout)) { - createLayout(widthMeasureSpec, heightMeasureSpec); - } - - setMeasuredDimension( - Math.round(mYogaNode.getLayoutWidth()), - Math.round(mYogaNode.getLayoutHeight())); - } - - private void createLayout(int widthMeasureSpec, int heightMeasureSpec) { - final int widthSize = MeasureSpec.getSize(widthMeasureSpec); - final int heightSize = MeasureSpec.getSize(heightMeasureSpec); - final int widthMode = MeasureSpec.getMode(widthMeasureSpec); - final int heightMode = MeasureSpec.getMode(heightMeasureSpec); - - if (heightMode == MeasureSpec.EXACTLY) { - mYogaNode.setHeight(heightSize); - } - if (widthMode == MeasureSpec.EXACTLY) { - mYogaNode.setWidth(widthSize); - } - if (heightMode == MeasureSpec.AT_MOST) { - mYogaNode.setMaxHeight(heightSize); - } - if (widthMode == MeasureSpec.AT_MOST) { - mYogaNode.setMaxWidth(widthSize); - } - mYogaNode.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED); - } - - /** - * Applies the layout parameters to the YogaNode. That is, this function is a translator from - * {@code yoga:X="Y"} to {@code yogaNode.setX(Y);}, with some reasonable defaults. - * - *

- * If the SDK version is high enough, and the {@code yoga:direction} is not set on - * the component, the direction (LTR or RTL) is set according to the locale. - * - *

- * The attributes {@code padding_top}, {@code padding_right} etc. default to those of the view's - * drawable background, if it has one. - * - * @param layoutParameters The source set of params - * @param node The destination node - */ - protected static void applyLayoutParams(LayoutParams layoutParameters, YogaNode node, View view) { - // JELLY_BEAN_MR1 (17) is the first version supporting getLayoutDirection() - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - Configuration configuration = view.getResources().getConfiguration(); - if (configuration.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { - node.setDirection(YogaDirection.RTL); - } - } - - Drawable background = view.getBackground(); - if (background != null) { - final Rect backgroundPadding = new Rect(); - if (background.getPadding(backgroundPadding)) { - node.setPadding(YogaEdge.LEFT, backgroundPadding.left); - node.setPadding(YogaEdge.TOP, backgroundPadding.top); - node.setPadding(YogaEdge.RIGHT, backgroundPadding.right); - node.setPadding(YogaEdge.BOTTOM, backgroundPadding.bottom); - } - } - - for (int i = 0; i < layoutParameters.numericAttributes.size(); i++) { - final int attribute = layoutParameters.numericAttributes.keyAt(i); - final float value = layoutParameters.numericAttributes.valueAt(i); - - if (attribute == R.styleable.yoga_yg_alignContent) { - node.setAlignContent(YogaAlign.fromInt(Math.round(value))); - } else if (attribute == R.styleable.yoga_yg_alignItems) { - node.setAlignItems(YogaAlign.fromInt(Math.round(value))); - } else if (attribute == R.styleable.yoga_yg_alignSelf) { - node.setAlignSelf(YogaAlign.fromInt(Math.round(value))); - } else if (attribute == R.styleable.yoga_yg_aspectRatio) { - node.setAspectRatio(value); - } else if (attribute == R.styleable.yoga_yg_borderLeft) { - node.setBorder(YogaEdge.LEFT, value); - } else if (attribute == R.styleable.yoga_yg_borderTop) { - node.setBorder(YogaEdge.TOP, value); - } else if (attribute == R.styleable.yoga_yg_borderRight) { - node.setBorder(YogaEdge.RIGHT, value); - } else if (attribute == R.styleable.yoga_yg_borderBottom) { - node.setBorder(YogaEdge.BOTTOM, value); - } else if (attribute == R.styleable.yoga_yg_borderStart) { - node.setBorder(YogaEdge.START, value); - } else if (attribute == R.styleable.yoga_yg_borderEnd) { - node.setBorder(YogaEdge.END, value); - } else if (attribute == R.styleable.yoga_yg_borderHorizontal) { - node.setBorder(YogaEdge.HORIZONTAL, value); - } else if (attribute == R.styleable.yoga_yg_borderVertical) { - node.setBorder(YogaEdge.VERTICAL, value); - } else if (attribute == R.styleable.yoga_yg_borderAll) { - node.setBorder(YogaEdge.ALL, value); - } else if (attribute == R.styleable.yoga_yg_direction) { - node.setDirection(YogaDirection.fromInt(Math.round(value))); - } else if (attribute == R.styleable.yoga_yg_display) { - node.setDisplay(YogaDisplay.fromInt(Math.round(value))); - } else if (attribute == R.styleable.yoga_yg_flex) { - node.setFlex(value); - } else if (attribute == R.styleable.yoga_yg_flexBasis) { - node.setFlexBasis(value); - } else if (attribute == R.styleable.yoga_yg_flexDirection) { - node.setFlexDirection(YogaFlexDirection.fromInt(Math.round(value))); - } else if (attribute == R.styleable.yoga_yg_flexGrow) { - node.setFlexGrow(value); - } else if (attribute == R.styleable.yoga_yg_flexShrink) { - node.setFlexShrink(value); - } else if (attribute == R.styleable.yoga_yg_height) { - node.setHeight(value); - } else if (attribute == R.styleable.yoga_yg_marginLeft) { - node.setMargin(YogaEdge.LEFT, value); - } else if (attribute == R.styleable.yoga_yg_justifyContent) { - node.setJustifyContent(YogaJustify.fromInt(Math.round(value))); - } else if (attribute == R.styleable.yoga_yg_marginTop) { - node.setMargin(YogaEdge.TOP, value); - } else if (attribute == R.styleable.yoga_yg_marginRight) { - node.setMargin(YogaEdge.RIGHT, value); - } else if (attribute == R.styleable.yoga_yg_marginBottom) { - node.setMargin(YogaEdge.BOTTOM, value); - } else if (attribute == R.styleable.yoga_yg_marginStart) { - node.setMargin(YogaEdge.START, value); - } else if (attribute == R.styleable.yoga_yg_marginEnd) { - node.setMargin(YogaEdge.END, value); - } else if (attribute == R.styleable.yoga_yg_marginHorizontal) { - node.setMargin(YogaEdge.HORIZONTAL, value); - } else if (attribute == R.styleable.yoga_yg_marginVertical) { - node.setMargin(YogaEdge.VERTICAL, value); - } else if (attribute == R.styleable.yoga_yg_marginAll) { - node.setMargin(YogaEdge.ALL, value); - } else if (attribute == R.styleable.yoga_yg_maxHeight) { - node.setMaxHeight(value); - } else if (attribute == R.styleable.yoga_yg_maxWidth) { - node.setMaxWidth(value); - } else if (attribute == R.styleable.yoga_yg_minHeight) { - node.setMinHeight(value); - } else if (attribute == R.styleable.yoga_yg_minWidth) { - node.setMinWidth(value); - } else if (attribute == R.styleable.yoga_yg_overflow) { - node.setOverflow(YogaOverflow.fromInt(Math.round(value))); - } else if (attribute == R.styleable.yoga_yg_paddingLeft) { - node.setPadding(YogaEdge.LEFT, value); - } else if (attribute == R.styleable.yoga_yg_paddingTop) { - node.setPadding(YogaEdge.TOP, value); - } else if (attribute == R.styleable.yoga_yg_paddingRight) { - node.setPadding(YogaEdge.RIGHT, value); - } else if (attribute == R.styleable.yoga_yg_paddingBottom) { - node.setPadding(YogaEdge.BOTTOM, value); - } else if (attribute == R.styleable.yoga_yg_paddingStart) { - node.setPadding(YogaEdge.START, value); - } else if (attribute == R.styleable.yoga_yg_paddingEnd) { - node.setPadding(YogaEdge.END, value); - } else if (attribute == R.styleable.yoga_yg_paddingHorizontal) { - node.setPadding(YogaEdge.HORIZONTAL, value); - } else if (attribute == R.styleable.yoga_yg_paddingVertical) { - node.setPadding(YogaEdge.VERTICAL, value); - } else if (attribute == R.styleable.yoga_yg_paddingAll) { - node.setPadding(YogaEdge.ALL, value); - } else if (attribute == R.styleable.yoga_yg_positionLeft) { - node.setPosition(YogaEdge.LEFT, value); - } else if (attribute == R.styleable.yoga_yg_positionTop) { - node.setPosition(YogaEdge.TOP, value); - } else if (attribute == R.styleable.yoga_yg_positionRight) { - node.setPosition(YogaEdge.RIGHT, value); - } else if (attribute == R.styleable.yoga_yg_positionBottom) { - node.setPosition(YogaEdge.BOTTOM, value); - } else if (attribute == R.styleable.yoga_yg_positionStart) { - node.setPosition(YogaEdge.START, value); - } else if (attribute == R.styleable.yoga_yg_positionEnd) { - node.setPosition(YogaEdge.END, value); - } else if (attribute == R.styleable.yoga_yg_positionHorizontal) { - node.setPosition(YogaEdge.HORIZONTAL, value); - } else if (attribute == R.styleable.yoga_yg_positionVertical) { - node.setPosition(YogaEdge.VERTICAL, value); - } else if (attribute == R.styleable.yoga_yg_positionAll) { - node.setPosition(YogaEdge.ALL, value); - } else if (attribute == R.styleable.yoga_yg_positionType) { - node.setPositionType(YogaPositionType.fromInt(Math.round(value))); - } else if (attribute == R.styleable.yoga_yg_width) { - node.setWidth(value); - } else if (attribute == R.styleable.yoga_yg_wrap) { - node.setWrap(YogaWrap.fromInt(Math.round(value))); - } - } - - for (int i = 0; i < layoutParameters.stringAttributes.size(); i++) { - final int attribute = layoutParameters.stringAttributes.keyAt(i); - final String value = layoutParameters.stringAttributes.valueAt(i); - - if (value.equals("auto")) { - if (attribute == R.styleable.yoga_yg_marginLeft) { - node.setMarginAuto(YogaEdge.LEFT); - } else if (attribute == R.styleable.yoga_yg_marginTop) { - node.setMarginAuto(YogaEdge.TOP); - } else if (attribute == R.styleable.yoga_yg_marginRight) { - node.setMarginAuto(YogaEdge.RIGHT); - } else if (attribute == R.styleable.yoga_yg_marginBottom) { - node.setMarginAuto(YogaEdge.BOTTOM); - } else if (attribute == R.styleable.yoga_yg_marginStart) { - node.setMarginAuto(YogaEdge.START); - } else if (attribute == R.styleable.yoga_yg_marginEnd) { - node.setMarginAuto(YogaEdge.END); - } else if (attribute == R.styleable.yoga_yg_marginHorizontal) { - node.setMarginAuto(YogaEdge.HORIZONTAL); - } else if (attribute == R.styleable.yoga_yg_marginVertical) { - node.setMarginAuto(YogaEdge.VERTICAL); - } else if (attribute == R.styleable.yoga_yg_marginAll) { - node.setMarginAuto(YogaEdge.ALL); - } - } - - if (value.endsWith("%")) { - final float numericValue = Float.parseFloat(value.substring(0, value.length()-1)); - - if (attribute == R.styleable.yoga_yg_flexBasis) { - node.setFlexBasisPercent(numericValue); - } else if (attribute == R.styleable.yoga_yg_height) { - node.setHeightPercent(numericValue); - } else if (attribute == R.styleable.yoga_yg_marginLeft) { - node.setMarginPercent(YogaEdge.LEFT, numericValue); - } else if (attribute == R.styleable.yoga_yg_marginTop) { - node.setMarginPercent(YogaEdge.TOP, numericValue); - } else if (attribute == R.styleable.yoga_yg_marginRight) { - node.setMarginPercent(YogaEdge.RIGHT, numericValue); - } else if (attribute == R.styleable.yoga_yg_marginBottom) { - node.setMarginPercent(YogaEdge.BOTTOM, numericValue); - } else if (attribute == R.styleable.yoga_yg_marginStart) { - node.setMarginPercent(YogaEdge.START, numericValue); - } else if (attribute == R.styleable.yoga_yg_marginEnd) { - node.setMarginPercent(YogaEdge.END, numericValue); - } else if (attribute == R.styleable.yoga_yg_marginHorizontal) { - node.setMarginPercent(YogaEdge.HORIZONTAL, numericValue); - } else if (attribute == R.styleable.yoga_yg_marginVertical) { - node.setMarginPercent(YogaEdge.VERTICAL, numericValue); - } else if (attribute == R.styleable.yoga_yg_marginAll) { - node.setMarginPercent(YogaEdge.ALL, numericValue); - } else if (attribute == R.styleable.yoga_yg_maxHeight) { - node.setMaxHeightPercent(numericValue); - } else if (attribute == R.styleable.yoga_yg_maxWidth) { - node.setMaxWidthPercent(numericValue); - } else if (attribute == R.styleable.yoga_yg_minHeight) { - node.setMinHeightPercent(numericValue); - } else if (attribute == R.styleable.yoga_yg_minWidth) { - node.setMinWidthPercent(numericValue); - } else if (attribute == R.styleable.yoga_yg_paddingLeft) { - node.setPaddingPercent(YogaEdge.LEFT, numericValue); - } else if (attribute == R.styleable.yoga_yg_paddingTop) { - node.setPaddingPercent(YogaEdge.TOP, numericValue); - } else if (attribute == R.styleable.yoga_yg_paddingRight) { - node.setPaddingPercent(YogaEdge.RIGHT, numericValue); - } else if (attribute == R.styleable.yoga_yg_paddingBottom) { - node.setPaddingPercent(YogaEdge.BOTTOM, numericValue); - } else if (attribute == R.styleable.yoga_yg_paddingStart) { - node.setPaddingPercent(YogaEdge.START, numericValue); - } else if (attribute == R.styleable.yoga_yg_paddingEnd) { - node.setPaddingPercent(YogaEdge.END, numericValue); - } else if (attribute == R.styleable.yoga_yg_paddingHorizontal) { - node.setPaddingPercent(YogaEdge.HORIZONTAL, numericValue); - } else if (attribute == R.styleable.yoga_yg_paddingVertical) { - node.setPaddingPercent(YogaEdge.VERTICAL, numericValue); - } else if (attribute == R.styleable.yoga_yg_paddingAll) { - node.setPaddingPercent(YogaEdge.ALL, numericValue); - } else if (attribute == R.styleable.yoga_yg_positionLeft) { - node.setPositionPercent(YogaEdge.LEFT, numericValue); - } else if (attribute == R.styleable.yoga_yg_positionTop) { - node.setPositionPercent(YogaEdge.TOP, numericValue); - } else if (attribute == R.styleable.yoga_yg_positionRight) { - node.setPositionPercent(YogaEdge.RIGHT, numericValue); - } else if (attribute == R.styleable.yoga_yg_positionBottom) { - node.setPositionPercent(YogaEdge.BOTTOM, numericValue); - } else if (attribute == R.styleable.yoga_yg_positionStart) { - node.setPositionPercent(YogaEdge.START, numericValue); - } else if (attribute == R.styleable.yoga_yg_positionEnd) { - node.setPositionPercent(YogaEdge.END, numericValue); - } else if (attribute == R.styleable.yoga_yg_positionHorizontal) { - node.setPositionPercent(YogaEdge.HORIZONTAL, numericValue); - } else if (attribute == R.styleable.yoga_yg_positionVertical) { - node.setPositionPercent(YogaEdge.VERTICAL, numericValue); - } else if (attribute == R.styleable.yoga_yg_positionAll) { - node.setPositionPercent(YogaEdge.ALL, numericValue); - } else if (attribute == R.styleable.yoga_yg_width) { - node.setWidthPercent(numericValue); - } - } - } - } - - @Override - public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { - return new YogaLayout.LayoutParams(getContext(), attrs); - } - - @Override - protected ViewGroup.LayoutParams generateDefaultLayoutParams() { - return new YogaLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT); - } - - @Override - protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { - return new YogaLayout.LayoutParams(p); - } - - @Override - protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { - return p instanceof LayoutParams; - } - - /** - * {@code YogaLayout.LayoutParams} are used by views to tell {@link YogaLayout} how they want to - * be laid out. More precisely, the specify the yoga parameters of the view. - * - *

- * This is actually mostly a wrapper around a {@code SparseArray} that holds a mapping between - * styleable id's ({@code R.styleable.yoga_yg_*}) and the float of their values. In cases where - * the value is an enum or an integer, they should first be cast to int (with rounding) before - * using. - */ - public static class LayoutParams extends ViewGroup.LayoutParams { - - /** - * A mapping from attribute keys ({@code R.styleable.yoga_yg_*}) to the float of their values. - * For attributes like position_percent_left (float), this is the native type. For attributes - * like align_self (enums), the integer enum value is cast (rounding is used on the other side - * to prevent precision errors). Dimension attributes are stored as float pixels. - */ - SparseArray numericAttributes; - - /** - * A mapping from attribute keys ({@code R.styleable.yoga_yg_*}) with string values to those - * strings. This is used for values such as "auto". - */ - SparseArray stringAttributes; - - /** - * Constructs a set of layout params from a source set. In the case that the source set is - * actually a {@link YogaLayout.LayoutParams}, we can copy all the yoga attributes. Otherwise - * we start with a blank slate. - * - * @param source The layout params to copy from - */ - public LayoutParams(ViewGroup.LayoutParams source) { - super(source); - if (source instanceof LayoutParams) { - numericAttributes = ((LayoutParams) source).numericAttributes.clone(); - stringAttributes = ((LayoutParams) source).stringAttributes.clone(); - } else { - numericAttributes = new SparseArray<>(); - stringAttributes = new SparseArray<>(); - - // Negative values include MATCH_PARENT and WRAP_CONTENT - if (source.width >= 0) { - numericAttributes.put(R.styleable.yoga_yg_width, (float) width); - } - if (source.height >= 0) { - numericAttributes.put(R.styleable.yoga_yg_height, (float) height); - } - } - } - - /** - * Constructs a set of layout params, given width and height specs. In this case, we can set - * the {@code yoga:width} and {@code yoga:height} if we are given them explicitly. If other - * options (such as {@code match_owner} or {@code wrap_content} are given, then the owner - * LayoutParams will store them, and we deal with them during layout. (see - * {@link YogaLayout#createLayout}) - * - * @param width the requested width, either a pixel size, {@code WRAP_CONTENT} or - * {@code MATCH_PARENT}. - * @param height the requested height, either a pixel size, {@code WRAP_CONTENT} or - * {@code MATCH_PARENT}. - */ - public LayoutParams(int width, int height) { - super(width, height); - numericAttributes = new SparseArray<>(); - stringAttributes = new SparseArray<>(); - // Negative values include MATCH_PARENT and WRAP_CONTENT - if (width >= 0) { - numericAttributes.put(R.styleable.yoga_yg_width, (float) width); - } - if (height >= 0) { - numericAttributes.put(R.styleable.yoga_yg_height, (float) height); - } - } - - /** - * Constructs a set of layout params, given attributes. Grabs all the {@code yoga:*} - * defined in {@code ALL_YOGA_ATTRIBUTES} and collects the ones that are set in {@code attrs}. - * - * @param context the application environment - * @param attrs the set of attributes from which to extract the yoga specific attributes - */ - public LayoutParams(Context context, AttributeSet attrs) { - super(context, attrs); - numericAttributes = new SparseArray<>(); - stringAttributes = new SparseArray<>(); - final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.yoga); - - // Negative values include MATCH_PARENT and WRAP_CONTENT - if (width >= 0) { - numericAttributes.put(R.styleable.yoga_yg_width, (float) width); - } - if (height >= 0) { - numericAttributes.put(R.styleable.yoga_yg_height, (float) height); - } - - final int attributeCount = a.getIndexCount(); - for (int i = 0; i < attributeCount; i++) { - final int attribute = a.getIndex(i); - final TypedValue val = new TypedValue(); - a.getValue(attribute, val); - - if (val.type == TypedValue.TYPE_DIMENSION) { - numericAttributes.put( - attribute, - (float) a.getDimensionPixelSize(attribute, 0)); - } else if (val.type == TypedValue.TYPE_STRING) { - stringAttributes.put(attribute, a.getString(attribute)); - } else { - numericAttributes.put(attribute, a.getFloat(attribute, 0)); - } - } - a.recycle(); - } - } - - /** - * Wrapper around measure function for yoga leaves. - */ - public static class ViewMeasureFunction implements YogaMeasureFunction { - - /** - * A function to measure leaves of the Yoga tree. Yoga needs some way to know how large - * elements want to be. This function passes that question directly through to the relevant - * {@code View}'s measure function. - * - * @param node The yoga node to measure - * @param width The suggested width from the owner - * @param widthMode The type of suggestion for the width - * @param height The suggested height from the owner - * @param heightMode The type of suggestion for the height - * @return A measurement output ({@code YogaMeasureOutput}) for the node - */ - public long measure( - YogaNode node, - float width, - YogaMeasureMode widthMode, - float height, - YogaMeasureMode heightMode) { - final View view = (View) node.getData(); - if (view == null || view instanceof YogaLayout) { - return YogaMeasureOutput.make(0, 0); - } - - final int widthMeasureSpec = MeasureSpec.makeMeasureSpec( - (int) width, - viewMeasureSpecFromYogaMeasureMode(widthMode)); - final int heightMeasureSpec = MeasureSpec.makeMeasureSpec( - (int) height, - viewMeasureSpecFromYogaMeasureMode(heightMode)); - - view.measure(widthMeasureSpec, heightMeasureSpec); - - return YogaMeasureOutput.make(view.getMeasuredWidth(), view.getMeasuredHeight()); - } - - private int viewMeasureSpecFromYogaMeasureMode(YogaMeasureMode mode) { - if (mode == YogaMeasureMode.AT_MOST) { - return MeasureSpec.AT_MOST; - } else if (mode == YogaMeasureMode.EXACTLY) { - return MeasureSpec.EXACTLY; - } else { - return MeasureSpec.UNSPECIFIED; - } - } - } -} diff --git a/android/src/main/java/com/facebook/yoga/android/YogaViewLayoutFactory.java b/android/src/main/java/com/facebook/yoga/android/YogaViewLayoutFactory.java deleted file mode 100644 index e8645351..00000000 --- a/android/src/main/java/com/facebook/yoga/android/YogaViewLayoutFactory.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.yoga.android; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.View; - -/** - * A layout inflater factory. This provides our custom {@link YogaViewLayoutFactory#onCreateView} - * to the XML inflation system, allowing us to replace XML tags. - */ -public class YogaViewLayoutFactory implements LayoutInflater.Factory { - private static YogaViewLayoutFactory sYogaViewLayoutFactory; - - /** - * Obtains (and initialises if necessary) the singleton {@link YogaViewLayoutFactory}. - * - * @return The singleton instance - */ - public static YogaViewLayoutFactory getInstance() { - if (sYogaViewLayoutFactory == null) { - sYogaViewLayoutFactory = new YogaViewLayoutFactory(); - } - return sYogaViewLayoutFactory; - } - - YogaViewLayoutFactory() {} - - /** - * Hook for inflating from a LayoutInflater. This hook replaces the cumbersome - * {@code com.facebook.etc.YogaLayout} with simply {@code YogaLayout} in your XML and the same - * with {@code VirtualYogaLayout}. - * - * @param name Tag name to be inflated. - * @param context The context the view is being created in. - * @param attrs Inflation attributes as specified in XML file. - * - * @return View Newly created view. Return null for the default behavior. - */ - @Override - public View onCreateView(String name, Context context, AttributeSet attrs) { - if (YogaLayout.class.getSimpleName().equals(name)) { - return new YogaLayout(context, attrs); - } - if (VirtualYogaLayout.class.getSimpleName().equals(name)) { - return new VirtualYogaLayout(context, attrs); - } - return null; - } -} diff --git a/android/src/main/res/values/attrs.xml b/android/src/main/res/values/attrs.xml deleted file mode 100644 index 3fca9997..00000000 --- a/android/src/main/res/values/attrs.xml +++ /dev/null @@ -1,150 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sample/build.gradle b/sample/build.gradle deleted file mode 100644 index c5399fe0..00000000 --- a/sample/build.gradle +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -plugins { - id("com.android.application") -} - -android { - namespace 'com.facebook.yoga.sample' - - compileSdkVersion rootProject.compileSdkVersion - buildToolsVersion rootProject.buildToolsVersion - ndkVersion rootProject.ndkVersion - - defaultConfig { - minSdkVersion rootProject.minSdkVersion - targetSdkVersion rootProject.targetSdkVersion - } - - compileOptions { - targetCompatibility rootProject.targetCompatibilityVersion - sourceCompatibility rootProject.sourceCompatibilityVersion - } -} - -dependencies { - implementation project(':yoga-layout') - implementation("androidx.appcompat:appcompat:1.6.1") - implementation("com.facebook.soloader:soloader:0.10.4") -} diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml deleted file mode 100644 index fd53d599..00000000 --- a/sample/src/main/AndroidManifest.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/sample/src/main/java/com/facebook/yoga/sample/BenchmarkActivity.java b/sample/src/main/java/com/facebook/yoga/sample/BenchmarkActivity.java deleted file mode 100644 index bbccee52..00000000 --- a/sample/src/main/java/com/facebook/yoga/sample/BenchmarkActivity.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.yoga.sample; - -import android.content.Intent; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; - -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentPagerAdapter; -import androidx.fragment.app.FragmentTransaction; -import androidx.viewpager.widget.ViewPager; - -import com.facebook.yoga.android.YogaViewLayoutFactory; - -public class BenchmarkActivity extends AppCompatActivity { - - @Override - public void onCreate(Bundle savedInstanceState) { - LayoutInflater.from(this).setFactory(YogaViewLayoutFactory.getInstance()); - super.onCreate(savedInstanceState); - - setContentView(R.layout.benchmark_select_layout); - - ViewPager viewPager = findViewById(R.id.viewpager); - viewPager.setAdapter(new PagerAdapter(getSupportFragmentManager())); - - final ActionBar actionBar = getSupportActionBar(); - actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); - - ActionBar.TabListener tabListener = new ActionBar.TabListener() { - @Override - public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) { - ViewPager viewPager = findViewById(R.id.viewpager); - viewPager.setCurrentItem(tab.getPosition()); - } - - @Override - public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) { - } - - @Override - public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) { - } - }; - actionBar.addTab( - actionBar.newTab() - .setText("Inflate") - .setTabListener(tabListener)); - actionBar.addTab( - actionBar.newTab() - .setText("Measure") - .setTabListener(tabListener)); - actionBar.addTab( - actionBar.newTab() - .setText("Layout") - .setTabListener(tabListener)); - - viewPager.setOnPageChangeListener( - new ViewPager.SimpleOnPageChangeListener() { - @Override - public void onPageSelected(int position) { - // When swiping between pages, select the - // corresponding tab. - actionBar.setSelectedNavigationItem(position); - } - }); - - viewPager.setOffscreenPageLimit(3); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.action_bar_benchmark, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // There is only one option - Intent intent = new Intent(this, MainActivity.class); - startActivity(intent); - this.finish(); - return true; - } - - public static class PagerAdapter extends FragmentPagerAdapter { - public PagerAdapter(FragmentManager fm) { - super(fm); - } - - @Override - public Fragment getItem(int i) { - switch (i) { - case 0: - return new BenchmarkInflate(); - case 1: - return new BenchmarkMeasure(); - default: - return new BenchmarkLayout(); - } - } - - @Override - public int getCount() { - return 3; - } - } -} diff --git a/sample/src/main/java/com/facebook/yoga/sample/BenchmarkAggregator.java b/sample/src/main/java/com/facebook/yoga/sample/BenchmarkAggregator.java deleted file mode 100644 index c1507f78..00000000 --- a/sample/src/main/java/com/facebook/yoga/sample/BenchmarkAggregator.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.yoga.sample; - -import java.io.File; -import java.io.PrintWriter; -import java.lang.Math; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.Date; - -import android.content.Context; -import android.util.Log; -import android.os.Environment; - -import static java.util.Collections.sort; - -public class BenchmarkAggregator { - - private final int GRAPH_WIDTH = 30; - private final int GRAPH_HEIGHT = 6; - - private List times; - private boolean tracing; - private long lastTraceStart; - - private boolean statsFresh; - private long mean; - private long variance; - private long stddev; - private long min; - private long max; - private long p10; - private long p50; - private long p90; - - private String name; - - public BenchmarkAggregator(String name) { - times = new ArrayList<>(); - tracing = false; - this.name = name; - } - - public void startTrace() { - if (tracing) { - throw new RuntimeException("Cannot start trace while running previous one"); - } - tracing = true; - lastTraceStart = System.nanoTime(); - } - - public void endTrace() { - if (!tracing) { - throw new RuntimeException("Cannot stop trace if none are running!"); - } - times.add(System.nanoTime() - lastTraceStart); - tracing = false; - statsFresh = false; - } - - private void computeStats() { - if (statsFresh) { - return; - } - - sort(times); - - min = Long.MAX_VALUE; - max = -1; - mean = 0; - for (long f: times) { - mean += f; - if (f < min) { - min = f; - } - if (f > max) { - max = f; - } - } - mean /= times.size(); - - variance = 0; - for (long f: times) { - variance += (f-mean)*(f-mean); - } - variance /= times.size(); - stddev = (long) Math.sqrt((double) variance); - - p10 = times.get(times.size()*10/100); - p50 = times.get(times.size()*50/100); - p90 = times.get(times.size()*90/100); - - statsFresh = true; - } - - public String toString() { - computeStats(); - return String.format( - "%s:\n" + - "| %d samples\n" + - "| Mean %.3f\u00B1%.3fms\n" + // plusminus - "| Min %.3fms ; Max %.3fms\n" + - "| p10 %.3fms ; p50 %.3fms ; p90 %.3fms\n" + - "%s", - name, - times.size(), - mean/10e6, - stddev/10e6, - min/10e6, - max/10e6, - p10/10e6, - p50/10e6, - p90/10e6, - makeGraph()); - } - - private String makeGraph() { - char canvas[][] = new char[GRAPH_HEIGHT][GRAPH_WIDTH]; - for (int i = 0; i < GRAPH_HEIGHT; i++) - for (int j = 0; j < GRAPH_WIDTH; j++) - canvas[i][j] = ' '; - - long bucketSize = (p90 - p10) / GRAPH_WIDTH+1; - int bucketCount[] = new int[GRAPH_WIDTH]; - for (long time : times) { - if (timep10) { - bucketCount[(int) ((time - p10) / bucketSize)]++; - } - } - - int maxBucket = 0; - for (int i = 0; i < GRAPH_WIDTH; i++) - if (bucketCount[i] > maxBucket) { - maxBucket = bucketCount[i]; - } - - for (int i = 0; i < GRAPH_HEIGHT; i++) - for (int j = 0; j < GRAPH_WIDTH; j++) - if (i < bucketCount[j] * GRAPH_HEIGHT / maxBucket) { - canvas[i][j] = 'Z'; - } - - String graph = new String(); - for (int i = 0; i < GRAPH_HEIGHT; i++) - { - int percentage = 100 * (GRAPH_HEIGHT - i - 1) * maxBucket / (times.size() * GRAPH_HEIGHT); - graph += String.format("| %2d%% ", percentage); - for (int j = 0; j < GRAPH_WIDTH; j++) - graph += canvas[GRAPH_HEIGHT-1-i][j]; - graph += '\n'; - } - - graph += "| p10"; - for (int i = 0; i < GRAPH_WIDTH-6; i++) - graph += " "; - graph += "p90\n"; - return graph; - } - - /** - * Dumps the collected times to a file on the device. This allows us to grab the raw data - * and perform more in-depth analysis. - */ - public void dump(Context context) { - String state = Environment.getExternalStorageState(); - if (!Environment.MEDIA_MOUNTED.equals(state)) { - Log.e("YogaLayoutBenchmark","No external file storage"); - return; - } - - SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); - String filename = format.format(new Date()) + "_" + name.replace(' ','_'); - File file = new File(context.getExternalFilesDir( - Environment.DIRECTORY_DOCUMENTS), filename); - - try { - PrintWriter printWriter = new PrintWriter(file); - for (long l : times) { - printWriter.println(l); - } - printWriter.close(); - - Log.i("YogaLayoutBenchmark","Benchmark data saved in "+file.getPath()); - } catch (java.io.IOException e) { - Log.e("YogaLayoutBenchmark", "Could not save benchmark data", e); - } - } -} diff --git a/sample/src/main/java/com/facebook/yoga/sample/BenchmarkFragment.java b/sample/src/main/java/com/facebook/yoga/sample/BenchmarkFragment.java deleted file mode 100644 index 949a08a4..00000000 --- a/sample/src/main/java/com/facebook/yoga/sample/BenchmarkFragment.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.yoga.sample; - - -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewParent; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.LinearLayout; -import android.widget.Spinner; -import android.widget.TextView; - -import androidx.fragment.app.Fragment; - -import com.facebook.yoga.android.YogaLayout; - -import java.util.Random; - -public class BenchmarkFragment extends Fragment implements AdapterView.OnItemSelectedListener { - private LayoutInflater mInflater; - - protected com.facebook.yoga.android.YogaLayout rootLayout; - protected int yogaLayout; - protected int linearLayout; - - static final Random random = new Random(); - - static void randomizeText(View root) { - if (root instanceof TextView) { - ((TextView) root).setText("" + random.nextInt(1000)); - ((TextView) root).setTextSize(10 + random.nextInt(20)); - ViewParent parent = root.getParent(); - if (parent instanceof YogaLayout) { - ((YogaLayout) parent).invalidate(root); - } - } else if (root instanceof ViewGroup) { - for (int i = 0; i < ((ViewGroup) root).getChildCount(); i++) { - randomizeText(((ViewGroup) root).getChildAt(i)); - } - } - } - - public BenchmarkFragment() { - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } - - @Override - public View onCreateView( - LayoutInflater inflater, - ViewGroup container, - Bundle savedInstanceState) { - mInflater = inflater; - - rootLayout = (YogaLayout) inflater.inflate( - R.layout.benchmark_fragment, - container, - false); - - Spinner benchmarkSelect = rootLayout.findViewById(R.id.benchmarkSelect); - String[] items = new String[]{"Basic", "Typical", "Nested"}; - ArrayAdapter adapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_spinner_dropdown_item, items); - benchmarkSelect.setAdapter(adapter); - benchmarkSelect.setOnItemSelectedListener(this); - return rootLayout; - } - - @Override - public void onItemSelected(AdapterView parent, View view, int pos, long id) { - switch (pos) { - case 0: - yogaLayout = R.layout.benchmark_layout_1; - linearLayout = R.layout.benchmark_layout_1_linear; - break; - case 1: - yogaLayout = R.layout.benchmark_layout_2; - linearLayout = R.layout.benchmark_layout_2_linear; - break; - case 2: - default: - yogaLayout = R.layout.benchmark_layout_3; - linearLayout = R.layout.benchmark_layout_3_linear; - break; - } - updatePreview(); - } - - @Override - public void onNothingSelected(AdapterView parent) { - yogaLayout = R.layout.benchmark_layout_1; - linearLayout = R.layout.benchmark_layout_1_linear; - updatePreview(); - } - - private void updatePreview() { - LinearLayout previewLayout = rootLayout.findViewById(R.id.preview); - View v = mInflater.inflate(yogaLayout, rootLayout, false); - v.setLayoutParams(new LinearLayout.LayoutParams( - LinearLayout.LayoutParams.MATCH_PARENT, - LinearLayout.LayoutParams.MATCH_PARENT)); - previewLayout.removeAllViews(); - previewLayout.addView(v); - } -} diff --git a/sample/src/main/java/com/facebook/yoga/sample/BenchmarkInflate.java b/sample/src/main/java/com/facebook/yoga/sample/BenchmarkInflate.java deleted file mode 100644 index 35fe3718..00000000 --- a/sample/src/main/java/com/facebook/yoga/sample/BenchmarkInflate.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.yoga.sample; - -import android.os.Bundle; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.TextView; - -public class BenchmarkInflate extends BenchmarkFragment { - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - - Button b = rootLayout.findViewById(R.id.btn); - b.setOnClickListener(v -> startBenchmark()); - - return rootLayout; - } - - protected void startBenchmark() { - LayoutInflater inflater = LayoutInflater.from(getActivity()); - TextView textView = rootLayout.findViewById(R.id.text); - - final int ITERATIONS = 500; - - inflater.inflate(yogaLayout, null); - inflater.inflate(linearLayout, null); - - BenchmarkAggregator yogaInflationAggregator = new BenchmarkAggregator("Yoga Inflate"); - BenchmarkAggregator linearInflationAggregator = new BenchmarkAggregator("Linear Inflate"); - for (int i = 0; i < ITERATIONS; i++) { - yogaInflationAggregator.startTrace(); - inflater.inflate(yogaLayout, null); - yogaInflationAggregator.endTrace(); - linearInflationAggregator.startTrace(); - inflater.inflate(linearLayout, null); - linearInflationAggregator.endTrace(); - } - - textView.setText( - yogaInflationAggregator.toString() + - "\n" + - linearInflationAggregator.toString()); - Log.i( - "YogaLayoutBenchmark", - yogaInflationAggregator.toString() + - "\n" + - linearInflationAggregator.toString()); - rootLayout.invalidate(); - } -} diff --git a/sample/src/main/java/com/facebook/yoga/sample/BenchmarkLayout.java b/sample/src/main/java/com/facebook/yoga/sample/BenchmarkLayout.java deleted file mode 100644 index b674d5dd..00000000 --- a/sample/src/main/java/com/facebook/yoga/sample/BenchmarkLayout.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.yoga.sample; - -import android.os.Bundle; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.TextView; - -public class BenchmarkLayout extends BenchmarkFragment { - - @Override - public View onCreateView( - LayoutInflater inflater, - ViewGroup container, - Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - - Button b = rootLayout.findViewById(R.id.btn); - b.setOnClickListener(v -> startBenchmark()); - - return rootLayout; - } - - protected void startBenchmark() { - LayoutInflater inflater = LayoutInflater.from(getActivity()); - TextView textView = rootLayout.findViewById(R.id.text); - - final int ITERATIONS = 500; - - BenchmarkAggregator yogaInflationAggregator = new BenchmarkAggregator("Yoga Layout"); - BenchmarkAggregator linearInflationAggregator = new BenchmarkAggregator("Linear Layout"); - View yogaView = inflater.inflate(yogaLayout, null); - View linearView = inflater.inflate(linearLayout, null); - for (int i = 0; i < ITERATIONS; i++) { - randomizeText(yogaView); - randomizeText(linearView); - yogaView.measure( - View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY), - View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY)); - linearView.measure( - View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY), - View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY)); - yogaInflationAggregator.startTrace(); - yogaView.layout(0, 0, yogaView.getMeasuredWidth(), yogaView.getMeasuredHeight()); - yogaInflationAggregator.endTrace(); - linearInflationAggregator.startTrace(); - linearView.layout(0, 0, linearView.getMeasuredWidth(), linearView.getMeasuredHeight()); - linearInflationAggregator.endTrace(); - } - - textView.setText( - yogaInflationAggregator + - "\n" + - linearInflationAggregator); - Log.i( - "YogaLayoutBenchmark", - yogaInflationAggregator + - "\n" + - linearInflationAggregator); - } -} diff --git a/sample/src/main/java/com/facebook/yoga/sample/BenchmarkMeasure.java b/sample/src/main/java/com/facebook/yoga/sample/BenchmarkMeasure.java deleted file mode 100644 index 61276eb9..00000000 --- a/sample/src/main/java/com/facebook/yoga/sample/BenchmarkMeasure.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.yoga.sample; - -import android.os.Bundle; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.TextView; - -import java.util.Random; - -public class BenchmarkMeasure extends BenchmarkFragment { - - @Override - public View onCreateView( - LayoutInflater inflater, - ViewGroup container, - Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - - Button b = rootLayout.findViewById(R.id.btn); - b.setOnClickListener(v -> startBenchmark()); - - return rootLayout; - } - - protected void startBenchmark() { - LayoutInflater inflater = LayoutInflater.from(getActivity()); - TextView textView = (TextView) rootLayout.findViewById(R.id.text); - Random random = new Random(); - - final int ITERATIONS = 500; - - BenchmarkAggregator yogaMeasureAggregator = new BenchmarkAggregator("Yoga Measure"); - BenchmarkAggregator linearMeasureAggregator = new BenchmarkAggregator("Linear Measure"); - View yogaView = inflater.inflate(yogaLayout, null); - View linearView = inflater.inflate(linearLayout, null); - for (int i = 0; i < ITERATIONS; i++) { - randomizeText(yogaView); - randomizeText(linearView); - yogaMeasureAggregator.startTrace(); - yogaView.measure( - View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY), - View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY)); - yogaMeasureAggregator.endTrace(); - linearMeasureAggregator.startTrace(); - linearView.measure( - View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY), - View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY)); - linearMeasureAggregator.endTrace(); - } - - textView.setText( - yogaMeasureAggregator.toString() + - "\n" + - linearMeasureAggregator.toString()); - Log.i( - "YogaLayoutBenchmark", - yogaMeasureAggregator.toString() + - "\n" + - linearMeasureAggregator.toString()); - - yogaMeasureAggregator.dump(getActivity()); - linearMeasureAggregator.dump(getActivity()); - } -} diff --git a/sample/src/main/java/com/facebook/yoga/sample/MainActivity.java b/sample/src/main/java/com/facebook/yoga/sample/MainActivity.java deleted file mode 100644 index 5d5e5210..00000000 --- a/sample/src/main/java/com/facebook/yoga/sample/MainActivity.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.yoga.sample; - -import android.content.Intent; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; - -import androidx.annotation.NonNull; -import androidx.appcompat.app.AppCompatActivity; - -import com.facebook.soloader.SoLoader; -import com.facebook.yoga.android.YogaViewLayoutFactory; - -/** - * An activity to show off Yoga in Android. This activity shows a simple layout (defined in - * {@code main_layout.xml}) that shows off the awesome functionality of the Yoga layout engine - * as well as some optimisations on layout systems that it facilitates. - */ -public class MainActivity extends AppCompatActivity { - - @Override - public void onCreate(Bundle savedInstanceState) { - LayoutInflater.from(this).setFactory(YogaViewLayoutFactory.getInstance()); - super.onCreate(savedInstanceState); - SoLoader.init(this, false); - - setContentView(R.layout.main_layout); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.action_bar_home, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(@NonNull MenuItem item) { - // There is only one option - Intent intent = new Intent(this, BenchmarkActivity.class); - startActivity(intent); - this.finish(); - return true; - } -} diff --git a/sample/src/main/res/drawable/action_bar_background.xml b/sample/src/main/res/drawable/action_bar_background.xml deleted file mode 100644 index 6c70b26b..00000000 --- a/sample/src/main/res/drawable/action_bar_background.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - diff --git a/sample/src/main/res/drawable/ic_launcher.png b/sample/src/main/res/drawable/ic_launcher.png deleted file mode 100644 index c99f9812..00000000 Binary files a/sample/src/main/res/drawable/ic_launcher.png and /dev/null differ diff --git a/sample/src/main/res/drawable/sample_children_background.xml b/sample/src/main/res/drawable/sample_children_background.xml deleted file mode 100644 index 8d63336a..00000000 --- a/sample/src/main/res/drawable/sample_children_background.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - diff --git a/sample/src/main/res/layout/benchmark_fragment.xml b/sample/src/main/res/layout/benchmark_fragment.xml deleted file mode 100644 index a2c98fdf..00000000 --- a/sample/src/main/res/layout/benchmark_fragment.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - -