Fixes for optical bounds feature.

1. Make the feature opt-in (ViewGroup::layoutMode defaults to CLIP_BOUNDS) without inheritance.
2. Rename COMPONENT_BOUNDS to CLIP_BOUNDS.
3. Rename LAYOUT_BOUNDS to OPTICAL_BOUNDS.
4. Complete GridLayout implementation.
5. Change the default_gap between components to 8dp, to align with the Style Guide.

Change-Id: I8d40dfc5f4ca469f6424eb3ff60d07bec56e3a9f
diff --git a/api/current.txt b/api/current.txt
index 921ff0b..284b11c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -24493,12 +24493,12 @@
     method public void startLayoutAnimation();
     method public void startViewTransition(android.view.View);
     method public void updateViewLayout(android.view.View, android.view.ViewGroup.LayoutParams);
+    field public static final int CLIP_BOUNDS = 0; // 0x0
     field protected static final int CLIP_TO_PADDING_MASK = 34; // 0x22
-    field public static final int COMPONENT_BOUNDS = 0; // 0x0
     field public static final int FOCUS_AFTER_DESCENDANTS = 262144; // 0x40000
     field public static final int FOCUS_BEFORE_DESCENDANTS = 131072; // 0x20000
     field public static final int FOCUS_BLOCK_DESCENDANTS = 393216; // 0x60000
-    field public static final int LAYOUT_BOUNDS = 1; // 0x1
+    field public static final int OPTICAL_BOUNDS = 1; // 0x1
     field public static final int PERSISTENT_ALL_CACHES = 3; // 0x3
     field public static final int PERSISTENT_ANIMATION_CACHE = 1; // 0x1
     field public static final int PERSISTENT_NO_CACHE = 0; // 0x0
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 461e7f1..588bb06 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13853,7 +13853,7 @@
     /**
      * @hide
      */
