Merge "Camera2: framework updates for HAL3.3 keys"
diff --git a/Android.mk b/Android.mk
index 2d0d1f7..a20798d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -202,6 +202,7 @@
 	core/java/android/os/INetworkActivityListener.aidl \
 	core/java/android/os/INetworkManagementService.aidl \
 	core/java/android/os/IPermissionController.aidl \
+	core/java/android/os/IProcessInfoService.aidl \
 	core/java/android/os/IPowerManager.aidl \
 	core/java/android/os/IRemoteCallback.aidl \
 	core/java/android/os/ISchedulingPolicyService.aidl \
diff --git a/api/current.txt b/api/current.txt
index ce01a66..123d8cc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -529,6 +529,7 @@
     field public static final int ellipsize = 16842923; // 0x10100ab
     field public static final int ems = 16843096; // 0x1010158
     field public static final int enabled = 16842766; // 0x101000e
+    field public static final int end = 16843997; // 0x10104dd
     field public static final int endColor = 16843166; // 0x101019e
     field public static final deprecated int endYear = 16843133; // 0x101017d
     field public static final int enterFadeDuration = 16843532; // 0x101030c
@@ -1128,6 +1129,7 @@
     field public static final int stackFromBottom = 16843005; // 0x10100fd
     field public static final int stackViewStyle = 16843838; // 0x101043e
     field public static final int starStyle = 16842882; // 0x1010082
+    field public static final int start = 16843996; // 0x10104dc
     field public static final int startColor = 16843165; // 0x101019d
     field public static final int startDelay = 16843746; // 0x10103e2
     field public static final int startOffset = 16843198; // 0x10101be
@@ -8432,7 +8434,6 @@
     field public java.lang.String parentActivityName;
     field public java.lang.String permission;
     field public int persistableMode;
-    field public boolean resizeable;
     field public int screenOrientation;
     field public int softInputMode;
     field public java.lang.String targetActivity;
@@ -11947,6 +11948,9 @@
     method public android.graphics.drawable.Drawable findDrawableByLayerId(int);
     method public android.graphics.drawable.Drawable getDrawable(int);
     method public int getId(int);
+    method public int getLayerGravity(int);
+    method public int getLayerHeight(int);
+    method public int getLayerWidth(int);
     method public int getNumberOfLayers();
     method public int getOpacity();
     method public int getPaddingMode();
@@ -11956,7 +11960,10 @@
     method public void setColorFilter(android.graphics.ColorFilter);
     method public boolean setDrawableByLayerId(int, android.graphics.drawable.Drawable);
     method public void setId(int, int);
+    method public void setLayerGravity(int, int);
     method public void setLayerInset(int, int, int, int, int);
+    method public void setLayerInsetRelative(int, int, int, int, int);
+    method public void setLayerSize(int, int, int);
     method public void setOpacity(int);
     method public void setPaddingMode(int);
     method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
diff --git a/api/system-current.txt b/api/system-current.txt
index dfe4298..6224dfb 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -601,6 +601,7 @@
     field public static final int ellipsize = 16842923; // 0x10100ab
     field public static final int ems = 16843096; // 0x1010158
     field public static final int enabled = 16842766; // 0x101000e
+    field public static final int end = 16843997; // 0x10104dd
     field public static final int endColor = 16843166; // 0x101019e
     field public static final deprecated int endYear = 16843133; // 0x101017d
     field public static final int enterFadeDuration = 16843532; // 0x101030c
@@ -1204,6 +1205,7 @@
     field public static final int stackFromBottom = 16843005; // 0x10100fd
     field public static final int stackViewStyle = 16843838; // 0x101043e
     field public static final int starStyle = 16842882; // 0x1010082
+    field public static final int start = 16843996; // 0x10104dc
     field public static final int startColor = 16843165; // 0x101019d
     field public static final int startDelay = 16843746; // 0x10103e2
     field public static final int startOffset = 16843198; // 0x10101be
@@ -8640,7 +8642,6 @@
     field public java.lang.String parentActivityName;
     field public java.lang.String permission;
     field public int persistableMode;
-    field public boolean resizeable;
     field public int screenOrientation;
     field public int softInputMode;
     field public java.lang.String targetActivity;
@@ -12215,6 +12216,9 @@
     method public android.graphics.drawable.Drawable findDrawableByLayerId(int);
     method public android.graphics.drawable.Drawable getDrawable(int);
     method public int getId(int);
+    method public int getLayerGravity(int);
+    method public int getLayerHeight(int);
+    method public int getLayerWidth(int);
     method public int getNumberOfLayers();
     method public int getOpacity();
     method public int getPaddingMode();
@@ -12224,7 +12228,10 @@
     method public void setColorFilter(android.graphics.ColorFilter);
     method public boolean setDrawableByLayerId(int, android.graphics.drawable.Drawable);
     method public void setId(int, int);
+    method public void setLayerGravity(int, int);
     method public void setLayerInset(int, int, int, int, int);
+    method public void setLayerInsetRelative(int, int, int, int, int);
+    method public void setLayerSize(int, int, int);
     method public void setOpacity(int);
     method public void setPaddingMode(int);
     method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 7a636db..c6ffef6 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -256,6 +256,9 @@
     /** @hide User operation call: given user id is the current user, can't be stopped. */
     public static final int USER_OP_IS_CURRENT = -2;
 
+    /** @hide Process does not exist. */
+    public static final int PROCESS_STATE_NONEXISTENT = -1;
+
     /** @hide Process is a persistent system process. */
     public static final int PROCESS_STATE_PERSISTENT = 0;
 
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 452603a..4723c0d 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -644,6 +644,7 @@
     /**
      * Value indicating if the activity is resizeable to any dimension.
      * See {@link android.R.attr#resizeableActivity}.
+     * @hide
      */
     public boolean resizeable;
 
diff --git a/core/java/android/hardware/camera2/DngCreator.java b/core/java/android/hardware/camera2/DngCreator.java
index 6fc99ac..33d539c2 100644
--- a/core/java/android/hardware/camera2/DngCreator.java
+++ b/core/java/android/hardware/camera2/DngCreator.java
@@ -530,9 +530,9 @@
         int uPixStride = uPlane.getPixelStride();
 
         byte[] yuvPixel = { 0, 0, 0 };
