Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6876b4fb authored by Romain Guy's avatar Romain Guy
Browse files

Replace HashMap with ArrayMap to remove unnecessary allocations

This change also fixes a race condition. If multiple UI threads are used
in a single process, RelativeLayouts could end up using the same nodes
in different windows, causing mayhem and headaches.

Change-Id: I9ba4a0bf05d44e1a1e7a82443d40c500c657cd7a
parent 20914c6a
Loading
Loading
Loading
Loading
+21 −106
Original line number Diff line number Diff line
@@ -16,22 +16,21 @@

package android.widget;

import android.util.ArrayMap;
import com.android.internal.R;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.SortedSet;
import java.util.TreeSet;

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Pools.SimplePool;
import android.util.Pools.SynchronizedPool;
import android.util.SparseArray;
import android.view.Gravity;
import android.view.View;
@@ -42,7 +41,6 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.RemoteViews.RemoteView;

import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
import static android.util.Log.d;

/**
 * A Layout where the positions of the children can be described in relation to each other or to the
@@ -83,10 +81,6 @@ import static android.util.Log.d;
 */
@RemoteView
public class RelativeLayout extends ViewGroup {
    private static final String LOG_TAG = "RelativeLayout";

    private static final boolean DEBUG_GRAPH = false;

    public static final int TRUE = -1;

    /**
@@ -212,8 +206,8 @@ public class RelativeLayout extends ViewGroup {
    private SortedSet<View> mTopToBottomLeftToRightSet = null;
    
    private boolean mDirtyHierarchy;
    private View[] mSortedHorizontalChildren = new View[0];
    private View[] mSortedVerticalChildren = new View[0];
    private View[] mSortedHorizontalChildren;
    private View[] mSortedVerticalChildren;
    private final DependencyGraph mGraph = new DependencyGraph();

    // Compatibility hack. Old versions of the platform had problems
@@ -360,42 +354,26 @@ public class RelativeLayout extends ViewGroup {
    }

    private void sortChildren() {
        int count = getChildCount();
        if (mSortedVerticalChildren.length != count) mSortedVerticalChildren = new View[count];
        if (mSortedHorizontalChildren.length != count) mSortedHorizontalChildren = new View[count];
        final int count = getChildCount();
        if (mSortedVerticalChildren == null || mSortedVerticalChildren.length != count) {
            mSortedVerticalChildren = new View[count];
        }

        if (mSortedHorizontalChildren == null || mSortedHorizontalChildren.length != count) {
            mSortedHorizontalChildren = new View[count];
        }

        final DependencyGraph graph = mGraph;
        graph.clear();

        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            graph.add(child);
        }

        if (DEBUG_GRAPH) {
            d(LOG_TAG, "=== Sorted vertical children");
            graph.log(getResources(), RULES_VERTICAL);
            d(LOG_TAG, "=== Sorted horizontal children");
            graph.log(getResources(), RULES_HORIZONTAL);
            graph.add(getChildAt(i));
        }

        graph.getSortedViews(mSortedVerticalChildren, RULES_VERTICAL);
        graph.getSortedViews(mSortedHorizontalChildren, RULES_HORIZONTAL);

        if (DEBUG_GRAPH) {
            d(LOG_TAG, "=== Ordered list of vertical children");
            for (View view : mSortedVerticalChildren) {
                DependencyGraph.printViewId(getResources(), view);
            }
            d(LOG_TAG, "=== Ordered list of horizontal children");
            for (View view : mSortedHorizontalChildren) {
                DependencyGraph.printViewId(getResources(), view);
            }
        }        
    }

    // TODO: we need to find another way to implement RelativeLayout
    // This implementation cannot handle every case
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mDirtyHierarchy) {
@@ -900,8 +878,6 @@ public class RelativeLayout extends ViewGroup {
        } else if (childParams.alignWithParent && rules[LEFT_OF] != 0) {
            if (myWidth >= 0) {
                childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
            } else {
                // FIXME uh oh...
            }
        }

@@ -926,8 +902,6 @@ public class RelativeLayout extends ViewGroup {
        } else if (childParams.alignWithParent && rules[ALIGN_RIGHT] != 0) {
            if (myWidth >= 0) {
                childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
            } else {
                // FIXME uh oh...
            }
        }

@@ -938,8 +912,6 @@ public class RelativeLayout extends ViewGroup {
        if (0 != rules[ALIGN_PARENT_RIGHT]) {
            if (myWidth >= 0) {
                childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
            } else {
                // FIXME uh oh...
            }
        }
    }
@@ -958,8 +930,6 @@ public class RelativeLayout extends ViewGroup {
        } else if (childParams.alignWithParent && rules[ABOVE] != 0) {
            if (myHeight >= 0) {
                childParams.mBottom = myHeight - mPaddingBottom - childParams.bottomMargin;
            } else {
                // FIXME uh oh...
            }
        }

@@ -984,8 +954,6 @@ public class RelativeLayout extends ViewGroup {
        } else if (childParams.alignWithParent && rules[ALIGN_BOTTOM] != 0) {
            if (myHeight >= 0) {
                childParams.mBottom = myHeight - mPaddingBottom - childParams.bottomMargin;
            } else {
                // FIXME uh oh...
            }
        }

@@ -996,8 +964,6 @@ public class RelativeLayout extends ViewGroup {
        if (0 != rules[ALIGN_PARENT_BOTTOM]) {
            if (myHeight >= 0) {
                childParams.mBottom = myHeight - mPaddingBottom - childParams.bottomMargin;
            } else {
                // FIXME uh oh...
            }
        }

@@ -1677,8 +1643,10 @@ public class RelativeLayout extends ViewGroup {

                sorted[index++] = view;

                final HashMap<Node, DependencyGraph> dependents = node.dependents;
                for (Node dependent : dependents.keySet()) {
                final ArrayMap<Node, DependencyGraph> dependents = node.dependents;
                final int count = dependents.size();
                for (int i = 0; i < count; i++) {
                    final Node dependent = dependents.keyAt(i);
                    final SparseArray<Node> dependencies = dependent.dependencies;

                    dependencies.remove(key);
@@ -1755,61 +1723,6 @@ public class RelativeLayout extends ViewGroup {
            return roots;
        }

        /**
         * Prints the dependency graph for the specified rules.
         *
         * @param resources The context's resources to print the ids.
         * @param rules The list of rules to take into account.
         */
        void log(Resources resources, int... rules) {
            final ArrayDeque<Node> roots = findRoots(rules);
            for (Node node : roots) {
                printNode(resources, node);
            }
        }

