Merge "Fix boot loop when deriving device name." into lmp-dev
diff --git a/core/java/android/animation/PathKeyframes.java b/core/java/android/animation/PathKeyframes.java
index 70eed90..2a47b68 100644
--- a/core/java/android/animation/PathKeyframes.java
+++ b/core/java/android/animation/PathKeyframes.java
@@ -17,7 +17,6 @@
 
 import android.graphics.Path;
 import android.graphics.PointF;
-import android.util.MathUtils;
 
 import java.util.ArrayList;
 
@@ -64,11 +63,12 @@
 
     @Override
     public Object getValue(float fraction) {
-        fraction = MathUtils.constrain(fraction, 0, 1);
-
         int numPoints = mKeyframeData.length / 3;
-
-        if (fraction == 0) {
+        if (fraction < 0) {
+            return interpolateInRange(fraction, 0, 1);
+        } else if (fraction > 1) {
+            return interpolateInRange(fraction, numPoints - 2, numPoints - 1);
+        } else if (fraction == 0) {
             return pointForIndex(0);
         } else if (fraction == 1) {
             return pointForIndex(numPoints - 1);
@@ -91,27 +91,31 @@
             }
 
             // now high is below the fraction and low is above the fraction
-            int startBase = (high * NUM_COMPONENTS);
-            int endBase = (low * NUM_COMPONENTS);
-
-            float startFraction = mKeyframeData[startBase + FRACTION_OFFSET];
-            float endFraction = mKeyframeData[endBase + FRACTION_OFFSET];
-
-            float intervalFraction = (fraction - startFraction)/(endFraction - startFraction);
-
-            float startX = mKeyframeData[startBase + X_OFFSET];
-            float endX = mKeyframeData[endBase + X_OFFSET];
-            float startY = mKeyframeData[startBase + Y_OFFSET];
-            float endY = mKeyframeData[endBase + Y_OFFSET];
-
-            float x = interpolate(intervalFraction, startX, endX);
-            float y = interpolate(intervalFraction, startY, endY);
-
-            mTempPointF.set(x, y);
-            return mTempPointF;
+            return interpolateInRange(fraction, high, low);
         }
     }
 
+    private PointF interpolateInRange(float fraction, int startIndex, int endIndex) {
+        int startBase = (startIndex * NUM_COMPONENTS);
+        int endBase = (endIndex * NUM_COMPONENTS);
+
+        float startFraction = mKeyframeData[startBase + FRACTION_OFFSET];
+        float endFraction = mKeyframeData[endBase + FRACTION_OFFSET];
+
+        float intervalFraction = (fraction - startFraction)/(endFraction - startFraction);
+
+        float startX = mKeyframeData[startBase + X_OFFSET];
+        float endX = mKeyframeData[endBase + X_OFFSET];
+        float startY = mKeyframeData[startBase + Y_OFFSET];
+        float endY = mKeyframeData[endBase + Y_OFFSET];
+
+        float x = interpolate(intervalFraction, startX, endX);
+        float y = interpolate(intervalFraction, startY, endY);
+
+        mTempPointF.set(x, y);
+        return mTempPointF;
+    }
+
     @Override
     public void invalidateCache() {
     }
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 43fa3f0..d02d17f 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -223,7 +223,10 @@
         mSharedElementNames.addAll(sharedElements.keySet());
         mSharedElements.addAll(sharedElements.values());
         if (getViewsTransition() != null) {
-            getDecor().captureTransitioningViews(mTransitioningViews);
+            ViewGroup decorView = getDecor();
+            if (decorView != null) {
+                decorView.captureTransitioningViews(mTransitioningViews);
+            }
             mTransitioningViews.removeAll(mSharedElements);
         }
         setEpicenter();
@@ -235,6 +238,7 @@
             View view = mTransitioningViews.get(i);
             if (!view.getGlobalVisibleRect(r)) {
                 mTransitioningViews.remove(i);
+                showView(view, true);
             }
         }
     }
@@ -350,7 +354,10 @@
                 sharedElements.put(accepted.get(i), localViews.get(i));
             }
         } else {
-            getDecor().findNamedViews(sharedElements);
+            ViewGroup decorView = getDecor();
+            if (decorView != null) {
+                decorView.findNamedViews(sharedElements);
+            }
         }
         return sharedElements;
     }
