Merge "QS: Fix NPE path inside cell tile." into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index 0d1cee4..42eaef0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5499,7 +5499,7 @@
     method public void uninstallCaCert(android.content.ComponentName, byte[]);
     method public void wipeData(int);
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
-    field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.ACTION_PROVISION_MANAGED_PROFILE";
+    field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
     field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
     field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
     field public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2
@@ -5512,7 +5512,7 @@
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
-    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.deviceAdminPackageName";
+    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
     field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
@@ -14075,29 +14075,6 @@
     method public android.media.AudioAttributes.Builder setUsage(int);
   }
 
-  public class AudioDevice {
-    field public static final int DEVICE_TYPE_AUX_LINE = 19; // 0x13
-    field public static final int DEVICE_TYPE_BLUETOOTH_A2DP = 8; // 0x8
-    field public static final int DEVICE_TYPE_BLUETOOTH_SCO = 7; // 0x7
-    field public static final int DEVICE_TYPE_BUILTIN_EARPIECE = 1; // 0x1
-    field public static final int DEVICE_TYPE_BUILTIN_MIC = 15; // 0xf
-    field public static final int DEVICE_TYPE_BUILTIN_SPEAKER = 2; // 0x2
-    field public static final int DEVICE_TYPE_DOCK = 13; // 0xd
-    field public static final int DEVICE_TYPE_FM = 14; // 0xe
-    field public static final int DEVICE_TYPE_FM_TUNER = 16; // 0x10
-    field public static final int DEVICE_TYPE_HDMI = 9; // 0x9
-    field public static final int DEVICE_TYPE_HDMI_ARC = 10; // 0xa
-    field public static final int DEVICE_TYPE_LINE_ANALOG = 5; // 0x5
-    field public static final int DEVICE_TYPE_LINE_DIGITAL = 6; // 0x6
-    field public static final int DEVICE_TYPE_TELEPHONY = 18; // 0x12
-    field public static final int DEVICE_TYPE_TV_TUNER = 17; // 0x11
-    field public static final int DEVICE_TYPE_UNKNOWN = 0; // 0x0
-    field public static final int DEVICE_TYPE_USB_ACCESSORY = 12; // 0xc
-    field public static final int DEVICE_TYPE_USB_DEVICE = 11; // 0xb
-    field public static final int DEVICE_TYPE_WIRED_HEADPHONES = 4; // 0x4
-    field public static final int DEVICE_TYPE_WIRED_HEADSET = 3; // 0x3
-  }
-
   public class AudioFormat {
     method public int getChannelMask();
     method public int getEncoding();
@@ -16190,12 +16167,16 @@
     method public short getRoundedStrength() throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
     method public boolean getSpeakerAngles(int, int, int[]) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
     method public boolean getStrengthSupported();
-    method public int getVirtualizationMode() throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
+    method public int getVirtualizationMode() throws java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
     method public void setParameterListener(android.media.audiofx.Virtualizer.OnParameterChangeListener);
     method public void setProperties(android.media.audiofx.Virtualizer.Settings) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
     method public void setStrength(short) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
     field public static final int PARAM_STRENGTH = 1; // 0x1
     field public static final int PARAM_STRENGTH_SUPPORTED = 0; // 0x0
+    field public static final int VIRTUALIZATION_MODE_AUTO = 1; // 0x1
+    field public static final int VIRTUALIZATION_MODE_BINAURAL = 2; // 0x2
+    field public static final int VIRTUALIZATION_MODE_OFF = 0; // 0x0
+    field public static final int VIRTUALIZATION_MODE_TRANSAURAL = 3; // 0x3
   }
 
   public static abstract interface Virtualizer.OnParameterChangeListener {
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 7c13dbe..0aa8fdd 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -636,6 +636,7 @@
         anim.mNodes = new ArrayList<Node>();
         anim.mSortedNodes = new ArrayList<Node>();
         anim.mReversible = mReversible;
+        anim.mSetListener = null;
 
         // Walk through the old nodes list, cloning each node and adding it to the new nodemap.
         // One problem is that the old node dependencies point to nodes in the old AnimatorSet.
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 394b183..677fcef 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2295,6 +2295,13 @@
             reply.writeNoException();
             return true;
         }
+
+        case BOOT_ANIMATION_COMPLETE_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            bootAnimationComplete();
+            reply.writeNoException();
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -5301,5 +5308,16 @@
         reply.recycle();
     }
 
+    @Override
+    public void bootAnimationComplete() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(BOOT_ANIMATION_COMPLETE_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 8227915..b09f169 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -38,7 +38,6 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Collection;
 
 final class BackStackState implements Parcelable {
     final int[] mOps;
@@ -745,13 +744,8 @@
 
         SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
         SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
-
         calculateFragments(firstOutFragments, lastInFragments);
-
-        TransitionState state = null;
-        if (firstOutFragments.size() != 0 || lastInFragments.size() != 0) {
-            state = beginTransition(firstOutFragments, lastInFragments, false);
-        }
+        beginTransition(firstOutFragments, lastInFragments, false);
 
         Op op = mHead;
         while (op != null) {
@@ -842,10 +836,6 @@
         if (mAddToBackStack) {
             mManager.addBackStackState(this);
         }
-
-        if (state != null) {
-            updateTransitionEndState(state, firstOutFragments, lastInFragments, false);
-        }
     }
 
     private static void setFirstOut(SparseArray<Fragment> fragments, Fragment fragment) {
@@ -920,43 +910,6 @@
 
             op = op.next;
         }
-
-        if (!haveTransitions(firstOutFragments, lastInFragments, false)) {
-            firstOutFragments.clear();
-            lastInFragments.clear();
-        }
-    }
-
-    /**
-     * @return true if custom transitions exist on any fragment in firstOutFragments or
-     * lastInFragments or false otherwise.
-     */
-    private static boolean haveTransitions(SparseArray<Fragment> firstOutFragments,
-            SparseArray<Fragment> lastInFragments, boolean isBack) {
-        for (int i = firstOutFragments.size() - 1; i >= 0; i--) {
-            Fragment f = firstOutFragments.valueAt(i);
-            if (isBack) {
-                if (f.getReturnTransition() != null ||
-                        f.getSharedElementReturnTransition() != null) {
-                    return true;
-                }
-            } else if (f.getExitTransition() != null) {
-                return true;
-            }
-        }
-
-        for (int i = lastInFragments.size() - 1; i >= 0; i--) {
-            Fragment f = lastInFragments.valueAt(i);
-            if (isBack) {
-                if (f.getReenterTransition() != null) {
-                    return true;
-                }
-            } else if (f.getEnterTransition() != null ||
-                    f.getSharedElementEnterTransition() != null) {
-                return true;
-            }
-        }
-        return false;
     }
 
     /**
@@ -1003,11 +956,6 @@
 
             op = op.next;
         }
-
-        if (!haveTransitions(firstOutFragments, lastInFragments, true)) {
-            firstOutFragments.clear();
-            lastInFragments.clear();
-        }
     }
 
     /**
@@ -1038,8 +986,8 @@
      * @param isBack true if this is popping the back stack or false if this is a
      *               forward operation.
      * @return The TransitionState used to complete the operation of the transition
-     * in {@link #updateTransitionEndState(android.app.BackStackRecord.TransitionState,
-     * android.util.SparseArray, android.util.SparseArray, boolean)}.
+     * in {@link #setNameOverrides(android.app.BackStackRecord.TransitionState, java.util.ArrayList,
+     * java.util.ArrayList)}.
      */
     private TransitionState beginTransition(SparseArray<Fragment> firstOutFragments,
             SparseArray<Fragment> lastInFragments, boolean isBack) {
@@ -1050,16 +998,11 @@
         // add any, then no views will be targeted.
         state.nonExistentView = new View(mManager.mActivity);
 
-        ArrayMap<String, View> tempViews1 = new ArrayMap<String, View>();
-        ArrayMap<String, View> tempViews2 = new ArrayMap<String, View>();
-        ArrayList<String> tempNames = new ArrayList<String>();
-        ArrayList<View> tempViewList = new ArrayList<View>();
-
         // Go over all leaving fragments.
         for (int i = 0; i < firstOutFragments.size(); i++) {
             int containerId = firstOutFragments.keyAt(i);
             configureTransitions(containerId, state, isBack, firstOutFragments,
-                    lastInFragments, tempViews1, tempViews2, tempNames, tempViewList);
+                    lastInFragments);
         }
 
         // Now go over all entering fragments that didn't have a leaving fragment.
@@ -1067,28 +1010,33 @@
             int containerId = lastInFragments.keyAt(i);
             if (firstOutFragments.get(containerId) == null) {
                 configureTransitions(containerId, state, isBack, firstOutFragments,
-                        lastInFragments, tempViews1, tempViews2, tempNames, tempViewList);
+                        lastInFragments);
             }
         }
-
-        if (state.overallTransitions.size() == 0) {
-            state = null;
-        }
         return state;
     }
 
+    private static Transition cloneTransition(Transition transition) {
+        if (transition != null) {
+            transition = transition.clone();
+        }
+        return transition;
+    }
+
     private static Transition getEnterTransition(Fragment inFragment, boolean isBack) {
         if (inFragment == null) {
             return null;
         }
-        return isBack ? inFragment.getReenterTransition() : inFragment.getEnterTransition();
+        return cloneTransition(isBack ? inFragment.getReenterTransition() :
+                inFragment.getEnterTransition());
     }
 
     private static Transition getExitTransition(Fragment outFragment, boolean isBack) {
         if (outFragment == null) {
             return null;
         }
-        return isBack ? outFragment.getReturnTransition() : outFragment.getExitTransition();
+        return cloneTransition(isBack ? outFragment.getReturnTransition() :
+                outFragment.getExitTransition());
     }
 
     private static Transition getSharedElementTransition(Fragment inFragment, Fragment outFragment,
@@ -1096,34 +1044,32 @@
         if (inFragment == null || outFragment == null) {
             return null;
         }
-        return isBack ? outFragment.getSharedElementReturnTransition() :
-                inFragment.getSharedElementEnterTransition();
+        return cloneTransition(isBack ? outFragment.getSharedElementReturnTransition() :
+                inFragment.getSharedElementEnterTransition());
     }
 