-    public Insets getLayoutInsets() {
+    public Insets getOpticalInsets() {
         if (mLayoutInsets == null) {
             mLayoutInsets = (mBackground == null) ? Insets.NONE : mBackground.getLayoutInsets();
         }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 9009e9a..6250623 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -173,10 +173,9 @@
     protected int mGroupFlags;
 
     /*
-     * THe layout mode: either {@link #UNDEFINED_LAYOUT_MODE}, {@link #COMPONENT_BOUNDS} or
-     * {@link #LAYOUT_BOUNDS}
+     * The layout mode: either {@link #CLIP_BOUNDS} or {@link #OPTICAL_BOUNDS}
      */
-    private int mLayoutMode = UNDEFINED_LAYOUT_MODE;
+    private int mLayoutMode = CLIP_BOUNDS;
 
     /**
      * NOTE: If you change the flags below make sure to reflect the changes
@@ -345,19 +344,20 @@
 
     // Layout Modes
 
-    private static final int UNDEFINED_LAYOUT_MODE = -1;
-
     /**
      * This constant is a {@link #setLayoutMode(int) layoutMode}.
-     * Component bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top},
+     * Clip bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top},
      * {@link #getRight() right} and {@link #getBottom() bottom}.
      */
-    public static final int COMPONENT_BOUNDS = 0;
+    public static final int CLIP_BOUNDS = 0;
 
     /**
      * This constant is a {@link #setLayoutMode(int) layoutMode}.
+     * Optical bounds describe where a widget appears to be. They sit inside the clip
+     * bounds which need to cover a larger area to allow other effects,
+     * such as shadows and glows, to be drawn.
      */
-    public static final int LAYOUT_BOUNDS = 1;
+    public static final int OPTICAL_BOUNDS = 1;
 
     /**
      * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
@@ -2696,10 +2696,10 @@
      */
     protected void onDebugDraw(Canvas canvas) {
         // Draw optical bounds
-        if (getLayoutMode() == LAYOUT_BOUNDS) {
+        if (getLayoutMode() == OPTICAL_BOUNDS) {
             for (int i = 0; i < getChildCount(); i++) {
                 View c = getChildAt(i);
-                Insets insets = c.getLayoutInsets();
+                Insets insets = c.getOpticalInsets();
                 drawRect(canvas,
                         c.getLeft() + insets.left,
                         c.getTop() + insets.top,
@@ -4597,37 +4597,22 @@
     }
 
     /**
-     * Returns the basis of alignment during the layout of this view group:
-     * either {@link #COMPONENT_BOUNDS} or {@link #LAYOUT_BOUNDS}.
+     * Returns the basis of alignment during layout operations on this view group:
+     * either {@link #CLIP_BOUNDS} or {@link #OPTICAL_BOUNDS}.
      *
      * @return the layout mode to use during layout operations
      *
      * @see #setLayoutMode(int)
      */
     public int getLayoutMode() {
-        if (mLayoutMode == UNDEFINED_LAYOUT_MODE) {
-            ViewParent parent = getParent();
-            if (parent instanceof ViewGroup) {
-                ViewGroup viewGroup = (ViewGroup) parent;
-                return viewGroup.getLayoutMode();
-            } else {
-                int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
-                boolean preJellyBean = targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN;
-                return preJellyBean ? COMPONENT_BOUNDS : LAYOUT_BOUNDS;
-            }
-
-        }
         return mLayoutMode;
     }
 
     /**
-     * Sets the basis of alignment during alignment of this view group.
-     * Valid values are either {@link #COMPONENT_BOUNDS} or {@link #LAYOUT_BOUNDS}.
+     * Sets the basis of alignment during the layout of this view group.
+     * Valid values are either {@link #CLIP_BOUNDS} or {@link #OPTICAL_BOUNDS}.
      * <p>
-     * The default is to query the property of the parent if this view group has a parent.
-     * If this ViewGroup is the root of the view hierarchy the default
-     * value is {@link #LAYOUT_BOUNDS} for target SDK's greater than JellyBean,
-     * {@link #LAYOUT_BOUNDS} otherwise.
+     * The default is {@link #CLIP_BOUNDS}.
      *
      * @param layoutMode the layout mode to use during layout operations
      *
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index e17e048..cb10d0a 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -581,10 +581,10 @@
     }
 
     private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) {
-        return isAtEdge ? DEFAULT_CONTAINER_MARGIN : getDefaultMargin(c, horizontal, leading);
+        return /*isAtEdge ? DEFAULT_CONTAINER_MARGIN :*/ getDefaultMargin(c, horizontal, leading);
     }
 
-    private int getDefaultMarginValue(View c, LayoutParams p, boolean horizontal, boolean leading) {
+    private int getDefaultMargin(View c, LayoutParams p, boolean horizontal, boolean leading) {
         if (!useDefaultMargins) {
             return 0;
         }
@@ -602,7 +602,7 @@
         int margin = horizontal ?
                 (leading ? lp.leftMargin : lp.rightMargin) :
                 (leading ? lp.topMargin : lp.bottomMargin);
-        return margin == UNDEFINED ? getDefaultMarginValue(view, lp, horizontal, leading) : margin;
+        return margin == UNDEFINED ? getDefaultMargin(view, lp, horizontal, leading) : margin;
     }
 
     private int getMargin(View view, boolean horizontal, boolean leading) {
@@ -777,11 +777,12 @@
         LayoutParams lp = new LayoutParams();
         for (int i = 0; i < getChildCount(); i++) {
             View c = getChildAt(i);
+            Insets insets = getLayoutMode() == OPTICAL_BOUNDS ? c.getOpticalInsets() : Insets.NONE;
             lp.setMargins(
-                    getMargin1(c, true, true),
-                    getMargin1(c, false, true),
-                    getMargin1(c, true, false),
-                    getMargin1(c, false, false));
+                    getMargin1(c, true, true) - insets.left,
+                    getMargin1(c, false, true) - insets.top,
+                    getMargin1(c, true, false) - insets.right,
+                    getMargin1(c, false, false) - insets.bottom);
             lp.onDebugDraw(c, canvas);
         }
     }
@@ -946,7 +947,12 @@
     }
 
     private int getMeasurement(View c, boolean horizontal) {
-        return horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight();
+        int result = horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight();
+        if (getLayoutMode() == OPTICAL_BOUNDS) {
+            Insets insets = c.getOpticalInsets();
+            return result - (horizontal ? insets.left + insets.right : insets.top + insets.bottom);
+        }
+        return result;
     }
 
     final int getMeasurementIncludingMargin(View c, boolean horizontal) {
@@ -1052,6 +1058,14 @@
                     targetWidth - width - paddingRight - rightMargin - dx;
             int cy = paddingTop + y1 + gravityOffsetY + alignmentOffsetY + topMargin;
 
+            boolean useLayoutBounds = getLayoutMode() == OPTICAL_BOUNDS;
+            if (useLayoutBounds) {
+                Insets insets = c.getOpticalInsets();
+                cx -= insets.left;
+                cy -= insets.top;
+                width += (insets.left + insets.right);
+                height += (insets.top + insets.bottom);
+            }
             if (width != c.getMeasuredWidth() || height != c.getMeasuredHeight()) {
                 c.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY));
             }
@@ -2135,21 +2149,8 @@
             return before + after;
         }
 
-        private int getAlignmentValue(GridLayout gl, View c, int size, Alignment a, boolean horiz) {
-            boolean useLayoutBounds = gl.getLayoutMode() == LAYOUT_BOUNDS;
-            if (!useLayoutBounds) {
-                return a.getAlignmentValue(c, size);
-            } else {
-                Insets insets = c.getLayoutInsets();
-                int leadingInset = horiz ? insets.left : insets.top; // RTL?
-                int trailingInset = horiz ? insets.right : insets.bottom; // RTL?
-                int totalInset = leadingInset + trailingInset;
-                return leadingInset + a.getAlignmentValue(c, size - totalInset);
-            }
-        }
-
         protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean horizontal) {
-            return before - getAlignmentValue(gl, c, size, a, horizontal);
+            return before - a.getAlignmentValue(c, size, gl.getLayoutMode());
         }
 
         protected final void include(GridLayout gl, View c, Spec spec, Axis axis) {
@@ -2158,7 +2159,7 @@
             int size = gl.getMeasurementIncludingMargin(c, horizontal);
             Alignment alignment = gl.getAlignment(spec.alignment, horizontal);
             // todo test this works correctly when the returned value is UNDEFINED
-            int before = getAlignmentValue(gl, c, size, alignment, horizontal);
+            int before = alignment.getAlignmentValue(c, size, gl.getLayoutMode());
             include(before, size - before);
         }
 
@@ -2441,9 +2442,10 @@
          *
          * @param view              the view to which this alignment should be applied
          * @param viewSize          the measured size of the view
+         * @param mode              the basis of alignment: CLIP or OPTICAL
          * @return the alignment value
          */
-        abstract int getAlignmentValue(View view, int viewSize);
+        abstract int getAlignmentValue(View view, int viewSize, int mode);
 
         /**
          * Returns the size of the view specified by this alignment.
@@ -2473,7 +2475,7 @@
         }
 
         @Override
-        public int getAlignmentValue(View view, int viewSize) {
+        public int getAlignmentValue(View view, int viewSize, int mode) {
             return UNDEFINED;
         }
     };
@@ -2489,7 +2491,7 @@
         }
 
         @Override
-        public int getAlignmentValue(View view, int viewSize) {
+        public int getAlignmentValue(View view, int viewSize, int mode) {
             return 0;
         }
     };
@@ -2505,7 +2507,7 @@
         }
 
         @Override
-        public int getAlignmentValue(View view, int viewSize) {
+        public int getAlignmentValue(View view, int viewSize, int mode) {
             return viewSize;
         }
     };
@@ -2542,8 +2544,8 @@
             }
 
             @Override
-            public int getAlignmentValue(View view, int viewSize) {
-                return (!view.isLayoutRtl() ? ltr : rtl).getAlignmentValue(view, viewSize);
+            public int getAlignmentValue(View view, int viewSize, int mode) {
+                return (!view.isLayoutRtl() ? ltr : rtl).getAlignmentValue(view, viewSize, mode);
             }
         };
     }
@@ -2572,7 +2574,7 @@
         }
 
         @Override
-        public int getAlignmentValue(View view, int viewSize) {
+        public int getAlignmentValue(View view, int viewSize, int mode) {
             return viewSize >> 1;
         }
     };
@@ -2591,9 +2593,16 @@
         }
 
         @Override
-        public int getAlignmentValue(View view, int viewSize) {
+        public int getAlignmentValue(View view, int viewSize, int mode) {
             int baseline = view.getBaseline();
-            return (baseline == -1) ? UNDEFINED : baseline;
+            if (baseline == -1) {
+                return UNDEFINED;
+            } else {
+                if (mode == OPTICAL_BOUNDS) {
+                    return baseline - view.getOpticalInsets().top;
+                }
+                return baseline;
+            }
         }
 
         @Override
@@ -2644,7 +2653,7 @@
         }
 
         @Override
-        public int getAlignmentValue(View view, int viewSize) {
+        public int getAlignmentValue(View view, int viewSize, int mode) {
             return UNDEFINED;
         }
 
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index bda6266..f812822 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -194,7 +194,7 @@
     <dimen name="activity_chooser_popup_min_width">200dip</dimen>
 
     <!-- The default gap between components in a layout. -->
-    <dimen name="default_gap">16dip</dimen>
+    <dimen name="default_gap">8dip</dimen>
 
     <!-- Text padding for dropdown items -->
     <dimen name="dropdownitem_text_padding_left">8dip</dimen>
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 006baa7..b68b267 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -56,6 +56,7 @@
     private NinePatchState mNinePatchState;
     private NinePatch mNinePatch;
     private Rect mPadding;
+    private Insets mLayoutInsets = Insets.NONE;
     private Paint mPaint;
     private boolean mMutated;
 
@@ -180,12 +181,21 @@
         }
     }
 
+    private Insets scaleFromDensity(Insets insets, int sdensity, int tdensity) {
+        int left = Bitmap.scaleFromDensity(insets.left, sdensity, tdensity);
+        int top = Bitmap.scaleFromDensity(insets.top, sdensity, tdensity);
+        int right = Bitmap.scaleFromDensity(insets.right, sdensity, tdensity);
+        int bottom = Bitmap.scaleFromDensity(insets.bottom, sdensity, tdensity);
+        return Insets.of(left, top, right, bottom);
+    }
+
     private void computeBitmapSize() {
         final int sdensity = mNinePatch.getDensity();
         final int tdensity = mTargetDensity;
         if (sdensity == tdensity) {
             mBitmapWidth = mNinePatch.getWidth();
             mBitmapHeight = mNinePatch.getHeight();
+            mLayoutInsets = mNinePatchState.mLayoutInsets;
         } else {
             mBitmapWidth = Bitmap.scaleFromDensity(mNinePatch.getWidth(),
                     sdensity, tdensity);
@@ -202,6 +212,7 @@
                 dest.right = Bitmap.scaleFromDensity(src.right, sdensity, tdensity);
                 dest.bottom = Bitmap.scaleFromDensity(src.bottom, sdensity, tdensity);
             }
+            mLayoutInsets = scaleFromDensity(mNinePatchState.mLayoutInsets, sdensity, tdensity);
         }
     }
 
@@ -226,7 +237,7 @@
      */
     @Override
     public Insets getLayoutInsets() {
-        return mNinePatchState.mLayoutInsets;
+        return mLayoutInsets;
     }
 
     @Override
diff --git a/tests/GridLayoutTest/res/drawable/btn_default.xml b/tests/GridLayoutTest/res/drawable/btn_default.xml
deleted file mode 100644
index c6cfda0..0000000
--- a/tests/GridLayoutTest/res/drawable/btn_default.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_window_focused="false" android:state_enabled="true"
-        android:drawable="@drawable/my_btn_default_normal" />
-    <item android:state_window_focused="false" android:state_enabled="false"
-        android:drawable="@drawable/my_btn_default_normal" />
-    <item android:state_pressed="true" 
-        android:drawable="@drawable/my_btn_default_pressed" />
-    <item android:state_focused="true" android:state_enabled="true"
-        android:drawable="@drawable/my_btn_default_selected" />
-    <item android:state_enabled="true"
-        android:drawable="@drawable/my_btn_default_normal" />
-    <item android:state_focused="true"
-        android:drawable="@drawable/my_btn_default_normal_disable_focused" />
-    <item
-         android:drawable="@drawable/my_btn_default_normal_disable" />
-</selector>
diff --git a/tests/GridLayoutTest/res/drawable/my_btn_default_normal.9.png b/tests/GridLayoutTest/res/drawable/btn_default_normal.9.png
similarity index 100%
rename from tests/GridLayoutTest/res/drawable/my_btn_default_normal.9.png
rename to tests/GridLayoutTest/res/drawable/btn_default_normal.9.png
Binary files differ
diff --git a/tests/GridLayoutTest/res/drawable/my_btn_default_normal_disable.9.png b/tests/GridLayoutTest/res/drawable/my_btn_default_normal_disable.9.png
deleted file mode 100755
index f4f01c7..0000000
--- a/tests/GridLayoutTest/res/drawable/my_btn_default_normal_disable.9.png
+++ /dev/null
Binary files differ
diff --git a/tests/GridLayoutTest/res/drawable/my_btn_default_normal_disable_focused.9.png b/tests/GridLayoutTest/res/drawable/my_btn_default_normal_disable_focused.9.png
deleted file mode 100755
index 5376db2..0000000
--- a/tests/GridLayoutTest/res/drawable/my_btn_default_normal_disable_focused.9.png
+++ /dev/null
Binary files differ
diff --git a/tests/GridLayoutTest/res/drawable/my_btn_default_pressed.9.png b/tests/GridLayoutTest/res/drawable/my_btn_default_pressed.9.png
deleted file mode 100755
index 4312c27..0000000
--- a/tests/GridLayoutTest/res/drawable/my_btn_default_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/tests/GridLayoutTest/res/drawable/my_btn_default_selected.9.png b/tests/GridLayoutTest/res/drawable/my_btn_default_selected.9.png
deleted file mode 100755
index 06b7790..0000000
--- a/tests/GridLayoutTest/res/drawable/my_btn_default_selected.9.png
+++ /dev/null
Binary files differ
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/LayoutInsetsTest.java b/tests/GridLayoutTest/src/com/android/test/layout/LayoutInsetsTest.java
index e9e1ae7..103de2f 100644
--- a/tests/GridLayoutTest/src/com/android/test/layout/LayoutInsetsTest.java
+++ b/tests/GridLayoutTest/src/com/android/test/layout/LayoutInsetsTest.java
@@ -4,46 +4,49 @@
 import android.content.Context;
 import android.os.Build;
 import android.os.Bundle;
+import android.view.Gravity;
 import android.view.View;
 import android.widget.Button;
 import android.widget.GridLayout;
 import android.widget.TextView;
 
-import static android.widget.GridLayout.*;
+import static android.widget.GridLayout.ALIGN_BOUNDS;
+import static android.widget.GridLayout.LayoutParams;
+import static android.widget.GridLayout.OPTICAL_BOUNDS;
 
 public class LayoutInsetsTest extends Activity {
+    static int[] GRAVITIES = {Gravity.LEFT, Gravity.LEFT, Gravity.CENTER_HORIZONTAL, Gravity.RIGHT, Gravity.RIGHT};
+
     public static View create(Context context) {
+        final int N = GRAVITIES.length;
+
         GridLayout p = new GridLayout(context);
         p.setUseDefaultMargins(true);
-        p.setAlignmentMode(ALIGN_BOUNDS);
-        p.setOrientation(VERTICAL);
+        //p.setAlignmentMode(ALIGN_BOUNDS);
+        p.setLayoutMode(OPTICAL_BOUNDS);
 
-        {
-            TextView c = new TextView(context);
-            c.setTextSize(32);
-            c.setText("Email setup");
-            p.addView(c);
-        }
-        {
-            Button c = new Button(context);
-            c.setBackgroundResource(R.drawable.btn_default);
-            c.setText("Test");
-            p.addView(c);
+        p.setColumnCount(N);
+
+        for (int i = 0; i < 2*N; i++) {
+            View c;
+            if (i % 2 == 0) {
+                TextView tv = new TextView(context);
+                tv.setTextSize(32);
+                tv.setText("A");
+                c = tv;
+            } else {
+                Button b = new Button(context);
+                b.setBackgroundResource(R.drawable.btn_default_normal);
+                b.setText("B");
+                c = b;
+            }
+
+            LayoutParams lp = new LayoutParams();
+            lp.setGravity(GRAVITIES[(i % N)]);
+            p.addView(c, lp);
+
         }
 
-        {
-            Button c = new Button(context);
-            c.setBackgroundResource(R.drawable.btn_default);
-            c.setText("Manual setup");
-            p.addView(c);
-            c.setOnClickListener(new OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    Button b = (Button) v;
-                    b.setEnabled(false);
-                }
-            });
-        }
 
         return p;
     }