@@ -471,16 +478,18 @@
 
     protected void scheduleSetSharedElementEnd(final ArrayList<View> snapshots) {
         final View decorView = getDecor();
-        decorView.getViewTreeObserver().addOnPreDrawListener(
-                new ViewTreeObserver.OnPreDrawListener() {
-                    @Override
-                    public boolean onPreDraw() {
-                        decorView.getViewTreeObserver().removeOnPreDrawListener(this);
-                        notifySharedElementEnd(snapshots);
-                        return true;
+        if (decorView != null) {
+            decorView.getViewTreeObserver().addOnPreDrawListener(
+                    new ViewTreeObserver.OnPreDrawListener() {
+                        @Override
+                        public boolean onPreDraw() {
+                            decorView.getViewTreeObserver().removeOnPreDrawListener(this);
+                            notifySharedElementEnd(snapshots);
+                            return true;
+                        }
                     }
-                }
-        );
+            );
+        }
     }
 
     private static SharedElementOriginalState getOldSharedElementState(View view, String name,
@@ -523,7 +532,10 @@
         ArrayList<View> snapshots = new ArrayList<View>(numSharedElements);
         Context context = getWindow().getContext();
         int[] decorLoc = new int[2];
-        getDecor().getLocationOnScreen(decorLoc);
+        ViewGroup decorView = getDecor();
+        if (decorView != null) {
+            decorView.getLocationOnScreen(decorLoc);
+        }
         for (String name: names) {
             Bundle sharedElementBundle = state.getBundle(name);
             if (sharedElementBundle != null) {
@@ -605,14 +617,17 @@
     protected void showViews(ArrayList<View> views, boolean setTransitionAlpha) {
         int count = views.size();
         for (int i = 0; i < count; i++) {
-            View view = views.get(i);
-            Float alpha = mOriginalAlphas.remove(view);
-            if (alpha != null) {
-                view.setAlpha(alpha);
-            }
-            if (setTransitionAlpha) {
-                view.setTransitionAlpha(1f);
-            }
+            showView(views.get(i), setTransitionAlpha);
+        }
+    }
+
+    private void showView(View view, boolean setTransitionAlpha) {
+        Float alpha = mOriginalAlphas.remove(view);
+        if (alpha != null) {
+            view.setAlpha(alpha);
+        }
+        if (setTransitionAlpha) {
+            view.setTransitionAlpha(1f);
         }
     }
 
@@ -746,15 +761,17 @@
 
     protected void scheduleGhostVisibilityChange(final int visibility) {
         final View decorView = getDecor();
-        decorView.getViewTreeObserver()
-                .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
-                    @Override
-                    public boolean onPreDraw() {
-                        decorView.getViewTreeObserver().removeOnPreDrawListener(this);
-                        setGhostVisibility(visibility);
-                        return true;
-                    }
-                });
+        if (decorView != null) {
+            decorView.getViewTreeObserver()
+                    .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+                        @Override
+                        public boolean onPreDraw() {
+                            decorView.getViewTreeObserver().removeOnPreDrawListener(this);
+                            setGhostVisibility(visibility);
+                            return true;
+                        }
+                    });
+        }
     }
 
     protected class ContinueTransitionListener extends Transition.TransitionListenerAdapter {
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 9ca150d..bfdb0eb 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -70,16 +70,18 @@
         resultReceiverBundle.putParcelable(KEY_REMOTE_RECEIVER, this);
         mResultReceiver.send(MSG_SET_REMOTE_RECEIVER, resultReceiverBundle);
         final View decorView = getDecor();
-        decorView.getViewTreeObserver().addOnPreDrawListener(
-                new ViewTreeObserver.OnPreDrawListener() {
-                    @Override
-                    public boolean onPreDraw() {
-                        if (mIsReadyForTransition) {
-                            decorView.getViewTreeObserver().removeOnPreDrawListener(this);
+        if (decorView != null) {
+            decorView.getViewTreeObserver().addOnPreDrawListener(
+                    new ViewTreeObserver.OnPreDrawListener() {
+                        @Override
+                        public boolean onPreDraw() {
+                            if (mIsReadyForTransition) {
+                                decorView.getViewTreeObserver().removeOnPreDrawListener(this);
+                            }
+                            return mIsReadyForTransition;
                         }
-                        return mIsReadyForTransition;
-                    }
-                });
+                    });
+        }
     }
 
     public void viewInstancesReady(ArrayList<String> accepted, ArrayList<String> localNames,
@@ -152,7 +154,10 @@
     private ArrayMap<String, View> mapNamedElements(ArrayList<String> accepted,
             ArrayList<String> localNames) {
         ArrayMap<String, View> sharedElements = new ArrayMap<String, View>();
-        getDecor().findNamedViews(sharedElements);
+        ViewGroup decorView = getDecor();
+        if (decorView != null) {
+            decorView.findNamedViews(sharedElements);
+        }
         if (accepted != null) {
             for (int i = 0; i < localNames.size(); i++) {
                 String localName = localNames.get(i);
@@ -170,10 +175,13 @@
 
     private void sendSharedElementDestination() {
         boolean allReady;
+        final View decorView = getDecor();
         if (allowOverlappingTransitions() && getEnterViewsTransition() != null) {
             allReady = false;
+        } else if (decorView == null) {
+            allReady = true;
         } else {
-            allReady = !getDecor().isLayoutRequested();
+            allReady = !decorView.isLayoutRequested();
             if (allReady) {
                 for (int i = 0; i < mSharedElements.size(); i++) {
                     if (mSharedElements.get(i).isLayoutRequested()) {
@@ -188,8 +196,7 @@
             setSharedElementMatrices();
             moveSharedElementsToOverlay();
             mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state);
-        } else {
-            final View decorView = getDecor();
+        } else if (decorView != null) {
             decorView.getViewTreeObserver()
                     .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                         @Override
@@ -291,6 +298,10 @@
     }
 
     private void startSharedElementTransition(Bundle sharedElementState) {
+        ViewGroup decorView = getDecor();
+        if (decorView == null) {
+            return;
+        }
         // Remove rejected shared elements
         ArrayList<String> rejectedNames = new ArrayList<String>(mAllSharedElementNames);
         rejectedNames.removeAll(mSharedElementNames);
@@ -311,7 +322,8 @@
         boolean startSharedElementTransition = true;
         setGhostVisibility(View.INVISIBLE);
         scheduleGhostVisibilityChange(View.INVISIBLE);
-        Transition transition = beginTransition(startEnterTransition, startSharedElementTransition);
+        Transition transition = beginTransition(decorView, startEnterTransition,
+                startSharedElementTransition);
         scheduleGhostVisibilityChange(View.VISIBLE);
         setGhostVisibility(View.VISIBLE);
 
@@ -324,8 +336,9 @@
         if (mResultReceiver != null) {
             // We can't trust that the view will disappear on the same frame that the shared
             // element appears here. Assure that we get at least 2 frames for double-buffering.
-            getDecor().postOnAnimation(new Runnable() {
+            decorView.postOnAnimation(new Runnable() {
                 int mAnimations;
+
                 @Override
                 public void run() {
                     if (mAnimations++ < MIN_ANIMATION_FRAMES) {
@@ -349,21 +362,23 @@
         final Bundle sharedElementState = mSharedElementsBundle;
         mSharedElementsBundle = null;
         final View decorView = getDecor();
-        decorView.getViewTreeObserver()
-                .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
-                    @Override
-                    public boolean onPreDraw() {
-                        decorView.getViewTreeObserver().removeOnPreDrawListener(this);
-                        startTransition(new Runnable() {
-                            @Override
-                            public void run() {
-                                startSharedElementTransition(sharedElementState);
-                            }
-                        });
-                        return false;
-                    }
-                });
-        decorView.invalidate();
+        if (decorView != null) {
+            decorView.getViewTreeObserver()
+                    .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+                        @Override
+                        public boolean onPreDraw() {
+                            decorView.getViewTreeObserver().removeOnPreDrawListener(this);
+                            startTransition(new Runnable() {
+                                @Override
+                                public void run() {
+                                    startSharedElementTransition(sharedElementState);
+                                }
+                            });
+                            return false;
+                        }
+                    });
+            decorView.invalidate();
+        }
     }
 
     private void requestLayoutForSharedElements() {
@@ -373,7 +388,7 @@
         }
     }
 
-    private Transition beginTransition(boolean startEnterTransition,
+    private Transition beginTransition(ViewGroup decorView, boolean startEnterTransition,
             boolean startSharedElementTransition) {
         Transition sharedElementTransition = null;
         if (startSharedElementTransition) {
@@ -433,7 +448,7 @@
         Transition transition = mergeTransitions(sharedElementTransition, viewsTransition);
         if (transition != null) {
             transition.addListener(new ContinueTransitionListener());
-            TransitionManager.beginDelayedTransition(getDecor(), transition);
+            TransitionManager.beginDelayedTransition(decorView, transition);
             if (startSharedElementTransition && !mSharedElementNames.isEmpty()) {
                 mSharedElements.get(0).invalidate();
             } else if (startEnterTransition && !mTransitioningViews.isEmpty()) {
@@ -467,8 +482,9 @@
     }
 
     private void startEnterTransition(Transition transition) {
-        if (!mIsReturning) {
-            Drawable background = getDecor().getBackground();
+        ViewGroup decorView = getDecor();
+        if (!mIsReturning && decorView != null) {
+            Drawable background = decorView.getBackground();
             if (background != null) {
                 background = background.mutate();
                 getWindow().setBackgroundDrawable(background);
@@ -539,25 +555,28 @@
         if (rejectedSnapshots == null || rejectedSnapshots.isEmpty()) {
             return;
         }
-        ViewGroupOverlay overlay = getDecor().getOverlay();
-        ObjectAnimator animator = null;
-        int numRejected = rejectedSnapshots.size();
-        for (int i = 0; i < numRejected; i++) {
-            View snapshot = rejectedSnapshots.get(i);
-            overlay.add(snapshot);
-            animator = ObjectAnimator.ofFloat(snapshot, View.ALPHA, 1, 0);
-            animator.start();
-        }
-        animator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                ViewGroupOverlay overlay = getDecor().getOverlay();
-                int numRejected = rejectedSnapshots.size();
-                for (int i = 0; i < numRejected; i++) {
-                    overlay.remove(rejectedSnapshots.get(i));
-                }
+        final ViewGroup decorView = getDecor();
+        if (decorView != null) {
+            ViewGroupOverlay overlay = decorView.getOverlay();
+            ObjectAnimator animator = null;
+            int numRejected = rejectedSnapshots.size();
+            for (int i = 0; i < numRejected; i++) {
+                View snapshot = rejectedSnapshots.get(i);
+                overlay.add(snapshot);
+                animator = ObjectAnimator.ofFloat(snapshot, View.ALPHA, 1, 0);
+                animator.start();
             }
-        });
+            animator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    ViewGroupOverlay overlay = decorView.getOverlay();
+                    int numRejected = rejectedSnapshots.size();
+                    for (int i = 0; i < numRejected; i++) {
+                        overlay.remove(rejectedSnapshots.get(i));
+                    }
+                }
+            });
+        }
     }
 
     protected void onRemoteExitTransitionComplete() {
@@ -572,9 +591,12 @@
             public void run() {
                 boolean startEnterTransition = true;
                 boolean startSharedElementTransition = false;
-                Transition transition = beginTransition(startEnterTransition,
-                        startSharedElementTransition);
-                startEnterTransition(transition);
+                ViewGroup decorView = getDecor();
+                if (decorView != null) {
+                    Transition transition = beginTransition(decorView, startEnterTransition,
+                            startSharedElementTransition);
+                    startEnterTransition(transition);
+                }
             }
         });
     }
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index e85ec63..41b0db6 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -129,22 +129,25 @@
         showViews(mTransitioningViews, true);
         showViews(mSharedElements, true);
         mIsHidden = true;
-        if (!mIsReturning && getDecor() != null) {
-            getDecor().suppressLayout(false);
+        ViewGroup decorView = getDecor();
+        if (!mIsReturning && decorView != null) {
+            decorView.suppressLayout(false);
         }
         moveSharedElementsFromOverlay();
         clearState();
     }
 
     private void sharedElementExitBack() {
-        if (getDecor() != null) {
-            getDecor().suppressLayout(true);
+        final ViewGroup decorView = getDecor();
+        if (decorView != null) {
+            decorView.suppressLayout(true);
         }
-        if (mExitSharedElementBundle != null && !mExitSharedElementBundle.isEmpty() &&
+        if (decorView != null && mExitSharedElementBundle != null &&
+                !mExitSharedElementBundle.isEmpty() &&
                 !mSharedElements.isEmpty() && getSharedElementTransition() != null) {
             startTransition(new Runnable() {
                 public void run() {
-                    startSharedElementExit();
+                    startSharedElementExit(decorView);
                 }
             });
         } else {
@@ -152,7 +155,7 @@
         }
     }
 
-    private void startSharedElementExit() {
+    private void startSharedElementExit(final ViewGroup decorView) {
         Transition transition = getSharedElementExitTransition();
         transition.addListener(new Transition.TransitionListenerAdapter() {
             @Override
@@ -165,7 +168,6 @@
         });
         final ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle,
                 mSharedElementNames);
-        final View decorView = getDecor();
         decorView.getViewTreeObserver()
                 .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                     @Override
@@ -178,10 +180,10 @@
         setGhostVisibility(View.INVISIBLE);
         scheduleGhostVisibilityChange(View.INVISIBLE);
         mListener.onSharedElementEnd(mSharedElementNames, mSharedElements, sharedElementSnapshots);
-        TransitionManager.beginDelayedTransition(getDecor(), transition);
+        TransitionManager.beginDelayedTransition(decorView, transition);
         scheduleGhostVisibilityChange(View.VISIBLE);
         setGhostVisibility(View.VISIBLE);
-        getDecor().invalidate();
+        decorView.invalidate();
     }
 
     private void hideSharedElements() {
@@ -196,8 +198,9 @@
     public void startExit() {
         if (!mIsExitStarted) {
             mIsExitStarted = true;
-            if (getDecor() != null) {
-                getDecor().suppressLayout(true);
+            ViewGroup decorView = getDecor();
+            if (decorView != null) {
+                decorView.suppressLayout(true);
             }
             moveSharedElementsToOverlay();
             startTransition(new Runnable() {
@@ -212,8 +215,9 @@
     public void startExit(int resultCode, Intent data) {
         if (!mIsExitStarted) {
             mIsExitStarted = true;
-            if (getDecor() != null) {
-                getDecor().suppressLayout(true);
+            ViewGroup decorView = getDecor();
+            if (decorView != null) {
+                decorView.suppressLayout(true);
             }
             mHandler = new Handler() {
                 @Override
@@ -224,7 +228,7 @@
             };
             delayCancel();
             moveSharedElementsToOverlay();
-            if (getDecor().getBackground() == null) {
+            if (decorView != null && decorView.getBackground() == null) {
                 getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
             }
             ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this,
@@ -248,8 +252,9 @@
 
     private void startExitTransition() {
         Transition transition = getExitTransition();
-        if (transition != null) {
-            TransitionManager.beginDelayedTransition(getDecor(), transition);
+        ViewGroup decorView = getDecor();
+        if (transition != null && decorView != null) {
+            TransitionManager.beginDelayedTransition(decorView, transition);
             mTransitioningViews.get(0).invalidate();
         } else {
             transitionStarted();
@@ -337,13 +342,14 @@
         Transition viewsTransition = getExitTransition();
 
         Transition transition = mergeTransitions(sharedElementTransition, viewsTransition);
-        if (transition != null) {
+        ViewGroup decorView = getDecor();
+        if (transition != null && decorView != null) {
             setGhostVisibility(View.INVISIBLE);
             scheduleGhostVisibilityChange(View.INVISIBLE);
-            TransitionManager.beginDelayedTransition(getDecor(), transition);
+            TransitionManager.beginDelayedTransition(decorView, transition);
             scheduleGhostVisibilityChange(View.VISIBLE);
             setGhostVisibility(View.VISIBLE);
-            getDecor().invalidate();
+            decorView.invalidate();
         } else {
             transitionStarted();
         }
@@ -392,8 +398,9 @@
                 mExitNotified = true;
                 mResultReceiver.send(MSG_EXIT_TRANSITION_COMPLETE, null);
                 mResultReceiver = null; // done talking
-                if (!mIsReturning && getDecor() != null) {
-                    getDecor().suppressLayout(false);
+                ViewGroup decorView = getDecor();
+                if (!mIsReturning && decorView != null) {
+                    decorView.suppressLayout(false);
                 }
                 finishIfNecessary();
             }
diff --git a/core/java/android/hardware/camera2/params/TonemapCurve.java b/core/java/android/hardware/camera2/params/TonemapCurve.java
index 481d67a..398a7e9 100644
--- a/core/java/android/hardware/camera2/params/TonemapCurve.java
+++ b/core/java/android/hardware/camera2/params/TonemapCurve.java
@@ -81,7 +81,8 @@
      * <p>Values are stored as a contiguous array of {@code (Pin, Pout)} points.</p>
      *
      * <p>All parameters may have independent length but should have at most
-     * {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS} * {@value #POINT_SIZE} elements.</p>
+     * {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS} * {@value #POINT_SIZE} elements and
+     * at least 2 * {@value #POINT_SIZE} elements.</p>
      *
      * <p>All sub-elements must be in the inclusive range of
      * [{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].</p>
@@ -110,6 +111,10 @@
         checkArgumentArrayLengthDivisibleBy(green, POINT_SIZE, "green");
         checkArgumentArrayLengthDivisibleBy(blue, POINT_SIZE, "blue");
 
+        checkArgumentArrayLengthNoLessThan(red, MIN_CURVE_LENGTH, "red");
+        checkArgumentArrayLengthNoLessThan(green, MIN_CURVE_LENGTH, "green");
+        checkArgumentArrayLengthNoLessThan(blue, MIN_CURVE_LENGTH, "blue");
+
         checkArrayElementsInRange(red, LEVEL_BLACK, LEVEL_WHITE, "red");
         checkArrayElementsInRange(green, LEVEL_BLACK, LEVEL_WHITE, "green");
         checkArrayElementsInRange(blue, LEVEL_BLACK, LEVEL_WHITE, "blue");
@@ -140,6 +145,14 @@
         return colorChannel;
     }
 
+    private static void checkArgumentArrayLengthNoLessThan(float[] array, int minLength,
+            String arrayName) {
+        if (array.length < minLength) {
+            throw new IllegalArgumentException(arrayName + " size must be at least "
+                    + minLength);
+        }
+    }
+
     /**
      * Get the number of points stored in this tonemap curve for the specified color channel.
      *
@@ -270,6 +283,47 @@
         return mHashCode;
     }
 
+    /**
+     * Return the TonemapCurve as a string representation.
+     *
+     * <p> {@code "TonemapCurve{R:[(%f, %f), (%f, %f) ... (%f, %f)], G:[(%f, %f), (%f, %f) ...
+     * (%f, %f)], B:[(%f, %f), (%f, %f) ... (%f, %f)]}"},
+     * where each {@code (%f, %f)} respectively represents one point of the corresponding
+     * tonemap curve. </p>
+     *
+     * @return string representation of {@link TonemapCurve}
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("TonemapCurve{");
+        sb.append("R:");
+        sb.append(curveToString(CHANNEL_RED));
+        sb.append(", G:");
+        sb.append(curveToString(CHANNEL_GREEN));
+        sb.append(", B:");
+        sb.append(curveToString(CHANNEL_BLUE));
+        sb.append("}");
+        return sb.toString();
+    }
+
+    private String curveToString(int colorChannel) {
+        checkArgumentColorChannel(colorChannel);
+        StringBuilder sb = new StringBuilder("[");
+        float[] curve = getCurve(colorChannel);
+        int pointCount = curve.length / POINT_SIZE;
+        for (int i = 0, j = 0; i < pointCount; i++, j += 2) {
+            sb.append("(");
+            sb.append(curve[j]);
+            sb.append(", ");
+            sb.append(curve[j+1]);
+            sb.append("), ");
+        }
+        // trim extra ", " at the end. Guaranteed to work because pointCount >= 2
+        sb.setLength(sb.length() - 2);
+        sb.append("]");
+        return sb.toString();
+    }
+
     private float[] getCurve(int colorChannel) {
         switch (colorChannel) {
             case CHANNEL_RED:
@@ -285,6 +339,8 @@
 
     private final static int OFFSET_POINT_IN = 0;
     private final static int OFFSET_POINT_OUT = 1;
+    private final static int TONEMAP_MIN_CURVE_POINTS = 2;
+    private final static int MIN_CURVE_LENGTH = TONEMAP_MIN_CURVE_POINTS * POINT_SIZE;
 
     private final float[] mRed;
     private final float[] mGreen;
@@ -292,4 +348,4 @@
 
     private int mHashCode;
     private boolean mHashCalculated = false;
-};
+}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index d1ad0ad..5230128 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -236,6 +236,7 @@
     private static final int EX_NULL_POINTER = -4;
     private static final int EX_ILLEGAL_STATE = -5;
     private static final int EX_NETWORK_MAIN_THREAD = -6;
+    private static final int EX_UNSUPPORTED_OPERATION = -7;
     private static final int EX_HAS_REPLY_HEADER = -128;  // special; see below
 
     private static native int nativeDataSize(long nativePtr);
@@ -1427,6 +1428,8 @@
             code = EX_ILLEGAL_STATE;
         } else if (e instanceof NetworkOnMainThreadException) {
             code = EX_NETWORK_MAIN_THREAD;
+        } else if (e instanceof UnsupportedOperationException) {
+            code = EX_UNSUPPORTED_OPERATION;
         }
         writeInt(code);
         StrictMode.clearGatheredViolations();
@@ -1545,6 +1548,8 @@
                 throw new IllegalStateException(msg);
             case EX_NETWORK_MAIN_THREAD:
                 throw new NetworkOnMainThreadException();
+            case EX_UNSUPPORTED_OPERATION:
+                throw new UnsupportedOperationException(msg);
         }
         throw new RuntimeException("Unknown exception code: " + code
                 + " msg " + msg);
diff --git a/core/res/res/layout/action_mode_close_item_material.xml b/core/res/res/layout/action_mode_close_item_material.xml
index 8eb780b..89a1797 100644
--- a/core/res/res/layout/action_mode_close_item_material.xml
+++ b/core/res/res/layout/action_mode_close_item_material.xml
@@ -20,6 +20,7 @@
         android:clickable="true"
         android:paddingStart="8dip"
         android:src="?android:attr/actionModeCloseDrawable"
+        android:contentDescription="@string/action_mode_done"
         style="?android:attr/actionModeCloseButtonStyle"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 438d1fb..0e597d0 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5271,11 +5271,16 @@
         <attr name="viewportWidth" format="float"/>
         <!-- The height of the canvas the drawing is on. -->
         <attr name="viewportHeight" format="float"/>
+        <!-- The name of this vector drawable -->
+        <attr name="name" />
+        <!-- The opacity of the whole vector drawable, as a value between 0
+             (completely transparent) and 1 (completely opaque). -->
+        <attr name="alpha" />
     </declare-styleable>
 
     <!-- Defines the group used in VectorDrawables. -->
     <declare-styleable name="VectorDrawableGroup">
-        <!-- The Name of this group -->
+        <!-- The name of this group -->
         <attr name="name" />
         <!-- The amount to rotate the group -->
         <attr name="rotation" />
@@ -5295,7 +5300,7 @@
 
     <!-- Defines the path used in VectorDrawables. -->
     <declare-styleable name="VectorDrawablePath">
-        <!-- The Name of this path -->
+        <!-- The name of this path -->
         <attr name="name" />
         <!-- The width a path stroke -->
         <attr name="strokeWidth" format="float" />
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 62eb4c8..dd87699 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -256,21 +256,22 @@
         }
 
         if (!mAllowCaching) {
-            mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height());
+            // AnimatedVectorDrawable
+            if (!mVectorState.hasTranslucentRoot()) {
+                mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height());
+            } else {
+                mVectorState.createCachedBitmapIfNeeded(bounds);
+                mVectorState.updateCachedBitmap(bounds);
+                mVectorState.drawCachedBitmapWithRootAlpha(canvas);
+            }
         } else {
-            Bitmap bitmap = mVectorState.mCachedBitmap;
-            if (bitmap == null || !mVectorState.canReuseCache(bounds.width(),
-                    bounds.height())) {
-                bitmap = Bitmap.createBitmap(bounds.width(), bounds.height(),
-                        Bitmap.Config.ARGB_8888);
-                Canvas tmpCanvas = new Canvas(bitmap);
-                mVectorState.mVPathRenderer.draw(tmpCanvas, bounds.width(), bounds.height());
-                mVectorState.mCachedBitmap = bitmap;
-
+            // Static Vector Drawable case.
+            mVectorState.createCachedBitmapIfNeeded(bounds);
+            if (!mVectorState.canReuseCache()) {
+                mVectorState.updateCachedBitmap(bounds);
                 mVectorState.updateCacheStates();
             }
-            // The bitmap's size is the same as the bounds.
-            canvas.drawBitmap(bitmap, 0, 0, null);
+            mVectorState.drawCachedBitmapWithRootAlpha(canvas);
         }
 
         canvas.restoreToCount(saveCount);
@@ -514,6 +515,15 @@
             throw new XmlPullParserException(a.getPositionDescription() +
                     "<vector> tag requires height > 0");
         }
+
+        final float alphaInFloat = a.getFloat(R.styleable.VectorDrawable_alpha,
+                pathRenderer.getAlpha());
+        pathRenderer.setAlpha(alphaInFloat);
+
+        pathRenderer.mRootName = a.getString(R.styleable.VectorDrawable_name);
+        if (pathRenderer.mRootName != null) {
+            pathRenderer.mVGTargetsMap.put(pathRenderer.mRootName, pathRenderer);
+        }
     }
 
     private void inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
@@ -668,15 +678,60 @@
             }
         }
 
-        public boolean canReuseCache(int width, int height) {
+        // TODO: Support colorFilter here.
+        public void drawCachedBitmapWithRootAlpha(Canvas canvas) {
+            Paint alphaPaint = getRootAlphaPaint();
+            // The bitmap's size is the same as the bounds.
+            canvas.drawBitmap(mCachedBitmap, 0, 0, alphaPaint);
+        }
+
+        public boolean hasTranslucentRoot() {
+            return mVPathRenderer.getRootAlpha() < 255;
+        }
+
+        /**
+         * @return null when there is no need for alpha paint.
+         */
+        public Paint getRootAlphaPaint() {
+            Paint paint = null;
+            boolean needsAlphaPaint = hasTranslucentRoot();
+            if (needsAlphaPaint) {
+                paint = new Paint();
+                paint.setAlpha(mVPathRenderer.getRootAlpha());
+            }
+            return paint;
+        }
+
+        public void updateCachedBitmap(Rect bounds) {
+            mCachedBitmap.eraseColor(Color.TRANSPARENT);
+            Canvas tmpCanvas = new Canvas(mCachedBitmap);
+            mVPathRenderer.draw(tmpCanvas, bounds.width(), bounds.height());
+        }
+
+        public void createCachedBitmapIfNeeded(Rect bounds) {
+            if (mCachedBitmap == null || !canReuseBitmap(bounds.width(),
+                    bounds.height())) {
+                mCachedBitmap = Bitmap.createBitmap(bounds.width(), bounds.height(),
+                        Bitmap.Config.ARGB_8888);
+            }
+
+        }
+
+        public boolean canReuseBitmap(int width, int height) {
+            if (width == mCachedBitmap.getWidth()
+                    && height == mCachedBitmap.getHeight()) {
+                return true;
+            }
+            return false;
+        }
+
+        public boolean canReuseCache() {
             if (!mCacheDirty
                     && mCachedThemeAttrs == mThemeAttrs
                     && mCachedTint == mTint
                     && mCachedTintMode == mTintMode
                     && mCachedAutoMirrored == mAutoMirrored
-                    && width == mCachedBitmap.getWidth()
-                    && height == mCachedBitmap.getHeight()
-                    && mCachedRootAlpha == mVPathRenderer.getRootAlpha())  {
+                    && mCachedRootAlpha == mVPathRenderer.getRootAlpha()) {
                 return true;
             }
             return false;
@@ -763,7 +818,8 @@
         float mBaseHeight = 0;
         float mViewportWidth = 0;
         float mViewportHeight = 0;
-        private int mRootAlpha = 0xFF;
+        int mRootAlpha = 0xFF;
+        String mRootName = null;
 
         final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>();
 
@@ -781,6 +837,17 @@
             return mRootAlpha;
         }
 
+        // setAlpha() and getAlpha() are used mostly for animation purpose, since
+        // Animator like to use alpha from 0 to 1.
+        public void setAlpha(float alpha) {
+            setRootAlpha((int) (alpha * 255));
+        }
+
+        @SuppressWarnings("unused")
+        public float getAlpha() {
+            return getRootAlpha() / 255.0f;
+        }
+
         public VPathRenderer(VPathRenderer copy) {
             mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap);
             mPath = new Path(copy.mPath);
@@ -791,6 +858,10 @@
             mViewportHeight = copy.mViewportHeight;
             mChangingConfigurations = copy.mChangingConfigurations;
             mRootAlpha = copy.mRootAlpha;
+            mRootName = copy.mRootName;
+            if (copy.mRootName != null) {
+                mVGTargetsMap.put(copy.mRootName, this);
+            }
         }
 
         public boolean canApplyTheme() {
@@ -894,7 +965,7 @@
         }
 
         private void drawPath(VGroup vGroup, VPath vPath, Canvas canvas, int w, int h) {
-            final float scaleX =  w / mViewportWidth;
+            final float scaleX = w / mViewportWidth;
             final float scaleY = h / mViewportHeight;
             final float minScale = Math.min(scaleX, scaleY);
 
@@ -1256,7 +1327,7 @@
     /**
      * Clip path, which only has name and pathData.
      */
-    private static class VClipPath extends VPath{
+    private static class VClipPath extends VPath {
         public VClipPath() {
             // Empty constructor.
         }
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index e0901d0..f0a2072 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -34,6 +34,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.SystemProperties;
+import android.provider.Settings;
 import android.util.Log;
 
 import com.android.internal.R;
@@ -110,6 +111,9 @@
     // Set to true if the phone is having emergency call.
     private volatile boolean mIsInEmergency;
 
+    // If Location function is enabled.
+    private volatile boolean mIsLocationEnabled = false;
+
     private final INetInitiatedListener mNetInitiatedListener;
 
     // Set to true if string from HAL is encoded as Hex, e.g., "3F0039"
@@ -132,7 +136,7 @@
     };
 
     public static class GpsNiResponse {
-        /* User reponse, one of the values in GpsUserResponseType */
+        /* User response, one of the values in GpsUserResponseType */
         int userResponse;
         /* Optional extra data to pass with the user response */
         Bundle extras;
@@ -154,8 +158,11 @@
                        Emergency call back mode will be checked by reading system properties
                        when necessary: SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)
                 */
-                mIsInEmergency |= PhoneNumberUtils.isEmergencyNumber(phoneNumber);
-                if (DEBUG) Log.v(TAG, "ACTION_NEW_OUTGOING_CALL - " + mIsInEmergency);
+                setInEmergency(PhoneNumberUtils.isEmergencyNumber(phoneNumber));
+                if (DEBUG) Log.v(TAG, "ACTION_NEW_OUTGOING_CALL - " + getInEmergency());
+            } else if (action.equals(LocationManager.MODE_CHANGED_ACTION)) {
+                updateLocationMode();
+                if (DEBUG) Log.d(TAG, "location enabled :" + getLocationEnabled());
             }
         }
     };
@@ -179,8 +186,9 @@
             mNetInitiatedListener = netInitiatedListener;
         }
 
-        mIsSuplEsEnabled = isSuplEsEnabled;
+        setSuplEsEnabled(isSuplEsEnabled);
         mLocationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
+        updateLocationMode();
         mTelephonyManager =
             (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
 
@@ -190,7 +198,7 @@
                 if (DEBUG) Log.d(TAG, "onCallStateChanged(): state is "+ state);
                 // listening for emergency call ends
                 if (state == TelephonyManager.CALL_STATE_IDLE) {
-                    mIsInEmergency = false;
+                    setInEmergency(false);
                 }
             }
         };
@@ -198,27 +206,65 @@
 
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);
+        intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION);
         mContext.registerReceiver(mBroadcastReciever, intentFilter);
     }
 
-    public void setSuplEsEnablement(boolean isEnabled)
-    {
+    public void setSuplEsEnabled(boolean isEnabled) {
         mIsSuplEsEnabled = isEnabled;
     }
 
+    public boolean getSuplEsEnabled() {
+        return mIsSuplEsEnabled;
+    }
+
+    /**
+     * Updates Location enabler based on location setting.
+     */
+    public void updateLocationMode() {
+        mIsLocationEnabled = mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
+    }
+
+    /**
+     * Checks if user agreed to use location.
+     */
+    public boolean getLocationEnabled() {
+        return mIsLocationEnabled;
+    }
+
+    // Note: Currently, there are two mechanisms involved to determine if a
+    // phone is in emergency mode:
+    // 1. If the user is making an emergency call, this is provided by activly
+    //    monitoring the outgoing phone number;
+    // 2. If the device is in a emergency callback state, this is provided by
+    //    system properties.
+    // If either one of above exists, the phone is considered in an emergency
+    // mode. Because of this complexity, we need to be careful about how to set
+    // and clear the emergency state.
+    public void setInEmergency(boolean isInEmergency) {
+        mIsInEmergency = isInEmergency;
+    }
+
+    public boolean getInEmergency() {
+        boolean isInEmergencyCallback = Boolean.parseBoolean(
+                SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE));
+        return mIsInEmergency || isInEmergencyCallback;
+    }
+
+
     // Handles NI events from HAL
-    public void handleNiNotification(GpsNiNotification notif)
-    {
+    public void handleNiNotification(GpsNiNotification notif) {
         if (DEBUG) Log.d(TAG, "in handleNiNotification () :"
                         + " notificationId: " + notif.notificationId
                         + " requestorId: " + notif.requestorId
                         + " text: " + notif.text
-                        + " mIsSuplEsEnabled" + mIsSuplEsEnabled);
+                        + " mIsSuplEsEnabled" + getSuplEsEnabled()
+                        + " mIsLocationEnabled" + getLocationEnabled());
 
-        if (mIsSuplEsEnabled == false) {
-            handleNi(notif);
-        } else {
+        if (getSuplEsEnabled()) {
             handleNiInEs(notif);
+        } else {
+            handleNi(notif);
         }
 
         //////////////////////////////////////////////////////////////////////////
@@ -240,9 +286,18 @@
                         + " needNotify: " + notif.needNotify
                         + " needVerify: " + notif.needVerify
                         + " privacyOverride: " + notif.privacyOverride
-                        + " mPopupImmediately: " + mPopupImmediately);
+                        + " mPopupImmediately: " + mPopupImmediately
+                        + " mInEmergency: " + getInEmergency());
 
-        // legacy behaviour
+        if (getLocationEnabled() && !getInEmergency()) {
+            // Location is currently disabled, ignore all NI requests.
+            try {
+                mNetInitiatedListener.sendNiResponse(notif.notificationId,
+                                                     GPS_NI_RESPONSE_IGNORE);
+            } catch (RemoteException e) {
+                Log.e(TAG, "RemoteException in sendNiResponse");
+            }
+        }
         if (notif.needNotify) {
         // If NI does not need verify or the dialog is not requested
         // to pop up immediately, the dialog box will not pop up.
@@ -274,9 +329,6 @@
                     + " notificationId: " + notif.notificationId);
 
         // UE is in emergency mode when in emergency call mode or in emergency call back mode
-        boolean isUEInEmergencyMode = mIsInEmergency ||
-            Boolean.parseBoolean(SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE));
-
         /*
            1. When SUPL ES bit is off and UE is not in emergency mode:
                   Call handleNi() to do legacy behaviour.
@@ -288,7 +340,7 @@
                   Ignore the emergency SUPL INIT.
         */
         boolean isNiTypeES = (notif.niType == GPS_NI_TYPE_EMERGENCY_SUPL);
-        if (isNiTypeES != isUEInEmergencyMode) {
+        if (isNiTypeES != getInEmergency()) {
             try {
                 mNetInitiatedListener.sendNiResponse(notif.notificationId,
                                                      GPS_NI_RESPONSE_IGNORE);
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index adff596..c7cf61a 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -55,7 +55,8 @@
 
         <service
             android:name=".renderer.PdfManipulationService"
-            android:isolatedProcess="true">
+            android:isolatedProcess="true"
+            android:process=":renderer">
         </service>
 
         <activity
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
index 239f006..429437d 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -135,7 +135,7 @@
     private final DeathRecipient mDeathRecipient = new DeathRecipient() {
         @Override
         public void binderDied() {
-            mAdapterDeathObserver.onDied();
+            notifyPrintingAppDied();
         }
     };
 
@@ -180,7 +180,6 @@
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "Error calling start()", re);
             mState = STATE_FAILED;
-            mAdapterDeathObserver.onDied();
         }
     }
 
@@ -269,7 +268,6 @@
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "Error calling finish()", re);
             mState = STATE_FAILED;
-            mAdapterDeathObserver.onDied();
         }
     }
 
@@ -1108,6 +1106,15 @@
         }
     }
 
+    private void notifyPrintingAppDied() {
+        new Handler(mLooper).post(new Runnable() {
+            @Override
+            public void run() {
+                mAdapterDeathObserver.onDied();
+            }
+        });
+    }
+
     private static final class PrintDocumentAdapterObserver
             extends IPrintDocumentAdapterObserver.Stub {
         private final WeakReference<RemotePrintDocument> mWeakDocument;
@@ -1120,12 +1127,7 @@
         public void onDestroy() {
             final RemotePrintDocument document = mWeakDocument.get();
             if (document != null) {
-                new Handler(document.mLooper).post(new Runnable() {
-                    @Override
-                    public void run() {
-                        document.mAdapterDeathObserver.onDied();
-                    }
-                });
+                document.notifyPrintingAppDied();
             }
         }
     }
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index ef6e07c..c3465d1 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -631,7 +631,7 @@
     @Override
     public int checkPackage(int uid, String packageName) {
         synchronized (this) {
-            if (getOpsLocked(uid, packageName, true) != null) {
+            if (getOpsRawLocked(uid, packageName, true) != null) {
                 return AppOpsManager.MODE_ALLOWED;
             } else {
                 return AppOpsManager.MODE_ERRORED;
@@ -769,6 +769,15 @@
     }
 
     private Ops getOpsLocked(int uid, String packageName, boolean edit) {
+        if (uid == 0) {
+            packageName = "root";
+        } else if (uid == Process.SHELL_UID) {
+            packageName = "com.android.shell";
+        }
+        return getOpsRawLocked(uid, packageName, edit);
+    }
+
+    private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {
         HashMap<String, Ops> pkgOps = mUidOps.get(uid);
         if (pkgOps == null) {
             if (!edit) {
@@ -777,11 +786,6 @@
             pkgOps = new HashMap<String, Ops>();
             mUidOps.put(uid, pkgOps);
         }
-        if (uid == 0) {
-            packageName = "root";
-        } else if (uid == Process.SHELL_UID) {
-            packageName = "com.android.shell";
-        }
         Ops ops = pkgOps.get(packageName);
         if (ops == null) {
             if (!edit) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 75090db..7f104c0 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -251,7 +251,7 @@
 
     private Context mContext;
     private int mNetworkPreference;
-    private int mActiveDefaultNetwork = -1;
+    private int mActiveDefaultNetwork = TYPE_NONE;
     // 0 is full bad, 100 is full good
     private int mDefaultInetConditionPublished = 0;
 
@@ -886,15 +886,6 @@
         return getNetworkInfo(mActiveDefaultNetwork, uid);
     }
 
-    // only called when the default request is satisfied
-    private void updateActiveDefaultNetwork(NetworkAgentInfo nai) {
-        if (nai != null) {
-            mActiveDefaultNetwork = nai.networkInfo.getType();
-        } else {
-            mActiveDefaultNetwork = TYPE_NONE;
-        }
-    }
-
     /**
      * Find the first Provisioning network.
      *
@@ -1936,7 +1927,9 @@
                 case NetworkMonitor.EVENT_NETWORK_VALIDATED: {
                     NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj;
                     if (isLiveNetworkAgent(nai, "EVENT_NETWORK_VALIDATED")) {
-                        handleConnectionValidated(nai);
+                        if (DBG) log("Validated " + nai.name());
+                        nai.validated = true;
+                        rematchNetworkAndRequests(nai);
                     }
                     break;
                 }
@@ -2057,7 +2050,7 @@
                     if (nri.isRequest == false) continue;
                     NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
                     ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK,
-                            (nai != null ? nai.currentScore : 0), 0, nri.request);
+                            (nai != null ? nai.getCurrentScore() : 0), 0, nri.request);
                 }
             } else {
                 loge("Error connecting NetworkFactory");
@@ -2136,7 +2129,7 @@
                                 request.networkCapabilities.satisfiedByNetworkCapabilities(
                                 existing.networkCapabilities) &&
                                 (alternative == null ||
-                                 alternative.currentScore < existing.currentScore)) {
+                                 alternative.getCurrentScore() < existing.getCurrentScore())) {
                             alternative = existing;
                         }
                     }
@@ -2169,8 +2162,9 @@
         for (NetworkAgentInfo network : mNetworkAgentInfos.values()) {
             if (DBG) log("handleRegisterNetworkRequest checking " + network.name());
             if (newCap.satisfiedByNetworkCapabilities(network.networkCapabilities)) {
-                if (DBG) log("apparently satisfied.  currentScore=" + network.currentScore);
-                if ((bestNetwork == null) || bestNetwork.currentScore < network.currentScore) {
+                if (DBG) log("apparently satisfied.  currentScore=" + network.getCurrentScore());
+                if ((bestNetwork == null) ||
+                        bestNetwork.getCurrentScore() < network.getCurrentScore()) {
                     if (!nri.isRequest) {
                         // Not setting bestNetwork here as a listening NetworkRequest may be
                         // satisfied by multiple Networks.  Instead the request is added to
@@ -2194,7 +2188,7 @@
             bestNetwork.addRequest(nri.request);
             mNetworkForRequestId.put(nri.request.requestId, bestNetwork);
             notifyNetworkCallback(bestNetwork, nri);
-            score = bestNetwork.currentScore;
+            score = bestNetwork.getCurrentScore();
             if (nri.request.legacyType != TYPE_NONE) {
                 mLegacyTypeTracker.add(nri.request.legacyType, bestNetwork);
             }
@@ -4516,19 +4510,34 @@
         updateTcpBufferSizes(newNetwork);
     }
 
-    private void handleConnectionValidated(NetworkAgentInfo newNetwork) {
-        if (newNetwork == null) {
-            loge("Unknown NetworkAgentInfo in handleConnectionValidated");
-            return;
-        }
-        if (newNetwork.validated) return;
-        newNetwork.validated = true;
+    // Handles a network appearing or improving its score.
+    //
+    // - Evaluates all current NetworkRequests that can be
+    //   satisfied by newNetwork, and reassigns to newNetwork
+    //   any such requests for which newNetwork is the best.
+    //
+    // - Tears down any Networks that as a result are no longer
+    //   needed. A network is needed if it is the best network for
+    //   one or more NetworkRequests, or if it is a VPN.
+    //
+    // - Tears down newNetwork if it is validated but turns out to be
+    //   unneeded. Does not tear down newNetwork if it is
+    //   unvalidated, because future validation may improve
+    //   newNetwork's score enough that it is needed.
+    //
+    // NOTE: This function only adds NetworkRequests that "newNetwork" could satisfy,
+    // it does not remove NetworkRequests that other Networks could better satisfy.
+    // If you need to handle decreases in score, use {@link rematchAllNetworksAndRequests}.
+    // This function should be used when possible instead of {@code rematchAllNetworksAndRequests}
+    // as it performs better by a factor of the number of Networks.
+    private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork) {
         boolean keep = newNetwork.isVPN();
         boolean isNewDefault = false;
-        if (DBG) log("handleConnectionValidated for "+newNetwork.name());
-        // check if any NetworkRequest wants this NetworkAgent
+        if (DBG) log("rematching " + newNetwork.name());
+        // Find and migrate to this Network any NetworkRequests for
+        // which this network is now the best.
         ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<NetworkAgentInfo>();
-        if (VDBG) log(" new Network has: " + newNetwork.networkCapabilities);
+        if (VDBG) log(" network has: " + newNetwork.networkCapabilities);
         for (NetworkRequestInfo nri : mNetworkRequests.values()) {
             NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
             if (newNetwork == currentNetwork) {
@@ -4543,18 +4552,21 @@
             if (nri.request.networkCapabilities.satisfiedByNetworkCapabilities(
                     newNetwork.networkCapabilities)) {
                 if (!nri.isRequest) {
+                    // This is not a request, it's a callback listener.
+                    // Add it to newNetwork regardless of score.
                     newNetwork.addRequest(nri.request);
                     continue;
                 }
+
                 // next check if it's better than any current network we're using for
                 // this request
                 if (VDBG) {
                     log("currentScore = " +
-                            (currentNetwork != null ? currentNetwork.currentScore : 0) +
-                            ", newScore = " + newNetwork.currentScore);
+                            (currentNetwork != null ? currentNetwork.getCurrentScore() : 0) +
+                            ", newScore = " + newNetwork.getCurrentScore());
                 }
                 if (currentNetwork == null ||
-                        currentNetwork.currentScore < newNetwork.currentScore) {
+                        currentNetwork.getCurrentScore() < newNetwork.getCurrentScore()) {
                     if (currentNetwork != null) {
                         if (DBG) log("   accepting network in place of " + currentNetwork.name());
                         currentNetwork.networkRequests.remove(nri.request.requestId);
@@ -4569,13 +4581,16 @@
                         mLegacyTypeTracker.add(nri.request.legacyType, newNetwork);
                     }
                     keep = true;
+                    // Tell NetworkFactories about the new score, so they can stop
+                    // trying to connect if they know they cannot match it.
                     // TODO - this could get expensive if we have alot of requests for this
                     // network.  Think about if there is a way to reduce this.  Push
                     // netid->request mapping to each factory?
-                    sendUpdatedScoreToFactories(nri.request, newNetwork.currentScore);
+                    sendUpdatedScoreToFactories(nri.request, newNetwork.getCurrentScore());
                     if (mDefaultRequest.requestId == nri.request.requestId) {
                         isNewDefault = true;
-                        updateActiveDefaultNetwork(newNetwork);
+                        // TODO: Remove following line.  It's redundant with makeDefault call.
+                        mActiveDefaultNetwork = newNetwork.networkInfo.getType();
                         if (newNetwork.linkProperties != null) {
                             updateTcpBufferSizes(newNetwork);
                             setDefaultDnsSystemProperties(
@@ -4591,12 +4606,13 @@
                             mLegacyTypeTracker.remove(currentNetwork.networkInfo.getType(),
                                                       currentNetwork);
                         }
-                        mDefaultInetConditionPublished = 100;
+                        mDefaultInetConditionPublished = newNetwork.validated ? 100 : 0;
                         mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
                     }
                 }
             }
         }
+        // Linger any networks that are no longer needed.
         for (NetworkAgentInfo nai : affectedNetworks) {
             boolean teardown = !nai.isVPN();
             for (int i = 0; i < nai.networkRequests.size() && teardown; i++) {
@@ -4624,6 +4640,7 @@
         }
         if (keep) {
             if (isNewDefault) {
+                // Notify system services that this network is up.
                 makeDefault(newNetwork);
                 synchronized (ConnectivityService.this) {
                     // have a new default network, release the transition wakelock in
@@ -4640,6 +4657,7 @@
 
             // Notify battery stats service about this network, both the normal
             // interface and any stacked links.
+            // TODO: Avoid redoing this; this must only be done once when a network comes online.
             try {
                 final IBatteryStats bs = BatteryStatsService.getService();
                 final int type = newNetwork.networkInfo.getType();
@@ -4655,7 +4673,12 @@
             }
 
             notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_AVAILABLE);
-        } else {
+        } else if (newNetwork.validated) {
+            // Only tear down validated networks here.  Leave unvalidated to either become
+            // validated (and get evaluated against peers, one losing here) or
+            // NetworkMonitor reports a bad network and we tear it down then.
+            // TODO: Could teardown unvalidated networks when their NetworkCapabilities
+            // satisfy no NetworkRequests.
             if (DBG && newNetwork.networkRequests.size() != 0) {
                 loge("tearing down network with live requests:");
                 for (int i=0; i < newNetwork.networkRequests.size(); i++) {
@@ -4667,6 +4690,31 @@
         }
     }
 
+    // Attempt to rematch all Networks with NetworkRequests.  This may result in Networks
+    // being disconnected.
+    // If only one Network's score or capabilities have been modified since the last time
+    // this function was called, pass this Network in via the "changed" arugment, otherwise
+    // pass null.
+    // If only one Network has been changed but its NetworkCapabilities have not changed,
+    // pass in the Network's score (from getCurrentScore()) prior to the change via
+    // "oldScore", otherwise pass changed.getCurrentScore() or 0 if "changed" is null.
+    private void rematchAllNetworksAndRequests(NetworkAgentInfo changed, int oldScore) {
+        // TODO: This may get slow.  The "changed" parameter is provided for future optimization
+        // to avoid the slowness.  It is not simply enough to process just "changed", for
+        // example in the case where "changed"'s score decreases and another network should begin
+        // satifying a NetworkRequest that "changed" currently satisfies.
+
+        // Optimization: Only reprocess "changed" if its score improved.  This is safe because it
+        // can only add more NetworkRequests satisfied by "changed", and this is exactly what
+        // rematchNetworkAndRequests() handles.
+        if (changed != null && oldScore < changed.getCurrentScore()) {
+            rematchNetworkAndRequests(changed);
+        } else {
+            for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+                rematchNetworkAndRequests(nai);
+            }
+        }
+    }
 
     private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {
         NetworkInfo.State state = newInfo.getState();
@@ -4721,12 +4769,14 @@
                 }
                 // TODO: support proxy per network.
             }
-            // Make default network if we have no default.  Any network is better than no network.
+            // Consider network even though it is not yet validated.
+            // TODO: All the if-statement conditions can be removed now that validation only confers
+            // a score increase.
             if (mNetworkForRequestId.get(mDefaultRequest.requestId) == null &&
                     networkAgent.isVPN() == false &&
                     mDefaultRequest.networkCapabilities.satisfiedByNetworkCapabilities(
                     networkAgent.networkCapabilities)) {
-                makeDefault(networkAgent);
+                rematchNetworkAndRequests(networkAgent);
             }
         } else if (state == NetworkInfo.State.DISCONNECTED ||
                 state == NetworkInfo.State.SUSPENDED) {
@@ -4752,23 +4802,11 @@
             score = 0;
         }
 
-        nai.currentScore = score;
+        final int oldScore = nai.getCurrentScore();
+        nai.setCurrentScore(score);
 
-        // TODO - This will not do the right thing if this network is lowering
-        // its score and has requests that can be served by other
-        // currently-active networks, or if the network is increasing its
-        // score and other networks have requests that can be better served
-        // by this network.
-        //
-        // Really we want to see if any of our requests migrate to other
-        // active/lingered networks and if any other requests migrate to us (depending
-        // on increasing/decreasing currentScore.  That's a bit of work and probably our
-        // score checking/network allocation code needs to be modularized so we can understand
-        // (see handleConnectionValided for an example).
-        //
-        // As a first order approx, lets just advertise the new score to factories.  If
-        // somebody can beat it they will nominate a network and our normal net replacement
-        // code will fire.
+        if (nai.created) rematchAllNetworksAndRequests(nai, oldScore);
+
         for (int i = 0; i < nai.networkRequests.size(); i++) {
             NetworkRequest nr = nai.networkRequests.valueAt(i);
             // Don't send listening requests to factories. b/17393458
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index 2896f60..6f378fd 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import android.Manifest;
+import android.app.ActivityManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Binder;
@@ -26,7 +27,9 @@
 import android.os.UserHandle;
 import android.service.persistentdata.IPersistentDataBlockService;
 import android.util.Slog;
+
 import com.android.internal.R;
+
 import libcore.io.IoUtils;
 
 import java.io.DataInputStream;
@@ -241,6 +244,10 @@
 
         @Override
         public void setOemUnlockEnabled(boolean enabled) {
+            // do not allow monkey to flip the flag
+            if (ActivityManager.isUserAMonkey()) {
+                return;
+            }
             enforceOemUnlockPermission();
             FileOutputStream outputStream;
             try {
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index bba786d..957d705 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -43,12 +43,16 @@
     public Network network;
     public LinkProperties linkProperties;
     public NetworkCapabilities networkCapabilities;
-    public int currentScore;
     public final NetworkMonitor networkMonitor;
     public final NetworkMisc networkMisc;
     public boolean created;
     public boolean validated;
 
+    // This represents the last score received from the NetworkAgent.
+    private int currentScore;
+    // Penalty applied to scores of Networks that have not been validated.
+    private static final int UNVALIDATED_SCORE_PENALTY = 40;
+
     // The list of NetworkRequests being satisfied by this Network.
     public final SparseArray<NetworkRequest> networkRequests = new SparseArray<NetworkRequest>();
     public final ArrayList<NetworkRequest> networkLingered = new ArrayList<NetworkRequest>();
@@ -80,11 +84,33 @@
         return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
     }
 
+    // Get the current score for this Network.  This may be modified from what the
+    // NetworkAgent sent, as it has modifiers applied to it.
+    public int getCurrentScore() {
+        // TODO: We may want to refactor this into a NetworkScore class that takes a base score from
+        // the NetworkAgent and signals from the NetworkAgent and uses those signals to modify the
+        // score.  The NetworkScore class would provide a nice place to centralize score constants
+        // so they are not scattered about the transports.
+
+        int score = currentScore;
+
+        if (!validated) score -= UNVALIDATED_SCORE_PENALTY;
+
+        if (score < 0) score = 0;
+
+        return score;
+    }
+
+    public void setCurrentScore(int newScore) {
+        currentScore = newScore;
+    }
+
     public String toString() {
         return "NetworkAgentInfo{ ni{" + networkInfo + "}  network{" +
                 network + "}  lp{" +
                 linkProperties + "}  nc{" +
-                networkCapabilities + "}  Score{" + currentScore + "} }";
+                networkCapabilities + "}  Score{" + getCurrentScore() + "} " +
+                "validated{" + validated + "} created{" + created + "} }";
     }
 
     public String name() {
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index 11818d8..df846a8 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -494,7 +494,7 @@
                     Log.d(TAG, "SIM STATE is ready, SIM MCC/MNC is " + mccMnc);
                     synchronized (mLock) {
                         reloadGpsProperties(context, mProperties);
-                        mNIHandler.setSuplEsEnablement(mSuplEsEnabled);
+                        mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
                     }
                 }
             }
@@ -590,6 +590,7 @@
                 com.android.internal.R.array.config_gpsParameters);
         for (String item : configValues) {
             Log.d(TAG, "GpsParamsResource: " + item);
+            // We need to support "KEY =", but not "=VALUE".
             String[] split = item.split("=");
             if (split.length == 2) {
                 properties.setProperty(split[0].trim().toUpperCase(), split[1]);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index efaf253..95332bc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3716,7 +3716,7 @@
         synchronized (this) {
             // Only SYSTEM_UID can override the userSetupComplete
             if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID
-                    && isUserSetupComplete(userHandle)) {
+                    && hasUserSetupCompleted(userHandle)) {
                 throw new IllegalStateException(
                         "Trying to set profile owner but user is already set-up.");
             }
@@ -3773,10 +3773,14 @@
 
     @Override
     public boolean hasUserSetupCompleted() {
+        return hasUserSetupCompleted(UserHandle.getCallingUserId());
+    }
+
+    private boolean hasUserSetupCompleted(int userHandle) {
         if (!mHasFeature) {
             return true;
         }
-        DevicePolicyData policy = getUserData(UserHandle.getCallingUserId());
+        DevicePolicyData policy = getUserData(userHandle);
         // If policy is null, return true, else check if the setup has completed.
         return policy == null || policy.mUserSetupComplete;
     }
@@ -3888,16 +3892,10 @@
         if (callingId == Process.SHELL_UID || callingId == Process.ROOT_UID) {
             return AccountManager.get(mContext).getAccounts().length == 0;
         } else {
-            return Settings.Global.getInt(mContext.getContentResolver(),
-                    Settings.Global.DEVICE_PROVISIONED, 0) == 0;
+            return !hasUserSetupCompleted(UserHandle.USER_OWNER);
         }
     }
 
-    private boolean isUserSetupComplete(int userId) {
-        return Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                Settings.Secure.USER_SETUP_COMPLETE, 0, userId) > 0;
-    }
-
     private void enforceCrossUserPermission(int userHandle) {
         if (userHandle < 0) {
             throw new IllegalArgumentException("Invalid userId " + userHandle);
diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation06.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation06.xml
new file mode 100644
index 0000000..1a81866
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/trim_path_animation06.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <objectAnimator
+        android:duration="9000"
+        android:propertyName="alpha"
+        android:valueFrom="1.0"
+        android:valueTo="0.0"/>
+
+</set>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
index 19b82ad..8b0ceda 100644
--- a/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
+++ b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
@@ -37,5 +37,8 @@
     <target
         android:name="rotationGroup"
         android:animation="@anim/trim_path_animation04" />
+    <target
+        android:name="rootGroup"
+        android:animation="@anim/trim_path_animation06" />
 
 </animated-vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
index 2c8b751..69ae62c 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
@@ -14,10 +14,12 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:name="rootGroup"
         android:height="64dp"
         android:width="64dp"
         android:viewportHeight="600"
-        android:viewportWidth="600" >
+        android:viewportWidth="600"
+        android:alpha="0.5" >
 
     <group
         android:name="rotationGroup"
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
index f165cde..05bf166 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
@@ -31,6 +31,8 @@
             R.drawable.animation_vector_progress_bar,
             R.drawable.animation_vector_drawable_favorite,
             R.drawable.animation_vector_drawable01,
+            // Duplicate to test constant state.
+            R.drawable.animation_vector_drawable01,
     };
 
     @Override