-    private static Transition captureExitingViews(Transition exitTransition, Fragment outFragment,
-            ArrayList<View> viewList) {
+    private static ArrayList<View> captureExitingViews(Transition exitTransition,
+            Fragment outFragment) {
+        ArrayList<View> viewList = null;
         if (exitTransition != null) {
+            viewList = new ArrayList<View>();
             View root = outFragment.getView();
-            viewList.clear();
             root.captureTransitioningViews(viewList);
-            if (viewList.isEmpty()) {
-                exitTransition = null;
-            } else {
-                addTransitioningViews(exitTransition, viewList);
-            }
+            addTargets(exitTransition, viewList);
         }
-        return exitTransition;
+        return viewList;
     }
 
     private ArrayMap<String, View> remapSharedElements(TransitionState state, Fragment outFragment,
-            ArrayMap<String, View> namedViews, ArrayMap<String, View> tempViews2, boolean isBack) {
+            boolean isBack) {
+        ArrayMap<String, View> namedViews = new ArrayMap<String, View>();
         if (mSharedElementSourceNames != null) {
             outFragment.getView().findNamedViews(namedViews);
             if (isBack) {
                 namedViews.retainAll(mSharedElementTargetNames);
             } else {
                 namedViews = remapNames(mSharedElementSourceNames, mSharedElementTargetNames,
-                        namedViews, tempViews2);
+                        namedViews);
             }
         }
 
@@ -1147,41 +1093,94 @@
      * We will add to the views before the end state of the transition is captured so that the
      * views will appear. At the start of the transition, we clear the list of targets so that
      * we can restore the state of the transition and use it again.
+     *
+     * <p>The shared element transition maps its shared elements immediately prior to
+     * capturing the final state of the Transition.</p>
      */
-    private void prepareEnterTransition(TransitionState state, final Transition enterTransition,
-            final View container, final Fragment inFragment) {
-        if (enterTransition != null) {
-            final ArrayList<View> enteringViews = new ArrayList<View>();
-            final View nonExistentView = state.nonExistentView;
-            enterTransition.addTarget(state.nonExistentView);
-            enterTransition.addListener(new Transition.TransitionListenerAdapter() {
-                @Override
-                public void onTransitionStart(Transition transition) {
-                    transition.removeListener(this);
-                    transition.removeTarget(nonExistentView);
-                    int numViews = enteringViews.size();
-                    for (int i = 0; i < numViews; i++) {
-                        transition.removeTarget(enteringViews.get(i));
-                    }
-                }
-            });
-            container.getViewTreeObserver().addOnPreDrawListener(
-                    new ViewTreeObserver.OnPreDrawListener() {
-                        @Override
-                        public boolean onPreDraw() {
-                            container.getViewTreeObserver().removeOnPreDrawListener(this);
+    private ArrayList<View> addTransitionTargets(final TransitionState state,
+            final Transition enterTransition, final Transition sharedElementTransition,
+            final Transition overallTransition, final View container,
+            final Fragment inFragment, final Fragment outFragment,
+            final ArrayList<View> hiddenFragmentViews, final boolean isBack) {
+        if (enterTransition == null && sharedElementTransition == null &&
+                overallTransition == null) {
+            return null;
+        }
+        final ArrayList<View> enteringViews = new ArrayList<View>();
+        container.getViewTreeObserver().addOnPreDrawListener(
+                new ViewTreeObserver.OnPreDrawListener() {
+                    @Override
+                    public boolean onPreDraw() {
+                        container.getViewTreeObserver().removeOnPreDrawListener(this);
+
+                        // Don't include any newly-hidden fragments in the transition.
+                        excludeHiddenFragments(hiddenFragmentViews, inFragment.mContainerId,
+                                overallTransition);
+
+                        if (sharedElementTransition != null) {
+                            ArrayMap<String, View> namedViews = mapSharedElementsIn(
+                                    state, isBack, inFragment);
+
+                            setEpicenterIn(namedViews, state);
+
+                            callSharedElementEnd(state, inFragment, outFragment, isBack,
+                                    namedViews);
+                        }
+
+                        if (enterTransition != null) {
                             View view = inFragment.getView();
                             if (view != null) {
                                 view.captureTransitioningViews(enteringViews);
-                                addTransitioningViews(enterTransition, enteringViews);
+                                addTargets(enterTransition, enteringViews);
                             }
-                            return true;
+                            setSharedElementEpicenter(enterTransition, state);
                         }
-                    });
-            setSharedElementEpicenter(enterTransition, state);
+                        return true;
+                    }
+                });
+        return enteringViews;
+    }
+
+    private void callSharedElementEnd(TransitionState state, Fragment inFragment,
+            Fragment outFragment, boolean isBack, ArrayMap<String, View> namedViews) {
+        SharedElementCallback sharedElementCallback = isBack ?
+                outFragment.mEnterTransitionCallback :
+                inFragment.mEnterTransitionCallback;
+        ArrayList<String> names = new ArrayList<String>(namedViews.keySet());
+        ArrayList<View> views = new ArrayList<View>(namedViews.values());
+        sharedElementCallback.onSharedElementEnd(names, views, null);
+    }
+
+    private void setEpicenterIn(ArrayMap<String, View> namedViews, TransitionState state) {
+        if (mSharedElementTargetNames != null && !namedViews.isEmpty()) {
+            // now we know the epicenter of the entering transition.
+            View epicenter = namedViews
+                    .get(mSharedElementTargetNames.get(0));
+            if (epicenter != null) {
+                state.enteringEpicenterView = epicenter;
+            }
         }
     }
 
+    private ArrayMap<String, View> mapSharedElementsIn(TransitionState state,
+            boolean isBack, Fragment inFragment) {
+        // Now map the shared elements in the incoming fragment
+        ArrayMap<String, View> namedViews = mapEnteringSharedElements(state, inFragment, isBack);
+
+        // remap shared elements and set the name mapping used
+        // in the shared element transition.
+        if (isBack) {
+            inFragment.mExitTransitionCallback.onMapSharedElements(
+                    mSharedElementTargetNames, namedViews);
+            setBackNameOverrides(state, namedViews, true);
+        } else {
+            inFragment.mEnterTransitionCallback.onMapSharedElements(
+                    mSharedElementTargetNames, namedViews);
+            setNameOverrides(state, namedViews, true);
+        }
+        return namedViews;
+    }
+
     private static Transition mergeTransitions(Transition enterTransition,
             Transition exitTransition, Transition sharedElementTransition, Fragment inFragment,
             boolean isBack) {
@@ -1209,26 +1208,16 @@
      * Configures custom transitions for a specific fragment container.
      *
      * @param containerId The container ID of the fragments to configure the transition for.
-     * @param state The Transition State to be shared with {@link #updateTransitionEndState(
-     * android.app.BackStackRecord.TransitionState, android.util.SparseArray,
-     * android.util.SparseArray, boolean)} later.
+     * @param state The Transition State keeping track of the executing transitions.
      * @param firstOutFragments The list of first fragments to be removed, keyed on the
      *                          container ID.
      * @param lastInFragments The list of last fragments to be added, keyed on the
      *                        container ID.
      * @param isBack true if this is popping the back stack or false if this is a
      *               forward operation.
-     * @param tempViews1 A temporary mapping of names to Views, used to avoid allocation
-     *                   inside a loop.
-     * @param tempViews2 A temporary mapping of names to Views, used to avoid allocation
-     *                   inside a loop.
-     * @param tempNames  A temporary list of Strings, used to avoid allocation inside a loop.
-     * @param tempViewList A temporary list of Views, used to avoid allocation inside a loop.
      */
     private void configureTransitions(int containerId, TransitionState state, boolean isBack,
-            SparseArray<Fragment> firstOutFragments, SparseArray<Fragment> lastInFragments,
-            ArrayMap<String, View> tempViews1, ArrayMap<String, View> tempViews2,
-            ArrayList<String> tempNames, ArrayList<View> tempViewList) {
+            SparseArray<Fragment> firstOutFragments, SparseArray<Fragment> lastInFragments) {
         ViewGroup sceneRoot = (ViewGroup) mManager.mContainer.findViewById(containerId);
         if (sceneRoot != null) {
             Fragment inFragment = lastInFragments.get(containerId);
@@ -1238,146 +1227,150 @@
             Transition sharedElementTransition = getSharedElementTransition(inFragment, outFragment,
                     isBack);
             Transition exitTransition = getExitTransition(outFragment, isBack);
-            exitTransition = captureExitingViews(exitTransition, outFragment, tempViewList);
 
-            ArrayMap<String, View> namedViews = tempViews1;
-            namedViews.clear();
-            if (sharedElementTransition != null) {
-                namedViews = remapSharedElements(state,
-                        outFragment, namedViews, tempViews2, isBack);
+            if (enterTransition == null && sharedElementTransition == null &&
+                    exitTransition == null) {
+                return; // no transitions!
+            }
+            ArrayList<View> exitingViews = captureExitingViews(exitTransition, outFragment);
+            if (exitingViews == null || exitingViews.isEmpty()) {
+                exitTransition = null;
             }
 
-            // Notify the start of the transition.
-            SharedElementCallback callback = isBack ?
-                    outFragment.mEnterTransitionCallback :
-                    inFragment.mEnterTransitionCallback;
-            tempNames.clear();
-            tempNames.addAll(namedViews.keySet());
-            tempViewList.clear();
-            tempViewList.addAll(namedViews.values());
-            callback.onSharedElementStart(tempNames, tempViewList, null);
+            ArrayMap<String, View> namedViews = null;
+            if (sharedElementTransition != null) {
+                namedViews = remapSharedElements(state, outFragment, isBack);
+
+                // Notify the start of the transition.
+                SharedElementCallback callback = isBack ?
+                        outFragment.mEnterTransitionCallback :
+                        inFragment.mEnterTransitionCallback;
+                ArrayList<String> names = new ArrayList<String>(namedViews.keySet());
+                ArrayList<View> views = new ArrayList<View>(namedViews.values());
+                callback.onSharedElementStart(names, views, null);
+            }
 
             // Set the epicenter of the exit transition
-            if (mSharedElementTargetNames != null && exitTransition != null) {
+            if (mSharedElementTargetNames != null && exitTransition != null && namedViews != null) {
                 View epicenterView = namedViews.get(mSharedElementTargetNames.get(0));
                 if (epicenterView != null) {
                     setEpicenter(exitTransition, epicenterView);
                 }
             }
 
-            prepareEnterTransition(state, enterTransition, sceneRoot, inFragment);
-
             Transition transition = mergeTransitions(enterTransition, exitTransition,
                     sharedElementTransition, inFragment, isBack);
 
             if (transition != null) {
-                state.overallTransitions.put(containerId, transition);
+                ArrayList<View> hiddenFragments = new ArrayList<View>();
+                ArrayList<View> enteringViews = addTransitionTargets(state, enterTransition,
+                        sharedElementTransition, transition, sceneRoot, inFragment, outFragment,
+                        hiddenFragments, isBack);
+
                 transition.setNameOverrides(state.nameOverrides);
                 // We want to exclude hidden views later, so we need a non-null list in the
                 // transition now.
                 transition.excludeTarget(state.nonExistentView, true);
                 // Now exclude all currently hidden fragments.
-                excludeHiddenFragments(state, containerId, transition);
-                cleanupHiddenFragments(transition, state);
+                excludeHiddenFragments(hiddenFragments, containerId, transition);
                 TransitionManager.beginDelayedTransition(sceneRoot, transition);
+                // Remove the view targeting after the transition starts
+                removeTargetedViewsFromTransitions(sceneRoot, state.nonExistentView,
+                        enterTransition, enteringViews, exitTransition, exitingViews,
+                        transition, hiddenFragments);
             }
         }
     }
 
     /**
+     * After the transition has started, remove all targets that we added to the transitions
+     * so that the transitions are left in a clean state.
+     */
+    private void removeTargetedViewsFromTransitions(
+            final ViewGroup sceneRoot, final View nonExistingView,
+            final Transition enterTransition, final ArrayList<View> enteringViews,
+            final Transition exitTransition, final ArrayList<View> exitingViews,
+            final Transition overallTransition, final ArrayList<View> hiddenViews) {
+        if (enterTransition != null || exitTransition != null) {
+            sceneRoot.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+                @Override
+                public boolean onPreDraw() {
+                    sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
+                    if (enterTransition != null) {
+                        enterTransition.removeTarget(nonExistingView);
+                        removeTargets(enterTransition, enteringViews);
+                    }
+                    if (exitTransition != null) {
+                        removeTargets(exitTransition, exitingViews);
+                    }
+                    int numViews = hiddenViews.size();
+                    for (int i = 0; i < numViews; i++) {
+                        overallTransition.excludeTarget(hiddenViews.get(i), false);
+                    }
+                    overallTransition.excludeTarget(nonExistingView, false);
+                    return true;
+                }
+            });
+        }
+    }
+
+    private static void removeTargets(Transition transition, ArrayList<View> views) {
+        int numViews = views.size();
+        for (int i = 0; i < numViews; i++) {
+            transition.removeTarget(views.get(i));
+        }
+    }
+
+    private static void addTargets(Transition transition, ArrayList<View> views) {
+        int numViews = views.size();
+        for (int i = 0; i < numViews; i++) {
+            transition.addTarget(views.get(i));
+        }
+    }
+
+    /**
      * Remaps a name-to-View map, substituting different names for keys.
      *
      * @param inMap A list of keys found in the map, in the order in toGoInMap
      * @param toGoInMap A list of keys to use for the new map, in the order of inMap
      * @param namedViews The current mapping
-     * @param tempMap A temporary mapping that will be filled with the new values.
-     * @return tempMap after it has been mapped with the new names as keys.
+     * @return a new Map after it has been mapped with the new names as keys.
      */
     private static ArrayMap<String, View> remapNames(ArrayList<String> inMap,
-            ArrayList<String> toGoInMap, ArrayMap<String, View> namedViews,
-            ArrayMap<String, View> tempMap) {
-        tempMap.clear();
+            ArrayList<String> toGoInMap, ArrayMap<String, View> namedViews) {
+        ArrayMap<String, View> remappedViews = new ArrayMap<String, View>();
         if (!namedViews.isEmpty()) {
             int numKeys = inMap.size();
             for (int i = 0; i < numKeys; i++) {
                 View view = namedViews.get(inMap.get(i));
+
                 if (view != null) {
-                    tempMap.put(toGoInMap.get(i), view);
+                    remappedViews.put(toGoInMap.get(i), view);
                 }
             }
         }
-        return tempMap;
+        return remappedViews;
     }
 
     /**
-     * After making all fragment changes, this updates the custom transitions to take into
-     * account the entering views and any remapping.
+     * Maps shared elements to views in the entering fragment.
      *
      * @param state The transition State as returned from {@link #beginTransition(
      * android.util.SparseArray, android.util.SparseArray, boolean)}.
-     * @param outFragments The list of first fragments to be removed, keyed on the
-     *                     container ID.
-     * @param inFragments The list of last fragments to be added, keyed on the
-     *                    container ID.
+     * @param inFragment The last fragment to be added.
      * @param isBack true if this is popping the back stack or false if this is a
      *               forward operation.
      */
-    private void updateTransitionEndState(TransitionState state, SparseArray<Fragment> outFragments,
-            SparseArray<Fragment> inFragments, boolean isBack) {
-        ArrayMap<String, View> tempViews1 = new ArrayMap<String, View>();
-        ArrayMap<String, View> tempViews2 = new ArrayMap<String, View>();
-        ArrayList<String> tempNames = new ArrayList<String>();
-        ArrayList<View> tempViews = new ArrayList<View>();
-
-        int numInFragments = inFragments.size();
-        for (int i = 0; i < numInFragments; i++) {
-            Fragment inFragment = inFragments.valueAt(i);
-            tempViews1.clear();
-            ArrayMap<String, View> namedViews = mapEnteringSharedElements(inFragment, tempViews1,
-                    tempViews2, isBack);
-            // remap shared elements and set the name mapping used in the shared element transition.
-            if (isBack) {
-                inFragment.mExitTransitionCallback.onMapSharedElements(
-                        mSharedElementTargetNames, namedViews);
-                setBackNameOverrides(state, namedViews, true);
-            } else {
-                inFragment.mEnterTransitionCallback.onMapSharedElements(
-                        mSharedElementTargetNames, namedViews);
-                setNameOverrides(state, namedViews, true);
-            }
-
-            if (mSharedElementTargetNames != null && !namedViews.isEmpty()) {
-                // now we know the epicenter of the entering transition.
-                View epicenter = namedViews.get(mSharedElementTargetNames.get(0));
-                if (epicenter != null) {
-                    state.enteringEpicenterView = epicenter;
-                }
-            }
-
-            int containerId = inFragments.keyAt(i);
-            SharedElementCallback sharedElementCallback = isBack ?
-                    outFragments.get(containerId).mEnterTransitionCallback :
-                    inFragment.mEnterTransitionCallback;
-            tempNames.clear();
-            tempNames.addAll(namedViews.keySet());
-            tempViews.clear();
-            tempViews.addAll(namedViews.values());
-            sharedElementCallback.onSharedElementEnd(tempNames, tempViews, null);
-        }
-
-        // Don't include any newly-hidden fragments in the transition.
-        excludeHiddenFragments(state);
-    }
-
-    private ArrayMap<String, View> mapEnteringSharedElements(Fragment inFragment,
-            ArrayMap<String, View> namedViews, ArrayMap<String, View> tempViews2, boolean isBack) {
+    private ArrayMap<String, View> mapEnteringSharedElements(TransitionState state,
+            Fragment inFragment, boolean isBack) {
+        ArrayMap<String, View> namedViews = new ArrayMap<String, View>();
         View root = inFragment.getView();
         if (root != null) {
             if (mSharedElementSourceNames != null) {
                 root.findNamedViews(namedViews);
                 if (isBack) {
                     namedViews = remapNames(mSharedElementSourceNames,
-                            mSharedElementTargetNames, namedViews, tempViews2);
+                            mSharedElementTargetNames, namedViews);
                 } else {
                     namedViews.retainAll(mSharedElementTargetNames);
                 }
@@ -1386,21 +1379,7 @@
         return namedViews;
     }
 
-    private static void cleanupHiddenFragments(Transition transition, TransitionState state) {
-        final ArrayList<View> hiddenViews = state.hiddenFragmentViews;
-        transition.addListener(new Transition.TransitionListenerAdapter() {
-            @Override
-            public void onTransitionStart(Transition transition) {
-                transition.removeListener(this);
-                int numViews = hiddenViews.size();
-                for (int i = 0; i < numViews; i++) {
-                    transition.excludeTarget(hiddenViews.get(i), false);
-                }
-            }
-        });
-    }
-
-    private void excludeHiddenFragments(TransitionState state, int containerId,
+    private void excludeHiddenFragments(final ArrayList<View> hiddenFragmentViews, int containerId,
             Transition transition) {
         if (mManager.mAdded != null) {
             for (int i = 0; i < mManager.mAdded.size(); i++) {
@@ -1408,44 +1387,19 @@
                 if (fragment.mView != null && fragment.mContainer != null &&
                         fragment.mContainerId == containerId) {
                     if (fragment.mHidden) {
-                        if (!state.hiddenFragmentViews.contains(fragment.mView)) {
+                        if (!hiddenFragmentViews.contains(fragment.mView)) {
                             transition.excludeTarget(fragment.mView, true);
-                            state.hiddenFragmentViews.add(fragment.mView);
+                            hiddenFragmentViews.add(fragment.mView);
                         }
                     } else {
                         transition.excludeTarget(fragment.mView, false);
-                        state.hiddenFragmentViews.remove(fragment.mView);
+                        hiddenFragmentViews.remove(fragment.mView);
                     }
                 }
             }
         }
     }
 
-    private void excludeHiddenFragments(TransitionState state) {
-        int numTransitions = state.overallTransitions.size();
-        for (int i = 0; i < numTransitions; i++) {
-            Transition transition = state.overallTransitions.valueAt(i);
-            int containerId = state.overallTransitions.keyAt(i);
-            excludeHiddenFragments(state, containerId, transition);
-        }
-    }
-
-    private static void addTransitioningViews(Transition transition, final Collection<View> views) {
-        for (View view : views) {
-            transition.addTarget(view);
-        }
-
-        transition.addListener(new Transition.TransitionListenerAdapter() {
-            @Override
-            public void onTransitionStart(Transition transition) {
-                transition.removeListener(this);
-                for (View view : views) {
-                    transition.removeTarget(view);
-                }
-            }
-        });
-    }
-
     private static void setEpicenter(Transition transition, View view) {
         final Rect epicenter = new Rect();
         view.getBoundsOnScreen(epicenter);
@@ -1566,10 +1520,7 @@
         if (doStateMove) {
             mManager.moveToState(mManager.mCurState,
                     FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle, true);
-            if (state != null) {
-                updateTransitionEndState(state, firstOutFragments, lastInFragments, true);
-                state = null;
-            }
+            state = null;
         }
 
         if (mIndex >= 0) {
@@ -1609,11 +1560,14 @@
         for (int i = 0; i < count; i++) {
             String source = mSharedElementSourceNames.get(i);
             String originalTarget = mSharedElementTargetNames.get(i);
-            String target = namedViews.get(originalTarget).getTransitionName();
-            if (isEnd) {
-                setNameOverride(state.nameOverrides, source, target);
-            } else {
-                setNameOverride(state.nameOverrides, target, source);
+            View view = namedViews.get(originalTarget);
+            if (view != null) {
+                String target = view.getTransitionName();
+                if (isEnd) {
+                    setNameOverride(state.nameOverrides, source, target);
+                } else {
+                    setNameOverride(state.nameOverrides, target, source);
+                }
             }
         }
     }
@@ -1649,10 +1603,7 @@
     }
 
     public class TransitionState {
-        public SparseArray<Transition> overallTransitions = new SparseArray<Transition>();
         public ArrayMap<String, String> nameOverrides = new ArrayMap<String, String>();
-        public ArrayList<View> hiddenFragmentViews = new ArrayList<View>();
-
         public View enteringEpicenterView;
         public View nonExistentView;
     }
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 672ef7b..4374622 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -166,11 +166,12 @@
  * activity: if the activity is stopped, no fragments inside of it can be
  * started; when the activity is destroyed, all fragments will be destroyed.
  *
- * <p>All subclasses of Fragment must include a public empty constructor.
+ * <p>All subclasses of Fragment must include a public no-argument constructor.
  * The framework will often re-instantiate a fragment class when needed,
  * in particular during state restore, and needs to be able to find this
- * constructor to instantiate it.  If the empty constructor is not available,
- * a runtime exception will occur in some cases during state restore.
+ * constructor to instantiate it.  If the no-argument constructor is not
+ * available, a runtime exception will occur in some cases during state
+ * restore.
  *
  * <p>Topics covered here:
  * <ol>
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 9483680..8fa1fd53 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -327,6 +327,8 @@
     public void notifyActivityDrawn(IBinder token) throws RemoteException;
     public ActivityOptions getActivityOptions(IBinder token) throws RemoteException;
 
+    public void bootAnimationComplete() throws RemoteException;
+
     public void setImmersive(IBinder token, boolean immersive) throws RemoteException;
     public boolean isImmersive(IBinder token) throws RemoteException;
     public boolean isTopActivityImmersive() throws RemoteException;
@@ -772,4 +774,5 @@
     int GET_APP_TASK_THUMBNAIL_SIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+234;
     int RELEASE_ACTIVITY_INSTANCE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+235;
     int RELEASE_SOME_ACTIVITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+236;
+    int BOOT_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+237;
 }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 5b02313..ea041e8 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -111,7 +111,7 @@
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_PROVISION_MANAGED_PROFILE
-        = "android.app.action.ACTION_PROVISION_MANAGED_PROFILE";
+        = "android.app.action.PROVISION_MANAGED_PROFILE";
 
     /**
      * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that allows
@@ -138,7 +138,7 @@
      * message containing an Nfc record with MIME type {@link #MIME_TYPE_PROVISIONING_NFC}.
      */
     public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME
-        = "android.app.extra.deviceAdminPackageName";
+        = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
 
     /**
      * A String extra that, holds the email address of the account which a managed profile is
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 843f117..0057f61 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -143,7 +143,6 @@
         }
 
         checkNotClosed();
-        checkLegalToCapture();
 
         handler = checkHandler(handler, callback);
 
@@ -166,7 +165,6 @@
         }
 
         checkNotClosed();
-        checkLegalToCapture();
 
         handler = checkHandler(handler, callback);
 
@@ -188,7 +186,6 @@
         }
 
         checkNotClosed();
-        checkLegalToCapture();
 
         handler = checkHandler(handler, callback);
 
@@ -211,7 +208,6 @@
         }
 
         checkNotClosed();
-        checkLegalToCapture();
 
         handler = checkHandler(handler, callback);
 
@@ -542,13 +538,6 @@
         }
     }
 
-    private void checkLegalToCapture() {
-        if (mAborting) {
-            throw new IllegalStateException(
-                    "Session is aborting captures; new captures are not permitted");
-        }
-    }
-
     private void checkNotClosed() {
         if (mClosed) {
             throw new IllegalStateException(
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index e6ff17b..e6da670 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -374,6 +374,9 @@
             }
 
             mIntermediateBufferSize = bestPreviewDimen;
+            mParams.setPreviewSize(mIntermediateBufferSize.getWidth(),
+                    mIntermediateBufferSize.getHeight());
+
             if (DEBUG) {
                 Log.d(TAG, "Intermediate buffer selected with dimens: " +
                         bestPreviewDimen.toString());
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 8df9916..80e5b91 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -223,6 +223,9 @@
      * Called by the bearer code when it has a new score for this network.
      */
     public void sendNetworkScore(int score) {
+        if (score < 0) {
+            throw new IllegalArgumentException("Score must be >= 0");
+        }
         queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new Integer(score));
     }
 
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index a94f973..12a49d5 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -875,6 +875,11 @@
                 data[i + 1] = theme.resolveAttribute(attributeId, outValue, true) ?
                         outValue.coerceToString().toString() :  nullString;
                 i += 2;
+
+                // attempt to replace reference data with its name
+                if (outValue.type == TypedValue.TYPE_REFERENCE) {
+                    data[i - 1] = resources.getResourceName(outValue.resourceId);
+                }
             } catch (Resources.NotFoundException e) {
                 // ignore resources we can't resolve
             }
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 3f168e8..128a06c 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1860,9 +1860,8 @@
         }
 
         final int originalLength = mTextView.getText().length();
-        long minMax = mTextView.prepareSpacesAroundPaste(offset, offset, content);
-        int min = TextUtils.unpackRangeStartFromLong(minMax);
-        int max = TextUtils.unpackRangeEndFromLong(minMax);
+        int min = offset;
+        int max = offset;
 
         Selection.setSelection((Spannable) mTextView.getText(), max);
         mTextView.replaceText_internal(min, max, content);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 80ea6ea..76e8ab5 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8754,57 +8754,6 @@
     }
 
     /**
-     * Prepare text so that there are not zero or two spaces at beginning and end of region defined
-     * by [min, max] when replacing this region by paste.
-     * Note that if there were two spaces (or more) at that position before, they are kept. We just
-     * make sure we do not add an extra one from the paste content.
-     */
-    long prepareSpacesAroundPaste(int min, int max, CharSequence paste) {
-        if (paste.length() > 0) {
-            if (min > 0) {
-                final char charBefore = mTransformed.charAt(min - 1);
-                final char charAfter = paste.charAt(0);
-
-                if (Character.isSpaceChar(charBefore) && Character.isSpaceChar(charAfter)) {
-                    // Two spaces at beginning of paste: remove one
-                    final int originalLength = mText.length();
-                    deleteText_internal(min - 1, min);
-                    // Due to filters, there is no guarantee that exactly one character was
-                    // removed: count instead.
-                    final int delta = mText.length() - originalLength;
-                    min += delta;
-                    max += delta;
-                } else if (!Character.isSpaceChar(charBefore) && charBefore != '\n' &&
-                        !Character.isSpaceChar(charAfter) && charAfter != '\n') {
-                    // No space at beginning of paste: add one
-                    final int originalLength = mText.length();
-                    replaceText_internal(min, min, " ");
-                    // Taking possible filters into account as above.
-                    final int delta = mText.length() - originalLength;
-                    min += delta;
-                    max += delta;
-                }
-            }
-
-            if (max < mText.length()) {
-                final char charBefore = paste.charAt(paste.length() - 1);
-                final char charAfter = mTransformed.charAt(max);
-
-                if (Character.isSpaceChar(charBefore) && Character.isSpaceChar(charAfter)) {
-                    // Two spaces at end of paste: remove one
-                    deleteText_internal(max, max + 1);
-                } else if (!Character.isSpaceChar(charBefore) && charBefore != '\n' &&
-                        !Character.isSpaceChar(charAfter) && charAfter != '\n') {
-                    // No space at end of paste: add one
-                    replaceText_internal(max, max, " ");
-                }
-            }
-        }
-
-        return TextUtils.packRangeInLong(min, max);
-    }
-
-    /**
      * Paste clipboard content between min and max positions.
      */
     private void paste(int min, int max) {
@@ -8817,9 +8766,6 @@
                 CharSequence paste = clip.getItemAt(i).coerceToStyledText(getContext());
                 if (paste != null) {
                     if (!didFirst) {
-                        long minMax = prepareSpacesAroundPaste(min, max, paste);
-                        min = TextUtils.unpackRangeStartFromLong(minMax);
-                        max = TextUtils.unpackRangeEndFromLong(minMax);
                         Selection.setSelection((Spannable) mText, max);
                         ((Editable) mText).replace(min, max, paste);
                         didFirst = true;
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 3ed4d51..8e786da 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -107,7 +107,7 @@
             return (T[]) EmptyArray.OBJECT;
         }
 
-        int bucket = ((System.identityHashCode(kind) / 8) & 0x7FFFFFFF) % CACHE_SIZE;
+        int bucket = (kind.hashCode() & 0x7FFFFFFF) % CACHE_SIZE;
         Object cache = sCache[bucket];
 
         if (cache == null || cache.getClass().getComponentType() != kind) {
diff --git a/core/res/res/layout/simple_spinner_dropdown_item.xml b/core/res/res/layout/simple_spinner_dropdown_item.xml
index e2bd474..f276cfa 100644
--- a/core/res/res/layout/simple_spinner_dropdown_item.xml
+++ b/core/res/res/layout/simple_spinner_dropdown_item.xml
@@ -4,24 +4,23 @@
 **
 ** Copyright 2008, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** 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 
+**     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 
+** 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.
 */
 -->
-<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android" 
+<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@android:id/text1"
     style="?android:attr/spinnerDropDownItemStyle"
     android:singleLine="true"
     android:layout_width="match_parent"
     android:layout_height="?android:attr/dropdownListPreferredItemHeight"
-    android:ellipsize="marquee"
-    android:textAlignment="inherit"/>
+    android:ellipsize="marquee"/>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b36387f..d67690a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -354,6 +354,12 @@
     <!-- Integer indicating associated scan interval in milliseconds -->
     <integer translatable="false" name="config_wifi_framework_associated_scan_interval">10000</integer>
 
+    <!-- Boolean indicating associated scan are allowed -->
+    <bool translatable="false" name="config_wifi_framework_enable_associated_autojoin_scan">true</bool>
+
+    <!-- Boolean indicating associated network selection is allowed -->
+    <bool translatable="false" name="config_wifi_framework_enable_associated_network_selection">true</bool>
+
     <!-- Wifi driver stop delay, in milliseconds.
          Default value is 2 minutes. -->
     <integer translatable="false" name="config_wifi_driver_stop_delay">120000</integer>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 556c07f..221269d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -294,6 +294,8 @@
   <java-symbol type="bool" name="config_hasRecents" />
   <java-symbol type="bool" name="config_windowShowCircularMask" />
   <java-symbol type="bool" name="config_windowEnableCircularEmulatorDisplayOverlay" />
+  <java-symbol type="bool" name="config_wifi_framework_enable_associated_autojoin_scan" />
+  <java-symbol type="bool" name="config_wifi_framework_enable_associated_network_selection" />
 
   <java-symbol type="integer" name="config_bluetooth_max_advertisers" />
   <java-symbol type="integer" name="config_bluetooth_max_scan_filters" />
diff --git a/docs/html/tools/building/index.jd b/docs/html/tools/building/index.jd
index c64942f..c1f3019 100644
--- a/docs/html/tools/building/index.jd
+++ b/docs/html/tools/building/index.jd
@@ -79,3 +79,14 @@
     running on a device.</li>
   </ul>
 
+<p class="note"><b>Note:</b> Apps are limited to a 64K method reference limit. If your app reaches
+this limit, the build process outputs the following error message:
+
+<pre>Unable to execute dex: method ID not in [0, 0xffff]: 65536.</pre>
+
+To avoid this, you can
+<a href="http://android-developers.blogspot.com.es/2011/07/custom-class-loading-in-dalvik.html">load
+secondary dex files at runtime</a> and use
+<a href="http://developer.android.com/tools/help/proguard.html">ProGuard</a> to strip out unnecessary
+class references (Proguard only works when building in release mode).
+</p>
\ No newline at end of file
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index e5e2f18..49e8b9d 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -27,6 +27,7 @@
 import android.graphics.Outline;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
+import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.Log;
 
@@ -131,7 +132,9 @@
 
     private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false;
 
-    private final AnimatedVectorDrawableState mAnimatedVectorState;
+    private AnimatedVectorDrawableState mAnimatedVectorState;
+
+    private boolean mMutated;
 
     public AnimatedVectorDrawable() {
         mAnimatedVectorState = new AnimatedVectorDrawableState(
@@ -140,7 +143,6 @@
 
     private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res,
             Theme theme) {
-        // TODO: Correctly handle the constant state for AVD.
         mAnimatedVectorState = new AnimatedVectorDrawableState(state);
         if (theme != null && canApplyTheme()) {
             applyTheme(theme);
@@ -148,8 +150,17 @@
     }
 
     @Override
+    public Drawable mutate() {
+        if (!mMutated && super.mutate() == this) {
+            mAnimatedVectorState = new AnimatedVectorDrawableState(mAnimatedVectorState);
+            mMutated = true;
+        }
+        return this;
+    }
+
+    @Override
     public ConstantState getConstantState() {
-        return null;
+        return mAnimatedVectorState;
     }
 
     @Override
@@ -311,14 +322,31 @@
         int mChangingConfigurations;
         VectorDrawable mVectorDrawable;
         ArrayList<Animator> mAnimators;
+        ArrayMap<Animator, String> mTargetNameMap;
 
         public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy) {
             if (copy != null) {
                 mChangingConfigurations = copy.mChangingConfigurations;
-                // TODO: Make sure the constant state are handled correctly.
-                mVectorDrawable = new VectorDrawable();
-                mVectorDrawable.setAllowCaching(false);
-                mAnimators = new ArrayList<Animator>();
+                if (copy.mVectorDrawable != null) {
+                    mVectorDrawable = (VectorDrawable) copy.mVectorDrawable.getConstantState().newDrawable();
+                    mVectorDrawable.mutate();
+                    mVectorDrawable.setAllowCaching(false);
+                    mVectorDrawable.setBounds(copy.mVectorDrawable.getBounds());
+                }
+                if (copy.mAnimators != null) {
+                    final int numAnimators = copy.mAnimators.size();
+                    mAnimators = new ArrayList<Animator>(numAnimators);
+                    mTargetNameMap = new ArrayMap<Animator, String>(numAnimators);
+                    for (int i = 0; i < numAnimators; ++i) {
+                        Animator anim = copy.mAnimators.get(i);
+                        Animator animClone = anim.clone();
+                        String targetName = copy.mTargetNameMap.get(anim);
+                        Object targetObject = mVectorDrawable.getTargetByName(targetName);
+                        animClone.setTarget(targetObject);
+                        mAnimators.add(animClone);
+                        mTargetNameMap.put(animClone, targetName);
+                    }
+                }
             }
         }
 
@@ -346,7 +374,12 @@
     private void setupAnimatorsForTarget(String name, Animator animator) {
         Object target = mAnimatedVectorState.mVectorDrawable.getTargetByName(name);
         animator.setTarget(target);
+        if (mAnimatedVectorState.mAnimators == null) {
+            mAnimatedVectorState.mAnimators = new ArrayList<Animator>();
+            mAnimatedVectorState.mTargetNameMap = new ArrayMap<Animator, String>();
+        }
         mAnimatedVectorState.mAnimators.add(animator);
+        mAnimatedVectorState.mTargetNameMap.put(animator, name);
         if (DBG_ANIMATION_VECTOR_DRAWABLE) {
             Log.v(LOGTAG, "add animator  for target " + name + " " + animator);
         }
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index a07ccc4..65ab454 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -629,6 +629,15 @@
                 mThemeAttrs = copy.mThemeAttrs;
                 mChangingConfigurations = copy.mChangingConfigurations;
                 mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
+                if (copy.mVPathRenderer.mFillPaint != null) {
+                    mVPathRenderer.mFillPaint = new Paint(copy.mVPathRenderer.mFillPaint);
+                }
+                if (copy.mVPathRenderer.mStrokePaint != null) {
+                    mVPathRenderer.mStrokePaint = new Paint(copy.mVPathRenderer.mStrokePaint);
+                }
+                if (copy.mVPathRenderer.mColorFilter != null) {
+                    mVPathRenderer.mColorFilter = copy.mVPathRenderer.mColorFilter;
+                }
                 mTint = copy.mTint;
                 mTintMode = copy.mTintMode;
                 mAutoMirrored = copy.mAutoMirrored;
@@ -700,8 +709,8 @@
          */
         // Variables that only used temporarily inside the draw() call, so there
         // is no need for deep copying.
-        private final Path mPath = new Path();
-        private final Path mRenderPath = new Path();
+        private final Path mPath;
+        private final Path mRenderPath;
         private static final Matrix IDENTITY_MATRIX = new Matrix();
         private final Matrix mFinalPathMatrix = new Matrix();
 
@@ -724,6 +733,8 @@
 
         public VPathRenderer() {
             mRootGroup = new VGroup();
+            mPath = new Path();
+            mRenderPath = new Path();
         }
 
         public void setRootAlpha(int alpha) {
@@ -736,6 +747,8 @@
 
         public VPathRenderer(VPathRenderer copy) {
             mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap);
+            mPath = new Path(copy.mPath);
+            mRenderPath = new Path(copy.mRenderPath);
             mBaseWidth = copy.mBaseWidth;
             mBaseHeight = copy.mBaseHeight;
             mViewportWidth = copy.mViewportWidth;
diff --git a/media/java/android/media/AudioDevice.java b/media/java/android/media/AudioDevice.java
index e078354..df4d60d 100644
--- a/media/java/android/media/AudioDevice.java
+++ b/media/java/android/media/AudioDevice.java
@@ -20,90 +20,91 @@
 
 /**
  * Class to provide information about the audio devices.
+ * @hide
  */
 public class AudioDevice {
 
     /**
      * A device type associated with an unknown or uninitialized device.
      */
-    public static final int DEVICE_TYPE_UNKNOWN          = 0;
+    public static final int TYPE_UNKNOWN          = 0;
     /**
      * A device type describing the attached earphone speaker.
      */
-    public static final int DEVICE_TYPE_BUILTIN_EARPIECE = 1;
+    public static final int TYPE_BUILTIN_EARPIECE = 1;
     /**
      * A device type describing the speaker system (i.e. a mono speaker or stereo speakers) built
      * in a device.
      */
-    public static final int DEVICE_TYPE_BUILTIN_SPEAKER  = 2;
+    public static final int TYPE_BUILTIN_SPEAKER  = 2;
     /**
      * A device type describing a headset, which is the combination of a headphones and microphone.
      */
-    public static final int DEVICE_TYPE_WIRED_HEADSET    = 3;
+    public static final int TYPE_WIRED_HEADSET    = 3;
     /**
      * A device type describing a pair of wired headphones .
      */
-    public static final int DEVICE_TYPE_WIRED_HEADPHONES = 4;
+    public static final int TYPE_WIRED_HEADPHONES = 4;
     /**
      * A device type describing an analog line-level connection.
      */
-    public static final int DEVICE_TYPE_LINE_ANALOG      = 5;
+    public static final int TYPE_LINE_ANALOG      = 5;
     /**
      * A device type describing a digital line connection (e.g. SPDIF).
      */
-    public static final int DEVICE_TYPE_LINE_DIGITAL     = 6;
+    public static final int TYPE_LINE_DIGITAL     = 6;
     /**
      * A device type describing a Bluetooth device typically used for telephony .
      */
-    public static final int DEVICE_TYPE_BLUETOOTH_SCO    = 7;
+    public static final int TYPE_BLUETOOTH_SCO    = 7;
     /**
      * A device type describing a Bluetooth device supporting the A2DP profile.
      */
-    public static final int DEVICE_TYPE_BLUETOOTH_A2DP   = 8;
+    public static final int TYPE_BLUETOOTH_A2DP   = 8;
     /**
      * A device type describing an HDMI connection .
      */
-    public static final int DEVICE_TYPE_HDMI             = 9;
+    public static final int TYPE_HDMI             = 9;
     /**
      * A device type describing the Audio Return Channel of an HDMI connection.
      */
-    public static final int DEVICE_TYPE_HDMI_ARC         = 10;
+    public static final int TYPE_HDMI_ARC         = 10;
     /**
      * A device type describing a USB audio device.
      */
-    public static final int DEVICE_TYPE_USB_DEVICE       = 11;
+    public static final int TYPE_USB_DEVICE       = 11;
     /**
      * A device type describing a USB audio device in accessory mode.
      */
-    public static final int DEVICE_TYPE_USB_ACCESSORY    = 12;
+    public static final int TYPE_USB_ACCESSORY    = 12;
     /**
      * A device type describing the audio device associated with a dock.
      */
-    public static final int DEVICE_TYPE_DOCK             = 13;
+    public static final int TYPE_DOCK             = 13;
     /**
      * A device type associated with the transmission of audio signals over FM.
      */
-    public static final int DEVICE_TYPE_FM               = 14;
+    public static final int TYPE_FM               = 14;
     /**
      * A device type describing the microphone(s) built in a device.
      */
-    public static final int DEVICE_TYPE_BUILTIN_MIC      = 15;
+    public static final int TYPE_BUILTIN_MIC      = 15;
     /**
      * A device type for accessing the audio content transmitted over FM.
      */
-    public static final int DEVICE_TYPE_FM_TUNER         = 16;
+    public static final int TYPE_FM_TUNER         = 16;
     /**
      * A device type for accessing the audio content transmitted over the TV tuner system.
      */
-    public static final int DEVICE_TYPE_TV_TUNER         = 17;
+    public static final int TYPE_TV_TUNER         = 17;
     /**
      * A device type describing the transmission of audio signals over the telephony network.
      */
-    public static final int DEVICE_TYPE_TELEPHONY        = 18;
+    public static final int TYPE_TELEPHONY        = 18;
     /**
      * A device type describing the auxiliary line-level connectors.
      */
-    public static final int DEVICE_TYPE_AUX_LINE         = 19;
+    public static final int TYPE_AUX_LINE         = 19;
 
     AudioDevicePortConfig mConfig;
 
@@ -135,7 +136,7 @@
      * @return
      */
     public int getDeviceType() {
-        return INT_TO_EXT_DEVICE_MAPPING.get(mConfig.port().type(), DEVICE_TYPE_UNKNOWN);
+        return INT_TO_EXT_DEVICE_MAPPING.get(mConfig.port().type(), TYPE_UNKNOWN);
     }
 
     /**
@@ -154,7 +155,7 @@
 
     /** @hide */
     public static int convertInternalDeviceToDeviceType(int intDevice) {
-        return INT_TO_EXT_DEVICE_MAPPING.get(intDevice, DEVICE_TYPE_UNKNOWN);
+        return INT_TO_EXT_DEVICE_MAPPING.get(intDevice, TYPE_UNKNOWN);
     }
 
     private static final SparseIntArray INT_TO_EXT_DEVICE_MAPPING;
@@ -163,43 +164,43 @@
 
     static {
         INT_TO_EXT_DEVICE_MAPPING = new SparseIntArray();
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_EARPIECE, DEVICE_TYPE_BUILTIN_EARPIECE);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_SPEAKER, DEVICE_TYPE_BUILTIN_SPEAKER);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_WIRED_HEADSET, DEVICE_TYPE_WIRED_HEADSET);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, DEVICE_TYPE_WIRED_HEADPHONES);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, DEVICE_TYPE_BLUETOOTH_SCO);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET, DEVICE_TYPE_BLUETOOTH_SCO);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT, DEVICE_TYPE_BLUETOOTH_SCO);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, DEVICE_TYPE_BLUETOOTH_A2DP);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, DEVICE_TYPE_BLUETOOTH_A2DP);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, DEVICE_TYPE_BLUETOOTH_A2DP);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_HDMI, DEVICE_TYPE_HDMI);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET, DEVICE_TYPE_DOCK);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET, DEVICE_TYPE_DOCK);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_USB_ACCESSORY, DEVICE_TYPE_USB_ACCESSORY);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_USB_DEVICE, DEVICE_TYPE_USB_DEVICE);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_TELEPHONY_TX, DEVICE_TYPE_TELEPHONY);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_LINE, DEVICE_TYPE_LINE_ANALOG);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_HDMI_ARC, DEVICE_TYPE_HDMI_ARC);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_SPDIF, DEVICE_TYPE_LINE_DIGITAL);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_FM, DEVICE_TYPE_FM);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_AUX_LINE, DEVICE_TYPE_AUX_LINE);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_EARPIECE, TYPE_BUILTIN_EARPIECE);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_SPEAKER, TYPE_BUILTIN_SPEAKER);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_WIRED_HEADSET, TYPE_WIRED_HEADSET);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, TYPE_WIRED_HEADPHONES);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, TYPE_BLUETOOTH_SCO);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET, TYPE_BLUETOOTH_SCO);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT, TYPE_BLUETOOTH_SCO);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, TYPE_BLUETOOTH_A2DP);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, TYPE_BLUETOOTH_A2DP);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, TYPE_BLUETOOTH_A2DP);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_HDMI, TYPE_HDMI);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET, TYPE_DOCK);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET, TYPE_DOCK);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_USB_ACCESSORY, TYPE_USB_ACCESSORY);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_USB_DEVICE, TYPE_USB_DEVICE);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_TELEPHONY_TX, TYPE_TELEPHONY);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_LINE, TYPE_LINE_ANALOG);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_HDMI_ARC, TYPE_HDMI_ARC);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_SPDIF, TYPE_LINE_DIGITAL);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_FM, TYPE_FM);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_AUX_LINE, TYPE_AUX_LINE);
 
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUILTIN_MIC, DEVICE_TYPE_BUILTIN_MIC);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET, DEVICE_TYPE_BLUETOOTH_SCO);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_WIRED_HEADSET, DEVICE_TYPE_WIRED_HEADSET);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_HDMI, DEVICE_TYPE_HDMI);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_TELEPHONY_RX, DEVICE_TYPE_TELEPHONY);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BACK_MIC, DEVICE_TYPE_BUILTIN_MIC);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET, DEVICE_TYPE_DOCK);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET, DEVICE_TYPE_DOCK);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_USB_ACCESSORY, DEVICE_TYPE_USB_ACCESSORY);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_USB_DEVICE, DEVICE_TYPE_USB_DEVICE);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_FM_TUNER, DEVICE_TYPE_FM_TUNER);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_TV_TUNER, DEVICE_TYPE_TV_TUNER);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_LINE, DEVICE_TYPE_LINE_ANALOG);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_SPDIF, DEVICE_TYPE_LINE_DIGITAL);
-        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, DEVICE_TYPE_BLUETOOTH_A2DP);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUILTIN_MIC, TYPE_BUILTIN_MIC);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET, TYPE_BLUETOOTH_SCO);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_WIRED_HEADSET, TYPE_WIRED_HEADSET);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_HDMI, TYPE_HDMI);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_TELEPHONY_RX, TYPE_TELEPHONY);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BACK_MIC, TYPE_BUILTIN_MIC);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET, TYPE_DOCK);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET, TYPE_DOCK);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_USB_ACCESSORY, TYPE_USB_ACCESSORY);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_USB_DEVICE, TYPE_USB_DEVICE);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_FM_TUNER, TYPE_FM_TUNER);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_TV_TUNER, TYPE_TV_TUNER);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_LINE, TYPE_LINE_ANALOG);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_SPDIF, TYPE_LINE_DIGITAL);
+        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, TYPE_BLUETOOTH_A2DP);
 
         // not covered here, legacy
         //AudioSystem.DEVICE_OUT_REMOTE_SUBMIX