-        byte[] yFullRow = new byte[yPixStride * width];
-        byte[] uFullRow = new byte[uPixStride * width / 2];
-        byte[] vFullRow = new byte[vPixStride * width / 2];
+        byte[] yFullRow = new byte[yPixStride * (width - 1) + 1];
+        byte[] uFullRow = new byte[uPixStride * (width / 2 - 1) + 1];
+        byte[] vFullRow = new byte[vPixStride * (width / 2 - 1) + 1];
         byte[] finalRow = new byte[BYTES_PER_RGB_PIX * width];
         for (int i = 0; i < height; i++) {
             int halfH = i / 2;
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 2099c3f..bf3d9aa 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -366,6 +366,7 @@
     public String toSafeString() {
         String scheme = getScheme();
         String ssp = getSchemeSpecificPart();
+        String authority = null;
         if (scheme != null) {
             if (scheme.equalsIgnoreCase("tel") || scheme.equalsIgnoreCase("sip")
                     || scheme.equalsIgnoreCase("sms") || scheme.equalsIgnoreCase("smsto")
@@ -384,6 +385,9 @@
                     }
                 }
                 return builder.toString();
+            } else if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")) {
+                ssp = null;
+                authority = "//" + getAuthority() + "/...";
             }
         }
         // Not a sensitive scheme, but let's still be conservative about
@@ -397,6 +401,9 @@
         if (ssp != null) {
             builder.append(ssp);
         }
+        if (authority != null) {
+            builder.append(authority);
+        }
         return builder.toString();
     }
 
