Merge "If audio startup fails while executing MediaPlayer::start() do NOT post an error"
diff --git a/api/current.txt b/api/current.txt
index 86339f2..6ded422 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2256,7 +2256,6 @@
     method public abstract void setCustomView(android.view.View);
     method public abstract void setCustomView(android.view.View, android.app.ActionBar.LayoutParams);
     method public abstract void setCustomView(int);
-    method public abstract void setDisplayDisableHomeEnabled(boolean);
     method public abstract void setDisplayHomeAsUpEnabled(boolean);
     method public abstract void setDisplayOptions(int);
     method public abstract void setDisplayOptions(int, int);
@@ -2264,6 +2263,7 @@
     method public abstract void setDisplayShowHomeEnabled(boolean);
     method public abstract void setDisplayShowTitleEnabled(boolean);
     method public abstract void setDisplayUseLogoEnabled(boolean);
+    method public abstract void setHomeButtonEnabled(boolean);
     method public abstract void setIcon(int);
     method public abstract void setIcon(android.graphics.drawable.Drawable);
     method public abstract void setListNavigationCallbacks(android.widget.SpinnerAdapter, android.app.ActionBar.OnNavigationListener);
@@ -2276,7 +2276,6 @@
     method public abstract void setTitle(java.lang.CharSequence);
     method public abstract void setTitle(int);
     method public abstract void show();
-    field public static final int DISPLAY_DISABLE_HOME = 32; // 0x20
     field public static final int DISPLAY_HOME_AS_UP = 4; // 0x4
     field public static final int DISPLAY_SHOW_CUSTOM = 16; // 0x10
     field public static final int DISPLAY_SHOW_HOME = 2; // 0x2
@@ -11958,6 +11957,8 @@
   public final class NdefRecord implements android.os.Parcelable {
     ctor public NdefRecord(short, byte[], byte[], byte[]);
     ctor public NdefRecord(byte[]) throws android.nfc.FormatException;
+    method public static android.nfc.NdefRecord createUri(android.net.Uri);
+    method public static android.nfc.NdefRecord createUri(java.lang.String);
     method public int describeContents();
     method public byte[] getId();
     method public byte[] getPayload();
@@ -25274,6 +25275,10 @@
     method public void setRowCount(int);
     method public void setRowOrderPreserved(boolean);
     method public void setUseDefaultMargins(boolean);
+    method public static android.widget.GridLayout.Spec spec(int, int, android.widget.GridLayout.Alignment, int);
+    method public static android.widget.GridLayout.Spec spec(int, android.widget.GridLayout.Alignment, int);
+    method public static android.widget.GridLayout.Spec spec(int, int, android.widget.GridLayout.Alignment);
+    method public static android.widget.GridLayout.Spec spec(int, android.widget.GridLayout.Alignment);
     field public static final int ALIGN_BOUNDS = 0; // 0x0
     field public static final int ALIGN_MARGINS = 1; // 0x1
     field public static final android.widget.GridLayout.Alignment BASELINE;
@@ -25292,23 +25297,19 @@
   public static abstract class GridLayout.Alignment {
   }
 
-  public static class GridLayout.Group {
-    ctor public GridLayout.Group(int, int, android.widget.GridLayout.Alignment);
-    ctor public GridLayout.Group(int, android.widget.GridLayout.Alignment);
-    field public final android.widget.GridLayout.Alignment alignment;
-    field public int flexibility;
-  }
-
   public static class GridLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
-    ctor public GridLayout.LayoutParams(android.widget.GridLayout.Group, android.widget.GridLayout.Group);
+    ctor public GridLayout.LayoutParams(android.widget.GridLayout.Spec, android.widget.GridLayout.Spec);
     ctor public GridLayout.LayoutParams();
     ctor public GridLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
     ctor public GridLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
     ctor public GridLayout.LayoutParams(android.widget.GridLayout.LayoutParams);
     ctor public GridLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
     method public void setGravity(int);
-    field public android.widget.GridLayout.Group columnGroup;
-    field public android.widget.GridLayout.Group rowGroup;
+    field public android.widget.GridLayout.Spec columnSpec;
+    field public android.widget.GridLayout.Spec rowSpec;
+  }
+
+  public static class GridLayout.Spec {
   }
 
   public class GridView extends android.widget.AbsListView {
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 3ec5edb..36940c2 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -81,6 +81,9 @@
      * Set this flag if selecting the 'home' button in the action bar to return
      * up by a single level in your UI rather than back to the top level or front page.
      *
+     * <p>Setting this option will implicitly enable interaction with the home/up
+     * button. See {@link #setHomeButtonEnabled(boolean)}.
+     *
      * @see #setDisplayOptions(int)
      * @see #setDisplayOptions(int, int)
      */
@@ -107,18 +110,6 @@
     public static final int DISPLAY_SHOW_CUSTOM = 0x10;
 
     /**
-     * Disable the 'home' element. This may be combined with
-     * {@link #DISPLAY_SHOW_HOME} to create a non-focusable/non-clickable
-     * 'home' element. Useful for a level of your app's navigation hierarchy
-     * where clicking 'home' doesn't do anything.
-     *
-     * @see #setDisplayOptions(int)
-     * @see #setDisplayOptions(int, int)
-     * @see #setDisplayDisableHomeEnabled(boolean)
-     */
-    public static final int DISPLAY_DISABLE_HOME = 0x20;
-
-    /**
      * Set the action bar into custom navigation mode, supplying a view
      * for custom navigation.
      *
@@ -405,21 +396,6 @@
     public abstract void setDisplayShowCustomEnabled(boolean showCustom);
 
     /**
-     * Set whether the 'home' affordance on the action bar should be disabled.
-     * If set, the 'home' element will not be focusable or clickable, useful if
-     * the user is at the top level of the app's navigation hierarchy.
-     *
-     * <p>To set several display options at once, see the setDisplayOptions methods.
-     *
-     * @param disableHome true to disable the 'home' element.
-     *
-     * @see #setDisplayOptions(int)
-     * @see #setDisplayOptions(int, int)
-     * @see #DISPLAY_DISABLE_HOME
-     */
-    public abstract void setDisplayDisableHomeEnabled(boolean disableHome);
-
-    /**
      * Set the ActionBar's background.
      * 
      * @param d Background drawable
@@ -632,6 +608,22 @@
     public abstract void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener);
 
     /**
+     * Enable or disable the "home" button in the corner of the action bar. (Note that this
+     * is the application home/up affordance on the action bar, not the systemwide home
+     * button.)
+     *
+     * <p>This defaults to true for packages targeting &lt; API 14. For packages targeting
+     * API 14 or greater, the application should call this method to enable interaction
+     * with the home/up affordance.
+     *
+     * <p>Setting the {@link #DISPLAY_HOME_AS_UP} display option will automatically enable
+     * the home button.
+     *
+     * @param enabled true to enable the home button, false to disable the home button.
+     */
+    public abstract void setHomeButtonEnabled(boolean enabled);
+
+    /**
      * Listener interface for ActionBar navigation events.
      */
     public interface OnNavigationListener {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ee04729..8994b17 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -932,6 +932,10 @@
             ucd.info = info;
             queueOrSendMessage(H.UPDATE_PACKAGE_COMPATIBILITY_INFO, ucd);
         }
+
+        public void scheduleTrimMemory(int level) {
+            queueOrSendMessage(H.TRIM_MEMORY, level);
+        }
     }
 
     private final class H extends Handler {
@@ -975,6 +979,7 @@
         public static final int SLEEPING                = 137;
         public static final int SET_CORE_SETTINGS       = 138;
         public static final int UPDATE_PACKAGE_COMPATIBILITY_INFO = 139;
+        public static final int TRIM_MEMORY             = 140;
         String codeToString(int code) {
             if (DEBUG_MESSAGES) {
                 switch (code) {
@@ -1018,6 +1023,7 @@
                     case SLEEPING: return "SLEEPING";
                     case SET_CORE_SETTINGS: return "SET_CORE_SETTINGS";
                     case UPDATE_PACKAGE_COMPATIBILITY_INFO: return "UPDATE_PACKAGE_COMPATIBILITY_INFO";
+                    case TRIM_MEMORY: return "TRIM_MEMORY";
                 }
             }
             return "(unknown)";
@@ -1158,6 +1164,8 @@
                     break;
                 case UPDATE_PACKAGE_COMPATIBILITY_INFO:
                     handleUpdatePackageCompatibilityInfo((UpdateCompatibilityData)msg.obj);
+                case TRIM_MEMORY:
+                    handleTrimMemory(msg.arg1);
             }
             if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what);
         }
@@ -3529,6 +3537,9 @@
         BinderInternal.forceGc("mem");
     }
 
+    final void handleTrimMemory(int level) {
+    }
+
     private final void handleBindApplication(AppBindData data) {
         mBoundApplication = data;
         mConfiguration = new Configuration(data.config);
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index dc0f529..16181e0 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -478,6 +478,13 @@
             updatePackageCompatibilityInfo(pkg, compat);
             return true;
         }
+
+        case SCHEDULE_TRIM_MEMORY_TRANSACTION: {
+            data.enforceInterface(IApplicationThread.descriptor);
+            int level = data.readInt();
+            scheduleTrimMemory(level);
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -989,4 +996,12 @@
         mRemote.transact(UPDATE_PACKAGE_COMPATIBILITY_INFO_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
     }
+
+    public void scheduleTrimMemory(int level) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        data.writeInterfaceToken(IApplicationThread.descriptor);
+        data.writeInt(level);
+        mRemote.transact(SCHEDULE_TRIM_MEMORY_TRANSACTION, data, null,
+                IBinder.FLAG_ONEWAY);
+    }
 }
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 05a68a8..94c2c86 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -119,6 +119,7 @@
             throws RemoteException;
     void setCoreSettings(Bundle coreSettings) throws RemoteException;
     void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info) throws RemoteException;
+    void scheduleTrimMemory(int level) throws RemoteException;
 
     String descriptor = "android.app.IApplicationThread";
 
@@ -162,4 +163,5 @@
     int SET_HTTP_PROXY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+38;
     int SET_CORE_SETTINGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+39;
     int UPDATE_PACKAGE_COMPATIBILITY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+40;
+    int SCHEDULE_TRIM_MEMORY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+41;
 }
diff --git a/core/java/android/content/ComponentCallbacks.java b/core/java/android/content/ComponentCallbacks.java
index dad60b0..92b98fd 100644
--- a/core/java/android/content/ComponentCallbacks.java
+++ b/core/java/android/content/ComponentCallbacks.java
@@ -51,4 +51,16 @@
      * The system will perform a gc for you after returning from this method.
      */
     void onLowMemory();
+
+    /** @hide */
+    static final int TRIM_MEMORY_COMPLETE = 80;
+
+    /** @hide */
+    static final int TRIM_MEMORY_MODERATE = 60;
+
+    /** @hide */
+    static final int TRIM_MEMORY_BACKGROUND = 40;
+
+    /** @hide */
+    static final int TRIM_MEMORY_INVISIBLE = 20;
 }
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 19894a0..f2f0e82 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -52,11 +52,26 @@
 public class LinkProperties implements Parcelable {
 
     String mIfaceName;
-    private Collection<LinkAddress> mLinkAddresses;
-    private Collection<InetAddress> mDnses;
-    private Collection<RouteInfo> mRoutes;
+    private Collection<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>();
+    private Collection<InetAddress> mDnses = new ArrayList<InetAddress>();
+    private Collection<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
     private ProxyProperties mHttpProxy;
 
+    public static class CompareAddressesResult {
+        public ArrayList<LinkAddress> removed = new ArrayList<LinkAddress>();
+        public ArrayList<LinkAddress> added = new ArrayList<LinkAddress>();
+
+        @Override
+        public String toString() {
+            String retVal = "removedAddresses=[";
+            for (LinkAddress addr : removed) retVal += addr.toString() + ",";
+            retVal += "] addedAddresses=[";
+            for (LinkAddress addr : added) retVal += addr.toString() + ",";
+            retVal += "]";
+            return retVal;
+        }
+    }
+
     public LinkProperties() {
         clear();
     }
@@ -121,9 +136,9 @@
 
     public void clear() {
         mIfaceName = null;
-        mLinkAddresses = new ArrayList<LinkAddress>();
-        mDnses = new ArrayList<InetAddress>();
-        mRoutes = new ArrayList<RouteInfo>();
+        mLinkAddresses.clear();
+        mDnses.clear();
+        mRoutes.clear();
         mHttpProxy = null;
     }
 
@@ -155,6 +170,63 @@
         return ifaceName + linkAddresses + routes + dns + proxy;
     }
 