@@ -207,25 +208,25 @@
 
         // privileges mapping to output device
         EXT_TO_INT_DEVICE_MAPPING = new SparseIntArray();
-        EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_BUILTIN_EARPIECE, AudioSystem.DEVICE_OUT_EARPIECE);
-        EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_BUILTIN_SPEAKER, AudioSystem.DEVICE_OUT_SPEAKER);
-        EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_WIRED_HEADSET, AudioSystem.DEVICE_OUT_WIRED_HEADSET);
-        EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_WIRED_HEADPHONES, AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
-        EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_LINE_ANALOG, AudioSystem.DEVICE_OUT_LINE);
-        EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_LINE_DIGITAL, AudioSystem.DEVICE_OUT_SPDIF);
-        EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_BLUETOOTH_SCO, AudioSystem.DEVICE_OUT_BLUETOOTH_SCO);
-        EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_BLUETOOTH_A2DP, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
-        EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_HDMI, AudioSystem.DEVICE_OUT_HDMI);
-        EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_HDMI_ARC, AudioSystem.DEVICE_OUT_HDMI_ARC);
-        EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_USB_DEVICE, AudioSystem.DEVICE_OUT_USB_DEVICE);
-        EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_USB_ACCESSORY, AudioSystem.DEVICE_OUT_USB_ACCESSORY);
-        EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_DOCK, AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
-        EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_FM, AudioSystem.DEVICE_OUT_FM);
-        EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_BUILTIN_MIC, AudioSystem.DEVICE_IN_BUILTIN_MIC);
-        EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_FM_TUNER, AudioSystem.DEVICE_IN_FM_TUNER);
-        EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_TV_TUNER, AudioSystem.DEVICE_IN_TV_TUNER);
-        EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_TELEPHONY, AudioSystem.DEVICE_OUT_TELEPHONY_TX);
-        EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_AUX_LINE, AudioSystem.DEVICE_OUT_AUX_LINE);
+        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BUILTIN_EARPIECE, AudioSystem.DEVICE_OUT_EARPIECE);
+        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BUILTIN_SPEAKER, AudioSystem.DEVICE_OUT_SPEAKER);
+        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_WIRED_HEADSET, AudioSystem.DEVICE_OUT_WIRED_HEADSET);
+        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_WIRED_HEADPHONES, AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
+        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_LINE_ANALOG, AudioSystem.DEVICE_OUT_LINE);
+        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_LINE_DIGITAL, AudioSystem.DEVICE_OUT_SPDIF);
+        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLUETOOTH_SCO, AudioSystem.DEVICE_OUT_BLUETOOTH_SCO);
+        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLUETOOTH_A2DP, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_HDMI, AudioSystem.DEVICE_OUT_HDMI);
+        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_HDMI_ARC, AudioSystem.DEVICE_OUT_HDMI_ARC);
+        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_USB_DEVICE, AudioSystem.DEVICE_OUT_USB_DEVICE);
+        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_USB_ACCESSORY, AudioSystem.DEVICE_OUT_USB_ACCESSORY);
+        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_DOCK, AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
+        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_FM, AudioSystem.DEVICE_OUT_FM);
+        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BUILTIN_MIC, AudioSystem.DEVICE_IN_BUILTIN_MIC);
+        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_FM_TUNER, AudioSystem.DEVICE_IN_FM_TUNER);
+        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_TV_TUNER, AudioSystem.DEVICE_IN_TV_TUNER);
+        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_TELEPHONY, AudioSystem.DEVICE_OUT_TELEPHONY_TX);
+        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_AUX_LINE, AudioSystem.DEVICE_OUT_AUX_LINE);
     }
 }
 