@@ -1742,7 +1749,7 @@
      *
      * @return normalized Uri (never null)
      * @see {@link android.content.Intent#setData}
-     * @see {@link #setNormalizedData}
+     * @see {@link android.content.Intent#setDataAndNormalize}
      */
     public Uri normalizeScheme() {
         String scheme = getScheme();
diff --git a/core/java/android/os/IProcessInfoService.aidl b/core/java/android/os/IProcessInfoService.aidl
new file mode 100644
index 0000000..c98daa2
--- /dev/null
+++ b/core/java/android/os/IProcessInfoService.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/** {@hide} */
+interface IProcessInfoService
+{
+    /**
+     * For each PID in the given input array, write the current process state
+     * for that process into the output array, or ActivityManager.PROCESS_STATE_NONEXISTENT
+     * to indicate that no process with the given PID exists.
+     */
+    void getProcessStatesFromPids(in int[] pids, out int[] states);
+}
+
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 559d750..d157cdc 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5078,14 +5078,31 @@
 
     <!-- Describes an item (or child) of a LayerDrawable. -->
     <declare-styleable name="LayerDrawableItem">
-        <!-- Left coordinate of the layer. -->
+        <!-- Left inset to apply to the layer. -->
         <attr name="left" />
-        <!-- Top coordinate of the layer. -->
+        <!-- Top inset to apply to the layer. -->
         <attr name="top" />
-        <!-- Right coordinate of the layer. -->
+        <!-- Right inset to apply to the layer. -->
         <attr name="right" />
-        <!-- Bottom coordinate of the layer. -->
+        <!-- Bottom inset to apply to the layer. -->
         <attr name="bottom" />
+        <!-- Start inset to apply to the layer. Overrides {@code left} or
+             {@code right} depending on layout direction. -->
+        <attr name="start" format="dimension" />
+        <!-- End inset to apply to the layer. Overrides {@code left} or
+             {@code right} depending on layout direction. -->
+        <attr name="end" format="dimension" />
+        <!-- Width of the layer. Defaults to the layer's intrinsic width. -->
+        <attr name="width" />
+        <!-- Height of the layer. Defaults to the layer's intrinsic height -->
+        <attr name="height" />
+        <!-- Gravity used to align the layer within its container. If no value
+             is specified, the default behavior depends on whether an explicit
+             width or height has been set, If no dimension is set, gravity in
+             that direction defaults to {@code fill_horizontal} or
+             {@code fill_vertical}; otherwise, it defaults to {@code left} or
+             {@code top}. -->
+        <attr name="gravity" />
         <!-- Drawable used to render the layer. -->
         <attr name="drawable" />
         <!-- Identifier of the layer. This can be used to retrieve the layer
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index b9ed78a..84609ca 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1017,7 +1017,7 @@
          at the same time.
 
          <p>The default value is <code>false</code> for applications with
-         <code>targetSdkVersion</code> lesser than {@link android.os.Build.VERSION_CODE#MNC} and
+         <code>targetSdkVersion</code> lesser than {@link android.os.Build.VERSION_CODES#MNC} and
          <code>true</code> otherwise.
 
          <p>NOTE: A task's root activity value is applied to all additional activities launched in
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 11cc181..3bf9631 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2611,6 +2611,8 @@
   <public type="attr" name="trackTint" />
   <public type="attr" name="trackTintMode" />
   <public type="attr" name="resizeableActivity" />
+  <public type="attr" name="start" />
+  <public type="attr" name="end" />
 
   <public type="style" name="Widget.Material.Button.Colored" />
 
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index daf4427..505bd1d 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -29,6 +29,8 @@
 import android.graphics.PorterDuff.Mode;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.LayoutDirection;
+import android.view.Gravity;
 import android.view.View;
 
 import com.android.internal.R;
@@ -54,6 +56,11 @@
  * @attr ref android.R.styleable#LayerDrawableItem_top
  * @attr ref android.R.styleable#LayerDrawableItem_right
  * @attr ref android.R.styleable#LayerDrawableItem_bottom
+ * @attr ref android.R.styleable#LayerDrawableItem_start
+ * @attr ref android.R.styleable#LayerDrawableItem_end
+ * @attr ref android.R.styleable#LayerDrawableItem_width
+ * @attr ref android.R.styleable#LayerDrawableItem_height
+ * @attr ref android.R.styleable#LayerDrawableItem_gravity
  * @attr ref android.R.styleable#LayerDrawableItem_drawable
  * @attr ref android.R.styleable#LayerDrawableItem_id
 */
@@ -73,6 +80,9 @@
      */
     public static final int PADDING_MODE_STACK = 1;
 
+    /** Value used for undefined start and end insets. */
+    private static final int UNDEFINED_INSET = Integer.MIN_VALUE;
+
     LayerState mLayerState;
 
     private int mOpacityOverride = PixelFormat.UNKNOWN;
@@ -231,6 +241,16 @@
                 R.styleable.LayerDrawableItem_right, layer.mInsetR);
         layer.mInsetB = a.getDimensionPixelOffset(
                 R.styleable.LayerDrawableItem_bottom, layer.mInsetB);
+        layer.mInsetS = a.getDimensionPixelOffset(
+                R.styleable.LayerDrawableItem_start, layer.mInsetS);
+        layer.mInsetE = a.getDimensionPixelOffset(
+                R.styleable.LayerDrawableItem_end, layer.mInsetE);
+        layer.mWidth = a.getDimensionPixelSize(
+                R.styleable.LayerDrawableItem_width, layer.mWidth);
+        layer.mHeight = a.getDimensionPixelSize(
+                R.styleable.LayerDrawableItem_height, layer.mHeight);
+        layer.mGravity = a.getInteger(
+                R.styleable.LayerDrawableItem_gravity, layer.mGravity);
         layer.mId = a.getResourceId(R.styleable.LayerDrawableItem_id, layer.mId);
 
         final Drawable dr = a.getDrawable(R.styleable.LayerDrawableItem_drawable);
@@ -447,6 +467,89 @@
     }
 
     /**
+     * Sets an explicit size for the specified layer.
+     * <p>
+     * <strong>Note:</strong> Setting an explicit layer size changes the
+     * default layer gravity behavior. See {@link #setLayerGravity(int, int)}
+     * for more information.
+     *
+     * @param index the index of the drawable to adjust
+     * @param w width in pixels, or -1 to use the intrinsic width
+     * @param h height in pixels, or -1 to use the intrinsic height
+     *
+     * @see #getLayerWidth(int)
+     * @see #getLayerHeight(int)
+     * @attr ref android.R.styleable#LayerDrawableItem_width
+     * @attr ref android.R.styleable#LayerDrawableItem_height
+     */
+    public void setLayerSize(int index, int w, int h) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mWidth = w;
+        childDrawable.mHeight = h;
+    }
+
+    /**
+     * @param index the index of the drawable to adjust
+     * @return the explicit width of the layer, or -1 if not specified
+     *
+     * @see #setLayerSize(int, int, int)
+     * @attr ref android.R.styleable#LayerDrawableItem_width
+     */
+    public int getLayerWidth(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mWidth;
+    }
+
+    /**
+     * @param index the index of the drawable to adjust
+     * @return the explicit height of the layer, or -1 if not specified
+     *
+     * @see #setLayerSize(int, int, int)
+     * @attr ref android.R.styleable#LayerDrawableItem_height
+     */
+    public int getLayerHeight(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mHeight;
+    }
+
+    /**
+     * Sets the gravity used to position or stretch the specified layer within
+     * its container. Gravity is applied after any layer insets (see
+     * {@link #setLayerInset(int, int, int, int, int)}) or padding (see
+     * {@link #setPaddingMode(int)}).
+     * <p>
+     * If gravity is specified as {@link Gravity#NO_GRAVITY}, the default
+     * behavior depends on whether an explicit width or height has been set
+     * (see {@link #setLayerSize(int, int, int)}), If a dimension is not set,
+     * gravity in that direction defaults to {@link Gravity#FILL_HORIZONTAL} or
+     * {@link Gravity#FILL_VERTICAL}; otherwise, gravity in that direction
+     * defaults to {@link Gravity#LEFT} or {@link Gravity#TOP}.
+     *
+     * @param index the index of the drawable to adjust
+     * @param gravity the gravity to set for the layer
+     *
+     * @see #getLayerGravity(int)
+     * @attr ref android.R.styleable#LayerDrawableItem_gravity
+     */
+    public void setLayerGravity(int index, int gravity) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mGravity = gravity;
+    }
+
+    /**
+     * @param index the index of the layer
+     * @return the gravity used to position or stretch the specified layer
+     *         within its container
+     *
+     * @see #setLayerGravity(int, int)
+     * @attr ref android.R.styleable#LayerDrawableItem_gravity
+     */
+    public int getLayerGravity(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mGravity;
+    }
+
+    /**
      * Specifies the insets in pixels for the drawable at the specified index.
      *
      * @param index the index of the drawable to adjust
@@ -454,13 +557,43 @@
      * @param t number of pixels to add to the top bound
      * @param r number of pixels to subtract from the right bound
      * @param b number of pixels to subtract from the bottom bound
+     *
+     * @attr ref android.R.styleable#LayerDrawableItem_left
+     * @attr ref android.R.styleable#LayerDrawableItem_top
+     * @attr ref android.R.styleable#LayerDrawableItem_right
+     * @attr ref android.R.styleable#LayerDrawableItem_bottom
      */
     public void setLayerInset(int index, int l, int t, int r, int b) {
+        setLayerInsetInternal(index, l, t, r, b, UNDEFINED_INSET, UNDEFINED_INSET);
+    }
+
+    /**
+     * Specifies the relative insets in pixels for the drawable at the
+     * specified index.
+     *
+     * @param index the index of the drawable to adjust
+     * @param s number of pixels to inset from the start bound
+     * @param t number of pixels to inset from the top bound
+     * @param e number of pixels to inset from the end bound
+     * @param b number of pixels to inset from the bottom bound
+     *
+     * @attr ref android.R.styleable#LayerDrawableItem_start
+     * @attr ref android.R.styleable#LayerDrawableItem_top
+     * @attr ref android.R.styleable#LayerDrawableItem_end
+     * @attr ref android.R.styleable#LayerDrawableItem_bottom
+     */
+    public void setLayerInsetRelative(int index, int s, int t, int e, int b) {
+        setLayerInsetInternal(index, 0, t, 0, b, s, e);
+    }
+
+    private void setLayerInsetInternal(int index, int l, int t, int r, int b, int s, int e) {
         final ChildDrawable childDrawable = mLayerState.mChildren[index];
         childDrawable.mInsetL = l;
         childDrawable.mInsetT = t;
         childDrawable.mInsetR = r;
         childDrawable.mInsetB = b;
+        childDrawable.mInsetS = s;
+        childDrawable.mInsetE = e;
     }
 
     /**
@@ -770,7 +903,7 @@
         }
 
         if (paddingChanged) {
-            onBoundsChange(getBounds());
+            updateLayerBounds(getBounds());
         }
 
         return changed;
@@ -795,7 +928,7 @@
         }
 
         if (paddingChanged) {
-            onBoundsChange(getBounds());
+            updateLayerBounds(getBounds());
         }
 
         return changed;
@@ -803,18 +936,50 @@
 
     @Override
     protected void onBoundsChange(Rect bounds) {
+        updateLayerBounds(bounds);
+    }
+
+    private void updateLayerBounds(Rect bounds) {
         int padL = 0;
         int padT = 0;
         int padR = 0;
         int padB = 0;
 
+        final Rect outRect = mTmpRect;
+        final int layoutDirection = getLayoutDirection();
         final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST;
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
             final ChildDrawable r = array[i];
-            r.mDrawable.setBounds(bounds.left + r.mInsetL + padL, bounds.top + r.mInsetT + padT,
-                    bounds.right - r.mInsetR - padR, bounds.bottom - r.mInsetB - padB);
+            final Drawable d = r.mDrawable;
+            final Rect container = d.getBounds();
+
+            // Take the resolved layout direction into account. If start / end
+            // padding are defined, they will be resolved (hence overriding) to
+            // left / right or right / left depending on the resolved layout
+            // direction. If start / end padding are not defined, use the
+            // left / right ones.
+            final int insetL, insetR;
+            if (layoutDirection == LayoutDirection.RTL) {
+                insetL = r.mInsetE == UNDEFINED_INSET ? r.mInsetL : r.mInsetE;
+                insetR = r.mInsetS == UNDEFINED_INSET ? r.mInsetR : r.mInsetS;
+            } else {
+                insetL = r.mInsetS == UNDEFINED_INSET ? r.mInsetL : r.mInsetS;
+                insetR = r.mInsetE == UNDEFINED_INSET ? r.mInsetR : r.mInsetE;
+            }
+
+            // Establish containing region based on aggregate padding and
+            // requested insets for the current layer.
+            container.set(bounds.left + insetL + padL, bounds.top + r.mInsetT + padT,
+                    bounds.right - insetR - padR, bounds.bottom - r.mInsetB - padB);
+
+            // Apply resolved gravity to drawable based on resolved size.
+            final int gravity = resolveGravity(r.mGravity, r.mWidth, r.mHeight);
+            final int w = r.mWidth < 0 ? d.getIntrinsicWidth() : r.mWidth;
+            final int h = r.mHeight < 0 ? d.getIntrinsicHeight() : r.mHeight;
+            Gravity.apply(gravity, w, h, container, outRect, layoutDirection);
+            d.setBounds(outRect);
 
             if (nest) {
                 padL += mPaddingL[i];
@@ -825,6 +990,38 @@
         }
     }
 
+    /**
+     * Resolves layer gravity given explicit gravity and dimensions.
+     * <p>
+     * If the client hasn't specified a gravity but has specified an explicit
+     * dimension, defaults to START or TOP. Otherwise, defaults to FILL to
+     * preserve legacy behavior.
+     *
+     * @param gravity
+     * @param width
+     * @param height
+     * @return
+     */
+    private int resolveGravity(int gravity, int width, int height) {
+        if (!Gravity.isHorizontal(gravity)) {
+            if (width < 0) {
+                gravity |= Gravity.FILL_HORIZONTAL;
+            } else {
+                gravity |= Gravity.START;
+            }
+        }
+
+        if (!Gravity.isVertical(gravity)) {
+            if (height < 0) {
+                gravity |= Gravity.FILL_VERTICAL;
+            } else {
+                gravity |= Gravity.TOP;
+            }
+        }
+
+        return gravity;
+    }
+
     @Override
     public int getIntrinsicWidth() {
         int width = -1;
@@ -836,7 +1033,8 @@
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
             final ChildDrawable r = array[i];
-            final int w = r.mDrawable.getIntrinsicWidth() + r.mInsetL + r.mInsetR + padL + padR;
+            final int minWidth = r.mWidth < 0 ? r.mDrawable.getIntrinsicWidth() : r.mWidth;
+            final int w = minWidth + r.mInsetL + r.mInsetR + padL + padR;
             if (w > width) {
                 width = w;
             }
@@ -861,7 +1059,8 @@
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
             final ChildDrawable r = array[i];
-            int h = r.mDrawable.getIntrinsicHeight() + r.mInsetT + r.mInsetB + padT + padB;
+            final int minHeight = r.mHeight < 0 ? r.mDrawable.getIntrinsicHeight() : r.mHeight;
+            final int h = minHeight + r.mInsetT + r.mInsetB + padT + padB;
             if (h > height) {
                 height = h;
             }
@@ -948,18 +1147,24 @@
     /** @hide */
     @Override
     public void setLayoutDirection(int layoutDirection) {
+        super.setLayoutDirection(layoutDirection);
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
             array[i].mDrawable.setLayoutDirection(layoutDirection);
         }
-        super.setLayoutDirection(layoutDirection);
+        updateLayerBounds(getBounds());
     }
 
     static class ChildDrawable {
         public Drawable mDrawable;
         public int[] mThemeAttrs;
         public int mInsetL, mInsetT, mInsetR, mInsetB;
+        public int mInsetS = UNDEFINED_INSET;
+        public int mInsetE = UNDEFINED_INSET;
+        public int mWidth = -1;
+        public int mHeight = -1;
+        public int mGravity = Gravity.NO_GRAVITY;
         public int mId = View.NO_ID;
 
         ChildDrawable() {
@@ -981,6 +1186,11 @@
             mInsetT = orig.mInsetT;
             mInsetR = orig.mInsetR;
             mInsetB = orig.mInsetB;
+            mInsetS = orig.mInsetS;
+            mInsetE = orig.mInsetE;
+            mWidth = orig.mWidth;
+            mHeight = orig.mHeight;
+            mGravity = orig.mGravity;
             mId = orig.mId;
         }
     }
diff --git a/location/java/android/location/GpsSatellite.java b/location/java/android/location/GpsSatellite.java
index 17af4a6..820f5746 100644
--- a/location/java/android/location/GpsSatellite.java
+++ b/location/java/android/location/GpsSatellite.java
@@ -40,13 +40,17 @@
      * cached GpsStatus instance to the client's copy.
      */
     void setStatus(GpsSatellite satellite) {
-        mValid = satellite.mValid;
-        mHasEphemeris = satellite.mHasEphemeris;
-        mHasAlmanac = satellite.mHasAlmanac;
-        mUsedInFix = satellite.mUsedInFix;
-        mSnr = satellite.mSnr;
-        mElevation = satellite.mElevation;
-        mAzimuth = satellite.mAzimuth;
+        if (satellite == null) {
+            mValid = false;
+        } else {
+            mValid = satellite.mValid;
+            mHasEphemeris = satellite.mHasEphemeris;
+            mHasAlmanac = satellite.mHasAlmanac;
+            mUsedInFix = satellite.mUsedInFix;
+            mSnr = satellite.mSnr;
+            mElevation = satellite.mElevation;
+            mAzimuth = satellite.mAzimuth;
+        }
     }
 
     /**
diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index 4af55a6..323f326 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -16,6 +16,8 @@
 
 package android.location;
 
+import android.util.SparseArray;
+
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
@@ -29,20 +31,24 @@
 
     /* These package private values are modified by the LocationManager class */
     private int mTimeToFirstFix;
-    private GpsSatellite mSatellites[] = new GpsSatellite[NUM_SATELLITES];
+    private final SparseArray<GpsSatellite> mSatellites = new SparseArray<>();
 
     private final class SatelliteIterator implements Iterator<GpsSatellite> {
 
-        private GpsSatellite[] mSatellites;
-        int mIndex = 0;
+        private final SparseArray<GpsSatellite> mSatellites;
+        private final int mSatellitesCount;
 
-        SatelliteIterator(GpsSatellite[] satellites) {
+        private int mIndex = 0;
+
+        SatelliteIterator(SparseArray<GpsSatellite> satellites) {
             mSatellites = satellites;
+            mSatellitesCount = satellites.size();
         }
 
         public boolean hasNext() {
-            for (int i = mIndex; i < mSatellites.length; i++) {
-                if (mSatellites[i].mValid) {
+            for (; mIndex < mSatellitesCount; ++mIndex) {
+                GpsSatellite satellite = mSatellites.valueAt(mIndex);
+                if (satellite.mValid) {
                     return true;
                 }
             }
@@ -50,8 +56,9 @@
         }
 
         public GpsSatellite next() {
-            while (mIndex < mSatellites.length) {
-                GpsSatellite satellite = mSatellites[mIndex++];
+            while (mIndex < mSatellitesCount) {
+                GpsSatellite satellite = mSatellites.valueAt(mIndex);
+                ++mIndex;
                 if (satellite.mValid) {
                     return satellite;
                 }
@@ -106,7 +113,7 @@
          * <li> {@link GpsStatus#GPS_EVENT_SATELLITE_STATUS}
          * </ul>
          *
-         * When this method is called, the client should call 
+         * When this method is called, the client should call
          * {@link LocationManager#getGpsStatus} to get additional
          * status information.
          *
@@ -127,11 +134,8 @@
         void onNmeaReceived(long timestamp, String nmea);
     }
 
-    GpsStatus() {
-        for (int i = 0; i < mSatellites.length; i++) {
-            mSatellites[i] = new GpsSatellite(i + 1);
-        }
-    }
+    // For API-compat a public ctor() is not available
+    GpsStatus() {}
 
     /**
      * Used internally within {@link LocationManager} to copy GPS status
@@ -141,18 +145,17 @@
     synchronized void setStatus(int svCount, int[] prns, float[] snrs,
             float[] elevations, float[] azimuths, int ephemerisMask,
             int almanacMask, int usedInFixMask) {
-        int i;
+        clearSatellites();
+        for (int i = 0; i < svCount; i++) {
+            int prn = prns[i];
+            int prnShift = (1 << (prn - 1));
+            if (prn > 0 && prn <= NUM_SATELLITES) {
+                GpsSatellite satellite = mSatellites.get(prn);
+                if (satellite == null) {
+                    satellite = new GpsSatellite(prn);
+                    mSatellites.put(prn, satellite);
+                }
 
-        for (i = 0; i < mSatellites.length; i++) {
-            mSatellites[i].mValid = false;
-        }
-        
-        for (i = 0; i < svCount; i++) {
-            int prn = prns[i] - 1;
-            int prnShift = (1 << prn);
-            if (prn >= 0 && prn < mSatellites.length) {
-                GpsSatellite satellite = mSatellites[prn];
-    
                 satellite.mValid = true;
                 satellite.mSnr = snrs[i];
                 satellite.mElevation = elevations[i];
@@ -172,10 +175,38 @@
      */
     void setStatus(GpsStatus status) {
         mTimeToFirstFix = status.getTimeToFirstFix();
+        clearSatellites();
 
-        for (int i = 0; i < mSatellites.length; i++) {
-            mSatellites[i].setStatus(status.mSatellites[i]);
-        } 
+        SparseArray<GpsSatellite> otherSatellites = status.mSatellites;
+        int otherSatellitesCount = otherSatellites.size();
+        int satelliteIndex = 0;
+        // merge both sparse arrays, note that we have already invalidated the elements in the
+        // receiver array
+        for (int i = 0; i < otherSatellitesCount; ++i) {
+            GpsSatellite otherSatellite = otherSatellites.valueAt(i);
+            int otherSatellitePrn = otherSatellite.getPrn();
+
+            int satellitesCount = mSatellites.size();
+            while (satelliteIndex < satellitesCount
+                    && mSatellites.valueAt(satelliteIndex).getPrn() < otherSatellitePrn) {
+                ++satelliteIndex;
+            }
+
+            if (satelliteIndex < mSatellites.size()) {
+                GpsSatellite satellite = mSatellites.valueAt(satelliteIndex);
+                if (satellite.getPrn() == otherSatellitePrn) {
+                    satellite.setStatus(otherSatellite);
+                } else {
+                    satellite = new GpsSatellite(otherSatellitePrn);
+                    satellite.setStatus(otherSatellite);
+                    mSatellites.put(otherSatellitePrn, satellite);
+                }
+            } else {
+                GpsSatellite satellite = new GpsSatellite(otherSatellitePrn);
+                satellite.setStatus(otherSatellite);
+                mSatellites.append(otherSatellitePrn, satellite);
+            }
+        }
     }
 
     void setTimeToFirstFix(int ttff) {
@@ -183,7 +214,7 @@
     }
 
     /**
-     * Returns the time required to receive the first fix since the most recent 
+     * Returns the time required to receive the first fix since the most recent
      * restart of the GPS engine.
      *
      * @return time to first fix in milliseconds
@@ -211,4 +242,12 @@
     public int getMaxSatellites() {
         return NUM_SATELLITES;
     }
+
+    private void clearSatellites() {
+        int satellitesCount = mSatellites.size();
+        for (int i = 0; i < satellitesCount; i++) {
+            GpsSatellite satellite = mSatellites.valueAt(i);
+            satellite.mValid = false;
+        }
+    }
 }
diff --git a/location/tests/locationtests/src/android/location/GpsStatusTest.java b/location/tests/locationtests/src/android/location/GpsStatusTest.java
new file mode 100644
index 0000000..4808faf
--- /dev/null
+++ b/location/tests/locationtests/src/android/location/GpsStatusTest.java
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.location;
+
+import junit.framework.TestCase;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Random;
+import java.util.Set;
+
+/**
+ * Unit tests for {@link GpsStatus}.
+ */
+@SmallTest
+public class GpsStatusTest extends TestCase {
+
+    private static final int MAX_VALUE = 250;
+
+    private final Random mRandom = new Random();
+
+    private GpsStatus mStatus;
+    private int mCount;
+    private int[] mPrns;
+    private float[] mSnrs;
+    private float[] mElevations;
+    private float[] mAzimuth;
+    private int mEphemerisMask;
+    private int mAlmanacMask;
+    private int mUsedInFixMask;
+
+    public void setUp() throws Exception {
+        super.setUp();
+        mStatus = createGpsStatus();
+        generateSatellitesData(generateInt());
+    }
+
+    public void testEmptyGpsStatus() throws Exception {
+        verifyIsEmpty(mStatus);
+    }
+
+    public void testGpsStatusIterator() throws Exception {
+        generateSatellitesData(2);
+        setSatellites(mStatus);
+        Iterator<GpsSatellite> iterator = mStatus.getSatellites().iterator();
+        assertTrue("hasNext(1)", iterator.hasNext());
+        assertTrue("hasNext(1) does not overflow", iterator.hasNext());
+        GpsSatellite satellite1 = iterator.next();
+        assertNotNull("satellite", satellite1);
+        assertTrue("hasNext(2)", iterator.hasNext());
+        assertTrue("hasNext(2) does not overflow", iterator.hasNext());
+        GpsSatellite satellite2 = iterator.next();
+        assertNotNull("satellite", satellite2);
+        assertFalse("hasNext() no elements", iterator.hasNext());
+    }
+
+    public void testTtff() throws Exception {
+        int testTtff = generateInt();
+        set(mStatus, testTtff);
+        verifyTtff(mStatus, testTtff);
+    }
+
+    public void testCopyTtff() throws Exception {
+        int testTtff = generateInt();
+        verifyTtff(mStatus, 0);
+
+        GpsStatus otherStatus = createGpsStatus();
+        set(otherStatus, testTtff);
+        verifyTtff(otherStatus, testTtff);
+
+        set(mStatus, otherStatus);
+        verifyTtff(mStatus, testTtff);
+    }
+
+    public void testSetSatellites() throws Exception {
+        setSatellites(mStatus);
+        verifySatellites(mStatus);
+    }
+
+    public void testCopySatellites() throws Exception {
+        verifyIsEmpty(mStatus);
+
+        GpsStatus otherStatus = createGpsStatus();
+        setSatellites(otherStatus);
+        verifySatellites(otherStatus);
+
+        set(mStatus, otherStatus);
+        verifySatellites(mStatus);
+    }
+
+    public void testOverrideSatellites() throws Exception {
+        setSatellites(mStatus);
+        verifySatellites(mStatus);
+
+        GpsStatus otherStatus = createGpsStatus();
+        generateSatellitesData(mCount, true /* reusePrns */);
+        setSatellites(otherStatus);
+        verifySatellites(otherStatus);
+
+        set(mStatus, otherStatus);
+        verifySatellites(mStatus);
+    }
+
+    public void testAddSatellites() throws Exception {
+        int count = 10;
+        generateSatellitesData(count);
+        setSatellites(mStatus);
+        verifySatellites(mStatus);
+
+        GpsStatus otherStatus = createGpsStatus();
+        generateSatellitesData(count);
+        setSatellites(otherStatus);
+        verifySatellites(otherStatus);
+
+        set(mStatus, otherStatus);
+        verifySatellites(mStatus);
+    }
+
+    public void testAddMoreSatellites() throws Exception {
+        int count = 25;
+        generateSatellitesData(count);
+        setSatellites(mStatus);
+        verifySatellites(mStatus);
+
+        GpsStatus otherStatus = createGpsStatus();
+        generateSatellitesData(count * 2);
+        setSatellites(otherStatus);
+        verifySatellites(otherStatus);
+
+        set(mStatus, otherStatus);
+        verifySatellites(mStatus);
+    }
+
+    public void testAddLessSatellites() throws Exception {
+        int count = 25;
+        generateSatellitesData(count * 2);
+        setSatellites(mStatus);
+        verifySatellites(mStatus);
+
+        GpsStatus otherStatus = createGpsStatus();
+        generateSatellitesData(count);
+        setSatellites(otherStatus);
+        verifySatellites(otherStatus);
+
+        set(mStatus, otherStatus);
+        verifySatellites(mStatus);
+    }
+
+    private static void verifyIsEmpty(GpsStatus status) {
+        verifySatelliteCount(status, 0);
+        verifyTtff(status, 0);
+    }
+
+    private static void verifySatelliteCount(GpsStatus status, int expectedCount) {
+        int satellites = 0;
+        for (GpsSatellite s : status.getSatellites()) {
+            ++satellites;
+        }
+        assertEquals("GpsStatus::SatelliteCount", expectedCount, satellites);
+    }
+
+    private void verifySatellites(GpsStatus status) {
+        verifySatelliteCount(status, mCount);
+        verifySatellites(status, mCount, mPrns, mSnrs, mElevations, mAzimuth, mEphemerisMask,
+                mAlmanacMask, mUsedInFixMask);
+    }
+
+    private static void verifySatellites(
+            GpsStatus status,
+            int count,
+            int[] prns,
+            float[] snrs,
+            float[] elevations,
+            float[] azimuth,
+            int ephemerisMask,
+            int almanacMask,
+            int usedInFixMask) {
+        for (int i = 0; i < count; ++i) {
+            int prn = prns[i];
+            GpsSatellite satellite = getSatellite(status, prn);
+            assertNotNull(getSatelliteAssertInfo(i, prn, "non-null"), satellite);
+            assertEquals(getSatelliteAssertInfo(i, prn, "Snr"), snrs[i], satellite.getSnr());
+            assertEquals(
+                    getSatelliteAssertInfo(i, prn, "Elevation"),
+                    elevations[i],
+                    satellite.getElevation());
+            assertEquals(
+                    getSatelliteAssertInfo(i, prn, "Azimuth"),
+                    azimuth[i],
+                    satellite.getAzimuth());
+            int prnShift = 1 << (prn - 1);
+            assertEquals(
+                    getSatelliteAssertInfo(i, prn, "ephemeris"),
+                    (ephemerisMask & prnShift) != 0,
+                    satellite.hasEphemeris());
+            assertEquals(
+                    getSatelliteAssertInfo(i, prn, "almanac"),
+                    (almanacMask & prnShift) != 0,
+                    satellite.hasAlmanac());
+            assertEquals(
+                    getSatelliteAssertInfo(i, prn, "usedInFix"),
+                    (usedInFixMask & prnShift) != 0,
+                    satellite.usedInFix());
+        }
+    }
+
+    private static void verifyTtff(GpsStatus status, int expectedTtff) {
+        assertEquals("GpsStatus::TTFF", expectedTtff, status.getTimeToFirstFix());
+    }
+
+    private static GpsStatus createGpsStatus() throws Exception {
+        Constructor<GpsStatus>  ctor = GpsStatus.class.getDeclaredConstructor();
+        ctor.setAccessible(true);
+        return ctor.newInstance();
+    }
+
+    private static void set(GpsStatus status, int ttff) throws Exception {
+        Class<?> statusClass = status.getClass();
+        Method setTtff = statusClass.getDeclaredMethod("setTimeToFirstFix", Integer.TYPE);
+        setTtff.setAccessible(true);
+        setTtff.invoke(status, ttff);
+    }
+
+    private static void set(GpsStatus status, GpsStatus statusToSet) throws Exception {
+        Class<?> statusClass = status.getClass();
+        Method setStatus = statusClass.getDeclaredMethod("setStatus", statusClass);
+        setStatus.setAccessible(true);
+        setStatus.invoke(status, statusToSet);
+    }
+
+    private void setSatellites(GpsStatus status) throws Exception {
+        set(status, mCount, mPrns, mSnrs, mElevations, mAzimuth, mEphemerisMask, mAlmanacMask,
+                mUsedInFixMask);
+    }
+
+    private static void set(
+            GpsStatus status,
+            int count,
+            int[] prns,
+            float[] snrs,
+            float[] elevations,
+            float[] azimuth,
+            int ephemerisMask,
+            int almanacMask,
+            int usedInFixMask) throws Exception {
+        Class<?> statusClass = status.getClass();
+        Class<?> intClass = Integer.TYPE;
+        Class<?> floatArrayClass = Class.forName("[F");
+        Method setStatus = statusClass.getDeclaredMethod(
+                "setStatus",
+                intClass,
+                Class.forName("[I"),
+                floatArrayClass,
+                floatArrayClass,
+                floatArrayClass,
+                intClass,
+                intClass,
+                intClass);
+        setStatus.setAccessible(true);
+        setStatus.invoke(
+                status,
+                count,
+                prns,
+                snrs,
+                elevations,
+                azimuth,
+                ephemerisMask,
+                almanacMask,
+                usedInFixMask);
+    }
+
+    private int generateInt() {
+        return mRandom.nextInt(MAX_VALUE) + 1;
+    }
+
+    private int[] generateIntArray(int count) {
+        Set<Integer> generatedPrns = new HashSet<>();
+        int[] array = new int[count];
+        for(int i = 0; i < count; ++i) {
+            int generated;
+            do {
+                generated = generateInt();
+            } while (generatedPrns.contains(generated));
+            array[i] = generated;
+            generatedPrns.add(generated);
+        }
+        return array;
+    }
+
+    private float[] generateFloatArray(int count) {
+        float[] array = new float[count];
+        for(int i = 0; i < count; ++i) {
+            array[i] = generateInt();
+        }
+        return array;
+    }
+
+    private int generateMask(int[] prns) {
+        int mask = 0;
+        int prnsLength = prns.length;
+        for (int i = 0; i < prnsLength; ++i) {
+            if (mRandom.nextBoolean()) {
+                mask |= 1 << (prns[i] - 1);
+            }
+        }
+        return mask;
+    }
+
+    private void generateSatellitesData(int count) {
+        generateSatellitesData(count, false /* reusePrns */);
+    }
+
+    private void generateSatellitesData(int count, boolean reusePrns) {
+        mCount = count;
+        if (!reusePrns) {
+            mPrns = generateIntArray(count);
+        }
+        mSnrs = generateFloatArray(count);
+        mElevations = generateFloatArray(count);
+        mAzimuth = generateFloatArray(count);
+        mEphemerisMask = generateMask(mPrns);
+        mAlmanacMask = generateMask(mPrns);
+        mUsedInFixMask = generateMask(mPrns);
+    }
+
+    private static GpsSatellite getSatellite(GpsStatus status, int prn) {
+        for (GpsSatellite satellite : status.getSatellites()) {
+            if (satellite.getPrn() == prn) {
+                return satellite;
+            }
+        }
+        return null;
+    }
+
+    private static String getSatelliteAssertInfo(int index, int prn, String param) {
+        return String.format("Satellite::%s [i=%d, prn=%d]", param, index, prn);
+    }
+}
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 489f552..ca242e4 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -709,7 +709,13 @@
         }
     }
 
-    /** @hide */
+    /**
+     * @hide
+     * Only use to get which stream type should be used for volume control, NOT for audio playback
+     * (all audio playback APIs are supposed to take AudioAttributes as input parameters)
+     * @param aa non-null AudioAttributes.
+     * @return a valid stream type for volume control that matches the attributes.
+     */
     public static int toLegacyStreamType(AudioAttributes aa) {
         // flags to stream type mapping
         if ((aa.getFlags() & FLAG_AUDIBILITY_ENFORCED) == FLAG_AUDIBILITY_ENFORCED) {
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 5b92266..bc9722e 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -756,8 +756,9 @@
          * </p><p>
          * Note that this sub-directory also supports opening the logo as an asset file in write
          * mode.  Callers can create or replace the primary logo associated with this channel by
-         * opening the asset file and writing the full-size photo contents into it.  When the file
-         * is closed, the image will be parsed, sized down if necessary, and stored.
+         * opening the asset file and writing the full-size photo contents into it. (Make sure there
+         * is no padding around the logo image.) When the file is closed, the image will be parsed,
+         * sized down if necessary, and stored.
          * </p><p>
          * Usage example:
          * <pre>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 1bed553..ea4c4ba 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -74,7 +74,7 @@
     RecentsViewLayoutAlgorithm mLayoutAlgorithm;
 
     ArrayList<TaskStack> mStacks;
-    List<TaskStackView> mImmutableTaskStackViews = new ArrayList<TaskStackView>();
+    List<TaskStackView> mTaskStackViews = new ArrayList<>();
     View mSearchBar;
     RecentsViewCallbacks mCb;
 
@@ -133,24 +133,18 @@
     public void setTaskStacks(ArrayList<TaskStack> stacks) {
         int numStacks = stacks.size();
 
-        // Make a list of the stack view children only
-        ArrayList<TaskStackView> stackViewsList = new ArrayList<TaskStackView>();
-        List<TaskStackView> stackViews = getTaskStackViews();
-
         // Remove all/extra stack views
         int numTaskStacksToKeep = 0; // Keep no tasks if we are recreating the layout
         if (mConfig.launchedReuseTaskStackViews) {
-            numTaskStacksToKeep = Math.min(stackViews.size(), numStacks);
+            numTaskStacksToKeep = Math.min(mTaskStackViews.size(), numStacks);
         }
-        for (int i = stackViews.size() - 1; i >= numTaskStacksToKeep; i--) {
-            removeView(stackViews.get(i));
-            stackViews.remove(i);
+        for (int i = mTaskStackViews.size() - 1; i >= numTaskStacksToKeep; i--) {
+            removeView(mTaskStackViews.remove(i));
         }
-        stackViewsList.addAll(stackViews);
 
         // Update the stack views that we are keeping
         for (int i = 0; i < numTaskStacksToKeep; i++) {
-            TaskStackView tsv = stackViews.get(i);
+            TaskStackView tsv = mTaskStackViews.get(i);
             // If onRecentsHidden is not triggered, we need to the stack view again here
             tsv.reset();
             tsv.setStack(stacks.get(i));
@@ -158,21 +152,18 @@
 
         // Add remaining/recreate stack views
         mStacks = stacks;
-        for (int i = stackViews.size(); i < numStacks; i++) {
+        for (int i = mTaskStackViews.size(); i < numStacks; i++) {
             TaskStack stack = stacks.get(i);
             TaskStackView stackView = new TaskStackView(getContext(), stack);
             stackView.setCallbacks(this);
             addView(stackView);
-            stackViewsList.add(stackView);
+            mTaskStackViews.add(stackView);
         }
 
-        // Set the immutable stack views list
-        mImmutableTaskStackViews = Collections.unmodifiableList(stackViewsList);
-
         // Enable debug mode drawing on all the stacks if necessary
         if (mConfig.debugModeEnabled) {
-            for (int i = mImmutableTaskStackViews.size() - 1; i >= 0; i--) {
-                TaskStackView stackView = mImmutableTaskStackViews.get(i);
+            for (int i = mTaskStackViews.size() - 1; i >= 0; i--) {
+                TaskStackView stackView = mTaskStackViews.get(i);
                 stackView.setDebugOverlay(mDebugOverlay);
             }
         }
@@ -188,7 +179,7 @@
 
     /** Gets the list of task views */
     List<TaskStackView> getTaskStackViews() {
-        return mImmutableTaskStackViews;
+        return mTaskStackViews;
     }
 
     /** Launches the focused task from the first stack if possible */
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 640f161..7a493c6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -170,6 +170,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IPermissionController;
+import android.os.IProcessInfoService;
 import android.os.IRemoteCallback;
 import android.os.IUserManager;
 import android.os.Looper;
@@ -1920,6 +1921,7 @@
                 ServiceManager.addService("cpuinfo", new CpuBinder(this));
             }
             ServiceManager.addService("permission", new PermissionController(this));
+            ServiceManager.addService("processinfo", new ProcessInfoService(this));
 
             ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
                     "android", STOCK_PM_FLAGS);
@@ -6287,7 +6289,46 @@
             }
         }
     }
-    
+
+    // =========================================================
+    // PROCESS INFO
+    // =========================================================
+
+    static class ProcessInfoService extends IProcessInfoService.Stub {
+        final ActivityManagerService mActivityManagerService;
+        ProcessInfoService(ActivityManagerService activityManagerService) {
+            mActivityManagerService = activityManagerService;
+        }
+
+        @Override
+        public void getProcessStatesFromPids(/*in*/ int[] pids, /*out*/ int[] states) {
+            mActivityManagerService.getProcessStatesForPIDs(/*in*/ pids, /*out*/ states);
+        }
+    }
+
+    /**
+     * For each PID in the given input array, write the current process state
+     * for that process into the output array, or -1 to indicate that no
+     * process with the given PID exists.
+     */
+    public void getProcessStatesForPIDs(/*in*/ int[] pids, /*out*/ int[] states) {
+        if (pids == null) {
+            throw new NullPointerException("pids");
+        } else if (states == null) {
+            throw new NullPointerException("states");
+        } else if (pids.length != states.length) {
+            throw new IllegalArgumentException("input and output arrays have different lengths!");
+        }
+
+        synchronized (mPidsSelfLocked) {
+            for (int i = 0; i < pids.length; i++) {
+                ProcessRecord pr = mPidsSelfLocked.get(pids[i]);
+                states[i] = (pr == null) ? ActivityManager.PROCESS_STATE_NONEXISTENT :
+                        pr.curProcState;
+            }
+        }
+    }
+
     // =========================================================
     // PERMISSIONS
     // =========================================================
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index f900d0d..87f78c1 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -28,6 +28,7 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkRequest;
+import android.net.ProxyInfo;
 import android.net.TrafficStats;
 import android.net.Uri;
 import android.net.wifi.WifiInfo;
@@ -656,12 +657,36 @@
         int httpResponseCode = 599;
         try {
             URL url = new URL("http", mServer, "/generate_204");
+            // On networks with a PAC instead of fetching a URL that should result in a 204
+            // reponse, we instead simply fetch the PAC script.  This is done for a few reasons:
+            // 1. At present our PAC code does not yet handle multiple PACs on multiple networks
+            //    until something like https://android-review.googlesource.com/#/c/115180/ lands.
+            //    Network.openConnection() will ignore network-specific PACs and instead fetch
+            //    using NO_PROXY.  If a PAC is in place, the only fetch we know will succeed with
+            //    NO_PROXY is the fetch of the PAC itself.
+            // 2. To proxy the generate_204 fetch through a PAC would require a number of things
+            //    happen before the fetch can commence, namely:
+            //        a) the PAC script be fetched
+            //        b) a PAC script resolver service be fired up and resolve mServer
+            //    Network validation could be delayed until these prerequisities are satisifed or
+            //    could simply be left to race them.  Neither is an optimal solution.
+            // 3. PAC scripts are sometimes used to block or restrict Internet access and may in
+            //    fact block fetching of the generate_204 URL which would lead to false negative
+            //    results for network validation.
+            boolean fetchPac = false;
+            {
+                final ProxyInfo proxyInfo = mNetworkAgentInfo.linkProperties.getHttpProxy();
+                if (proxyInfo != null && !Uri.EMPTY.equals(proxyInfo.getPacFileUrl())) {
+                    url = new URL(proxyInfo.getPacFileUrl().toString());
+                    fetchPac = true;
+                }
+            }
             if (DBG) {
                 log("Checking " + url.toString() + " on " +
                         mNetworkAgentInfo.networkInfo.getExtraInfo());
             }
             urlConnection = (HttpURLConnection) mNetworkAgentInfo.network.openConnection(url);
-            urlConnection.setInstanceFollowRedirects(false);
+            urlConnection.setInstanceFollowRedirects(fetchPac);
             urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
             urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
             urlConnection.setUseCaches(false);
@@ -695,6 +720,11 @@
                 httpResponseCode = 204;
             }
 
+            if (httpResponseCode == 200 && fetchPac) {
+                if (DBG) log("PAC fetch 200 response interpreted as 204 response.");
+                httpResponseCode = 204;
+            }
+
             sendNetworkConditionsBroadcast(true /* response received */,
                     httpResponseCode != 204 /* isCaptivePortal */,
                     requestTimestamp, responseTimestamp);