        static void printViewId(Resources resources, View view) {
            if (view.getId() != View.NO_ID) {
                d(LOG_TAG, resources.getResourceEntryName(view.getId()));
            } else {
                d(LOG_TAG, "NO_ID");
            }
        }

        private static void appendViewId(Resources resources, Node node, StringBuilder buffer) {
            if (node.view.getId() != View.NO_ID) {
                buffer.append(resources.getResourceEntryName(node.view.getId()));
            } else {
                buffer.append("NO_ID");
            }
        }

        private static void printNode(Resources resources, Node node) {
            if (node.dependents.size() == 0) {
                printViewId(resources, node.view);
            } else {
                for (Node dependent : node.dependents.keySet()) {
                    StringBuilder buffer = new StringBuilder();
                    appendViewId(resources, node, buffer);
                    printdependents(resources, dependent, buffer);
                }
            }
        }

        private static void printdependents(Resources resources, Node node, StringBuilder buffer) {
            buffer.append(" -> ");
            appendViewId(resources, node, buffer);

            if (node.dependents.size() == 0) {
                d(LOG_TAG, buffer.toString());
            } else {
                for (Node dependent : node.dependents.keySet()) {
                    StringBuilder subBuffer = new StringBuilder(buffer);
                    printdependents(resources, dependent, subBuffer);
                }
            }
        }

        /**
         * A node in the dependency graph. A node is a view, its list of dependencies
         * and its list of dependents.
@@ -1826,7 +1739,8 @@ public class RelativeLayout extends ViewGroup {
             * The list of dependents for this node; a dependent is a node
             * that needs this node to be processed first.
             */
            final HashMap<Node, DependencyGraph> dependents = new HashMap<Node, DependencyGraph>();
            final ArrayMap<Node, DependencyGraph> dependents =
                    new ArrayMap<Node, DependencyGraph>();

            /**
             * The list of dependencies for this node.
@@ -1839,7 +1753,8 @@ public class RelativeLayout extends ViewGroup {
            // The pool is static, so all nodes instances are shared across
            // activities, that's why we give it a rather high limit
            private static final int POOL_LIMIT = 100;
            private static final SimplePool<Node> sPool = new SimplePool<Node>(POOL_LIMIT);
            private static final SynchronizedPool<Node> sPool =
                    new SynchronizedPool<Node>(POOL_LIMIT);

            static Node acquire(View view) {
                Node node = sPool.acquire();