diff --git a/media/java/android/media/audiofx/Virtualizer.java b/media/java/android/media/audiofx/Virtualizer.java
index b314c02..be5adc8 100644
--- a/media/java/android/media/audiofx/Virtualizer.java
+++ b/media/java/android/media/audiofx/Virtualizer.java
@@ -16,11 +16,14 @@
 
 package android.media.audiofx;
 
+import android.annotation.IntDef;
 import android.media.AudioDevice;
 import android.media.AudioFormat;
 import android.media.audiofx.AudioEffect;
 import android.util.Log;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.StringTokenizer;
@@ -248,14 +251,114 @@
     }
 
     /**
-     * Checks if the combination of a channel mask and device type is supported by this virtualizer.
+     * A virtualization mode indicating virtualization processing is not active.
+     * See {@link #getVirtualizationMode()} as one of the possible return value.
+     */
+    public static final int VIRTUALIZATION_MODE_OFF = 0;
+
+    /**
+     * A virtualization mode used to indicate the virtualizer effect must stop forcing the
+     * processing to a particular mode in {@link #forceVirtualizationMode(int)}.
+     */
+    public static final int VIRTUALIZATION_MODE_AUTO = 1;
+    /**
+     * A virtualization mode typically used over headphones.
+     * Binaural virtualization describes an audio processing configuration for virtualization
+     * where the left and right channels are respectively reaching the left and right ear of the
+     * user, without also feeding the opposite ear (as is the case when listening over speakers).
+     * <p>Such a mode is therefore meant to be used when audio is playing over stereo wired
+     * headphones or headsets, but also stereo headphones through a wireless A2DP Bluetooth link.
+     * <p>See {@link #canVirtualize(int, int)} to verify this mode is supported by this Virtualizer.
+     */
+    public final static int VIRTUALIZATION_MODE_BINAURAL = 2;
+
+    /**
+     * A virtualization mode typically used over speakers.
+     * Transaural virtualization describes an audio processing configuration that differs from
+     * binaural (as described in {@link #VIRTUALIZATION_MODE_BINAURAL} in that cross-talk is
+     * present, i.e. audio played from the left channel also reaches the right ear of the user,
+     * and vice-versa.
+     * <p>When supported, such a mode is therefore meant to be used when audio is playing over the
+     * built-in stereo speakers of a device, if they are featured.
+     * <p>See {@link #canVirtualize(int, int)} to verify this mode is supported by this Virtualizer.
+     */
+    public final static int VIRTUALIZATION_MODE_TRANSAURAL = 3;
+
+    /** @hide */
+    @IntDef( {
+        VIRTUALIZATION_MODE_BINAURAL,
+        VIRTUALIZATION_MODE_TRANSAURAL
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface VirtualizationMode {}
+
+    /** @hide */
+    @IntDef( {
+        VIRTUALIZATION_MODE_AUTO,
+        VIRTUALIZATION_MODE_BINAURAL,
+        VIRTUALIZATION_MODE_TRANSAURAL
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ForceVirtualizationMode {}
+
+    private static int getDeviceForModeQuery(@VirtualizationMode int virtualizationMode)
+            throws IllegalArgumentException {
+        switch (virtualizationMode) {
+            case VIRTUALIZATION_MODE_BINAURAL:
+                return AudioDevice.TYPE_WIRED_HEADPHONES;
+            case VIRTUALIZATION_MODE_TRANSAURAL:
+                return AudioDevice.TYPE_BUILTIN_SPEAKER;
+            default:
+                throw (new IllegalArgumentException(
+                        "Virtualizer: illegal virtualization mode " + virtualizationMode));
+        }
+    }
+
+    private static int getDeviceForModeForce(@ForceVirtualizationMode int virtualizationMode)
+            throws IllegalArgumentException {
+        if (virtualizationMode == VIRTUALIZATION_MODE_AUTO) {
+            return AudioDevice.TYPE_UNKNOWN;
+        } else {
+            return getDeviceForModeQuery(virtualizationMode);
+        }
+    }
+
+    private static int deviceToMode(int deviceType) {
+        switch (deviceType) {
+            case AudioDevice.TYPE_WIRED_HEADSET:
+            case AudioDevice.TYPE_WIRED_HEADPHONES:
+            case AudioDevice.TYPE_BLUETOOTH_SCO:
+            case AudioDevice.TYPE_BUILTIN_EARPIECE:
+                return VIRTUALIZATION_MODE_BINAURAL;
+            case AudioDevice.TYPE_BUILTIN_SPEAKER:
+            case AudioDevice.TYPE_LINE_ANALOG:
+            case AudioDevice.TYPE_LINE_DIGITAL:
+            case AudioDevice.TYPE_BLUETOOTH_A2DP:
+            case AudioDevice.TYPE_HDMI:
+            case AudioDevice.TYPE_HDMI_ARC:
+            case AudioDevice.TYPE_USB_DEVICE:
+            case AudioDevice.TYPE_USB_ACCESSORY:
+            case AudioDevice.TYPE_DOCK:
+            case AudioDevice.TYPE_FM:
+            case AudioDevice.TYPE_AUX_LINE:
+                return VIRTUALIZATION_MODE_TRANSAURAL;
+            case AudioDevice.TYPE_UNKNOWN:
+            default:
+                return VIRTUALIZATION_MODE_OFF;
+        }
+    }
+
+    /**
+     * Checks if the combination of a channel mask and virtualization mode is supported by this
+     * virtualizer.
      * Some virtualizer implementations may only support binaural processing (i.e. only support
-     * headphone output), some may support transaural processing (i.e. for speaker output) for the
+     * headphone output, see {@link #VIRTUALIZATION_MODE_BINAURAL}), some may support transaural
+     * processing (i.e. for speaker output, see {@link #VIRTUALIZATION_MODE_TRANSAURAL}) for the
      * built-in speakers. Use this method to query the virtualizer implementation capabilities.
      * @param inputChannelMask the channel mask of the content to virtualize.
-     * @param deviceType the device type for which virtualization processing is to be performed.
-     *    Valid values are the device types defined in {@link AudioDevice}.
-     * @return true if the combination of channel mask and output device type is supported, false
+     * @param virtualizationMode the mode for which virtualization processing is to be performed,
+     *    one of {@link #VIRTUALIZATION_MODE_BINAURAL}, {@link #VIRTUALIZATION_MODE_TRANSAURAL}.
+     * @return true if the combination of channel mask and virtualization mode is supported, false
      *    otherwise.
      *    <br>An indication that a certain channel mask is not supported doesn't necessarily mean
      *    you cannot play content with that channel mask, it more likely implies the content will
@@ -268,22 +371,22 @@
      * @throws IllegalArgumentException
      * @throws UnsupportedOperationException
      */
-    public boolean canVirtualize(int inputChannelMask, int deviceType)
+    public boolean canVirtualize(int inputChannelMask, @VirtualizationMode int virtualizationMode)
             throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
-        return getAnglesInt(inputChannelMask, deviceType, null);
+        return getAnglesInt(inputChannelMask, getDeviceForModeQuery(virtualizationMode), null);
     }
 
     /**
      * Queries the virtual speaker angles (azimuth and elevation) for a combination of a channel
-     * mask and device type.
-     * If the virtualization configuration (mask and device) is supported (see
+     * mask and virtualization mode.
+     * If the virtualization configuration (mask and mode) is supported (see
      * {@link #canVirtualize(int, int)}, the array angles will contain upon return the
      * definition of each virtual speaker and its azimuth and elevation angles relative to the
      * listener.
      * <br>Note that in some virtualizer implementations, the angles may be strength-dependent.
      * @param inputChannelMask the channel mask of the content to virtualize.
-     * @param deviceType the device type for which virtualization processing is to be performed.
-     *    Valid values are the device types defined in {@link AudioDevice}.
+     * @param virtualizationMode the mode for which virtualization processing is to be performed,
+     *    one of {@link #VIRTUALIZATION_MODE_BINAURAL}, {@link #VIRTUALIZATION_MODE_TRANSAURAL}.
      * @param angles a non-null array whose length is 3 times the number of channels in the channel
      *    mask.
      *    If the method indicates the configuration is supported, the array will contain upon return
@@ -297,37 +400,39 @@
      *      <li>the element at index <code>3*i+2</code> contains its corresponding elevation angle
      *          where +90 is directly above the listener, 0 is the horizontal plane, and -90 is
      *          directly below the listener.</li>
-     * @return true if the combination of channel mask and output device type is supported, false
+     * @return true if the combination of channel mask and virtualization mode is supported, false
      *    otherwise.
      * @throws IllegalStateException
      * @throws IllegalArgumentException
      * @throws UnsupportedOperationException
      */
-    public boolean getSpeakerAngles(int inputChannelMask, int deviceType, int[] angles)
+    public boolean getSpeakerAngles(int inputChannelMask,
+            @VirtualizationMode int virtualizationMode, int[] angles)
             throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
         if (angles == null) {
             throw (new IllegalArgumentException(
                     "Virtualizer: illegal null channel / angle array"));
         }
 
-        return getAnglesInt(inputChannelMask, deviceType, angles);
+        return getAnglesInt(inputChannelMask, getDeviceForModeQuery(virtualizationMode), angles);
     }
 
     /**
-     * Forces the virtualizer effect to use the processing mode used for the given device type.
+     * Forces the virtualizer effect to use the given processing mode.
      * The effect must be enabled for the forced mode to be applied.
-     * @param deviceType one of the device types defined in {@link AudioDevice}.
-     *     Use {@link AudioDevice#DEVICE_TYPE_UNKNOWN} to return to the non-forced mode.
-     * @return true if the processing mode for the device type is supported, and it is successfully
-     *     set, or forcing was successfully disabled with {@link AudioDevice#DEVICE_TYPE_UNKNOWN},
-     *     false otherwise.
+     * @param virtualizationMode one of {@link #VIRTUALIZATION_MODE_BINAURAL},
+     *     {@link #VIRTUALIZATION_MODE_TRANSAURAL} to force a particular processing mode, or
+     *     {@value #VIRTUALIZATION_MODE_AUTO} to stop forcing a mode.
+     * @return true if the processing mode is supported, and it is successfully set, or
+     *     forcing was successfully disabled, false otherwise.
      * @throws IllegalStateException
      * @throws IllegalArgumentException
      * @throws UnsupportedOperationException
      */
-    public boolean forceVirtualizationMode(int deviceType)
+    public boolean forceVirtualizationMode(@ForceVirtualizationMode int virtualizationMode)
             throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
         // convert Java device type to internal representation
+        int deviceType = getDeviceForModeForce(virtualizationMode);
         int internalDevice = AudioDevice.convertDeviceTypeToInternalDevice(deviceType);
 
         int status = setParameter(PARAM_FORCE_VIRTUALIZATION_MODE, internalDevice);
@@ -335,8 +440,8 @@
         if (status >= 0) {
             return true;
         } else if (status == AudioEffect.ERROR_BAD_VALUE) {
-            // a BAD_VALUE return from setParameter indicates the mode can't be forced to that
-            // of this device, don't throw an exception, just return false
+            // a BAD_VALUE return from setParameter indicates the mode can't be forced
+            // don't throw an exception, just return false
             return false;
         } else {
             // something wrong may have happened
@@ -349,31 +454,25 @@
     }
 
     /**
-     * Return the device type which reflects the virtualization mode being used, if any.
-     * @return a device type (as defined in {@link AudioDevice}) which reflects the virtualization
-     *     mode being used.
-     *     If virtualization is not active, the device type will be
-     *     {@link AudioDevice#DEVICE_TYPE_UNKNOWN}. Virtualization may not be active either because
-     *     the effect is not enabled or because the current output device is not compatible with
-     *     this virtualization implementation.
-     *     <p>Note that the return value may differ from a device type successfully set with
-     *     {@link #forceVirtualizationMode(int)} as the implementation
-     *     may use a single mode for multiple devices. An example of this is with
-     *     {@link AudioDevice#DEVICE_TYPE_WIRED_HEADSET} that would typically be handled
-     *     like {@link AudioDevice#DEVICE_TYPE_WIRED_HEADPHONES} from a virtualization
-     *     standpoint.
+     * Return the virtualization mode being used, if any.
+     * @return the virtualization mode being used.
+     *     If virtualization is not active, the virtualization mode will be
+     *     {@link #VIRTUALIZATION_MODE_OFF}. Otherwise the value will be
+     *     {@link #VIRTUALIZATION_MODE_BINAURAL} or {@link #VIRTUALIZATION_MODE_TRANSAURAL}.
+     *     Virtualization may not be active either because the effect is not enabled or
+     *     because the current output device is not compatible with this virtualization
+     *     implementation.
      * @throws IllegalStateException
-     * @throws IllegalArgumentException
      * @throws UnsupportedOperationException
      */
     public int getVirtualizationMode()
-            throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+            throws IllegalStateException, UnsupportedOperationException {
         int[] value = new int[1];
         int status = getParameter(PARAM_VIRTUALIZATION_MODE, value);
         if (status >= 0) {
-            return AudioDevice.convertInternalDeviceToDeviceType(value[0]);
+            return deviceToMode(AudioDevice.convertInternalDeviceToDeviceType(value[0]));
         } else if (status == AudioEffect.ERROR_BAD_VALUE) {
-            return AudioDevice.DEVICE_TYPE_UNKNOWN;
+            return VIRTUALIZATION_MODE_OFF;
         } else {
             // something wrong may have happened
             checkStatus(status);
@@ -381,7 +480,7 @@
         // unexpected virtualizer behavior
         Log.e(TAG, "unexpected status code " + status
                 + " after getParameter(PARAM_VIRTUALIZATION_MODE)");
-        return AudioDevice.DEVICE_TYPE_UNKNOWN;
+        return VIRTUALIZATION_MODE_OFF;
     }
 
     /**
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index d2deb66..b7a230c 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -709,7 +709,9 @@
             }
         };
         try {
-            mService.registerCallback(mManagerCallback, mUserId);
+            if (mService != null) {
+                mService.registerCallback(mManagerCallback, mUserId);
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "mService.registerCallback failed: " + e);
         }
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 4171e6d..213e34c 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -312,7 +312,9 @@
             // is newly assigned for every createSession request and compared with
             // MySessionCreateCallback.this.
             mSessionCallback = new MySessionCallback(inputId, channelUri, params);
-            mTvInputManager.createSession(inputId, mSessionCallback, mHandler);
+            if (mTvInputManager != null) {
+                mTvInputManager.createSession(inputId, mSessionCallback, mHandler);
+            }
         }
     }
 
diff --git a/packages/Keyguard/res/drawable-hdpi/kg_bouncer_bg_white.9.png b/packages/Keyguard/res/drawable-hdpi/kg_bouncer_bg_white.9.png
deleted file mode 100644
index cfd5db3..0000000
--- a/packages/Keyguard/res/drawable-hdpi/kg_bouncer_bg_white.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/kg_bouncer_bg_white.9.png b/packages/Keyguard/res/drawable-mdpi/kg_bouncer_bg_white.9.png
deleted file mode 100644
index e3cb6db..0000000
--- a/packages/Keyguard/res/drawable-mdpi/kg_bouncer_bg_white.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/kg_bouncer_bg_white.9.png b/packages/Keyguard/res/drawable-xhdpi/kg_bouncer_bg_white.9.png
deleted file mode 100644
index b9e30e2..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/kg_bouncer_bg_white.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/layout/keyguard_face_unlock_view.xml b/packages/Keyguard/res/layout/keyguard_face_unlock_view.xml
index 8c8ec7a..0c85dab 100644
--- a/packages/Keyguard/res/layout/keyguard_face_unlock_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_face_unlock_view.xml
@@ -36,7 +36,6 @@
 
     <FrameLayout
        android:id="@+id/keyguard_bouncer_frame"
-       android:background="@drawable/kg_bouncer_bg_white"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
diff --git a/packages/Keyguard/res/layout/keyguard_password_view.xml b/packages/Keyguard/res/layout/keyguard_password_view.xml
index 9e886f2..b7d5d30 100644
--- a/packages/Keyguard/res/layout/keyguard_password_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_password_view.xml
@@ -42,7 +42,6 @@
     <!-- Password entry field -->
       <FrameLayout
          android:id="@+id/keyguard_bouncer_frame"
-         android:background="@drawable/kg_bouncer_bg_white"
          android:layout_height="wrap_content"
          android:layout_width="280dp"
          android:layout_gravity="center_horizontal"
diff --git a/packages/Keyguard/res/layout/keyguard_pattern_view.xml b/packages/Keyguard/res/layout/keyguard_pattern_view.xml
index a126465..bd585b5 100644
--- a/packages/Keyguard/res/layout/keyguard_pattern_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_pattern_view.xml
@@ -49,7 +49,6 @@
 
           <FrameLayout
              android:id="@+id/keyguard_bouncer_frame"
-             android:background="@drawable/kg_bouncer_bg_white"
              android:layout_width="match_parent"
              android:layout_height="0dp"
              android:layout_weight="1"
diff --git a/packages/Keyguard/res/layout/keyguard_selector_view.xml b/packages/Keyguard/res/layout/keyguard_selector_view.xml
index d3064ed..5330363 100644
--- a/packages/Keyguard/res/layout/keyguard_selector_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_selector_view.xml
@@ -48,8 +48,7 @@
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_marginLeft="16dp"
-            android:layout_marginRight="16dp"
-            android:background="@drawable/kg_bouncer_bg_white"/>
+            android:layout_marginRight="16dp"/>
 
         <include layout="@layout/keyguard_glow_pad_container" />
 
diff --git a/packages/PrintSpooler/res/layout/print_activity.xml b/packages/PrintSpooler/res/layout/print_activity.xml
index 30b96292..6b8aa47 100644
--- a/packages/PrintSpooler/res/layout/print_activity.xml
+++ b/packages/PrintSpooler/res/layout/print_activity.xml
@@ -98,7 +98,7 @@
         android:id="@+id/print_button"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginEnd="16dip"
+        android:layout_marginStart="16dip"
         android:elevation="@dimen/preview_controls_elevation"
         android:background="@drawable/print_button">
     </ImageButton>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
index ce0b9b6..b6c36c7 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
@@ -442,7 +442,8 @@
                 * mPreviewPageMargin);
 
         final int verticalPadding;
-        if (mPageContentHeight + mFooterHeight + mPreviewListPadding > availableHeight) {
+        if (mPageContentHeight + mFooterHeight + mPreviewListPadding
+                + 2 * mPreviewPageMargin > availableHeight) {
             verticalPadding = Math.max(0,
                     (availableHeight - mPageContentHeight - mFooterHeight) / 2
                             - mPreviewPageMargin);
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
index c84b06a..970e3c0 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
@@ -283,8 +283,13 @@
         mDynamicContent.layout(left, dynContentTop, right, dynContentBottom);
 
         MarginLayoutParams params = (MarginLayoutParams) mPrintButton.getLayoutParams();
-        final int rightMargin = params.rightMargin;
-        final int printButtonLeft = right - mPrintButton.getMeasuredWidth() - rightMargin;
+
+        final int printButtonLeft;
+        if (getLayoutDirection() == View.LAYOUT_DIRECTION_LTR) {
+            printButtonLeft = right - mPrintButton.getMeasuredWidth() - params.getMarginStart();
+        } else {
+            printButtonLeft = left + params.getMarginStart();
+        }
         final int printButtonTop = dynContentBottom - mPrintButton.getMeasuredHeight() / 2;
         final int printButtonRight = printButtonLeft + mPrintButton.getMeasuredWidth();
         final int printButtonBottom = printButtonTop + mPrintButton.getMeasuredHeight();
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintOptionsLayout.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintOptionsLayout.java
index 71f4aa7..7a80a8b 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintOptionsLayout.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintOptionsLayout.java
@@ -89,7 +89,7 @@
                             columnWidth - childParams.getMarginStart() - childParams.getMarginEnd(),
                             MeasureSpec.EXACTLY);
                 } else {
-                    childWidthMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
+                    childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
                             getPaddingStart() + getPaddingEnd() + width, childParams.width);
                 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index fc737bee..70b6952 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -17,14 +17,10 @@
 package com.android.systemui.statusbar.phone;
 
 import android.content.Context;
-import android.os.SystemClock;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardViewBase;
@@ -33,7 +29,7 @@
 import com.android.systemui.keyguard.KeyguardViewMediator;
 
 import static com.android.keyguard.KeyguardHostView.OnDismissAction;
-import static com.android.keyguard.KeyguardSecurityModel.*;
+import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 
 /**
  * A class which manages the bouncer on the lockscreen.
@@ -62,6 +58,10 @@
     public void show() {
         ensureView();
         if (mRoot.getVisibility() == View.VISIBLE) {
+
+            // show() updates the current security method. This is needed in case we are already
+            // showing and the current security method changed.
+            mKeyguardView.show();
             return;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 9585e17..902123d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -631,9 +631,10 @@
     }
 
     private boolean isInQsArea(float x, float y) {
-        return mStatusBarState != StatusBarState.SHADE
-                || y <= mNotificationStackScroller.getBottomMostNotificationBottom()
-                || y <= mQsContainer.getY() + mQsContainer.getHeight();
+        return mStatusBarState != StatusBarState.SHADE ||
+                (x >= mScrollView.getLeft() && x <= mScrollView.getRight()) &&
+                        (y <= mNotificationStackScroller.getBottomMostNotificationBottom()
+                                || y <= mQsContainer.getY() + mQsContainer.getHeight());
     }
 
     private void handleQsDown(MotionEvent event) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 2f21781..006e480 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -691,18 +691,20 @@
             mClosing = true;
             notifyExpandingStarted();
             if (delayed) {
-                postDelayed(new Runnable() {
-                    @Override
-                    public void run() {
-                        fling(0, false /* expand */);
-                    }
-                }, 120);
+                postDelayed(mFlingCollapseRunnable, 120);
             } else {
                 fling(0, false /* expand */);
             }
         }
     }
 