+    /**
+     * Compares this {@code LinkProperties} interface name against the target
+     *
+     * @param target LinkProperties to compare.
+     * @return {@code true} if both are identical, {@code false} otherwise.
+     */
+    public boolean isIdenticalInterfaceName(LinkProperties target) {
+        return TextUtils.equals(getInterfaceName(), target.getInterfaceName());
+    }
+
+    /**
+     * Compares this {@code LinkProperties} interface name against the target
+     *
+     * @param target LinkProperties to compare.
+     * @return {@code true} if both are identical, {@code false} otherwise.
+     */
+    public boolean isIdenticalAddresses(LinkProperties target) {
+        Collection<InetAddress> targetAddresses = target.getAddresses();
+        Collection<InetAddress> sourceAddresses = getAddresses();
+        return (sourceAddresses.size() == targetAddresses.size()) ?
+                    sourceAddresses.containsAll(targetAddresses) : false;
+    }
+
+    /**
+     * Compares this {@code LinkProperties} DNS addresses against the target
+     *
+     * @param target LinkProperties to compare.
+     * @return {@code true} if both are identical, {@code false} otherwise.
+     */
+    public boolean isIdenticalDnses(LinkProperties target) {
+        Collection<InetAddress> targetDnses = target.getDnses();
+        return (mDnses.size() == targetDnses.size()) ?
+                    mDnses.containsAll(targetDnses) : false;
+    }
+
+    /**
+     * Compares this {@code LinkProperties} Routes against the target
+     *
+     * @param target LinkProperties to compare.
+     * @return {@code true} if both are identical, {@code false} otherwise.
+     */
+    public boolean isIdenticalRoutes(LinkProperties target) {
+        Collection<RouteInfo> targetRoutes = target.getRoutes();
+        return (mRoutes.size() == targetRoutes.size()) ?
+                    mRoutes.containsAll(targetRoutes) : false;
+    }
+
+    /**
+     * Compares this {@code LinkProperties} HttpProxy against the target
+     *
+     * @param target LinkProperties to compare.
+     * @return {@code true} if both are identical, {@code false} otherwise.
+     */
+    public boolean isIdenticalHttpProxy(LinkProperties target) {
+        return getHttpProxy() == null ? target.getHttpProxy() == null :
+                    getHttpProxy().equals(target.getHttpProxy());
+    }
 
     @Override
     /**
@@ -176,30 +248,41 @@
 
         if (!(obj instanceof LinkProperties)) return false;
 
-        boolean sameAddresses;
-        boolean sameDnses;
-        boolean sameRoutes;
-
         LinkProperties target = (LinkProperties) obj;
 
-        Collection<InetAddress> targetAddresses = target.getAddresses();
-        Collection<InetAddress> sourceAddresses = getAddresses();
-        sameAddresses = (sourceAddresses.size() == targetAddresses.size()) ?
-                sourceAddresses.containsAll(targetAddresses) : false;
+        return isIdenticalInterfaceName(target) &&
+                isIdenticalAddresses(target) &&
+                isIdenticalDnses(target) &&
+                isIdenticalRoutes(target) &&
+                isIdenticalHttpProxy(target);
+    }
 
-        Collection<InetAddress> targetDnses = target.getDnses();
-        sameDnses = (mDnses.size() == targetDnses.size()) ?
-                mDnses.containsAll(targetDnses) : false;
-
-        Collection<RouteInfo> targetRoutes = target.getRoutes();
-        sameRoutes = (mRoutes.size() == targetRoutes.size()) ?
-                mRoutes.containsAll(targetRoutes) : false;
-
-        return
-            sameAddresses && sameDnses && sameRoutes
-            && TextUtils.equals(getInterfaceName(), target.getInterfaceName())
-            && (getHttpProxy() == null ? target.getHttpProxy() == null :
-                getHttpProxy().equals(target.getHttpProxy()));
+    /**
+     * Return two lists, a list of addresses that would be removed from
+     * mLinkAddresses and a list of addresses that would be added to
+     * mLinkAddress which would then result in target and mLinkAddresses
+     * being the same list.
+     *
+     * @param target is a new list of addresses
+     * @return the removed and added lists.
+     */
+    public CompareAddressesResult compareAddresses(LinkProperties target) {
+        /*
+         * Duplicate the LinkAddresses into removed, we will be removing
+         * address which are common between mLinkAddresses and target
+         * leaving the addresses that are different. And address which
+         * are in target but not in mLinkAddresses are placed in the
+         * addedAddresses.
+         */
+        CompareAddressesResult result = new CompareAddressesResult();
+        result.removed = new ArrayList<LinkAddress>(mLinkAddresses);
+        result.added.clear();
+        for (LinkAddress newAddress : target.getLinkAddresses()) {
+            if (! result.removed.remove(newAddress)) {
+                result.added.add(newAddress);
+            }
+        }
+        return result;
     }
 
     @Override
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index 0eb8cd8..b668f30 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -334,8 +334,6 @@
 
     /**
      * Creates an NDEF record of well known type URI.
-     * TODO: Make a public API
-     * @hide
      */
     public static NdefRecord createUri(Uri uri) {
         return createUri(uri.toString());
@@ -343,8 +341,6 @@
 
     /**
      * Creates an NDEF record of well known type URI.
-     * TODO: Make a public API
-     * @hide
      */
     public static NdefRecord createUri(String uriString) {
         byte prefix = 0x0;
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 5b1f563..3362575 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -86,6 +86,12 @@
     public static final int WIFI_UID = 1010;
 
     /**
+     * Defines the UID/GID for the mediaserver process.
+     * @hide
+     */
+    public static final int MEDIA_UID = 1013;
+
+    /**
      * Defines the GID for the group that allows write access to the SD card.
      * @hide
      */
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 63c420a..f345a6a 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -660,7 +660,6 @@
             case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
             case BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES:
             case BluetoothClass.Device.AUDIO_VIDEO_PORTABLE_AUDIO:
-            case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
             case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
                 if (mBluetoothService.attemptAutoPair(address)) return;
            }
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index c2759e5..b9eb5ff 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -53,12 +53,12 @@
  * container and grid index {@code N} is fixed to its trailing edge
  * (after padding is taken into account).
  *
- * <h4>Row and Column Groups</h4>
+ * <h4>Row and Column Specs</h4>
  *
  * Children occupy one or more contiguous cells, as defined
- * by their {@link GridLayout.LayoutParams#rowGroup rowGroup} and
- * {@link GridLayout.LayoutParams#columnGroup columnGroup} layout parameters.
- * Each group specifies the set of rows or columns that are to be
+ * by their {@link GridLayout.LayoutParams#rowSpec rowSpec} and
+ * {@link GridLayout.LayoutParams#columnSpec columnSpec} layout parameters.
+ * Each spec defines the set of rows or columns that are to be
  * occupied; and how children should be aligned within the resulting group of cells.
  * Although cells do not normally overlap in a GridLayout, GridLayout does
  * not prevent children being defined to occupy the same cell or group of cells.
@@ -92,7 +92,7 @@
  *
  * <h4>Excess Space Distribution</h4>
  *
- * A child's ability to stretch is controlled using the {@link Group#flexibility flexibility}
+ * A child's ability to stretch is controlled using the flexibility
  * properties of its row and column groups.
  * <p>
  * <p>
@@ -167,8 +167,7 @@
     // Misc constants
 
     private static final String TAG = GridLayout.class.getName();
-    private static final boolean DEBUG = false;
-    private static final double GOLDEN_RATIO = (1 + Math.sqrt(5)) / 2;
+    static final boolean DEBUG = false;
     private static final int PRF = 1;
 
     // Defaults
@@ -178,8 +177,9 @@
     private static final boolean DEFAULT_USE_DEFAULT_MARGINS = false;
     private static final boolean DEFAULT_ORDER_PRESERVED = false;
     private static final int DEFAULT_ALIGNMENT_MODE = ALIGN_MARGINS;
-    // todo remove this
-    private static final int DEFAULT_CONTAINER_MARGIN = 20;
+    private static final int DEFAULT_CONTAINER_MARGIN = 0;
+    private static final int DEFAULT_MARGIN = 8;
+    private static final int DEFAULT_CONTAINER_PADDING = 16;
     private static final int MAX_SIZE = 100000;
 
     // TypedArray indices
@@ -278,12 +278,12 @@
     /**
      * Returns the current number of rows. This is either the last value that was set
      * with {@link #setRowCount(int)} or, if no such value was set, the maximum
-     * value of each the upper bounds defined in {@link LayoutParams#rowGroup}.
+     * value of each the upper bounds defined in {@link LayoutParams#rowSpec}.
      *
      * @return the current number of rows
      *
      * @see #setRowCount(int)
-     * @see LayoutParams#rowGroup
+     * @see LayoutParams#rowSpec
      *
      * @attr ref android.R.styleable#GridLayout_rowCount
      */
@@ -299,7 +299,7 @@
      * @param rowCount the number of rows
      *
      * @see #getRowCount()
-     * @see LayoutParams#rowGroup
+     * @see LayoutParams#rowSpec
      *
      * @attr ref android.R.styleable#GridLayout_rowCount
      */
@@ -310,12 +310,12 @@
     /**
      * Returns the current number of columns. This is either the last value that was set
      * with {@link #setColumnCount(int)} or, if no such value was set, the maximum
-     * value of each the upper bounds defined in {@link LayoutParams#columnGroup}.
+     * value of each the upper bounds defined in {@link LayoutParams#columnSpec}.
      *
      * @return the current number of columns
      *
      * @see #setColumnCount(int)
-     * @see LayoutParams#columnGroup
+     * @see LayoutParams#columnSpec
      *
      * @attr ref android.R.styleable#GridLayout_columnCount
      */
@@ -331,7 +331,7 @@
      * @param columnCount the number of columns.
      *
      * @see #getColumnCount()
-     * @see LayoutParams#columnGroup
+     * @see LayoutParams#columnSpec
      *
      * @attr ref android.R.styleable#GridLayout_columnCount
      */
@@ -381,6 +381,10 @@
      */
     public void setUseDefaultMargins(boolean useDefaultMargins) {
         mUseDefaultMargins = useDefaultMargins;
+        if (useDefaultMargins) {
+            int padding = DEFAULT_CONTAINER_PADDING;
+            setPadding(padding, padding, padding, padding);
+        }
         requestLayout();
     }
 
@@ -518,6 +522,14 @@
         return result;
     }
 
+    private static int sum(int[] a) {
+        int result = 0;
+        for (int i = 0, N = a.length; i < N; i++) {
+            result += a[i];
+        }
+        return result;
+    }
+
     private static <T> T[] append(T[] a, T[] b) {
         T[] result = (T[]) Array.newInstance(a.getClass().getComponentType(), a.length + b.length);
         System.arraycopy(a, 0, result, 0, a.length);
@@ -526,16 +538,10 @@
     }
 
     private int getDefaultMargin(View c, boolean horizontal, boolean leading) {
-        // In the absence of any other information, calculate a default gap such
-        // that, in a grid of identical components, the heights and the vertical
-        // gaps are in the proportion of the golden ratio.
-        // To effect this with equal margins at each edge, set each of the
-        // four margin values to half this amount.
-        return (int) (c.getMeasuredHeight() / GOLDEN_RATIO / 2);
+        return DEFAULT_MARGIN;
     }
 
     private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) {
-        // todo remove DEFAULT_CONTAINER_MARGIN. Use padding? Seek advice on Themes/Styles, etc.
         return isAtEdge ? DEFAULT_CONTAINER_MARGIN : getDefaultMargin(c, horizontal, leading);
     }
 
@@ -543,9 +549,9 @@
         if (!mUseDefaultMargins) {
             return 0;
         }
-        Group group = horizontal ? p.columnGroup : p.rowGroup;
+        Spec spec = horizontal ? p.columnSpec : p.rowSpec;
         Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
-        Interval span = group.span;
+        Interval span = spec.span;
         boolean isAtEdge = leading ? (span.min == 0) : (span.max == axis.getCount());
 
         return getDefaultMargin(c, isAtEdge, horizontal, leading);
@@ -593,12 +599,12 @@
                     if (isGone(c)) continue;
                     LayoutParams lp = getLayoutParams1(c);
 
-                    final Group colGroup = lp.columnGroup;
-                    final Interval cols = colGroup.span;
+                    final Spec colSpec = lp.columnSpec;
+                    final Interval cols = colSpec.span;
                     final int colSpan = cols.size();
 
-                    final Group rowGroup = lp.rowGroup;
-                    final Interval rows = rowGroup.span;
+                    final Spec rowSpec = lp.rowSpec;
+                    final Interval rows = rowSpec.span;
                     final int rowSpan = rows.size();
 
                     if (horizontal) {
@@ -623,8 +629,8 @@
                         maxSize = max(maxSize, colSpan);
                     }
 
-                    lp.setColumnGroupSpan(new Interval(col, col + colSpan));
-                    lp.setRowGroupSpan(new Interval(row, row + rowSpan));
+                    lp.setColumnSpecSpan(new Interval(col, col + colSpan));
+                    lp.setRowSpecSpan(new Interval(row, row + rowSpan));
 
                     if (horizontal) {
                         col = col + colSpan;
@@ -737,7 +743,7 @@
             }
 
             // Draw margins
-            paint.setColor(Color.YELLOW);
+            paint.setColor(Color.MAGENTA);
             for (int i = 0; i < getChildCount(); i++) {
                 View c = getChildAt(i);
                 drawRectangle(canvas,
@@ -872,11 +878,11 @@
             View c = getChildAt(i);
             if (isGone(c)) continue;
             LayoutParams lp = getLayoutParams(c);
-            Group columnGroup = lp.columnGroup;
-            Group rowGroup = lp.rowGroup;
+            Spec columnSpec = lp.columnSpec;
+            Spec rowSpec = lp.rowSpec;
 
-            Interval colSpan = columnGroup.span;
-            Interval rowSpan = rowGroup.span;
+            Interval colSpan = columnSpec.span;
+            Interval rowSpan = rowSpec.span;
 
             int x1 = mHorizontalAxis.getLocationIncludingMargin(true, colSpan.min);
             int y1 = mVerticalAxis.getLocationIncludingMargin(true, rowSpan.min);
@@ -890,8 +896,8 @@
             int pWidth = getMeasurement(c, true);
             int pHeight = getMeasurement(c, false);
 
-            Alignment hAlign = columnGroup.alignment;
-            Alignment vAlign = rowGroup.alignment;
+            Alignment hAlign = columnSpec.alignment;
+            Alignment vAlign = rowSpec.alignment;
 
             int dx, dy;
 
@@ -961,7 +967,7 @@
         public boolean countValid = false;
         public boolean countWasExplicitySet = false;
 
-        PackedMap<Group, Bounds> groupBounds;
+        PackedMap<Spec, Bounds> groupBounds;
         public boolean groupBoundsValid = false;
 
         PackedMap<Interval, MutableInt> forwardLinks;
@@ -998,9 +1004,9 @@
                 View c = getChildAt(i);
                 if (isGone(c)) continue;
                 LayoutParams params = getLayoutParams(c);
-                Group g = horizontal ? params.columnGroup : params.rowGroup;
-                count = max(count, g.span.min);
-                count = max(count, g.span.max);
+                Spec spec = horizontal ? params.columnSpec : params.rowSpec;
+                count = max(count, spec.span.min);
+                count = max(count, spec.span.max);
             }
             return count == -1 ? UNDEFINED : count;
         }
@@ -1027,17 +1033,17 @@
             invalidateStructure();
         }
 
-        private PackedMap<Group, Bounds> createGroupBounds() {
-            Assoc<Group, Bounds> assoc = Assoc.of(Group.class, Bounds.class);
+        private PackedMap<Spec, Bounds> createGroupBounds() {
+            Assoc<Spec, Bounds> assoc = Assoc.of(Spec.class, Bounds.class);
             for (int i = 0, N = getChildCount(); i < N; i++) {
                 View c = getChildAt(i);
                 if (isGone(c)) {
-                    assoc.put(Group.GONE, Bounds.GONE);
+                    assoc.put(Spec.GONE, Bounds.GONE);
                 } else {
                     LayoutParams lp = getLayoutParams(c);
-                    Group group = horizontal ? lp.columnGroup : lp.rowGroup;
-                    Bounds bounds = group.alignment.getBounds();
-                    assoc.put(group, bounds);
+                    Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
+                    Bounds bounds = spec.alignment.getBounds();
+                    assoc.put(spec, bounds);
                 }
             }
             return assoc.pack();
@@ -1052,12 +1058,12 @@
                 View c = getChildAt(i);
                 if (isGone(c)) continue;
                 LayoutParams lp = getLayoutParams(c);
-                Group g = horizontal ? lp.columnGroup : lp.rowGroup;
-                groupBounds.getValue(i).include(c, g, GridLayout.this, this);
+                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
+                groupBounds.getValue(i).include(c, spec, GridLayout.this, this);
             }
         }
 
-        private PackedMap<Group, Bounds> getGroupBounds() {
+        private PackedMap<Spec, Bounds> getGroupBounds() {
             if (groupBounds == null) {
                 groupBounds = createGroupBounds();
             }
@@ -1071,7 +1077,7 @@
         // Add values computed by alignment - taking the max of all alignments in each span
         private PackedMap<Interval, MutableInt> createLinks(boolean min) {
             Assoc<Interval, MutableInt> result = Assoc.of(Interval.class, MutableInt.class);
-            Group[] keys = getGroupBounds().keys;
+            Spec[] keys = getGroupBounds().keys;
             for (int i = 0, N = keys.length; i < N; i++) {
                 Interval span = min ? keys[i].span : keys[i].span.inverse();
                 result.put(span, new MutableInt());
@@ -1092,8 +1098,7 @@
                 MutableInt valueHolder = links.getValue(i);
                 if (min) {
                     valueHolder.value = max(valueHolder.value, size);
-                }
-                else {
+                } else {
                     valueHolder.value = -max(-valueHolder.value, size);
                 }
             }
@@ -1236,8 +1241,8 @@
                 View c = getChildAt(i);
                 if (isGone(c)) continue;
                 LayoutParams lp = getLayoutParams(c);
-                Group g = horizontal ? lp.columnGroup : lp.rowGroup;
-                Interval span = g.span;
+                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
+                Interval span = spec.span;
                 leadingEdgeCount[span.min]++;
                 trailingEdgeCount[span.max]++;
             }
@@ -1436,8 +1441,8 @@
                 View c = getChildAt(i);
                 if (isGone(c)) continue;
                 LayoutParams lp = getLayoutParams(c);
-                Group g = horizontal ? lp.columnGroup : lp.rowGroup;
-                Interval span = g.span;
+                Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
+                Interval span = spec.span;
                 int index = leading ? span.min : span.max;
                 margins[index] = max(margins[index], getMargin(c, horizontal, leading));
             }
@@ -1514,6 +1519,12 @@
         }
 
         private void setParentConstraints(int min, int max) {
+            if (mAlignmentMode != ALIGN_MARGINS) {
+                int margins = sum(getLeadingMargins()) + sum(getTrailingMargins());
+                min -= margins;
+                max -= margins;
+            }
+
             parentMin.value = min;
             parentMax.value = -max;
             locationsValid = false;
@@ -1529,7 +1540,7 @@
             int size = MeasureSpec.getSize(measureSpec);
             switch (mode) {
                 case MeasureSpec.UNSPECIFIED: {
-                     return getMeasure(0, MAX_SIZE);
+                    return getMeasure(0, MAX_SIZE);
                 }
                 case MeasureSpec.EXACTLY: {
                     return getMeasure(size, size);
@@ -1584,14 +1595,14 @@
      * GridLayout supports both row and column spanning and arbitrary forms of alignment within
      * each cell group. The fundamental parameters associated with each cell group are
      * gathered into their vertical and horizontal components and stored
-     * in the {@link #rowGroup} and {@link #columnGroup} layout parameters.
-     * {@link Group Groups} are immutable structures and may be shared between the layout
+     * in the {@link #rowSpec} and {@link #columnSpec} layout parameters.
+     * {@link android.widget.GridLayout.Spec Specs} are immutable structures and may be shared between the layout
      * parameters of different children.
      * <p>
-     * The row and column groups contain the leading and trailing indices along each axis
+     * The row and column specs contain the leading and trailing indices along each axis
      * and together specify the four grid indices that delimit the cells of this cell group.
      * <p>
-     * The {@link Group#alignment alignment} fields of the row and column groups together specify
+     * The  alignment properties of the row and column specs together specify
      * both aspects of alignment within the cell group. It is also possible to specify a child's
      * alignment within its cell group by using the {@link GridLayout.LayoutParams#setGravity(int)}
      * method.
@@ -1620,10 +1631,10 @@
      *          {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
      *          {@code false}; otherwise {@link #UNDEFINED}, to
      *          indicate that a default value should be computed on demand. </li>
-     *     <li>{@link #rowGroup}{@code .span} = {@code [0, 1]} </li>
-     *     <li>{@link #rowGroup}{@code .alignment} = {@link #BASELINE} </li>
-     *     <li>{@link #columnGroup}{@code .span} = {@code [0, 1]} </li>
-     *     <li>{@link #columnGroup}{@code .alignment} = {@link #LEFT} </li>
+     *     <li>{@link #rowSpec}{@code .span} = {@code [0, 1]} </li>
+     *     <li>{@link #rowSpec}{@code .alignment} = {@link #BASELINE} </li>
+     *     <li>{@link #columnSpec}{@code .span} = {@code [0, 1]} </li>
+     *     <li>{@link #columnSpec}{@code .alignment} = {@link #LEFT} </li>
      * </ul>
      *
      * @attr ref android.R.styleable#GridLayout_Layout_layout_row
@@ -1678,48 +1689,48 @@
         // Instance variables
 
         /**
-         * The group that specifies the vertical characteristics of the cell group
+         * The spec that specifies the vertical characteristics of the cell group
          * described by these layout parameters.
          */
-        public Group rowGroup;
+        public Spec rowSpec;
         /**
-         * The group that specifies the horizontal characteristics of the cell group
+         * The spec that specifies the horizontal characteristics of the cell group
          * described by these layout parameters.
          */
-        public Group columnGroup;
+        public Spec columnSpec;
 
         // Constructors
 
         private LayoutParams(
                 int width, int height,
                 int left, int top, int right, int bottom,
-                Group rowGroup, Group columnGroup) {
+                Spec rowSpec, Spec columnSpec) {
             super(width, height);
             setMargins(left, top, right, bottom);
-            this.rowGroup = rowGroup;
-            this.columnGroup = columnGroup;
+            this.rowSpec = rowSpec;
+            this.columnSpec = columnSpec;
         }
 
         /**
-         * Constructs a new LayoutParams instance for this <code>rowGroup</code>
-         * and <code>columnGroup</code>. All other fields are initialized with
+         * Constructs a new LayoutParams instance for this <code>rowSpec</code>
+         * and <code>columnSpec</code>. All other fields are initialized with
          * default values as defined in {@link LayoutParams}.
          *
-         * @param rowGroup    the rowGroup
-         * @param columnGroup the columnGroup
+         * @param rowSpec    the rowSpec
+         * @param columnSpec the columnSpec
          */
-        public LayoutParams(Group rowGroup, Group columnGroup) {
+        public LayoutParams(Spec rowSpec, Spec columnSpec) {
             this(DEFAULT_WIDTH, DEFAULT_HEIGHT,
                     DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN,
-                    rowGroup, columnGroup);
+                    rowSpec, columnSpec);
         }
 
         /**
          * Constructs a new LayoutParams with default values as defined in {@link LayoutParams}.
          */
         public LayoutParams() {
-            this(new Group(DEFAULT_SPAN, DEFAULT_ROW_ALIGNMENT),
-                 new Group(DEFAULT_SPAN, DEFAULT_COLUMN_ALIGNMENT));
+            this(new Spec(DEFAULT_SPAN, DEFAULT_ROW_ALIGNMENT, Spec.DEFAULT_FLEXIBILITY),
+                    new Spec(DEFAULT_SPAN, DEFAULT_COLUMN_ALIGNMENT, Spec.DEFAULT_FLEXIBILITY));
         }
 
         // Copying constructors
@@ -1743,8 +1754,8 @@
          */
         public LayoutParams(LayoutParams that) {
             super(that);
-            this.columnGroup = new Group(that.columnGroup);
-            this.rowGroup = new Group(that.rowGroup);
+            this.columnSpec = new Spec(that.columnSpec);
+            this.rowSpec = new Spec(that.rowSpec);
         }
 
         // AttributeSet constructors
@@ -1836,14 +1847,14 @@
                 int column = a.getInt(COLUMN, DEFAULT_COLUMN);
                 int columnSpan = a.getInt(COLUMN_SPAN, DEFAULT_SPAN_SIZE);
                 Interval hSpan = new Interval(column, column + columnSpan);
-                int hFlexibility = a.getInt(COLUMN_FLEXIBILITY, Group.DEFAULT_FLEXIBILITY);
-                this.columnGroup = new Group(hSpan, getColAlignment(gravity, width), hFlexibility);
+                int hFlexibility = a.getInt(COLUMN_FLEXIBILITY, Spec.DEFAULT_FLEXIBILITY);
+                this.columnSpec = new Spec(hSpan, getColAlignment(gravity, width), hFlexibility);
 
                 int row = a.getInt(ROW, DEFAULT_ROW);
                 int rowSpan = a.getInt(ROW_SPAN, DEFAULT_SPAN_SIZE);
                 Interval vSpan = new Interval(row, row + rowSpan);
-                int vFlexibility = a.getInt(ROW_FLEXIBILITY, Group.DEFAULT_FLEXIBILITY);
-                this.rowGroup = new Group(vSpan, getRowAlignment(gravity, height), vFlexibility);
+                int vFlexibility = a.getInt(ROW_FLEXIBILITY, Spec.DEFAULT_FLEXIBILITY);
+                this.rowSpec = new Spec(vSpan, getRowAlignment(gravity, height), vFlexibility);
             } finally {
                 a.recycle();
             }
@@ -1858,8 +1869,8 @@
          * @attr ref android.R.styleable#GridLayout_Layout_layout_gravity
          */
         public void setGravity(int gravity) {
-            columnGroup = columnGroup.copyWriteAlignment(getColAlignment(gravity, width));
-            rowGroup = rowGroup.copyWriteAlignment(getRowAlignment(gravity, height));
+            columnSpec = columnSpec.copyWriteAlignment(getColAlignment(gravity, width));
+            rowSpec = rowSpec.copyWriteAlignment(getRowAlignment(gravity, height));
         }
 
         @Override
@@ -1868,12 +1879,12 @@
             this.height = attributes.getLayoutDimension(heightAttr, DEFAULT_HEIGHT);
         }
 
-        private void setRowGroupSpan(Interval span) {
-            rowGroup = rowGroup.copyWriteSpan(span);
+        private void setRowSpecSpan(Interval span) {
+            rowSpec = rowSpec.copyWriteSpan(span);
         }
 
-        private void setColumnGroupSpan(Interval span) {
-            columnGroup = columnGroup.copyWriteSpan(span);
+        private void setColumnSpecSpan(Interval span) {
+            columnSpec = columnSpec.copyWriteSpan(span);
         }
     }
 
@@ -2019,14 +2030,14 @@
     }
 
     /*
-    For each Group (with a given alignment) we need to store the amount of space required
+    For each group (with a given alignment) we need to store the amount of space required
     before the alignment point and the amount of space required after it. One side of this
     calculation is always 0 for LEADING and TRAILING alignments but we don't make use of this.
     For CENTER and BASELINE alignments both sides are needed and in the BASELINE case no
     simple optimisations are possible.
 
     The general algorithm therefore is to create a Map (actually a PackedMap) from
-    Group to Bounds and to loop through all Views in the group taking the maximum
+    group to Bounds and to loop through all Views in the group taking the maximum
     of the values for each View.
     */
     private static class Bounds {
@@ -2067,11 +2078,11 @@
             return before - alignment.getAlignmentValue(c, size);
         }
 
-        protected void include(View c, Group group, GridLayout gridLayout, Axis axis) {
-            this.flexibility &= group.flexibility;
+        protected void include(View c, Spec spec, GridLayout gridLayout, Axis axis) {
+            this.flexibility &= spec.flexibility;
             int size = gridLayout.getMeasurementIncludingMargin(c, axis.horizontal);
             // todo test this works correctly when the returned value is UNDEFINED
-            int before = group.alignment.getAlignmentValue(c, size);
+            int before = spec.alignment.getAlignmentValue(c, size);
             include(before, size - before);
         }
 
@@ -2176,16 +2187,13 @@
     }
 
     /**
-     * A group specifies either the horizontal or vertical characteristics of a group of
+     * A spec defines either the horizontal or vertical characteristics of a group of
      * cells.
-     * <p>
-     * Groups are immutable and so may be shared between views with the same
-     * {@code span} and {@code alignment}.
      */
-    public static class Group {
+    public static class Spec {
         private static final int DEFAULT_FLEXIBILITY = UNDEFINED_FLEXIBILITY;
 
-        private static final Group GONE = new Group(Interval.GONE, Alignment.GONE);
+        private static final Spec GONE = new Spec(Interval.GONE, Alignment.GONE);
 
         /**
          * The grid indices of the leading and trailing edges of this cell group for the
@@ -2200,7 +2208,7 @@
          * For row groups, this specifies the vertical alignment.
          * For column groups, this specifies the horizontal alignment.
          */
-        public final Alignment alignment;
+        final Alignment alignment;
 
         /**
          * The flexibility field tells GridLayout how to derive minimum and maximum size
@@ -2212,82 +2220,48 @@
          *
          * @see GridLayout#CAN_STRETCH
          */
-         public int flexibility = DEFAULT_FLEXIBILITY;
+        final int flexibility;
 
-        /**
-         * Construct a new Group, {@code group}, where:
-         * <ul>
-         *     <li> {@code group.span = span} </li>
-         *     <li> {@code group.alignment = alignment} </li>
-         * </ul>
-         *
-         * @param span      the span
-         * @param alignment the alignment
-         */
-        private Group(Interval span, Alignment alignment) {
-            this.span = span;
-            this.alignment = alignment;
-        }
-
-        private Group(Interval span, Alignment alignment, int flexibility) {
+        private Spec(Interval span, Alignment alignment, int flexibility) {
             this.span = span;
             this.alignment = alignment;
             this.flexibility = flexibility;
         }
 
+        private Spec(Interval span, Alignment alignment) {
+            this(span, alignment, DEFAULT_FLEXIBILITY);
+        }
+
         /* Copying constructor */
-        private Group(Group that) {
-            this.span = that.span;
-            this.alignment = that.alignment;
-            this.flexibility = that.flexibility;
+        private Spec(Spec that) {
+            this(that.span, that.alignment, that.flexibility);
+        }
+
+        Spec(int start, int size, Alignment alignment, int flexibility) {
+            this(new Interval(start, start + size), alignment, flexibility);
+        }
+
+        private Spec copyWriteSpan(Interval span) {
+            return new Spec(span, alignment, flexibility);
+        }
+
+        private Spec copyWriteAlignment(Alignment alignment) {
+            return new Spec(span, alignment, flexibility);
+        }
+
+        private Spec copyWriteFlexibility(int flexibility) {
+            return new Spec(span, alignment, flexibility);
         }
 
         /**
-         * Construct a new Group, {@code group}, where:
-         * <ul>
-         *     <li> {@code group.span = [start, start + size]} </li>
-         *     <li> {@code group.alignment = alignment} </li>
-         * </ul>
-         *
-         * @param start     the start
-         * @param size      the size
-         * @param alignment the alignment
-         */
-        public Group(int start, int size, Alignment alignment) {
-            this(new Interval(start, start + size), alignment);
-        }
-
-        /**
-         * Construct a new Group, {@code group}, where:
-         * <ul>
-         *     <li> {@code group.span = [start, start + 1]} </li>
-         *     <li> {@code group.alignment = alignment} </li>
-         * </ul>
-         *
-         * @param start     the start index
-         * @param alignment the alignment
-         */
-        public Group(int start, Alignment alignment) {
-            this(start, 1, alignment);
-        }
-
-        private Group copyWriteSpan(Interval span) {
-            return new Group(span, alignment, flexibility);
-        }
-
-        private Group copyWriteAlignment(Alignment alignment) {
-            return new Group(span, alignment, flexibility);
-        }
-
-        /**
-         * Returns {@code true} if the {@link #getClass class}, {@link #alignment} and {@code span}
-         * properties of this Group and the supplied parameter are pairwise equal,
+         * Returns {@code true} if the {@code class}, {@code alignment} and {@code span}
+         * properties of this Spec and the supplied parameter are pairwise equal,
          * {@code false} otherwise.
          *
-         * @param that the object to compare this group with
+         * @param that the object to compare this spec with
          *
          * @return {@code true} if the specified object is equal to this
-         *         {@code Group}; {@code false} otherwise
+         *         {@code Spec}; {@code false} otherwise
          */
         @Override
         public boolean equals(Object that) {
@@ -2298,12 +2272,12 @@
                 return false;
             }
 
-            Group group = (Group) that;
+            Spec spec = (Spec) that;
 
-            if (!alignment.equals(group.alignment)) {
+            if (!alignment.equals(spec.alignment)) {
                 return false;
             }
-            if (!span.equals(group.span)) {
+            if (!span.equals(spec.span)) {
                 return false;
             }
 
@@ -2319,12 +2293,93 @@
     }
 
     /**
+     * Temporary backward compatibility class for Launcher - to avoid
+     * dependent multi-project commit. This class will be deleted after
+     * AppsCustomizePagedView is updated to new API.
+     *
+     * @hide
+     */
+    @Deprecated
+    public static class Group extends Spec {
+    /**
+     * @deprecated  Please replace with {@link #spec(int, int, Alignment)}
+     * @hide
+     */
+        @Deprecated
+        public Group(int start, int size, Alignment alignment) {
+            super(start, size, alignment, UNDEFINED_FLEXIBILITY);
+        }
+    }
+
+    /**
+     * Return a Spec, {@code spec}, where:
+     * <ul>
+     *     <li> {@code spec.span = [start, start + size]} </li>
+     *     <li> {@code spec.alignment = alignment} </li>
+     *     <li> {@code spec.flexibility = flexibility} </li>
+     * </ul>
+     *
+     * @param start         the start
+     * @param size          the size
+     * @param alignment     the alignment
+     * @param flexibility   the flexibility
+     */
+    public static Spec spec(int start, int size, Alignment alignment, int flexibility) {
+        return new Spec(start, size, alignment, flexibility);
+    }
+
+    /**
+     * Return a Spec, {@code spec}, where:
+     * <ul>
+     *     <li> {@code spec.span = [start, start + 1]} </li>
+     *     <li> {@code spec.alignment = alignment} </li>
+     *     <li> {@code spec.flexibility = flexibility} </li>
+     * </ul>
+     *
+     * @param start         the start
+     * @param alignment     the alignment
+     * @param flexibility   the flexibility
+     */
+    public static Spec spec(int start, Alignment alignment, int flexibility) {
+        return spec(start, 1, alignment, flexibility);
+    }
+
+    /**
+     * Return a Spec, {@code spec}, where:
+     * <ul>
+     *     <li> {@code spec.span = [start, start + size]} </li>
+     *     <li> {@code spec.alignment = alignment} </li>
+     * </ul>
+     *
+     * @param start     the start
+     * @param size      the size
+     * @param alignment the alignment
+     */
+    public static Spec spec(int start, int size, Alignment alignment) {
+        return spec(start, size, alignment, Spec.DEFAULT_FLEXIBILITY);
+    }
+
+    /**
+     * Return a Spec, {@code spec}, where:
+     * <ul>
+     *     <li> {@code spec.span = [start, start + 1]} </li>
+     *     <li> {@code spec.alignment = alignment} </li>
+     * </ul>
+     *
+     * @param start     the start index
+     * @param alignment the alignment
+     */
+    public static Spec spec(int start, Alignment alignment) {
+        return spec(start, 1, alignment);
+    }
+
+    /**
      * Alignments specify where a view should be placed within a cell group and
      * what size it should be.
      * <p>
-     * The {@link LayoutParams} class contains a {@link LayoutParams#rowGroup rowGroup}
-     * and a {@link LayoutParams#columnGroup columnGroup} each of which contains an
-     * {@link Group#alignment alignment}. Overall placement of the view in the cell
+     * The {@link LayoutParams} class contains a {@link LayoutParams#rowSpec rowSpec}
+     * and a {@link LayoutParams#columnSpec columnSpec} each of which contains an
+     * {@code alignment}. Overall placement of the view in the cell
      * group is specified by the two alignments which act along each axis independently.
      * <p>
      *  The GridLayout class defines the most common alignments used in general layout:
@@ -2425,8 +2480,8 @@
 
     /**
      * Indicates that a view should be <em>centered</em> with the other views in its cell group.
-     * This constant may be used in both {@link LayoutParams#rowGroup rowGroups} and {@link
-     * LayoutParams#columnGroup columnGroups}.
+     * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and {@link
+     * LayoutParams#columnSpec columnSpecs}.
      */
     public static final Alignment CENTER = new Alignment() {
         public int getAlignmentValue(View view, int viewSize) {
@@ -2437,7 +2492,7 @@
     /**
      * Indicates that a view should be aligned with the <em>baselines</em>
      * of the other views in its cell group.
-     * This constant may only be used as an alignment in {@link LayoutParams#rowGroup rowGroups}.
+     * This constant may only be used as an alignment in {@link LayoutParams#rowSpec rowSpecs}.
      *
      * @see View#getBaseline()
      */
@@ -2488,8 +2543,8 @@
 
     /**
      * Indicates that a view should expanded to fit the boundaries of its cell group.
-     * This constant may be used in both {@link LayoutParams#rowGroup rowGroups} and
-     * {@link LayoutParams#columnGroup columnGroups}.
+     * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and
+     * {@link LayoutParams#columnSpec columnSpecs}.
      */
     public static final Alignment FILL = new Alignment() {
         public int getAlignmentValue(View view, int viewSize) {
@@ -2513,42 +2568,30 @@
     /**
      * Indicates that a view requests precisely the size specified by its layout parameters.
      *
-     * @see Group#flexibility
-     *
-     * @hide
+     * @see Spec#flexibility
      */
-    public static final int FIXED = 0;
+    private static final int NONE = 0;
 
     /**
      * Indicates that a view's size should lie between its minimum and the size specified by
      * its layout parameters.
      *
-     * @see Group#flexibility
-     *
-     * @hide
+     * @see Spec#flexibility
      */
-    public static final int CAN_SHRINK = 1;
+    private static final int CAN_SHRINK = 1;
 
     /**
      * Indicates that a view's size should be greater than or equal to the size specified by
      * its layout parameters.
      *
-     * @see Group#flexibility
+     * @see Spec#flexibility
      */
     public static final int CAN_STRETCH = 2;
 
     /**
-     * Indicates that a view will ignore its measurement, and can take any size that is greater
-     * than its minimum.
-     *
-     * @see Group#flexibility
-     */
-    private static final int CAN_SHRINK_OR_STRETCH = CAN_SHRINK | CAN_STRETCH;
-
-    /**
      * A default value for flexibility.
      *
-     * @see Group#flexibility
+     * @see Spec#flexibility
      */
     private static final int UNDEFINED_FLEXIBILITY = UNDEFINED | CAN_SHRINK | CAN_STRETCH;
 
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 519acf5..243c605 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -36,6 +36,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.Handler;
 import android.view.ActionMode;
 import android.view.LayoutInflater;
@@ -155,6 +156,13 @@
                 CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
 
         mContentHeight = mActionView.getContentHeight();
+
+        // Older apps get the home button interaction enabled by default.
+        // Newer apps need to enable it explicitly.
+        if (mContext.getApplicationInfo().targetSdkVersion <
+                Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+            setHomeButtonEnabled(true);
+        }
     }
 
     public void onConfigurationChanged(Configuration newConfig) {
@@ -266,8 +274,8 @@
     }
 
     @Override
-    public void setDisplayDisableHomeEnabled(boolean disableHome) {
-        setDisplayOptions(disableHome ? DISPLAY_DISABLE_HOME : 0, DISPLAY_DISABLE_HOME);
+    public void setHomeButtonEnabled(boolean enable) {
+        mActionView.setHomeButtonEnabled(enable);
     }
 
     @Override
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 595753a..58043c9 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -434,22 +434,40 @@
         }
     }
 
+    public void setHomeButtonEnabled(boolean enable) {
+        mHomeLayout.setEnabled(enable);
+        // Make sure the home button has an accurate content description for accessibility.
+        if (!enable) {
+            mHomeLayout.setContentDescription(null);
+        } else if ((mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+            mHomeLayout.setContentDescription(mContext.getResources().getText(
+                    R.string.action_bar_up_description));
+        } else {
+            mHomeLayout.setContentDescription(mContext.getResources().getText(
+                    R.string.action_bar_home_description));
+        }
+    }
+
     public void setDisplayOptions(int options) {
         final int flagsChanged = options ^ mDisplayOptions;
         mDisplayOptions = options;
 
-        if ((flagsChanged & ActionBar.DISPLAY_DISABLE_HOME) != 0) {
-            final boolean disableHome = (options & ActionBar.DISPLAY_DISABLE_HOME) != 0;
-            mHomeLayout.setEnabled(!disableHome);
-        }
-
         if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) {
             final boolean showHome = (options & ActionBar.DISPLAY_SHOW_HOME) != 0;
             final int vis = showHome ? VISIBLE : GONE;
             mHomeLayout.setVisibility(vis);
 
             if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
-                mHomeLayout.setUp((options & ActionBar.DISPLAY_HOME_AS_UP) != 0);
+                final boolean setUp = (options & ActionBar.DISPLAY_HOME_AS_UP) != 0;
+                mHomeLayout.setUp(setUp);
+
+                // Showing home as up implicitly enables interaction with it.
+                // In honeycomb it was always enabled, so make this transition
+                // a bit easier for developers in the common case.
+                // (It would be silly to show it as up without responding to it.)
+                if (setUp) {
+                    setHomeButtonEnabled(true);
+                }
             }
 
             if ((flagsChanged & ActionBar.DISPLAY_USE_LOGO) != 0) {
@@ -487,7 +505,7 @@
         }
 
         // Make sure the home button has an accurate content description for accessibility.
-        if ((options & ActionBar.DISPLAY_DISABLE_HOME) != 0) {
+        if (!mHomeLayout.isEnabled()) {
             mHomeLayout.setContentDescription(null);
         } else if ((options & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
             mHomeLayout.setContentDescription(mContext.getResources().getText(
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 258ffa5..ea35006 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -116,7 +116,7 @@
                         bool forcePurgeable = false) {
     int sampleSize = 1;
     SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode;
-    SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
+    SkBitmap::Config prefConfig = SkBitmap::kARGB_8888_Config;
     bool doDither = true;
     bool isMutable = false;
     bool isPurgeable = forcePurgeable ||
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index cfc5041..9613712 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3349,7 +3349,7 @@
         <!-- The row span: the difference between the bottom and top
         boundaries delimiting the group of cells occupied by this view.
         The default is one.
-        See {@link android.widget.GridLayout.Group}. -->
+        See {@link android.widget.GridLayout.Spec}. -->
         <attr name="layout_rowSpan" format="integer" min="1" />
         <!-- The column boundary delimiting the left of the group of cells
         occupied by this view. -->
@@ -3357,23 +3357,21 @@
         <!-- The column span: the difference between the right and left
         boundaries delimiting the group of cells occupied by this view.
         The default is one.
-        See {@link android.widget.GridLayout.Group}. -->
+        See {@link android.widget.GridLayout.Spec}. -->
         <attr name="layout_columnSpan" format="integer" min="1" />
         <!-- Gravity specifies how a component should be placed in its group of cells.
         The default is LEFT | BASELINE.
         See {@link android.widget.GridLayout.LayoutParams#setGravity(int)}. -->
         <attr name="layout_gravity" />
         <!-- A value specifying how much deficit or excess width this component can accomodate.
-        The default is FIXED.
-        See {@link android.widget.GridLayout.Group#flexibility}.-->
+        The default is FIXED. -->
         <attr name="layout_columnFlexibility" >
             <!-- If possible, width should be greater than or equal to the specified width.
             See {@link android.widget.GridLayout#CAN_STRETCH}. -->
             <enum name="canStretch" value="2" />
         </attr>
         <!-- A value specifying how much deficit or excess height this component can accomodate.
-        The default is FIXED.
-        See {@link android.widget.GridLayout.Group#flexibility}.-->
+        The default is FIXED. -->
         <attr name="layout_rowFlexibility" >
             <!-- If possible, height should be greater than or equal to the specified height.
             See {@link android.widget.GridLayout#CAN_STRETCH}. -->
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 3c65147..02ad703 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -184,6 +184,11 @@
             uint32_t flags = 0);
 };
 
+struct CodecProfileLevel {
+    OMX_U32 mProfile;
+    OMX_U32 mLevel;
+};
+
 }  // namespace android
 
 #endif  // ANDROID_IOMX_H_
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 7f3c497..a042ddb 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -336,11 +336,6 @@
     OMXCodec &operator=(const OMXCodec &);
 };
 
-struct CodecProfileLevel {
-    OMX_U32 mProfile;
-    OMX_U32 mLevel;
-};
-
 struct CodecCapabilities {
     String8 mComponentName;
     Vector<CodecProfileLevel> mProfileLevels;
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index b97c3c4..b20a6e9 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -32,24 +32,25 @@
  * It allows to stream PCM audio buffers to the audio hardware for playback. This is
  * achieved by "pushing" the data to the AudioTrack object using one of the
  *  {@link #write(byte[], int, int)} and {@link #write(short[], int, int)} methods.
- *  
+ *
  * <p>An AudioTrack instance can operate under two modes: static or streaming.<br>
  * In Streaming mode, the application writes a continuous stream of data to the AudioTrack, using
- * one of the write() methods. These are blocking and return when the data has been transferred
- * from the Java layer to the native layer and queued for playback. The streaming mode
- *  is most useful when playing blocks of audio data that for instance are:
+ * one of the {@code write()} methods. These are blocking and return when the data has been
+ * transferred from the Java layer to the native layer and queued for playback. The streaming
+ * mode is most useful when playing blocks of audio data that for instance are:
+ *
  * <ul>
  *   <li>too big to fit in memory because of the duration of the sound to play,</li>
  *   <li>too big to fit in memory because of the characteristics of the audio data
  *         (high sampling rate, bits per sample ...)</li>
  *   <li>received or generated while previously queued audio is playing.</li>
  * </ul>
+ *
  * The static mode is to be chosen when dealing with short sounds that fit in memory and
- * that need to be played with the smallest latency possible. AudioTrack instances in static mode
- * can play the sound without the need to transfer the audio data from Java to native layer
- * each time the sound is to be played. The static mode will therefore be preferred for UI and
- * game sounds that are played often, and with the smallest overhead possible.
- * 
+ * that need to be played with the smallest latency possible. The static mode will
+ * therefore be preferred for UI and game sounds that are played often, and with the
+ * smallest overhead possible.
+ *
  * <p>Upon creation, an AudioTrack object initializes its associated audio buffer.
  * The size of this buffer, specified during the construction, determines how long an AudioTrack
  * can play before running out of data.<br>
@@ -816,6 +817,7 @@
     //--------------------
     /**
      * Starts playing an AudioTrack.
+     *
      * @throws IllegalStateException
      */
     public void play()
@@ -832,6 +834,7 @@
 
     /**
      * Stops playing the audio data.
+     *
      * @throws IllegalStateException
      */
     public void stop()
@@ -848,7 +851,10 @@
     }
 
     /**
-     * Pauses the playback of the audio data.
+     * Pauses the playback of the audio data. Data that has not been played
+     * back will not be discarded. Subsequent calls to {@link #play} will play
+     * this data back.
+     *
      * @throws IllegalStateException
      */
     public void pause()
@@ -871,9 +877,9 @@
     //--------------------
 
     /**
-     * Flushes the audio data currently queued for playback.
+     * Flushes the audio data currently queued for playback. Any data that has
+     * not been played back will be discarded.
      */
-
     public void flush() {
         if (mState == STATE_INITIALIZED) {
             // flush the data in native layer
@@ -883,9 +889,14 @@
     }
 
     /**
-     * Writes the audio data to the audio hardware for playback.
+     * Writes the audio data to the audio hardware for playback. Will block until
+     * all data has been written to the audio mixer.
+     * Note that the actual playback of this data might occur after this function
+     * returns. This function is thread safe with respect to {@link #stop} calls,
+     * in which case all of the specified data might not be written to the mixer.
+     *
      * @param audioData the array that holds the data to play.
-     * @param offsetInBytes the offset expressed in bytes in audioData where the data to play 
+     * @param offsetInBytes the offset expressed in bytes in audioData where the data to play
      *    starts.
      * @param sizeInBytes the number of bytes to read in audioData after the offset.
      * @return the number of bytes that were written or {@link #ERROR_INVALID_OPERATION}
@@ -914,7 +925,12 @@
 
 
     /**
-     * Writes the audio data to the audio hardware for playback.
+     * Writes the audio data to the audio hardware for playback. Will block until
+     * all data has been written to the audio mixer.
+     * Note that the actual playback of this data might occur after this function
+     * returns. This function is thread safe with respect to {@link #stop} calls,
+     * in which case all of the specified data might not be written to the mixer.
+     *
      * @param audioData the array that holds the data to play.
      * @param offsetInShorts the offset expressed in shorts in audioData where the data to play
      *     starts.
@@ -988,7 +1004,7 @@
 
     /**
      * Sets the send level of the audio track to the attached auxiliary effect
-     * {@see #attachAuxEffect(int)}. The level value range is 0 to 1.0.
+     * {@link #attachAuxEffect(int)}. The level value range is 0 to 1.0.
      * <p>By default the send level is 0, so even if an effect is attached to the player
      * this method must be called for the effect to be applied.
      * <p>Note that the passed level value is a raw scalar. UI controls should be scaled
diff --git a/media/libstagefright/codecs/avc/dec/SoftAVC.cpp b/media/libstagefright/codecs/avc/dec/SoftAVC.cpp
index 9f141ac..6a476f6 100644
--- a/media/libstagefright/codecs/avc/dec/SoftAVC.cpp
+++ b/media/libstagefright/codecs/avc/dec/SoftAVC.cpp
@@ -23,6 +23,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
+#include <media/IOMX.h>
 
 #include "avcdec_api.h"
 #include "avcdec_int.h"
@@ -31,6 +32,13 @@
 
 static const char kStartCode[4] = { 0x00, 0x00, 0x00, 0x01 };
 
+static const CodecProfileLevel kProfileLevels[] = {
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1b },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel11 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel12 },
+};
+
 template<class T>
 static void InitOMXParams(T *params) {
     params->nSize = sizeof(T);
@@ -181,6 +189,28 @@
             return OMX_ErrorNone;
         }
 
+        case OMX_IndexParamVideoProfileLevelQuerySupported:
+        {
+            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
+                    (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params;
+
+            if (profileLevel->nPortIndex != 0) {  // Input port only
+                LOGE("Invalid port index: %ld", profileLevel->nPortIndex);
+                return OMX_ErrorUnsupportedIndex;
+            }
+
+            size_t index = profileLevel->nProfileIndex;
+            size_t nProfileLevels =
+                    sizeof(kProfileLevels) / sizeof(kProfileLevels[0]);
+            if (index >= nProfileLevels) {
+                return OMX_ErrorNoMore;
+            }
+
+            profileLevel->eProfile = kProfileLevels[index].mProfile;
+            profileLevel->eLevel = kProfileLevels[index].mLevel;
+            return OMX_ErrorNone;
+        }
+
         default:
             return SimpleSoftOMXComponent::internalGetParameter(index, params);
     }
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
index cffbfb5..ddced5f 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
@@ -23,11 +23,31 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
+#include <media/IOMX.h>
 
 #include "mp4dec_api.h"
 
 namespace android {
 
+static const CodecProfileLevel kM4VProfileLevels[] = {
+    { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0 },
+    { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0b },
+    { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1 },
+    { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level2 },
+    { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level3 },
+};
+
+static const CodecProfileLevel kH263ProfileLevels[] = {
+    { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level10 },
+    { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level20 },
+    { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level30 },
+    { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level45 },
+    { OMX_VIDEO_H263ProfileISWV2,    OMX_VIDEO_H263Level10 },
+    { OMX_VIDEO_H263ProfileISWV2,    OMX_VIDEO_H263Level20 },
+    { OMX_VIDEO_H263ProfileISWV2,    OMX_VIDEO_H263Level30 },
+    { OMX_VIDEO_H263ProfileISWV2,    OMX_VIDEO_H263Level45 },
+};
+
 template<class T>
 static void InitOMXParams(T *params) {
     params->nSize = sizeof(T);
@@ -181,6 +201,39 @@
             return OMX_ErrorNone;
         }
 
+        case OMX_IndexParamVideoProfileLevelQuerySupported:
+        {
+            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
+                    (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params;
+
+            if (profileLevel->nPortIndex != 0) {  // Input port only
+                LOGE("Invalid port index: %ld", profileLevel->nPortIndex);
+                return OMX_ErrorUnsupportedIndex;
+            }
+
+            size_t index = profileLevel->nProfileIndex;
+            if (mMode == MODE_H263) {
+                size_t nProfileLevels =
+                    sizeof(kH263ProfileLevels) / sizeof(kH263ProfileLevels[0]);
+                if (index >= nProfileLevels) {
+                    return OMX_ErrorNoMore;
+                }
+
+                profileLevel->eProfile = kH263ProfileLevels[index].mProfile;
+                profileLevel->eLevel = kH263ProfileLevels[index].mLevel;
+            } else {
+                size_t nProfileLevels =
+                    sizeof(kM4VProfileLevels) / sizeof(kM4VProfileLevels[0]);
+                if (index >= nProfileLevels) {
+                    return OMX_ErrorNoMore;
+                }
+
+                profileLevel->eProfile = kM4VProfileLevels[index].mProfile;
+                profileLevel->eLevel = kM4VProfileLevels[index].mLevel;
+            }
+            return OMX_ErrorNone;
+        }
+
         default:
             return SimpleSoftOMXComponent::internalGetParameter(index, params);
     }
diff --git a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
index ec7bd1c..740c957 100644
--- a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
+++ b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
@@ -23,10 +23,30 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
+#include <media/IOMX.h>
 
 
 namespace android {
 
+static const CodecProfileLevel kProfileLevels[] = {
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1  },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1b },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel11 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel12 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel13 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel2  },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel21 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel22 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel3  },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel31 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel32 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel4  },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel41 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel42 },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel5  },
+    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel51 },
+};
+
 template<class T>
 static void InitOMXParams(T *params) {
     params->nSize = sizeof(T);
@@ -177,6 +197,28 @@
             return OMX_ErrorNone;
         }
 
+        case OMX_IndexParamVideoProfileLevelQuerySupported:
+        {
+            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
+                    (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params;
+
+            if (profileLevel->nPortIndex != kInputPortIndex) {
+                LOGE("Invalid port index: %ld", profileLevel->nPortIndex);
+                return OMX_ErrorUnsupportedIndex;
+            }
+
+            size_t index = profileLevel->nProfileIndex;
+            size_t nProfileLevels =
+                    sizeof(kProfileLevels) / sizeof(kProfileLevels[0]);
+            if (index >= nProfileLevels) {
+                return OMX_ErrorNoMore;
+            }
+
+            profileLevel->eProfile = kProfileLevels[index].mProfile;
+            profileLevel->eLevel = kProfileLevels[index].mLevel;
+            return OMX_ErrorNone;
+        }
+
         default:
             return SimpleSoftOMXComponent::internalGetParameter(index, params);
     }
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 41450d2..85891a2 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -33,7 +33,9 @@
 import android.net.IConnectivityManager;
 import android.net.INetworkPolicyListener;
 import android.net.INetworkPolicyManager;
+import android.net.LinkAddress;
 import android.net.LinkProperties;
+import android.net.LinkProperties.CompareAddressesResult;
 import android.net.MobileDataStateTracker;
 import android.net.NetworkConfig;
 import android.net.NetworkInfo;
@@ -76,6 +78,8 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
@@ -92,6 +96,7 @@
 public class ConnectivityService extends IConnectivityManager.Stub {
 
     private static final boolean DBG = true;
+    private static final boolean VDBG = true;
     private static final String TAG = "ConnectivityService";
 
     private static final boolean LOGD_RULES = false;
@@ -126,6 +131,11 @@
     private NetworkStateTracker mNetTrackers[];
 
     /**
+     * The link properties that define the current links
+     */
+    private LinkProperties mCurrentLinkProperties[];
+
+    /**
      * A per Net list of the PID's that requested access to the net
      * used both as a refcount and for per-PID DNS selection
      */
@@ -332,6 +342,7 @@
 
         mNetTrackers = new NetworkStateTracker[
                 ConnectivityManager.MAX_NETWORK_TYPE+1];
+        mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1];
 
         mNetworkPreference = getPersistedNetworkPreference();
 
@@ -468,6 +479,7 @@
                         mNetConfigs[netType].radio);
                 continue;
             }
+            mCurrentLinkProperties[netType] = mNetTrackers[netType].getLinkProperties();
         }
 
         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
@@ -1563,6 +1575,8 @@
      * right routing table entries exist.
      */
     private void handleConnectivityChange(int netType, boolean doReset) {
+        int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
+
         /*
          * If a non-default network is enabled, add the host routes that
          * will allow it's DNS servers to be accessed.
@@ -1570,6 +1584,45 @@
         handleDnsConfigurationChange(netType);
 
         if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
+            LinkProperties newLp = mNetTrackers[netType].getLinkProperties();
+            LinkProperties curLp = mCurrentLinkProperties[netType];
+            mCurrentLinkProperties[netType] = newLp;
+            if (VDBG) {
+                log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
+                        " doReset=" + doReset + " resetMask=" + resetMask +
+                        "\n   curLp=" + curLp +
+                        "\n   newLp=" + newLp);
+            }
+
+            if (curLp.isIdenticalInterfaceName(newLp)) {
+                CompareAddressesResult car = curLp.compareAddresses(newLp);
+                if ((car.removed.size() != 0) || (car.added.size() != 0)) {
+                    for (LinkAddress linkAddr : car.removed) {
+                        if (linkAddr.getAddress() instanceof Inet4Address) {
+                            resetMask |= NetworkUtils.RESET_IPV4_ADDRESSES;
+                        }
+                        if (linkAddr.getAddress() instanceof Inet6Address) {
+                            resetMask |= NetworkUtils.RESET_IPV6_ADDRESSES;
+                        }
+                    }
+                    if (DBG) {
+                        log("handleConnectivityChange: addresses changed" +
+                                " linkProperty[" + netType + "]:" + " resetMask=" + resetMask +
+                                "\n   car=" + car);
+                    }
+                } else {
+                    if (DBG) {
+                        log("handleConnectivityChange: address are the same reset per doReset" +
+                               " linkProperty[" + netType + "]:" +
+                               " resetMask=" + resetMask);
+                    }
+                }
+            } else {
+                resetMask = NetworkUtils.RESET_ALL_ADDRESSES;
+                log("handleConnectivityChange: interface not not equivalent reset both" +
+                        " linkProperty[" + netType + "]:" +
+                        " resetMask=" + resetMask);
+            }
             if (mNetConfigs[netType].isDefault()) {
                 handleApplyDefaultProxy(netType);
                 addDefaultRoute(mNetTrackers[netType]);
@@ -1597,15 +1650,13 @@
             }
         }
 
-        if (doReset) {
+        if (doReset || resetMask != 0) {
             LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties();
             if (linkProperties != null) {
                 String iface = linkProperties.getInterfaceName();
                 if (TextUtils.isEmpty(iface) == false) {
-                    if (DBG) {
-                        log("resetConnections(" + iface + ", NetworkUtils.RESET_ALL_ADDRESSES)");
-                    }
-                    NetworkUtils.resetConnections(iface, NetworkUtils.RESET_ALL_ADDRESSES);
+                    if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")");
+                    NetworkUtils.resetConnections(iface, resetMask);
                 }
             }
         }
diff --git a/services/java/com/android/server/LoadAverageService.java b/services/java/com/android/server/LoadAverageService.java
index da9fc99..e05b570 100644
--- a/services/java/com/android/server/LoadAverageService.java
+++ b/services/java/com/android/server/LoadAverageService.java
@@ -28,7 +28,6 @@
 import android.view.Gravity;
 import android.view.View;
 import android.view.WindowManager;
-import android.view.WindowManagerImpl;
 
 public class LoadAverageService extends Service {
     private View mView;
@@ -91,32 +90,46 @@
             setPadding(4, 4, 4, 4);
             //setBackgroundResource(com.android.internal.R.drawable.load_average_background);
 
+            // Need to scale text size by density...  but we won't do it
+            // linearly, because with higher dps it is nice to squeeze the
+            // text a bit to fit more of it.  And with lower dps, trying to
+            // go much smaller will result in unreadable text.
+            int textSize = 10;
+            float density = c.getResources().getDisplayMetrics().density;
+            if (density < 1) {
+                textSize = 9;
+            } else {
+                textSize = (int)(10*density);
+                if (textSize < 10) {
+                    textSize = 10;
+                }
+            }
             mLoadPaint = new Paint();
             mLoadPaint.setAntiAlias(true);
-            mLoadPaint.setTextSize(10);
+            mLoadPaint.setTextSize(textSize);
             mLoadPaint.setARGB(255, 255, 255, 255);
 
             mAddedPaint = new Paint();
             mAddedPaint.setAntiAlias(true);
-            mAddedPaint.setTextSize(10);
+            mAddedPaint.setTextSize(textSize);
             mAddedPaint.setARGB(255, 128, 255, 128);
 
             mRemovedPaint = new Paint();
             mRemovedPaint.setAntiAlias(true);
             mRemovedPaint.setStrikeThruText(true);
-            mRemovedPaint.setTextSize(10);
+            mRemovedPaint.setTextSize(textSize);
             mRemovedPaint.setARGB(255, 255, 128, 128);
 
             mShadowPaint = new Paint();
             mShadowPaint.setAntiAlias(true);
-            mShadowPaint.setTextSize(10);
+            mShadowPaint.setTextSize(textSize);
             //mShadowPaint.setFakeBoldText(true);
             mShadowPaint.setARGB(192, 0, 0, 0);
             mLoadPaint.setShadowLayer(4, 0, 0, 0xff000000);
 
             mShadow2Paint = new Paint();
             mShadow2Paint.setAntiAlias(true);
-            mShadow2Paint.setTextSize(10);
+            mShadow2Paint.setTextSize(textSize);
             //mShadow2Paint.setFakeBoldText(true);
             mShadow2Paint.setARGB(192, 0, 0, 0);
             mLoadPaint.setShadowLayer(2, 0, 0, 0xff000000);
@@ -153,14 +166,16 @@
         }
 
         @Override
-        protected void onMeasure(int widthMeasureSpect, int heightMeasureSpec) {
-            setMeasuredDimension(mNeededWidth, mNeededHeight);
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            setMeasuredDimension(resolveSize(mNeededWidth, widthMeasureSpec),
+                    resolveSize(mNeededHeight, heightMeasureSpec));
         }
 
         @Override
         public void onDraw(Canvas canvas) {
             super.onDraw(canvas);
-            final int W = getWidth();
+            final int W = mNeededWidth;
+            final int RIGHT = getWidth()-1;
 
             final Stats stats = mStats;
             final int userTime = stats.getLastUserTime();
@@ -178,7 +193,7 @@
             int systemW = (systemTime*W)/totalTime;
             int irqW = ((iowaitTime+irqTime+softIrqTime)*W)/totalTime;
 
-            int x = W - mPaddingRight;
+            int x = RIGHT - mPaddingRight;
             int top = mPaddingTop + 2;
             int bottom = mPaddingTop + mFH - 2;
 
@@ -196,15 +211,15 @@
             }
 
             int y = mPaddingTop - (int)mAscent;
-            canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth-1,
+            canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth-1,
                     y-1, mShadowPaint);
-            canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth-1,
+            canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth-1,
                     y+1, mShadowPaint);
-            canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth+1,
+            canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth+1,
                     y-1, mShadow2Paint);
-            canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth+1,
+            canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth+1,
                     y+1, mShadow2Paint);
-            canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth,
+            canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth,
                     y, mLoadPaint);
 
             int N = stats.countWorkingStats();
@@ -216,7 +231,7 @@
 
                 userW = (st.rel_utime*W)/totalTime;
                 systemW = (st.rel_stime*W)/totalTime;
-                x = W - mPaddingRight;
+                x = RIGHT - mPaddingRight;
                 if (systemW > 0) {
                     canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint);
                     x -= systemW;
@@ -226,18 +241,18 @@
                     x -= userW;
                 }
 
-                canvas.drawText(st.name, W-mPaddingRight-st.nameWidth-1,
+                canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth-1,
                         y-1, mShadowPaint);
-                canvas.drawText(st.name, W-mPaddingRight-st.nameWidth-1,
+                canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth-1,
                         y+1, mShadowPaint);
-                canvas.drawText(st.name, W-mPaddingRight-st.nameWidth+1,
+                canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth+1,
                         y-1, mShadow2Paint);
-                canvas.drawText(st.name, W-mPaddingRight-st.nameWidth+1,
+                canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth+1,
                         y+1, mShadow2Paint);
                 Paint p = mLoadPaint;
                 if (st.added) p = mAddedPaint;
                 if (st.removed) p = mRemovedPaint;
-                canvas.drawText(st.name, W-mPaddingRight-st.nameWidth, y, p);
+                canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth, y, p);
             }
         }
 
@@ -270,7 +285,7 @@
         super.onCreate();
         mView = new LoadView(this);
         WindowManager.LayoutParams params = new WindowManager.LayoutParams(
-            WindowManager.LayoutParams.WRAP_CONTENT,
+            WindowManager.LayoutParams.MATCH_PARENT,
             WindowManager.LayoutParams.WRAP_CONTENT,
             WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY,
             WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 8501163..fd93bcf 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -45,7 +45,6 @@
 import android.app.IProcessObserver;
 import android.app.IServiceConnection;
 import android.app.IThumbnailReceiver;
-import android.app.IThumbnailRetriever;
 import android.app.Instrumentation;
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -54,6 +53,7 @@
 import android.app.backup.IBackupManager;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
+import android.content.ComponentCallbacks;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -181,22 +181,8 @@
     // The flags that are set for all calls we make to the package manager.
     static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
     
-    private static final String SYSTEM_SECURE = "ro.secure";
     private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
 
-    // This is the maximum number of application processes we would like
-    // to have running.  Due to the asynchronous nature of things, we can
-    // temporarily go beyond this limit.
-    static final int MAX_PROCESSES = 2;
-
-    // Set to false to leave processes running indefinitely, relying on
-    // the kernel killing them as resources are required.
-    static final boolean ENFORCE_PROCESS_LIMIT = false;
-
-    // This is the maximum number of activities that we would like to have
-    // running at a given time.
-    static final int MAX_ACTIVITIES = 20;
-
     // Maximum number of recent tasks that we can remember.
     static final int MAX_RECENT_TASKS = 20;
     
@@ -914,7 +900,8 @@
      */
     boolean mBooted = false;
 
-    int mProcessLimit = 0;
+    int mProcessLimit = MAX_HIDDEN_APPS;
+    int mProcessLimitOverride = -1;
 
     WindowManagerService mWindowManager;
 
@@ -2291,11 +2278,10 @@
         }
 
         synchronized (this) {
-            int index = mMainStack.indexOfTokenLocked(callingActivity);
-            if (index < 0) {
+            ActivityRecord r = mMainStack.isInStackLocked(callingActivity);
+            if (r == null) {
                 return false;
             }
-            ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
             if (r.app == null || r.app.thread == null) {
                 // The caller is not running...  d'oh!
                 return false;
@@ -2442,11 +2428,10 @@
     public void setRequestedOrientation(IBinder token,
             int requestedOrientation) {
         synchronized (this) {
-            int index = mMainStack.indexOfTokenLocked(token);
-            if (index < 0) {
+            ActivityRecord r = mMainStack.isInStackLocked(token);
+            if (r == null) {
                 return;
             }
-            ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
             final long origId = Binder.clearCallingIdentity();
             mWindowManager.setAppOrientation(r, requestedOrientation);
             Configuration config = mWindowManager.updateOrientationFromAppTokens(
@@ -2464,11 +2449,10 @@
 
     public int getRequestedOrientation(IBinder token) {
         synchronized (this) {
-            int index = mMainStack.indexOfTokenLocked(token);
-            if (index < 0) {
+            ActivityRecord r = mMainStack.isInStackLocked(token);
+            if (r == null) {
                 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
             }
-            ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
             return mWindowManager.getAppOrientation(r);
         }
     }
@@ -2609,11 +2593,10 @@
     public final void finishSubActivity(IBinder token, String resultWho,
             int requestCode) {
         synchronized(this) {
-            int index = mMainStack.indexOfTokenLocked(token);
-            if (index < 0) {
+            ActivityRecord self = mMainStack.isInStackLocked(token);
+            if (self == null) {
                 return;
             }
-            ActivityRecord self = (ActivityRecord)mMainStack.mHistory.get(index);
 
             final long origId = Binder.clearCallingIdentity();
 
@@ -2652,11 +2635,10 @@
     public void overridePendingTransition(IBinder token, String packageName,
             int enterAnim, int exitAnim) {
         synchronized(this) {
-            int index = mMainStack.indexOfTokenLocked(token);
-            if (index < 0) {
+            ActivityRecord self = mMainStack.isInStackLocked(token);
+            if (self == null) {
                 return;
             }
-            ActivityRecord self = (ActivityRecord)mMainStack.mHistory.get(index);
 
             final long origId = Binder.clearCallingIdentity();
             
@@ -2735,8 +2717,7 @@
                     }
                 }
 
-                r.stack.cleanUpActivityLocked(r, true);
-                r.state = ActivityState.STOPPED;
+                r.stack.cleanUpActivityLocked(r, true, true);
             }
             atTop = false;
         }
@@ -3920,20 +3901,9 @@
         final long origId = Binder.clearCallingIdentity();
 
         synchronized (this) {
-            int index = mMainStack.indexOfTokenLocked(token);
-            if (index >= 0) {
-                r = (ActivityRecord)mMainStack.mHistory.get(index);
-                r.icicle = icicle;
-                r.haveState = true;
-                r.updateThumbnail(thumbnail, description);
-                r.stopped = true;
-                r.state = ActivityState.STOPPED;
-                if (!r.finishing) {
-                    if (r.configDestroy) {
-                        r.stack.destroyActivityLocked(r, true);
-                        r.stack.resumeTopActivityLocked(null);
-                    }
-                }
+            r = mMainStack.isInStackLocked(token);
+            if (r != null) {
+                r.stack.activityStoppedLocked(r, icicle, thumbnail, description);
             }
         }
 
@@ -3966,35 +3936,30 @@
     }
 
     private ActivityRecord getCallingRecordLocked(IBinder token) {
-        int index = mMainStack.indexOfTokenLocked(token);
-        if (index >= 0) {
-            ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
-            if (r != null) {
-                return r.resultTo;
-            }
+        ActivityRecord r = mMainStack.isInStackLocked(token);
+        if (r == null) {
+            return null;
         }
-        return null;
+        return r.resultTo;
     }
 
     public ComponentName getActivityClassForToken(IBinder token) {
         synchronized(this) {
-            int index = mMainStack.indexOfTokenLocked(token);
-            if (index >= 0) {
-                ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
-                return r.intent.getComponent();
+            ActivityRecord r = mMainStack.isInStackLocked(token);
+            if (r == null) {
+                return null;
             }
-            return null;
+            return r.intent.getComponent();
         }
     }
 
     public String getPackageForToken(IBinder token) {
         synchronized(this) {
-            int index = mMainStack.indexOfTokenLocked(token);
-            if (index >= 0) {
-                ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
-                return r.packageName;
+            ActivityRecord r = mMainStack.isInStackLocked(token);
+            if (r == null) {
+                return null;
             }
-            return null;
+            return r.packageName;
         }
     }
 
@@ -4057,11 +4022,10 @@
             int requestCode, Intent[] intents, String[] resolvedTypes, int flags) {
         ActivityRecord activity = null;
         if (type == INTENT_SENDER_ACTIVITY_RESULT) {
-            int index = mMainStack.indexOfTokenLocked(token);
-            if (index < 0) {
+            activity = mMainStack.isInStackLocked(token);
+            if (activity == null) {
                 return null;
             }
-            activity = (ActivityRecord)mMainStack.mHistory.get(index);
             if (activity.finishing) {
                 return null;
             }
@@ -4183,11 +4147,17 @@
     public void setProcessLimit(int max) {
         enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
                 "setProcessLimit()");
-        mProcessLimit = max;
+        synchronized (this) {
+            mProcessLimit = max < 0 ? MAX_HIDDEN_APPS : max;
+            mProcessLimitOverride = max;
+        }
+        trimApplications();
     }
 
     public int getProcessLimit() {
-        return mProcessLimit;
+        synchronized (this) {
+            return mProcessLimitOverride;
+        }
     }
 
     void foregroundTokenDied(ForegroundToken token) {
@@ -5451,11 +5421,10 @@
 
         synchronized(this) {
             if (r == null) {
-                int index = mMainStack.indexOfTokenLocked(token);
-                if (index < 0) {
+                r = mMainStack.isInStackLocked(token);
+                if (r == null) {
                     return;
                 }
-                r = (ActivityRecord)mMainStack.mHistory.get(index);
             }
             if (thumbnail == null && r.thumbHolder != null) {
                 thumbnail = r.thumbHolder.lastThumbnail;
@@ -6169,9 +6138,8 @@
         final long origId = Binder.clearCallingIdentity();
 
         synchronized (this) {
-            int index = mMainStack.indexOfTokenLocked(token);
-            if (index >= 0) {
-                r = (ActivityRecord)mMainStack.mHistory.get(index);
+            r = mMainStack.isInStackLocked(token);
+            if (r != null) {
                 mMainStack.activitySleptLocked(r);
             }
         }
@@ -6322,22 +6290,20 @@
 
     public void setImmersive(IBinder token, boolean immersive) {
         synchronized(this) {
-            int index = (token != null) ? mMainStack.indexOfTokenLocked(token) : -1;
-            if (index < 0) {
+            ActivityRecord r = mMainStack.isInStackLocked(token);
+            if (r == null) {
                 throw new IllegalArgumentException();
             }
-            ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
             r.immersive = immersive;
         }
     }
 
     public boolean isImmersive(IBinder token) {
         synchronized (this) {
-            int index = (token != null) ? mMainStack.indexOfTokenLocked(token) : -1;
-            if (index < 0) {
+            ActivityRecord r = mMainStack.isInStackLocked(token);
+            if (r == null) {
                 throw new IllegalArgumentException();
             }
-            ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
             return r.immersive;
         }
     }
@@ -8800,9 +8766,10 @@
             } else {
                 foreground = " ";
             }
-            pw.println(String.format("%s%s #%2d: adj=%s/%s%s %s (%s)",
+            pw.println(String.format("%s%s #%2d: adj=%s/%s%s trm=%2d %s (%s)",
                     prefix, (r.persistent ? persistentLabel : normalLabel),
-                    N-i, oomAdj, schedGroup, foreground, r.toShortString(), r.adjType));
+                    N-i, oomAdj, schedGroup, foreground, r.trimMemoryLevel,
+                    r.toShortString(), r.adjType));
             if (r.adjSource != null || r.adjTarget != null) {
                 pw.print(prefix);
                 pw.print("    ");
@@ -10337,12 +10304,11 @@
 
             ActivityRecord activity = null;
             if (token != null) {
-                int aindex = mMainStack.indexOfTokenLocked(token);
-                if (aindex < 0) {
+                activity = mMainStack.isInStackLocked(token);
+                if (activity == null) {
                     Slog.w(TAG, "Binding with unknown activity: " + token);
                     return 0;
                 }
-                activity = (ActivityRecord)mMainStack.mHistory.get(aindex);
             }
 
             int clientLabel = 0;
@@ -11556,8 +11522,8 @@
             return false;
         }
         int state = r.state;
-        r.state = r.IDLE;
-        if (state == r.IDLE) {
+        r.state = BroadcastRecord.IDLE;
+        if (state == BroadcastRecord.IDLE) {
             if (explicit) {
                 Slog.w(TAG, "finishReceiver called but state is IDLE");
             }
@@ -12941,7 +12907,7 @@
             ProcessRecord proc = mProcessesToGc.get(0);
             Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
             
-            long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
+            long when = proc.lastRequestedGc + GC_MIN_INTERVAL;
             long now = SystemClock.uptimeMillis();
             if (when < (now+GC_TIMEOUT)) {
                 when = now + GC_TIMEOUT;
@@ -13084,16 +13050,14 @@
         }
     }
 
-    private final boolean updateOomAdjLocked(
+    private final void updateOomAdjLocked(
             ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
         app.hiddenAdj = hiddenAdj;
 
         if (app.thread == null) {
-            return true;
+            return;
         }
 
-        boolean success = true;
-
         final boolean wasKeeping = app.keeping;
 
         int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
@@ -13129,10 +13093,10 @@
             if (Process.setOomAdj(app.pid, adj)) {
                 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
                     TAG, "Set app " + app.processName +
-                    " oom adj to " + adj);
+                    " oom adj to " + adj + " because " + app.adjType);
                 app.setAdj = adj;
             } else {
-                success = false;
+                Slog.w(TAG, "Failed setting oom adj of " + app + " to " + adj);
             }
         }
         if (app.setSchedGroup != app.curSchedGroup) {
@@ -13158,8 +13122,7 @@
                     } finally {
                         Binder.restoreCallingIdentity(oldId);
                     }
-                }
-                if (false) {
+                } else {
                     if (app.thread != null) {
                         try {
                             app.thread.setSchedulingGroup(app.curSchedGroup);
@@ -13169,8 +13132,6 @@
                 }
             }
         }
-
-        return success;
     }
 
     private final ActivityRecord resumedAppLocked() {
@@ -13184,30 +13145,26 @@
         return resumedActivity;
     }
 
-    private final boolean updateOomAdjLocked(ProcessRecord app) {
+    private final void updateOomAdjLocked(ProcessRecord app) {
         final ActivityRecord TOP_ACT = resumedAppLocked();
         final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
         int curAdj = app.curAdj;
-        final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
-            && app.curAdj <= HIDDEN_APP_MAX_ADJ;
+        final boolean wasHidden = curAdj >= HIDDEN_APP_MIN_ADJ
+            && curAdj <= HIDDEN_APP_MAX_ADJ;
 
         mAdjSeq++;
 
-        final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
-        if (res) {
-            final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
-                && app.curAdj <= HIDDEN_APP_MAX_ADJ;
-            if (nowHidden != wasHidden) {
-                // Changed to/from hidden state, so apps after it in the LRU
-                // list may also be changed.
-                updateOomAdjLocked();
-            }
+        updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
+        final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
+            && app.curAdj <= HIDDEN_APP_MAX_ADJ;
+        if (nowHidden != wasHidden) {
+            // Changed to/from hidden state, so apps after it in the LRU
+            // list may also be changed.
+            updateOomAdjLocked();
         }
-        return res;
     }
 
-    final boolean updateOomAdjLocked() {
-        boolean didOomAdj = true;
+    final void updateOomAdjLocked() {
         final ActivityRecord TOP_ACT = resumedAppLocked();
         final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
 
@@ -13229,45 +13186,104 @@
         int step = 0;
         int numHidden = 0;
         
-        // First try updating the OOM adjustment for each of the
+        // First update the OOM adjustment for each of the
         // application processes based on their current state.
         int i = mLruProcesses.size();
         int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
+        int numBg = 0;
         while (i > 0) {
             i--;
             ProcessRecord app = mLruProcesses.get(i);
             //Slog.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
-            if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
-                if (curHiddenAdj < EMPTY_APP_ADJ
-                    && app.curAdj == curHiddenAdj) {
-                    step++;
-                    if (step >= factor) {
-                        step = 0;
-                        curHiddenAdj++;
-                    }
+            updateOomAdjLocked(app, curHiddenAdj, TOP_APP);
+            if (curHiddenAdj < EMPTY_APP_ADJ
+                && app.curAdj == curHiddenAdj) {
+                step++;
+                if (step >= factor) {
+                    step = 0;
+                    curHiddenAdj++;
                 }
+            }
+            if (!app.killedBackground) {
                 if (app.curAdj >= HIDDEN_APP_MIN_ADJ) {
-                    if (!app.killedBackground) {
-                        numHidden++;
-                        if (numHidden > MAX_HIDDEN_APPS) {
-                            Slog.i(TAG, "No longer want " + app.processName
-                                    + " (pid " + app.pid + "): hidden #" + numHidden);
-                            EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
-                                    app.processName, app.setAdj, "too many background");
-                            app.killedBackground = true;
-                            Process.killProcessQuiet(app.pid);
-                        }
+                    numHidden++;
+                    if (numHidden > mProcessLimit) {
+                        Slog.i(TAG, "No longer want " + app.processName
+                                + " (pid " + app.pid + "): hidden #" + numHidden);
+                        EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+                                app.processName, app.setAdj, "too many background");
+                        app.killedBackground = true;
+                        Process.killProcessQuiet(app.pid);
+                    } else {
+                        numBg++;
                     }
+                } else if (app.curAdj >= HOME_APP_ADJ) {
+                    numBg++;
                 }
-            } else {
-                didOomAdj = false;
             }
         }
 
-        // If we return false, we will fall back on killing processes to
-        // have a fixed limit.  Do this if a limit has been requested; else
-        // only return false if one of the adjustments failed.
-        return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
+        // Now determine the memory trimming level of background processes.
+        // Unfortunately we need to start at the back of the list to do this
+        // properly.  We only do this if the number of background apps we
+        // are managing to keep around is less than half the maximum we desire;
+        // if we are keeping a good number around, we'll let them use whatever
+        // memory they want.
+        if (numHidden <= (MAX_HIDDEN_APPS/2)) {
+            final int N = mLruProcesses.size();
+            factor = numBg/3;
+            step = 0;
+            int curLevel = ComponentCallbacks.TRIM_MEMORY_COMPLETE;
+            for (i=0; i<N; i++) {
+                ProcessRecord app = mLruProcesses.get(i);
+                if (app.curAdj >= HIDDEN_APP_MIN_ADJ && !app.killedBackground) {
+                    if (app.trimMemoryLevel < curLevel && app.thread != null) {
+                        try {
+                            app.thread.scheduleTrimMemory(curLevel);
+                        } catch (RemoteException e) {
+                        }
+                        if (curLevel >= ComponentCallbacks.TRIM_MEMORY_COMPLETE) {
+                            // For these apps we will also finish their activities
+                            // to help them free memory.
+                            mMainStack.destroyActivitiesLocked(app, false);
+                        }
+                    }
+                    app.trimMemoryLevel = curLevel;
+                    step++;
+                    if (step >= factor) {
+                        switch (curLevel) {
+                            case ComponentCallbacks.TRIM_MEMORY_COMPLETE:
+                                curLevel = ComponentCallbacks.TRIM_MEMORY_MODERATE;
+                                break;
+                            case ComponentCallbacks.TRIM_MEMORY_MODERATE:
+                                curLevel = ComponentCallbacks.TRIM_MEMORY_BACKGROUND;
+                                break;
+                        }
+                    }
+                } else if (app.curAdj >= PERCEPTIBLE_APP_ADJ) {
+                    if (app.trimMemoryLevel < ComponentCallbacks.TRIM_MEMORY_INVISIBLE
+                            && app.thread != null) {
+                        try {
+                            app.thread.scheduleTrimMemory(ComponentCallbacks.TRIM_MEMORY_INVISIBLE);
+                        } catch (RemoteException e) {
+                        }
+                    }
+                    app.trimMemoryLevel = ComponentCallbacks.TRIM_MEMORY_INVISIBLE;
+                } else {
+                    app.trimMemoryLevel = 0;
+                }
+            }
+        } else {
+            final int N = mLruProcesses.size();
+            for (i=0; i<N; i++) {
+                ProcessRecord app = mLruProcesses.get(i);
+                app.trimMemoryLevel = 0;
+            }
+        }
+
+        if (mAlwaysFinishActivities) {
+            mMainStack.destroyActivitiesLocked(null, false);
+        }
     }
 
     final void trimApplications() {
@@ -13307,165 +13323,8 @@
                 }
             }
 
-            // Now try updating the OOM adjustment for each of the
-            // application processes based on their current state.
-            // If the setOomAdj() API is not supported, then go with our
-            // back-up plan...
-            if (!updateOomAdjLocked()) {
-
-                // Count how many processes are running services.
-                int numServiceProcs = 0;
-                for (i=mLruProcesses.size()-1; i>=0; i--) {
-                    final ProcessRecord app = mLruProcesses.get(i);
-
-                    if (app.persistent || app.services.size() != 0
-                            || app.curReceiver != null) {
-                        // Don't count processes holding services against our
-                        // maximum process count.
-                        if (localLOGV) Slog.v(
-                            TAG, "Not trimming app " + app + " with services: "
-                            + app.services);
-                        numServiceProcs++;
-                    }
-                }
-
-                int curMaxProcs = mProcessLimit;
-                if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
-                if (mAlwaysFinishActivities) {
-                    curMaxProcs = 1;
-                }
-                curMaxProcs += numServiceProcs;
-
-                // Quit as many processes as we can to get down to the desired
-                // process count.  First remove any processes that no longer
-                // have activites running in them.
-                for (   i=0;
-                        i<mLruProcesses.size()
-                            && mLruProcesses.size() > curMaxProcs;
-                        i++) {
-                    final ProcessRecord app = mLruProcesses.get(i);
-                    // Quit an application only if it is not currently
-                    // running any activities.
-                    if (!app.persistent && app.activities.size() == 0
-                            && app.curReceiver == null && app.services.size() == 0) {
-                        Slog.i(
-                            TAG, "Exiting empty application process "
-                            + app.processName + " ("
-                            + (app.thread != null ? app.thread.asBinder() : null)
-                            + ")\n");
-                        if (app.pid > 0 && app.pid != MY_PID) {
-                            EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
-                                    app.processName, app.setAdj, "empty");
-                            Process.killProcessQuiet(app.pid);
-                        } else {
-                            try {
-                                app.thread.scheduleExit();
-                            } catch (Exception e) {
-                                // Ignore exceptions.
-                            }
-                        }
-                        // todo: For now we assume the application is not buggy
-                        // or evil, and will quit as a result of our request.
-                        // Eventually we need to drive this off of the death
-                        // notification, and kill the process if it takes too long.
-                        cleanUpApplicationRecordLocked(app, false, i);
-                        i--;
-                    }
-                }
-
-                // If we still have too many processes, now from the least
-                // recently used process we start finishing activities.
-                if (false) Slog.v(
-                    TAG, "*** NOW HAVE " + mLruProcesses.size() +
-                    " of " + curMaxProcs + " processes");
-                for (   i=0;
-                        i<mLruProcesses.size()
-                            && mLruProcesses.size() > curMaxProcs;
-                        i++) {
-                    final ProcessRecord app = mLruProcesses.get(i);
-                    // Quit the application only if we have a state saved for
-                    // all of its activities.
-                    boolean canQuit = !app.persistent && app.curReceiver == null
-                        && app.services.size() == 0;
-                    int NUMA = app.activities.size();
-                    int j;
-                    if (false) Slog.v(
-                        TAG, "Looking to quit " + app.processName);
-                    for (j=0; j<NUMA && canQuit; j++) {
-                        ActivityRecord r = app.activities.get(j);
-                        if (false) Slog.v(
-                            TAG, "  " + r.intent.getComponent().flattenToShortString()
-                            + ": frozen=" + r.haveState + ", visible=" + r.visible);
-                        canQuit = (r.haveState || !r.stateNotNeeded)
-                                && !r.visible && r.stopped;
-                    }
-                    if (canQuit) {
-                        // Finish all of the activities, and then the app itself.
-                        for (j=0; j<NUMA; j++) {
-                            ActivityRecord r = app.activities.get(j);
-                            if (!r.finishing) {
-                                r.stack.destroyActivityLocked(r, false);
-                            }
-                            r.resultTo = null;
-                        }
-                        Slog.i(TAG, "Exiting application process "
-                              + app.processName + " ("
-                              + (app.thread != null ? app.thread.asBinder() : null)
-                              + ")\n");
-                        if (app.pid > 0 && app.pid != MY_PID) {
-                            EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
-                                    app.processName, app.setAdj, "old background");
-                            Process.killProcessQuiet(app.pid);
-                        } else {
-                            try {
-                                app.thread.scheduleExit();
-                            } catch (Exception e) {
-                                // Ignore exceptions.
-                            }
-                        }
-                        // todo: For now we assume the application is not buggy
-                        // or evil, and will quit as a result of our request.
-                        // Eventually we need to drive this off of the death
-                        // notification, and kill the process if it takes too long.
-                        cleanUpApplicationRecordLocked(app, false, i);
-                        i--;
-                        //dump();
-                    }
-                }
-
-            }
-
-            int curMaxActivities = MAX_ACTIVITIES;
-            if (mAlwaysFinishActivities) {
-                curMaxActivities = 1;
-            }
-
-            // Finally, if there are too many activities now running, try to
-            // finish as many as we can to get back down to the limit.
-            for (   i=0;
-                    i<mMainStack.mLRUActivities.size()
-                        && mMainStack.mLRUActivities.size() > curMaxActivities;
-                    i++) {
-                final ActivityRecord r
-                    = (ActivityRecord)mMainStack.mLRUActivities.get(i);
-
-                // We can finish this one if we have its icicle saved and
-                // it is not persistent.
-                if ((r.haveState || !r.stateNotNeeded) && !r.visible
-                        && r.stopped && !r.finishing) {
-                    final int origSize = mMainStack.mLRUActivities.size();
-                    r.stack.destroyActivityLocked(r, true);
-
-                    // This will remove it from the LRU list, so keep
-                    // our index at the same value.  Note that this check to
-                    // see if the size changes is just paranoia -- if
-                    // something unexpected happens, we don't want to end up
-                    // in an infinite loop.
-                    if (origSize > mMainStack.mLRUActivities.size()) {
-                        i--;
-                    }
-                }
-            }
+            // Now update the oom adj for all processes.
+            updateOomAdjLocked();
         }
     }
 
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index b1da69f..93d8164 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -52,6 +52,7 @@
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
@@ -83,6 +84,8 @@
     static final boolean DEBUG_CONFIGURATION = ActivityManagerService.DEBUG_CONFIGURATION;
     static final boolean DEBUG_TASKS = ActivityManagerService.DEBUG_TASKS;
     
+    static final boolean DEBUG_STATES = false;
+
     static final boolean VALIDATE_TOKENS = ActivityManagerService.VALIDATE_TOKENS;
     
     // How long we wait until giving up on the last activity telling us it
@@ -392,19 +395,25 @@
     }
 
     final int indexOfTokenLocked(IBinder token) {
-        int count = mHistory.size();
-
-        // convert the token to an entry in the history.
-        int index = -1;
-        for (int i=count-1; i>=0; i--) {
-            Object o = mHistory.get(i);
-            if (o == token) {
-                index = i;
-                break;
-            }
+        try {
+            ActivityRecord r = (ActivityRecord)token;
+            return mHistory.indexOf(r);
+        } catch (ClassCastException e) {
+            Slog.w(TAG, "Bad activity token: " + token, e);
+            return -1;
         }
+    }
 
-        return index;
+    final ActivityRecord isInStackLocked(IBinder token) {
+        try {
+            ActivityRecord r = (ActivityRecord)token;
+            if (mHistory.contains(r)) {
+                return r;
+            }
+        } catch (ClassCastException e) {
+            Slog.w(TAG, "Bad activity token: " + token, e);
+        }
+        return null;
     }
 
     private final boolean updateLRUListLocked(ActivityRecord r) {
@@ -604,6 +613,8 @@
             // As part of the process of launching, ActivityThread also performs
             // a resume.
             r.state = ActivityState.RESUMED;
+            if (DEBUG_STATES) Slog.v(TAG, "Moving to RESUMED: " + r
+                    + " (starting new instance)");
             r.stopped = false;
             mResumedActivity = r;
             r.task.touchActiveTime();
@@ -617,6 +628,8 @@
             // should look like we asked it to pause+stop (but remain visible),
             // and it has done so and reported back the current icicle and
             // other state.
+            if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r
+                    + " (starting in stopped state)");
             r.state = ActivityState.STOPPED;
             r.stopped = true;
         }
@@ -797,7 +810,8 @@
             resumeTopActivityLocked(null);
             return;
         }
-        if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
+        if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev);
+        else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
         mResumedActivity = null;
         mPausingActivity = prev;
         mLastPausedActivity = prev;
@@ -879,6 +893,8 @@
                 r = mHistory.get(index);
                 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
                 if (mPausingActivity == r) {
+                    if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
+                            + (timeout ? " (due to timeout)" : " (pause complete)"));
                     r.state = ActivityState.PAUSED;
                     completePauseLocked();
                 } else {
@@ -891,6 +907,22 @@
         }
     }
 
+    final void activityStoppedLocked(ActivityRecord r, Bundle icicle, Bitmap thumbnail,
+            CharSequence description) {
+        r.icicle = icicle;
+        r.haveState = true;
+        r.updateThumbnail(thumbnail, description);
+        r.stopped = true;
+        if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r + " (stop complete)");
+        r.state = ActivityState.STOPPED;
+        if (!r.finishing) {
+            if (r.configDestroy) {
+                destroyActivityLocked(r, true, false);
+                resumeTopActivityLocked(null);
+            }
+        }
+    }
+
     private final void completePauseLocked() {
         ActivityRecord prev = mPausingActivity;
         if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);
@@ -914,7 +946,7 @@
                     // instance right now, we need to first completely stop
                     // the current instance before starting the new one.
                     if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
-                    destroyActivityLocked(prev, true);
+                    destroyActivityLocked(prev, true, false);
                 } else {
                     mStoppingActivities.add(prev);
                     if (mStoppingActivities.size() > 3) {
@@ -1371,6 +1403,7 @@
 
             mService.updateCpuStats();
             
+            if (DEBUG_STATES) Slog.v(TAG, "Moving to RESUMED: " + next + " (in existing)");
             next.state = ActivityState.RESUMED;
             mResumedActivity = next;
             next.task.touchActiveTime();
@@ -1447,6 +1480,8 @@
 
             } catch (Exception e) {
                 // Whoops, need to restart this activity!
+                if (DEBUG_STATES) Slog.v(TAG, "Resume failed; resetting state to "
+                        + lastState + ": " + next);
                 next.state = lastState;
                 mResumedActivity = lastResumedActivity;
                 Slog.i(TAG, "Restarting because process died: " + next);
@@ -2960,6 +2995,8 @@
             r.resumeKeyDispatchingLocked();
             try {
                 r.stopped = false;
+                if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
+                        + " (stop requested)");
                 r.state = ActivityState.STOPPING;
                 if (DEBUG_VISBILITY) Slog.v(
                         TAG, "Stopping visible=" + r.visible + " for " + r);
@@ -2977,9 +3014,10 @@
                 Slog.w(TAG, "Exception thrown during pause", e);
                 // Just in case, assume it to be stopped.
                 r.stopped = true;
+                if (DEBUG_STATES) Slog.v(TAG, "Stop failed; moving to STOPPED: " + r);
                 r.state = ActivityState.STOPPED;
                 if (r.configDestroy) {
-                    destroyActivityLocked(r, true);
+                    destroyActivityLocked(r, true, false);
                 }
             }
         }
@@ -3145,7 +3183,7 @@
         for (i=0; i<NF; i++) {
             ActivityRecord r = (ActivityRecord)finishes.get(i);
             synchronized (mService) {
-                destroyActivityLocked(r, true);
+                destroyActivityLocked(r, true, false);
             }
         }
 
@@ -3340,6 +3378,8 @@
                     checkReadyForSleepLocked();
                 }
             }
+            if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
+                    + " (finish requested)");
             r.state = ActivityState.STOPPING;
             mService.updateOomAdjLocked();
             return r;
@@ -3353,6 +3393,7 @@
             mResumedActivity = null;
         }
         final ActivityState prevState = r.state;
+        if (DEBUG_STATES) Slog.v(TAG, "Moving to FINISHING: " + r);
         r.state = ActivityState.FINISHING;
 
         if (mode == FINISH_IMMEDIATELY
@@ -3360,7 +3401,7 @@
                 || prevState == ActivityState.INITIALIZING) {
             // If this activity is already stopped, we can just finish
             // it right now.
-            return destroyActivityLocked(r, true) ? null : r;
+            return destroyActivityLocked(r, true, true) ? null : r;
         } else {
             // Need to go through the full pause cycle to get this
             // activity into the stopped state and then finish it.
@@ -3378,7 +3419,8 @@
      * processing going away, in which case there is no remaining client-side
      * state to destroy so only the cleanup here is needed.
      */
-    final void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices) {
+    final void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices,
+            boolean setState) {
         if (mResumedActivity == r) {
             mResumedActivity = null;
         }
@@ -3389,6 +3431,11 @@
         r.configDestroy = false;
         r.frozenBeforeDestroy = false;
 
+        if (setState) {
+            if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r + " (cleaning up)");
+            r.state = ActivityState.DESTROYED;
+        }
+
         // Make sure this record is no longer in the pending finishes list.
         // This could happen, for example, if we are trimming activities
         // down to the max limit while they are still waiting to finish.
@@ -3428,6 +3475,8 @@
             r.makeFinishing();
             mHistory.remove(r);
             r.takeFromHistory();
+            if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
+                    + " (removed from history)");
             r.state = ActivityState.DESTROYED;
             mService.mWindowManager.removeAppToken(r);
             if (VALIDATE_TOKENS) {
@@ -3453,6 +3502,22 @@
         }
     }
     
+    final void destroyActivitiesLocked(ProcessRecord owner, boolean oomAdj) {
+        for (int i=mHistory.size()-1; i>=0; i--) {
+            ActivityRecord r = mHistory.get(i);
+            if (owner != null && r.app != owner) {
+                continue;
+            }
+            // We can destroy this one if we have its icicle saved and
+            // it is not in the process of pausing/stopping/finishing.
+            if (r.app != null && r.haveState && !r.visible && r.stopped && !r.finishing
+                    && r.state != ActivityState.DESTROYING
+                    && r.state != ActivityState.DESTROYED) {
+                destroyActivityLocked(r, true, oomAdj);
+            }
+        }
+    }
+
     /**
      * Destroy the current CLIENT SIDE instance of an activity.  This may be
      * called both when actually finishing an activity, or when performing
@@ -3460,7 +3525,7 @@
      * but then create a new client-side object for this same HistoryRecord.
      */
     final boolean destroyActivityLocked(ActivityRecord r,
-            boolean removeFromApp) {
+            boolean removeFromApp, boolean oomAdj) {
         if (DEBUG_SWITCH) Slog.v(
             TAG, "Removing activity: token=" + r
               + ", app=" + (r.app != null ? r.app.processName : "(null)"));
@@ -3470,7 +3535,7 @@
 
         boolean removedFromHistory = false;
         
-        cleanUpActivityLocked(r, false);
+        cleanUpActivityLocked(r, false, false);
 
         final boolean hadApp = r.app != null;
         
@@ -3488,7 +3553,7 @@
                 if (r.app.activities.size() == 0) {
                     // No longer have activities, so update location in
                     // LRU list.
-                    mService.updateLruProcessLocked(r.app, true, false);
+                    mService.updateLruProcessLocked(r.app, oomAdj, false);
                 }
             }
 
@@ -3513,12 +3578,23 @@
             r.app = null;
             r.nowVisible = false;
             
+            // If the activity is finishing, we need to wait on removing it
+            // from the list to give it a chance to do its cleanup.  During
+            // that time it may make calls back with its token so we need to
+            // be able to find it on the list and so we don't want to remove
+            // it from the list yet.  Otherwise, we can just immediately put
+            // it in the destroyed state since we are not removing it from the
+            // list.
             if (r.finishing && !skipDestroy) {
+                if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYING: " + r
+                        + " (destroy requested)");
                 r.state = ActivityState.DESTROYING;
                 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
                 msg.obj = r;
                 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
             } else {
+                if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
+                        + " (destroy skipped)");
                 r.state = ActivityState.DESTROYED;
             }
         } else {
@@ -3527,6 +3603,8 @@
                 removeActivityFromHistoryLocked(r);
                 removedFromHistory = true;
             } else {
+                if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
+                        + " (no app)");
                 r.state = ActivityState.DESTROYED;
             }
         }
@@ -3919,7 +3997,7 @@
             if (r.app == null || r.app.thread == null) {
                 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
                         "Switch is destroying non-running " + r);
-                destroyActivityLocked(r, true);
+                destroyActivityLocked(r, true, false);
             } else if (r.state == ActivityState.PAUSING) {
                 // A little annoying: we are waiting for this activity to
                 // finish pausing.  Let's not do anything now, but just
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index da83e7d..99830f9 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -61,6 +61,7 @@
     int setAdj;                 // Last set OOM adjustment for this process
     int curSchedGroup;          // Currently desired scheduling class
     int setSchedGroup;          // Last set to background scheduling class
+    int trimMemoryLevel;        // Last selected memory trimming level
     boolean keeping;            // Actively running code so don't kill due to that?
     boolean setIsForeground;    // Running foreground UI when last set?
     boolean foregroundServices; // Running any services that are foreground?
@@ -181,7 +182,8 @@
                 pw.print(" cur="); pw.print(curAdj);
                 pw.print(" set="); pw.println(setAdj);
         pw.print(prefix); pw.print("curSchedGroup="); pw.print(curSchedGroup);
-                pw.print(" setSchedGroup="); pw.println(setSchedGroup);
+                pw.print(" setSchedGroup="); pw.print(setSchedGroup);
+                pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
         pw.print(prefix); pw.print("setIsForeground="); pw.print(setIsForeground);
                 pw.print(" foregroundServices="); pw.print(foregroundServices);
                 pw.print(" forcingToForeground="); pw.println(forcingToForeground);
@@ -305,8 +307,6 @@
     }
     
     void toShortString(StringBuilder sb) {
-        sb.append(Integer.toHexString(System.identityHashCode(this)));
-        sb.append(' ');
         sb.append(pid);
         sb.append(':');
         sb.append(processName);
@@ -320,6 +320,8 @@
         }
         StringBuilder sb = new StringBuilder(128);
         sb.append("ProcessRecord{");
+        sb.append(Integer.toHexString(System.identityHashCode(this)));
+        sb.append(' ');
         toShortString(sb);
         sb.append('}');
         return stringName = sb.toString();
diff --git a/telephony/java/com/android/internal/telephony/DataCallState.java b/telephony/java/com/android/internal/telephony/DataCallState.java
index fba3184..a69ce8b 100644
--- a/telephony/java/com/android/internal/telephony/DataCallState.java
+++ b/telephony/java/com/android/internal/telephony/DataCallState.java
@@ -52,7 +52,7 @@
     /**
      * Class returned by onSetupConnectionCompleted.
      */
-    protected enum SetupResult {
+    public enum SetupResult {
         SUCCESS,
         ERR_BadCommand,
         ERR_UnacceptableParameter,
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 5c84fdc..1bba8e3 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -17,30 +17,25 @@
 package com.android.internal.telephony;
 
 
+import com.android.internal.telephony.DataCallState.SetupResult;
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
 
 import android.app.PendingIntent;
-import android.net.LinkAddress;
 import android.net.LinkCapabilities;
 import android.net.LinkProperties;
-import android.net.NetworkUtils;
+import android.net.LinkProperties.CompareAddressesResult;
 import android.net.ProxyProperties;
 import android.os.AsyncResult;
-import android.os.Bundle;
 import android.os.Message;
-import android.os.Parcel;
-import android.os.Parcelable;
 import android.os.SystemProperties;
 import android.text.TextUtils;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * {@hide}
@@ -497,8 +492,7 @@
         } else {
             if (DBG) log("onSetupConnectionCompleted received DataCallState: " + response);
             cid = response.cid;
-            // set link properties based on data call response
-            result = setLinkProperties(response, mLinkProperties);
+            result = updateLinkProperty(response).setupResult;
         }
 
         return result;
@@ -527,48 +521,41 @@
         return response.setLinkProperties(lp, okToUseSystemPropertyDns);
     }
 
-    private DataConnectionAc.LinkPropertyChangeAction updateLinkProperty(
-                                                      DataCallState newState) {
-        DataConnectionAc.LinkPropertyChangeAction changed =
-                        DataConnectionAc.LinkPropertyChangeAction.NONE;
+    public static class UpdateLinkPropertyResult {
+        public DataCallState.SetupResult setupResult = DataCallState.SetupResult.SUCCESS;
+        public LinkProperties oldLp;
+        public LinkProperties newLp;
+        public UpdateLinkPropertyResult(LinkProperties curLp) {
+            oldLp = curLp;
+            newLp = curLp;
+        }
+    }
 
-        if (newState == null) return changed;
+    private UpdateLinkPropertyResult updateLinkProperty(DataCallState newState) {
+        UpdateLinkPropertyResult result = new UpdateLinkPropertyResult(mLinkProperties);
 
-        DataCallState.SetupResult result;
-        LinkProperties newLp = new LinkProperties();
+        if (newState == null) return result;
+
+        DataCallState.SetupResult setupResult;
+        result.newLp = new LinkProperties();
 
         // set link properties based on data call response
-        result = setLinkProperties(newState, newLp);
-        if (result != DataCallState.SetupResult.SUCCESS) {
-            if (DBG) log("UpdateLinkProperty failed : " + result);
-            return changed;
+        result.setupResult = setLinkProperties(newState, result.newLp);
+        if (result.setupResult != DataCallState.SetupResult.SUCCESS) {
+            if (DBG) log("updateLinkProperty failed : " + result.setupResult);
+            return result;
         }
         // copy HTTP proxy as it is not part DataCallState.
-        newLp.setHttpProxy(mLinkProperties.getHttpProxy());
+        result.newLp.setHttpProxy(mLinkProperties.getHttpProxy());
 
-        if (DBG) log("old LP=" + mLinkProperties);
-        if (DBG) log("new LP=" + newLp);
-
-        // Check consistency of link address. Currently we expect
-        // only one "global" address is assigned per each IP type.
-        Collection<LinkAddress> oLinks = mLinkProperties.getLinkAddresses();
-        Collection<LinkAddress> nLinks = newLp.getLinkAddresses();
-        for (LinkAddress oldLink : oLinks) {
-            for (LinkAddress newLink : nLinks) {
-                if ((NetworkUtils.addressTypeMatches(oldLink.getAddress(),
-                                        newLink.getAddress())) &&
-                    (oldLink.equals(newLink) == false)) {
-                    return DataConnectionAc.LinkPropertyChangeAction.RESET;
-                }
-            }
+        if (DBG && (! result.oldLp.equals(result.newLp))) {
+            if (DBG) log("updateLinkProperty old != new");
+            if (VDBG) log("updateLinkProperty old LP=" + result.oldLp);
+            if (VDBG) log("updateLinkProperty new LP=" + result.newLp);
         }
+        mLinkProperties = result.newLp;
 
-        if (mLinkProperties == null || !mLinkProperties.equals(newLp)) {
-            mLinkProperties = newLp;
-            changed = DataConnectionAc.LinkPropertyChangeAction.CHANGED;
-        }
-
-        return changed;
+        return result;
     }
 
     /**
@@ -643,14 +630,15 @@
                 }
                 case DataConnectionAc.REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE: {
                     DataCallState newState = (DataCallState) msg.obj;
-                    DataConnectionAc.LinkPropertyChangeAction action = updateLinkProperty(newState);
+                    UpdateLinkPropertyResult result =
+                                             updateLinkProperty(newState);
                     if (VDBG) {
-                        log("REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE action="
-                            + action + " newState=" + newState);
+                        log("REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE result="
+                            + result + " newState=" + newState);
                     }
                     mAc.replyToMessage(msg,
                                    DataConnectionAc.RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE,
-                                   action.ordinal());
+                                   result);
                     break;
                 }
                 case DataConnectionAc.REQ_GET_LINK_CAPABILITIES: {
@@ -688,7 +676,7 @@
                 case DataConnectionAc.REQ_GET_APNCONTEXT_LIST: {
                     if (VDBG) log("REQ_GET_APNCONTEXT_LIST num in list=" + mApnList.size());
                     mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_APNCONTEXT_LIST,
-                                       new ArrayList(mApnList));
+                                       new ArrayList<ApnContext>(mApnList));
                     break;
                 }
                 case DataConnectionAc.REQ_SET_RECONNECT_INTENT: {
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionAc.java b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
index 309dbed..9e185e5 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionAc.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
@@ -16,12 +16,14 @@
 
 package com.android.internal.telephony;
 
+import com.android.internal.telephony.DataConnection.UpdateLinkPropertyResult;
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 
 import android.app.PendingIntent;
 import android.net.LinkCapabilities;
 import android.net.LinkProperties;
+import android.net.LinkProperties.CompareAddressesResult;
 import android.net.ProxyProperties;
 import android.os.Message;
 
@@ -310,18 +312,18 @@
         if (DBG) log("reqUpdateLinkPropertiesDataCallState");
     }
 
-    public LinkPropertyChangeAction rspUpdateLinkPropertiesDataCallState(Message response) {
-        LinkPropertyChangeAction retVal = LinkPropertyChangeAction.fromInt(response.arg1);
-        if (DBG) log("rspUpdateLinkPropertiesState=" + retVal);
+    public UpdateLinkPropertyResult rspUpdateLinkPropertiesDataCallState(Message response) {
+        UpdateLinkPropertyResult retVal = (UpdateLinkPropertyResult)response.obj;
+        if (DBG) log("rspUpdateLinkPropertiesState: retVal=" + retVal);
         return retVal;
     }
 
     /**
      * Update link properties in the data connection
      *
-     * @return true if link property has been updated. false otherwise.
+     * @return the removed and added addresses.
      */
-    public LinkPropertyChangeAction updateLinkPropertiesDataCallStateSync(DataCallState newState) {
+    public UpdateLinkPropertyResult updateLinkPropertiesDataCallStateSync(DataCallState newState) {
         Message response =
             sendMessageSynchronously(REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE, newState);
         if ((response != null) &&
@@ -329,7 +331,7 @@
             return rspUpdateLinkPropertiesDataCallState(response);
         } else {
             log("getLinkProperties error response=" + response);
-            return LinkPropertyChangeAction.NONE;
+            return new UpdateLinkPropertyResult(new LinkProperties());
         }
     }
 
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 48c5318..4b02e8e 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -1430,6 +1430,11 @@
     String getMeid();
 
     /**
+     * Retrieves IMEI for phones. Returns null if IMEI is not set.
+     */
+    String getImei();
+
+    /**
      * Retrieves the PhoneSubInfo of the Phone
      */
     public PhoneSubInfo getPhoneSubInfo();
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index c2212db..b5bfc76f 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -685,6 +685,10 @@
         return mActivePhone.getMeid();
     }
 
+    public String getImei() {
+        return mActivePhone.getImei();
+    }
+
     public PhoneSubInfo getPhoneSubInfo(){
         return mActivePhone.getPhoneSubInfo();
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
index a31b704..0d9d27d 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
@@ -136,6 +136,11 @@
     }
 
     @Override
+    public String getImei() {
+        return mImei;
+    }
+
+    @Override
     protected void log(String s) {
         if (DBG)
             Log.d(LOG_TAG, "[CDMALTEPhone] " + s);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 8a60b5a..286515e 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -122,6 +122,8 @@
     //keep track of if phone is in emergency callback mode
     private boolean mIsPhoneInEcmState;
     private Registrant mEcmExitRespRegistrant;
+    protected String mImei;
+    protected String mImeiSv;
     private String mEsn;
     private String mMeid;
     // string to define how the carrier specifies its own ota sp number
@@ -489,6 +491,11 @@
         return mSST.getImsi();
     }
 
+    public String getImei() {
+        Log.e(LOG_TAG, "IMEI is not available in CDMA");
+        return null;
+    }
+
     public boolean canConference() {
         Log.e(LOG_TAG, "canConference: not possible in CDMA");
         return false;
@@ -987,6 +994,8 @@
                     break;
                 }
                 String[] respId = (String[])ar.result;
+                mImei = respId[0];
+                mImeiSv = respId[1];
                 mEsn  =  respId[2];
                 mMeid =  respId[3];
             }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index d357eac..1db9860 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -855,6 +855,10 @@
         return mImeiSv;
     }
 
+    public String getImei() {
+        return mImei;
+    }
+
     public String getEsn() {
         Log.e(LOG_TAG, "[GSMPhone] getEsn() is a CDMA method");
         return "0";
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index df5898b..bf964b7 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -26,6 +26,9 @@
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.net.ConnectivityManager;
+import android.net.LinkAddress;
+import android.net.LinkProperties.CompareAddressesResult;
+import android.net.NetworkUtils;
 import android.net.ProxyProperties;
 import android.net.TrafficStats;
 import android.net.Uri;
@@ -53,6 +56,7 @@
 import com.android.internal.telephony.ApnSetting;
 import com.android.internal.telephony.DataCallState;
 import com.android.internal.telephony.DataConnection;
+import com.android.internal.telephony.DataConnection.UpdateLinkPropertyResult;
 import com.android.internal.telephony.DataConnectionAc;
 import com.android.internal.telephony.DataConnectionTracker;
 import com.android.internal.telephony.Phone;
@@ -1037,7 +1041,7 @@
 
     /**
      * @param dcacs Collection of DataConnectionAc reported from RIL.
-     * @return List of ApnContext whihc is connected, but does not present in
+     * @return List of ApnContext which is connected, but is not present in
      *         data connection list reported from RIL.
      */
     private List<ApnContext> findApnContextToClean(Collection<DataConnectionAc> dcacs) {
@@ -1091,32 +1095,30 @@
         if (DBG) log("onDataStateChanged(ar): DataCallState size=" + dataCallStates.size());
 
         // Create a hash map to store the dataCallState of each DataConnectionAc
-        // TODO: Depends on how frequent the DATA_CALL_LIST got updated,
-        //       may cache response to reduce comparison.
-        HashMap<DataCallState, DataConnectionAc> response;
-        response = new HashMap<DataCallState, DataConnectionAc>();
+        HashMap<DataCallState, DataConnectionAc> dataCallStateToDcac;
+        dataCallStateToDcac = new HashMap<DataCallState, DataConnectionAc>();
         for (DataCallState dataCallState : dataCallStates) {
             DataConnectionAc dcac = findDataConnectionAcByCid(dataCallState.cid);
 
-            if (dcac != null) response.put(dataCallState, dcac);
+            if (dcac != null) dataCallStateToDcac.put(dataCallState, dcac);
         }
 
-        // step1: Find a list of "connected" APN which does not have reference to
-        //        calls listed in the Data Call List.
-        List<ApnContext> apnsToClear = findApnContextToClean(response.values());
+        // A list of apns to cleanup, those that aren't in the list we know we have to cleanup
+        List<ApnContext> apnsToCleanup = findApnContextToClean(dataCallStateToDcac.values());
 
-        // step2: Check status of each calls in Data Call List.
-        //        Collect list of ApnContext associated with the data call if the link
-        //        has to be cleared.
+        // Find which connections have changed state and send a notification or cleanup
         for (DataCallState newState : dataCallStates) {
-            DataConnectionAc dcac = response.get(newState);
+            DataConnectionAc dcac = dataCallStateToDcac.get(newState);
 
-            // no associated DataConnection found. Ignore.
-            if (dcac == null) continue;
+            if (dcac == null) {
+                loge("onDataStateChanged(ar): No associated DataConnection ignore");
+                continue;
+            }
 
+            // The list of apn's associated with this DataConnection
             Collection<ApnContext> apns = dcac.getApnListSync();
 
-            // filter out ApnContext with "Connected/Connecting" state.
+            // Find which ApnContexts of this DC are in the "Connected/Connecting" state.
             ArrayList<ApnContext> connectedApns = new ArrayList<ApnContext>();
             for (ApnContext apnContext : apns) {
                 if (apnContext.getState() == State.CONNECTED ||
@@ -1125,67 +1127,86 @@
                     connectedApns.add(apnContext);
                 }
             }
-
-            // No "Connected" ApnContext associated with this CID. Ignore.
-            if (connectedApns.isEmpty()) {
-                continue;
-            }
-
-            if (DBG) log("onDataStateChanged(ar): Found ConnId=" + newState.cid
-                            + " newState=" + newState.toString());
-            if (newState.active != 0) {
-                boolean resetConnection;
-                switch (dcac.updateLinkPropertiesDataCallStateSync(newState)) {
-                case NONE:
-                    if (DBG) log("onDataStateChanged(ar): Found but no change, skip");
-                    resetConnection = false;
-                    break;
-                case CHANGED:
-                    for (ApnContext apnContext : connectedApns) {
-                        if (DBG) log("onDataStateChanged(ar): Found and changed, notify (" +
-                                     apnContext.toString() + ")");
-                        mPhone.notifyDataConnection(Phone.REASON_LINK_PROPERTIES_CHANGED,
-                                                    apnContext.getApnType());
+            if (connectedApns.size() == 0) {
+                if (DBG) log("onDataStateChanged(ar): no connected apns");
+            } else {
+                // Determine if the connection/apnContext should be cleaned up
+                // or just a notification should be sent out.
+                if (DBG) log("onDataStateChanged(ar): Found ConnId=" + newState.cid
+                        + " newState=" + newState.toString());
+                if (newState.active == 0) {
+                    if (DBG) {
+                        log("onDataStateChanged(ar): inactive, cleanup apns=" + connectedApns);
                     }
-                    // Temporary hack, at this time a transition from CDMA -> Global
-                    // fails so we'll hope for the best and not reset the connection.
-                    // @see bug/4455071
-                    if (SystemProperties.getBoolean("telephony.ignore-state-changes",
-                                                    true)) {
-                        log("onDataStateChanged(ar): STOPSHIP don't reset, continue");
-                        resetConnection = false;
+                    apnsToCleanup.addAll(connectedApns);
+                } else {
+                    // Its active so update the DataConnections link properties
+                    UpdateLinkPropertyResult result =
+                        dcac.updateLinkPropertiesDataCallStateSync(newState);
+                    if (result.oldLp.equals(result.newLp)) {
+                        if (DBG) log("onDataStateChanged(ar): no change");
                     } else {
-                        // Things changed so reset connection, when hack is removed
-                        // this is the normal path.
-                        log("onDataStateChanged(ar): changed so resetting connection");
-                        resetConnection = true;
+                        if (result.oldLp.isIdenticalInterfaceName(result.newLp)) {
+                            if (! result.oldLp.isIdenticalDnses(result.newLp) ||
+                                    ! result.oldLp.isIdenticalRoutes(result.newLp) ||
+                                    ! result.oldLp.isIdenticalHttpProxy(result.newLp) ||
+                                    ! result.oldLp.isIdenticalAddresses(result.newLp)) {
+                                // If the same address type was removed and added we need to cleanup
+                                CompareAddressesResult car =
+                                    result.oldLp.compareAddresses(result.newLp);
+                                boolean needToClean = false;
+                                for (LinkAddress added : car.added) {
+                                    for (LinkAddress removed : car.removed) {
+                                        if (NetworkUtils.addressTypeMatches(removed.getAddress(),
+                                                added.getAddress())) {
+                                            needToClean = true;
+                                            break;
+                                        }
+                                    }
+                                }
+                                if (needToClean) {
+                                    if (DBG) {
+                                        log("onDataStateChanged(ar): addr change, cleanup apns=" +
+                                                connectedApns);
+                                    }
+                                    apnsToCleanup.addAll(connectedApns);
+                                } else {
+                                    if (DBG) log("onDataStateChanged(ar): simple change");
+                                    for (ApnContext apnContext : connectedApns) {
+                                         mPhone.notifyDataConnection(
+                                                 Phone.REASON_LINK_PROPERTIES_CHANGED,
+                                                 apnContext.getApnType());
+                                    }
+                                }
+                            } else {
+                                if (DBG) {
+                                    log("onDataStateChanged(ar): no changes");
+                                }
+                            }
+                        } else {
+                            if (DBG) {
+                                log("onDataStateChanged(ar): interface change, cleanup apns="
+                                        + connectedApns);
+                            }
+                            apnsToCleanup.addAll(connectedApns);
+                        }
                     }
-                    break;
-                case RESET:
-                default:
-                    if (DBG) log("onDataStateChanged(ar): an error, reset connection");
-                    resetConnection = true;
-                    break;
                 }
-                if (resetConnection == false) continue;
             }
-
-            if (DBG) log("onDataStateChanged(ar): reset connection.");
-
-            apnsToClear.addAll(connectedApns);
         }
 
-        // step3: Clear apn connection if applicable.
-        if (!apnsToClear.isEmpty()) {
+        if (apnsToCleanup.size() != 0) {
             // Add an event log when the network drops PDP
             int cid = getCellLocationId();
             EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid,
                                 TelephonyManager.getDefault().getNetworkType());
         }
 
-        for (ApnContext apnContext : apnsToClear) {
+        // Cleanup those dropped connections
+        for (ApnContext apnContext : apnsToCleanup) {
             cleanUpConnection(true, apnContext);
         }
+
         if (DBG) log("onDataStateChanged(ar): X");
     }
 
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
index 9dfc015..5c4b446 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
@@ -264,6 +264,10 @@
         return null;
     }
 
+    public String getImei() {
+        return null;
+    }
+
     public String getEsn() {
         Log.e(LOG_TAG, "[SipPhone] getEsn() is a CDMA method");
         return "0";
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
index b9bf526..af5006f 100644
--- a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
+++ b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
@@ -38,20 +38,20 @@
         vg.setUseDefaultMargins(true);
         vg.setAlignmentMode(ALIGN_BOUNDS);
 
-        Group row1 = new Group(1, CENTER);
-        Group row2 = new Group(2, CENTER);
-        Group row3 = new Group(3, BASELINE);
-        Group row4 = new Group(4, BASELINE);
-        Group row5 = new Group(5, FILL);
-        Group row6 = new Group(6, CENTER);
-        Group row7 = new Group(7, CENTER);
+        Spec row1 = spec(0, CENTER);
+        Spec row2 = spec(1, CENTER);
+        Spec row3 = spec(2, BASELINE);
+        Spec row4 = spec(3, BASELINE);
+        Spec row5 = spec(4, FILL, CAN_STRETCH);
+        Spec row6 = spec(5, CENTER);
+        Spec row7 = spec(6, CENTER);
 
-        Group col1a = new Group(1, 4, CENTER);
-        Group col1b = new Group(1, 4, LEFT);
-        Group col1c = new Group(1, RIGHT);
-        Group col2 = new Group(2, LEFT);
-        Group col3 = new Group(3, FILL);
-        Group col4 = new Group(4, FILL);
+        Spec col1a = spec(0, 4, CENTER);
+        Spec col1b = spec(0, 4, LEFT);
+        Spec col1c = spec(0, RIGHT);
+        Spec col2 = spec(1, LEFT);
+        Spec col3 = spec(2, FILL, CAN_STRETCH);
+        Spec col4 = spec(3, FILL);
 
         {
             TextView v = new TextView(context);
@@ -96,10 +96,7 @@
         {
             Space v = new Space(context);
             {
-                LayoutParams lp = new LayoutParams(row5, col3);
-                lp.columnGroup.flexibility = CAN_STRETCH;
-                lp.rowGroup.flexibility = CAN_STRETCH;
-                vg.addView(v, lp);
+                vg.addView(v, new LayoutParams(row5, col3));
             }
         }
         {
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java b/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java
index 505c83d..b1c4486 100755
--- a/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java
+++ b/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java
@@ -21,7 +21,6 @@
 import android.os.Bundle;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewParent;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.GridLayout;
@@ -84,9 +83,7 @@
             Alignment va = VERTICAL_ALIGNMENTS[i];
             for (int j = 0; j < HORIZONTAL_ALIGNMENTS.length; j++) {
                 Alignment ha = HORIZONTAL_ALIGNMENTS[j];
-                Group rowGroup = new Group(i, va);
-                Group colGroup = new Group(j, ha);
-                LayoutParams layoutParams = new LayoutParams(rowGroup, colGroup);
+                LayoutParams layoutParams = new LayoutParams(spec(i, va), spec(j, ha));
                 String name = VERTICAL_NAMES[i] + "-" + HORIZONTAL_NAMES[j];
                 ViewFactory factory = FACTORIES[(i + j) % FACTORIES.length];
                 container.addView(factory.create(name, 20), layoutParams);
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java b/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java
index c5681e2..4ce449a 100644
--- a/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java
+++ b/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java
@@ -33,9 +33,9 @@
             int va = VERTICAL_ALIGNMENTS[i];
             for (int j = 0; j < HORIZONTAL_ALIGNMENTS.length; j++) {
                 int ha = HORIZONTAL_ALIGNMENTS[j];
-                GridLayout.Group rowGroup = new GridLayout.Group(UNDEFINED, null);
-                GridLayout.Group colGroup = new GridLayout.Group(UNDEFINED, null);
-                GridLayout.LayoutParams lp = new GridLayout.LayoutParams(rowGroup, colGroup);
+                Spec rowSpec = spec(UNDEFINED, null);
+                Spec colSpec = spec(UNDEFINED, null);
+                GridLayout.LayoutParams lp = new GridLayout.LayoutParams(rowSpec, colSpec);
                 //GridLayout.LayoutParams lp = new GridLayout.LayoutParams();
                 lp.setGravity(va | ha);
                 View v = create(context, VERTICAL_NAMES[i] + "-" + HORIZONTAL_NAMES[j], 20);