+    private final Runnable mFlingCollapseRunnable = new Runnable() {
+        @Override
+        public void run() {
+            fling(0, false /* expand */);
+        }
+    };
+
     public void expand() {
         if (DEBUG) logf("expand: " + this);
         if (isFullyCollapsed()) {
@@ -728,7 +730,9 @@
 
     public void instantExpand() {
         mInstantExpanding = true;
+        mUpdateFlingOnLayout = false;
         abortAnimations();
+        cancelPeek();
         if (mTracking) {
             onTrackingStopped(true /* expands */); // The panel is expanded after this call.
         }
@@ -761,6 +765,8 @@
         if (mHeightAnimator != null) {
             mHeightAnimator.cancel();
         }
+        removeCallbacks(mPostCollapseRunnable);
+        removeCallbacks(mFlingCollapseRunnable);
     }
 
     protected void startUnlockHintAnimation() {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 3062a92..75090db 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4746,6 +4746,11 @@
 
     private void updateNetworkScore(NetworkAgentInfo nai, int score) {
         if (DBG) log("updateNetworkScore for " + nai.name() + " to " + score);
+        if (score < 0) {
+            loge("updateNetworkScore for " + nai.name() + " got a negative score (" + score +
+                    ").  Bumping score to min of 0");
+            score = 0;
+        }
 
         nai.currentScore = score;
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a9a4732..5845ad0 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -888,6 +888,8 @@
     boolean mProcessesReady = false;
     boolean mSystemReady = false;
     boolean mBooting = false;
+    boolean mCallFinishBooting = false;
+    boolean mBootAnimationComplete = false;
     boolean mWaitingUpdate = false;
     boolean mDidUpdate = false;
     boolean mOnBattery = false;
@@ -6195,6 +6197,14 @@
     }
 
     final void finishBooting() {
+        synchronized (this) {
+            if (!mBootAnimationComplete) {
+                mCallFinishBooting = true;
+                return;
+            }
+            mCallFinishBooting = false;
+        }
+
         // Register receivers to handle package update events
         mPackageMonitor.register(mContext, Looper.getMainLooper(), false);
 
@@ -6253,6 +6263,18 @@
         }
     }
 
+    @Override
+    public void bootAnimationComplete() {
+        final boolean callFinishBooting;
+        synchronized (this) {
+            callFinishBooting = mCallFinishBooting;
+            mBootAnimationComplete = true;
+        }
+        if (callFinishBooting) {
+            finishBooting();
+        }
+    }
+
     final void ensureBootCompleted() {
         boolean booting;
         boolean enableScreen;
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index f6beb9a..9292d45 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -16,6 +16,7 @@
 
 package com.android.server.content;
 
+import android.Manifest;
 import android.accounts.Account;
 import android.accounts.AccountAndUser;
 import android.accounts.AccountManager;
@@ -478,7 +479,7 @@
             mContext.registerReceiverAsUser(mAccountsUpdatedReceiver,
                     UserHandle.ALL,
                     new IntentFilter(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION),
-                    null, null);
+                    Manifest.permission.ACCOUNT_MANAGER, null);
         }
 
         // Pick a random second in a day to seed all periodic syncs
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 5f97a00..7808800 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -91,8 +91,6 @@
     private static final int MSG_SANDMAN = 2;
     // Message: Sent when the screen on blocker is released.
     private static final int MSG_SCREEN_ON_BLOCKER_RELEASED = 3;
-    // Message: Sent to poll whether the boot animation has terminated.
-    private static final int MSG_CHECK_IF_BOOT_ANIMATION_FINISHED = 4;
 
     // Dirty bit: mWakeLocks changed
     private static final int DIRTY_WAKE_LOCKS = 1 << 0;
@@ -154,12 +152,6 @@
     // provider populates the actual default value (R.integer.def_screen_off_timeout).
     private static final int DEFAULT_SCREEN_OFF_TIMEOUT = 15 * 1000;
 
-    // The name of the boot animation service in init.rc.
-    private static final String BOOT_ANIMATION_SERVICE = "bootanim";
-
-    // Poll interval in milliseconds for watching boot animation finished.
-    private static final int BOOT_ANIMATION_POLL_INTERVAL = 200;
-
     // Power hints defined in hardware/libhardware/include/hardware/power.h.
     private static final int POWER_HINT_INTERACTION = 2;
     private static final int POWER_HINT_LOW_POWER = 5;
@@ -478,14 +470,15 @@
 
     @Override
     public void onBootPhase(int phase) {
-        if (phase == PHASE_BOOT_COMPLETED) {
-            // This is our early signal that the system thinks it has finished booting.
-            // However, the boot animation may still be running for a few more seconds
-            // since it is ultimately in charge of when it terminates.
-            // Defer transitioning into the boot completed state until the animation exits.
-            // We do this so that the screen does not start to dim prematurely before
-            // the user has actually had a chance to interact with the device.
-            startWatchingForBootAnimationFinished();
+        synchronized (mLock) {
+            if (phase == PHASE_BOOT_COMPLETED) {
+                final long now = SystemClock.uptimeMillis();
+                mBootCompleted = true;
+                mDirty |= DIRTY_BOOT_COMPLETED;
+                userActivityNoUpdateLocked(
+                        now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
+                updatePowerStateLocked();
+            }
         }
     }
 
@@ -2076,38 +2069,6 @@
         updatePowerStateLocked();
     }
 
-    private void startWatchingForBootAnimationFinished() {
-        mHandler.sendEmptyMessage(MSG_CHECK_IF_BOOT_ANIMATION_FINISHED);
-    }
-
-    private void checkIfBootAnimationFinished() {
-        if (DEBUG) {
-            Slog.d(TAG, "Check if boot animation finished...");
-        }
-
-        if (SystemService.isRunning(BOOT_ANIMATION_SERVICE)) {
-            mHandler.sendEmptyMessageDelayed(MSG_CHECK_IF_BOOT_ANIMATION_FINISHED,
-                    BOOT_ANIMATION_POLL_INTERVAL);
-            return;
-        }
-
-        synchronized (mLock) {
-            if (!mBootCompleted) {
-                Slog.i(TAG, "Boot animation finished.");
-                handleBootCompletedLocked();
-            }
-        }
-    }
-
-    private void handleBootCompletedLocked() {
-        final long now = SystemClock.uptimeMillis();
-        mBootCompleted = true;
-        mDirty |= DIRTY_BOOT_COMPLETED;
-        userActivityNoUpdateLocked(
-                now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
-        updatePowerStateLocked();
-    }
-
     private void shutdownOrRebootInternal(final boolean shutdown, final boolean confirm,
             final String reason, boolean wait) {
         if (mHandler == null || !mSystemReady) {
@@ -2528,9 +2489,6 @@
                 case MSG_SCREEN_ON_BLOCKER_RELEASED:
                     handleScreenOnBlockerReleased();
                     break;
-                case MSG_CHECK_IF_BOOT_ANIMATION_FINISHED:
-                    checkIfBootAnimationFinished();
-                    break;
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 10ab6b5..54af851 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -21,6 +21,7 @@
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import android.app.AppOpsManager;
 import android.os.Build;
+import android.os.SystemService;
 import android.util.ArraySet;
 import android.util.TimeUtils;
 import android.view.IWindowId;
@@ -272,6 +273,12 @@
     // Default input dispatching timeout in nanoseconds.
     static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L;
 
+    // Poll interval in milliseconds for watching boot animation finished.
+    private static final int BOOT_ANIMATION_POLL_INTERVAL = 200;
+
+    // The name of the boot animation service in init.rc.
+    private static final String BOOT_ANIMATION_SERVICE = "bootanim";
+
     /** Minimum value for attachStack and resizeStack weight value */
     public static final float STACK_WEIGHT_MIN = 0.2f;
 
@@ -458,6 +465,7 @@
     boolean mSystemBooted = false;
     boolean mForceDisplayEnabled = false;
     boolean mShowingBootMessages = false;
+    boolean mBootAnimationStopped = false;
 
     String mLastANRState;
 
@@ -5607,17 +5615,70 @@
         performEnableScreen();
     }
 
+    private boolean checkWaitingForWindowsLocked() {
+
+        boolean haveBootMsg = false;
+        boolean haveApp = false;
+        // if the wallpaper service is disabled on the device, we're never going to have
+        // wallpaper, don't bother waiting for it
+        boolean haveWallpaper = false;
+        boolean wallpaperEnabled = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableWallpaperService)
+                && !mOnlyCore;
+        boolean haveKeyguard = true;
+        // TODO(multidisplay): Expand to all displays?
+        final WindowList windows = getDefaultWindowListLocked();
+        final int N = windows.size();
+        for (int i=0; i<N; i++) {
+            WindowState w = windows.get(i);
+            if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
+                return true;
+            }
+            if (w.isDrawnLw()) {
+                if (w.mAttrs.type == TYPE_BOOT_PROGRESS) {
+                    haveBootMsg = true;
+                } else if (w.mAttrs.type == TYPE_APPLICATION) {
+                    haveApp = true;
+                } else if (w.mAttrs.type == TYPE_WALLPAPER) {
+                    haveWallpaper = true;
+                } else if (w.mAttrs.type == TYPE_STATUS_BAR) {
+                    haveKeyguard = mPolicy.isKeyguardDrawnLw();
+                }
+            }
+        }
+
+        if (DEBUG_SCREEN_ON || DEBUG_BOOT) {
+            Slog.i(TAG, "******** booted=" + mSystemBooted + " msg=" + mShowingBootMessages
+                    + " haveBoot=" + haveBootMsg + " haveApp=" + haveApp
+                    + " haveWall=" + haveWallpaper + " wallEnabled=" + wallpaperEnabled
+                    + " haveKeyguard=" + haveKeyguard);
+        }
+
+        // If we are turning on the screen to show the boot message,
+        // don't do it until the boot message is actually displayed.
+        if (!mSystemBooted && !haveBootMsg) {
+            return true;
+        }
+
+        // If we are turning on the screen after the boot is completed
+        // normally, don't do so until we have the application and
+        // wallpaper.
+        if (mSystemBooted && ((!haveApp && !haveKeyguard) ||
+                (wallpaperEnabled && !haveWallpaper))) {
+            return true;
+        }
+
+        return false;
+    }
+
     public void performEnableScreen() {
         synchronized(mWindowMap) {
-            if (DEBUG_BOOT) {
-                RuntimeException here = new RuntimeException("here");
-                here.fillInStackTrace();
-                Slog.i(TAG, "performEnableScreen: mDisplayEnabled=" + mDisplayEnabled
-                        + " mForceDisplayEnabled=" + mForceDisplayEnabled
-                        + " mShowingBootMessages=" + mShowingBootMessages
-                        + " mSystemBooted=" + mSystemBooted
-                        + " mOnlyCore=" + mOnlyCore, here);
-            }
+            if (DEBUG_BOOT) Slog.i(TAG, "performEnableScreen: mDisplayEnabled=" + mDisplayEnabled
+                    + " mForceDisplayEnabled=" + mForceDisplayEnabled
+                    + " mShowingBootMessages=" + mShowingBootMessages
+                    + " mSystemBooted=" + mSystemBooted
+                    + " mOnlyCore=" + mOnlyCore,
+                    new RuntimeException("here").fillInStackTrace());
             if (mDisplayEnabled) {
                 return;
             }
@@ -5625,94 +5686,64 @@
                 return;
             }
 
-            if (!mForceDisplayEnabled) {
-                // Don't enable the screen until all existing windows
-                // have been drawn.
-                boolean haveBootMsg = false;
-                boolean haveApp = false;
-                // if the wallpaper service is disabled on the device, we're never going to have
-                // wallpaper, don't bother waiting for it
-                boolean haveWallpaper = false;
-                boolean wallpaperEnabled = mContext.getResources().getBoolean(
-                        com.android.internal.R.bool.config_enableWallpaperService)
-                        && !mOnlyCore;
-                boolean haveKeyguard = true;
-                // TODO(multidisplay): Expand to all displays?
-                final WindowList windows = getDefaultWindowListLocked();
-                final int N = windows.size();
-                for (int i=0; i<N; i++) {
-                    WindowState w = windows.get(i);
-                    if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
-                        return;
+            // Don't enable the screen until all existing windows have been drawn.
+            if (!mForceDisplayEnabled && checkWaitingForWindowsLocked()) {
+                return;
+            }
+
+            if (!mBootAnimationStopped) {
+                // Do this one time.
+                try {
+                    IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
+                    if (surfaceFlinger != null) {
+                        //Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
+                        Parcel data = Parcel.obtain();
+                        data.writeInterfaceToken("android.ui.ISurfaceComposer");
+                        surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
+                                data, null, 0);
+                        data.recycle();
                     }
-                    if (w.isDrawnLw()) {
-                        if (w.mAttrs.type == TYPE_BOOT_PROGRESS) {
-                            haveBootMsg = true;
-                        } else if (w.mAttrs.type == TYPE_APPLICATION) {
-                            haveApp = true;
-                        } else if (w.mAttrs.type == TYPE_WALLPAPER) {
-                            haveWallpaper = true;
-                        } else if (w.mAttrs.type == TYPE_STATUS_BAR) {
-                            haveKeyguard = mPolicy.isKeyguardDrawnLw();
-                        }
-                    }
+                } catch (RemoteException ex) {
+                    Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
                 }
+                mBootAnimationStopped = true;
+            }
 
-                if (DEBUG_SCREEN_ON || DEBUG_BOOT) {
-                    Slog.i(TAG, "******** booted=" + mSystemBooted + " msg=" + mShowingBootMessages
-                            + " haveBoot=" + haveBootMsg + " haveApp=" + haveApp
-                            + " haveWall=" + haveWallpaper + " wallEnabled=" + wallpaperEnabled
-                            + " haveKeyguard=" + haveKeyguard);
-                }
-
-                // If we are turning on the screen to show the boot message,
-                // don't do it until the boot message is actually displayed.
-                if (!mSystemBooted && !haveBootMsg) {
-                    return;
-                }
-
-                // If we are turning on the screen after the boot is completed
-                // normally, don't do so until we have the application and
-                // wallpaper.
-                if (mSystemBooted && ((!haveApp && !haveKeyguard) ||
-                        (wallpaperEnabled && !haveWallpaper))) {
-                    return;
-                }
+            if (!mForceDisplayEnabled && !checkBootAnimationCompleteLocked()) {
+                if (DEBUG_BOOT) Slog.i(TAG, "performEnableScreen: Waiting for anim complete");
+                return;
             }
 
             mDisplayEnabled = true;
             if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG, "******************** ENABLING SCREEN!");
-            if (false) {
-                StringWriter sw = new StringWriter();
-                PrintWriter pw = new FastPrintWriter(sw, false, 1024);
-                this.dump(null, pw, null);
-                pw.flush();
-                Slog.i(TAG, sw.toString());
-            }
-            try {
-                IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
-                if (surfaceFlinger != null) {
-                    //Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
-                    Parcel data = Parcel.obtain();
-                    data.writeInterfaceToken("android.ui.ISurfaceComposer");
-                    surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
-                                            data, null, 0);
-                    data.recycle();
-                }
-            } catch (RemoteException ex) {
-                Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
-            }
 
             // Enable input dispatch.
             mInputMonitor.setEventDispatchingLw(mEventDispatchingEnabled);
         }
 
+        try {
+            mActivityManager.bootAnimationComplete();
+        } catch (RemoteException e) {
+        }
+
         mPolicy.enableScreenAfterBoot();
 
         // Make sure the last requested orientation has been applied.
         updateRotationUnchecked(false, false);
     }
 
+    private boolean checkBootAnimationCompleteLocked() {
+        if (SystemService.isRunning(BOOT_ANIMATION_SERVICE)) {
+            mH.removeMessages(H.CHECK_IF_BOOT_ANIMATION_FINISHED);
+            mH.sendEmptyMessageDelayed(H.CHECK_IF_BOOT_ANIMATION_FINISHED,
+                    BOOT_ANIMATION_POLL_INTERVAL);
+            if (DEBUG_BOOT) Slog.i(TAG, "checkBootAnimationComplete: Waiting for anim complete");
+            return false;
+        }
+        if (DEBUG_BOOT) Slog.i(TAG, "checkBootAnimationComplete: Animation complete!");
+        return true;
+    }
+
     public void showBootMessage(final CharSequence msg, final boolean always) {
         boolean first = false;
         synchronized(mWindowMap) {
@@ -7457,6 +7488,8 @@
         public static final int SHOW_CIRCULAR_DISPLAY_MASK = 35;
         public static final int SHOW_EMULATOR_DISPLAY_OVERLAY = 36;
 
+        public static final int CHECK_IF_BOOT_ANIMATION_FINISHED = 37;
+
         @Override
         public void handleMessage(Message msg) {
             if (DEBUG_WINDOW_TRACE) {
@@ -7941,6 +7974,17 @@
                     }
                 }
                 break;
+                case CHECK_IF_BOOT_ANIMATION_FINISHED: {
+                    final boolean bootAnimationComplete;
+                    synchronized (mWindowMap) {
+                        if (DEBUG_BOOT) Slog.i(TAG, "CHECK_IF_BOOT_ANIMATION_FINISHED:");
+                        bootAnimationComplete = checkBootAnimationCompleteLocked();
+                    }
+                    if (bootAnimationComplete) {
+                        performEnableScreen();
+                    }
+                }
+                break;
             }
             if (DEBUG_WINDOW_TRACE) {
                 Slog.v(TAG, "handleMessage: exit");
diff --git a/telecomm/java/android/telecomm/Conference.java b/telecomm/java/android/telecomm/Conference.java
index f9c3ac3..a4f9c2c 100644
--- a/telecomm/java/android/telecomm/Conference.java
+++ b/telecomm/java/android/telecomm/Conference.java
@@ -50,22 +50,47 @@
     private int mCapabilities;
     private String mDisconnectMessage;
 
+    /**
+     * Constructs a new Conference with a mandatory {@link PhoneAccountHandle}
+     *
+     * @param phoneAccount The {@code PhoneAccountHandle} associated with the conference.
+     */
     public Conference(PhoneAccountHandle phoneAccount) {
         mPhoneAccount = phoneAccount;
     }
 
+    /**
+     * Returns the {@link PhoneAccountHandle} the conference call is being placed through.
+     *
+     * @return A {@code PhoneAccountHandle} object representing the PhoneAccount of the conference.
+     */
     public final PhoneAccountHandle getPhoneAccountHandle() {
         return mPhoneAccount;
     }
 
+    /**
+     * Returns the list of connections currently associated with the conference call.
+     *
+     * @return A list of {@code Connection} objects which represent the children of the conference.
+     */
     public final List<Connection> getConnections() {
         return mUnmodifiableChildConnections;
     }
 
+    /**
+     * Gets the state of the conference call. See {@link Connection} for valid values.
+     *
+     * @return A constant representing the state the conference call is currently in.
+     */
     public final int getState() {
         return mState;
     }
 
+    /**
+     * Returns the capabilities of a conference. See {@link PhoneCapabilities} for valid values.
+     *
+     * @return A bitmask of the {@code PhoneCapabilities} of the conference call.
+     */
     public final int getCapabilities() {
         return mCapabilities;
     }
@@ -135,7 +160,9 @@
     }
 
     /**
-     * Sets the capabilities of a conference.
+     * Sets the capabilities of a conference. See {@link PhoneCapabilities} for valid values.
+     *
+     * @param capabilities A bitmask of the {@code PhoneCapabilities} of the conference call.
      */
     public final void setCapabilities(int capabilities) {
         if (capabilities != mCapabilities) {
@@ -170,7 +197,6 @@
      * Removes the specified connection as a child of this conference.
      *
      * @param connection The connection to remove.
-     * @return True if the connection was successfully removed.
      */
     public final void removeConnection(Connection connection) {
         Log.d(this, "removing %s from %s", connection, mChildConnections);
diff --git a/telecomm/java/android/telecomm/RemoteConnectionService.java b/telecomm/java/android/telecomm/RemoteConnectionService.java
index 348c36c..8b8e8eb 100644
--- a/telecomm/java/android/telecomm/RemoteConnectionService.java
+++ b/telecomm/java/android/telecomm/RemoteConnectionService.java
@@ -60,13 +60,14 @@
             if (connection != NULL_CONNECTION && mPendingConnections.contains(connection)) {
                 mPendingConnections.remove(connection);
                 // Unconditionally initialize the connection ...
-                connection.setState(parcel.getState());
                 connection.setCallCapabilities(parcel.getCapabilities());
                 connection.setHandle(
                         parcel.getHandle(), parcel.getHandlePresentation());
                 connection.setCallerDisplayName(
                         parcel.getCallerDisplayName(),
                         parcel.getCallerDisplayNamePresentation());
+                // Set state after handle so that the client can identify the connection.
+                connection.setState(parcel.getState());
                 List<RemoteConnection> conferenceable = new ArrayList<>();
                 for (String confId : parcel.getConferenceableConnectionIds()) {
                     if (mConnectionById.containsKey(confId)) {
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 21f200f..aeaff71 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -367,9 +367,9 @@
 
     /**
      * @hide
-     * Uid of app owning the BSSID
+     * Uid used by autoJoin
      */
-    public int bssidOwnerUid;
+    public String autoJoinBSSID;
 
     /**
      * @hide
@@ -467,8 +467,10 @@
         public int rssi24;  // strongest 2.4GHz RSSI
         public int num5;    // number of BSSIDs on 5GHz
         public int num24;   // number of BSSIDs on 2.4GHz
-        public long age5;  // timestamp of the strongest 5GHz BSSID (last time it was seen)
-        public long age24;   // timestamp of the strongest 2.4GHz BSSID (last time it was seen)
+        public long age5;   // timestamp of the strongest 5GHz BSSID (last time it was seen)
+        public long age24;  // timestamp of the strongest 2.4GHz BSSID (last time it was seen)
+        public String BSSID24;
+        public String BSSID5;
 
         public Visibility() {
             rssi5 = INVALID_RSSI;
@@ -482,6 +484,8 @@
             age5 = source.age5;
             num24 = source.num24;
             num5 = source.num5;
+            BSSID5 = source.BSSID5;
+            BSSID24 = source.BSSID24;
         }
 
         @Override
@@ -492,6 +496,7 @@
                 sbuf.append(Integer.toString(rssi24));
                 sbuf.append(",");
                 sbuf.append(Integer.toString(num24));
+                if (BSSID24 != null) sbuf.append(",").append(BSSID24);
             } else {
                 sbuf.append("*");
             }
@@ -500,6 +505,7 @@
                 sbuf.append(Integer.toString(rssi5));
                 sbuf.append(",");
                 sbuf.append(Integer.toString(num5));
+                if (BSSID5 != null) sbuf.append(",").append(BSSID5);
             }
             sbuf.append("]");
             return sbuf.toString();
@@ -549,11 +555,13 @@
                 if (result.level > status.rssi5) {
                     status.rssi5 = result.level;
                     status.age5 = result.seen;
+                    status.BSSID5 = result.BSSID;
                 }
             } else if (result.is24GHz()) {
                 if (result.level > status.rssi24) {
                     status.rssi24 = result.level;
                     status.age24 = result.seen;
+                    status.BSSID24 = result.BSSID;
                 }
             }
         }
@@ -949,7 +957,7 @@
         sbuf.append(mIpConfiguration.toString());
 
         if (this.creatorUid != 0)  sbuf.append("uid=" + Integer.toString(creatorUid));
-
+        if (this.autoJoinBSSID != null) sbuf.append("autoJoinBSSID=" + autoJoinBSSID);
         if (this.blackListTimestamp != 0) {
             long now_ms = System.currentTimeMillis();
             long diff = now_ms - this.blackListTimestamp;
@@ -1284,7 +1292,6 @@
             didSelfAdd = source.didSelfAdd;
             lastConnectUid = source.lastConnectUid;
             lastUpdateUid = source.lastUpdateUid;
-            bssidOwnerUid = source.bssidOwnerUid;
             creatorUid = source.creatorUid;
             peerWifiConfiguration = source.peerWifiConfiguration;
             blackListTimestamp = source.blackListTimestamp;
@@ -1302,6 +1309,7 @@
             numTicksAtBadRSSI = source.numTicksAtBadRSSI;
             numTicksAtNotHighRSSI = source.numTicksAtNotHighRSSI;
             numUserTriggeredJoinAttempts = source.numUserTriggeredJoinAttempts;
+            autoJoinBSSID = source.autoJoinBSSID;
         }
     }
 
@@ -1318,6 +1326,7 @@
         dest.writeInt(disableReason);
         dest.writeString(SSID);
         dest.writeString(BSSID);
+        dest.writeString(autoJoinBSSID);
         dest.writeString(FQDN);
         dest.writeString(naiRealm);
         dest.writeString(preSharedKey);
@@ -1348,7 +1357,6 @@
         dest.writeInt(creatorUid);
         dest.writeInt(lastConnectUid);
         dest.writeInt(lastUpdateUid);
-        dest.writeInt(bssidOwnerUid);
         dest.writeLong(blackListTimestamp);
         dest.writeLong(lastConnectionFailure);
         dest.writeInt(numConnectionFailures);
@@ -1375,6 +1383,7 @@
                 config.disableReason = in.readInt();
                 config.SSID = in.readString();
                 config.BSSID = in.readString();
+                config.autoJoinBSSID = in.readString();
                 config.FQDN = in.readString();
                 config.naiRealm = in.readString();
                 config.preSharedKey = in.readString();
@@ -1405,7 +1414,6 @@
                 config.creatorUid = in.readInt();
                 config.lastConnectUid = in.readInt();
                 config.lastUpdateUid = in.readInt();
-                config.bssidOwnerUid = in.readInt();
                 config.blackListTimestamp = in.readLong();
                 config.lastConnectionFailure = in.readLong();
                 config.numConnectionFailures = in.readInt();