Merge "Some fixes for transition animation selection"
diff --git a/api/current.txt b/api/current.txt
index 778ef7b..64838a4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12295,6 +12295,7 @@
     method public void addRoundRect(float, float, float, float, float, float, android.graphics.Path.Direction);
     method public void addRoundRect(android.graphics.RectF, float[], android.graphics.Path.Direction);
     method public void addRoundRect(float, float, float, float, float[], android.graphics.Path.Direction);
+    method public float[] approximate(float);
     method public void arcTo(android.graphics.RectF, float, float, boolean);
     method public void arcTo(android.graphics.RectF, float, float);
     method public void arcTo(float, float, float, float, float, float, boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index b27c5f0..c7a05b2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -12726,6 +12726,7 @@
     method public void addRoundRect(float, float, float, float, float, float, android.graphics.Path.Direction);
     method public void addRoundRect(android.graphics.RectF, float[], android.graphics.Path.Direction);
     method public void addRoundRect(float, float, float, float, float[], android.graphics.Path.Direction);
+    method public float[] approximate(float);
     method public void arcTo(android.graphics.RectF, float, float, boolean);
     method public void arcTo(android.graphics.RectF, float, float);
     method public void arcTo(float, float, float, float, float, float, boolean);
diff --git a/api/test-current.txt b/api/test-current.txt
index 9bb1a7d..881d290 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -12309,6 +12309,7 @@
     method public void addRoundRect(float, float, float, float, float, float, android.graphics.Path.Direction);
     method public void addRoundRect(android.graphics.RectF, float[], android.graphics.Path.Direction);
     method public void addRoundRect(float, float, float, float, float[], android.graphics.Path.Direction);
+    method public float[] approximate(float);
     method public void arcTo(android.graphics.RectF, float, float, boolean);
     method public void arcTo(android.graphics.RectF, float, float);
     method public void arcTo(float, float, float, float, float, float, boolean);
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 199e9aa..f4f8d69 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -54,39 +54,22 @@
     final ArrayList<String> mSharedElementTargetNames;
 
     public BackStackState(FragmentManagerImpl fm, BackStackRecord bse) {
-        int numRemoved = 0;
-        BackStackRecord.Op op = bse.mHead;
-        while (op != null) {
-            if (op.removed != null) {
-                numRemoved += op.removed.size();
-            }
-            op = op.next;
-        }
-        mOps = new int[bse.mNumOp * 7 + numRemoved];
+        final int numOps = bse.mOps.size();
+        mOps = new int[numOps * 6];
 
         if (!bse.mAddToBackStack) {
             throw new IllegalStateException("Not on back stack");
         }
 
-        op = bse.mHead;
         int pos = 0;
-        while (op != null) {
+        for (int opNum = 0; opNum < numOps; opNum++) {
+            final BackStackRecord.Op op = bse.mOps.get(opNum);
             mOps[pos++] = op.cmd;
             mOps[pos++] = op.fragment != null ? op.fragment.mIndex : -1;
             mOps[pos++] = op.enterAnim;
             mOps[pos++] = op.exitAnim;
             mOps[pos++] = op.popEnterAnim;
             mOps[pos++] = op.popExitAnim;
-            if (op.removed != null) {
-                final int N = op.removed.size();
-                mOps[pos++] = N;
-                for (int i = 0; i < N; i++) {
-                    mOps[pos++] = op.removed.get(i).mIndex;
-                }
-            } else {
-                mOps[pos++] = 0;
-            }
-            op = op.next;
         }
         mTransition = bse.mTransition;
         mTransitionStyle = bse.mTransitionStyle;
@@ -136,18 +119,6 @@
             op.exitAnim = mOps[pos++];
             op.popEnterAnim = mOps[pos++];
             op.popExitAnim = mOps[pos++];
-            final int N = mOps[pos++];
-            if (N > 0) {
-                op.removed = new ArrayList<Fragment>(N);
-                for (int i = 0; i < N; i++) {
-                    if (FragmentManagerImpl.DEBUG) {
-                        Log.v(FragmentManagerImpl.TAG,
-                                "Instantiate " + bse + " set remove fragment #" + mOps[pos]);
-                    }
-                    Fragment r = fm.mActive.get(mOps[pos++]);
-                    op.removed.add(r);
-                }
-            }
             bse.mEnterAnim = op.enterAnim;
             bse.mExitAnim = op.exitAnim;
             bse.mPopEnterAnim = op.popEnterAnim;
@@ -219,20 +190,15 @@
     static final int OP_ATTACH = 7;
 
     static final class Op {
-        Op next;
-        Op prev;
         int cmd;
         Fragment fragment;
         int enterAnim;
         int exitAnim;
         int popEnterAnim;
         int popExitAnim;
-        ArrayList<Fragment> removed;
     }
 
-    Op mHead;
-    Op mTail;
-    int mNumOp;
+    ArrayList<Op> mOps = new ArrayList<>();
     int mEnterAnim;
     int mExitAnim;
     int mPopEnterAnim;
@@ -320,13 +286,13 @@
             }
         }
 
-        if (mHead != null) {
+        if (!mOps.isEmpty()) {
             writer.print(prefix);
             writer.println("Operations:");
             String innerPrefix = prefix + "    ";
-            Op op = mHead;
-            int num = 0;
-            while (op != null) {
+            final int numOps = mOps.size();
+            for (int opNum = 0; opNum < numOps; opNum++) {
+                final Op op = mOps.get(opNum);
                 String cmdStr;
                 switch (op.cmd) {
                     case OP_NULL:
@@ -359,7 +325,7 @@
                 }
                 writer.print(prefix);
                 writer.print("  Op #");
-                writer.print(num);
+                writer.print(opNum);
                 writer.print(": ");
                 writer.print(cmdStr);
                 writer.print(" ");
@@ -380,25 +346,6 @@
                         writer.println(Integer.toHexString(op.popExitAnim));
                     }
                 }
-                if (op.removed != null && op.removed.size() > 0) {
-                    for (int i = 0; i < op.removed.size(); i++) {
-                        writer.print(innerPrefix);
-                        if (op.removed.size() == 1) {
-                            writer.print("Removed: ");
-                        } else {
-                            if (i == 0) {
-                                writer.println("Removed:");
-                            }
-                            writer.print(innerPrefix);
-                            writer.print("  #");
-                            writer.print(i);
-                            writer.print(": ");
-                        }
-                        writer.println(op.removed.get(i));
-                    }
-                }
-                op = op.next;
-                num++;
             }
         }
     }
@@ -434,18 +381,11 @@
     }
 
     void addOp(Op op) {
-        if (mHead == null) {
-            mHead = mTail = op;
-        } else {
-            op.prev = mTail;
-            mTail.next = op;
-            mTail = op;
-        }
+        mOps.add(op);
         op.enterAnim = mEnterAnim;
         op.exitAnim = mExitAnim;
         op.popEnterAnim = mPopEnterAnim;
         op.popExitAnim = mPopExitAnim;
-        mNumOp++;
     }
 
     public FragmentTransaction add(Fragment fragment, String tag) {
@@ -660,8 +600,9 @@
             Log.v(TAG, "Bump nesting in " + this
                     + " by " + amt);
         }
-        Op op = mHead;
-        while (op != null) {
+        final int numOps = mOps.size();
+        for (int opNum = 0; opNum < numOps; opNum++) {
+            final Op op = mOps.get(opNum);
             if (op.fragment != null) {
                 op.fragment.mBackStackNesting += amt;
                 if (FragmentManagerImpl.DEBUG) {
@@ -669,17 +610,6 @@
                             + op.fragment + " to " + op.fragment.mBackStackNesting);
                 }
             }
-            if (op.removed != null) {
-                for (int i = op.removed.size() - 1; i >= 0; i--) {
-                    Fragment r = op.removed.get(i);
-                    r.mBackStackNesting += amt;
-                    if (FragmentManagerImpl.DEBUG) {
-                        Log.v(TAG, "Bump nesting of "
-                                + r + " to " + r.mBackStackNesting);
-                    }
-                }
-            }
-            op = op.next;
         }
     }
 
@@ -735,6 +665,7 @@
             }
         }
 
+        expandReplaceOps();
         bumpBackStackNesting(1);
 
         if (mManager.mCurState >= Fragment.CREATED) {
@@ -744,88 +675,38 @@
             beginTransition(firstOutFragments, lastInFragments, false);
         }
 
-        Op op = mHead;
-        while (op != null) {
+        final int numOps = mOps.size();
+        for (int opNum = 0; opNum < numOps; opNum++) {
+            final Op op = mOps.get(opNum);
+            Fragment f = op.fragment;
             switch (op.cmd) {
-                case OP_ADD: {
-                    Fragment f = op.fragment;
+                case OP_ADD:
                     f.mNextAnim = op.enterAnim;
                     mManager.addFragment(f, false);
-                }
-                break;
-                case OP_REPLACE: {
-                    Fragment f = op.fragment;
-                    int containerId = f.mContainerId;
-                    if (mManager.mAdded != null) {
-                        for (int i = mManager.mAdded.size() - 1; i >= 0; i--) {
-                            Fragment old = mManager.mAdded.get(i);
-                            if (FragmentManagerImpl.DEBUG) {
-                                Log.v(TAG,
-                                        "OP_REPLACE: adding=" + f + " old=" + old);
-                            }
-                            if (old.mContainerId == containerId) {
-                                if (old == f) {
-                                    op.fragment = f = null;
-                                } else {
-                                    if (op.removed == null) {
-                                        op.removed = new ArrayList<Fragment>();
-                                    }
-                                    op.removed.add(old);
-                                    old.mNextAnim = op.exitAnim;
-                                    if (mAddToBackStack) {
-                                        old.mBackStackNesting += 1;
-                                        if (FragmentManagerImpl.DEBUG) {
-                                            Log.v(TAG, "Bump nesting of "
-                                                    + old + " to " + old.mBackStackNesting);
-                                        }
-                                    }
-                                    mManager.removeFragment(old, mTransition, mTransitionStyle);
-                                }
-                            }
-                        }
-                    }
-                    if (f != null) {
-                        f.mNextAnim = op.enterAnim;
-                        mManager.addFragment(f, false);
-                    }
-                }
-                break;
-                case OP_REMOVE: {
-                    Fragment f = op.fragment;
+                    break;
+                case OP_REMOVE:
                     f.mNextAnim = op.exitAnim;
                     mManager.removeFragment(f, mTransition, mTransitionStyle);
-                }
-                break;
-                case OP_HIDE: {
-                    Fragment f = op.fragment;
+                    break;
+                case OP_HIDE:
                     f.mNextAnim = op.exitAnim;
                     mManager.hideFragment(f, mTransition, mTransitionStyle);
-                }
-                break;
-                case OP_SHOW: {
-                    Fragment f = op.fragment;
+                    break;
+                case OP_SHOW:
                     f.mNextAnim = op.enterAnim;
                     mManager.showFragment(f, mTransition, mTransitionStyle);
-                }
-                break;
-                case OP_DETACH: {
-                    Fragment f = op.fragment;
+                    break;
+                case OP_DETACH:
                     f.mNextAnim = op.exitAnim;
                     mManager.detachFragment(f, mTransition, mTransitionStyle);
-                }
-                break;
-                case OP_ATTACH: {
-                    Fragment f = op.fragment;
+                    break;
+                case OP_ATTACH:
                     f.mNextAnim = op.enterAnim;
                     mManager.attachFragment(f, mTransition, mTransitionStyle);
-                }
-                break;
-                default: {
+                    break;
+                default:
                     throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
-                }
             }
-
-            op = op.next;
         }
 
         mManager.moveToState(mManager.mCurState, mTransition,
@@ -836,6 +717,72 @@
         }
     }
 
+    private void expandReplaceOps() {
+        final int numOps = mOps.size();
+
+        boolean hasReplace = false;
+        // Before we do anything, check to see if any replace operations exist:
+        for (int opNum = 0; opNum < numOps; opNum++) {
+            final Op op = mOps.get(opNum);
+            if (op.cmd == OP_REPLACE) {
+                hasReplace = true;
+                break;
+            }
+        }
+
+        if (!hasReplace) {
+            return; // nothing to expand
+        }
+
+        ArrayList<Fragment> added = (mManager.mAdded == null) ? new ArrayList<Fragment>() :
+                new ArrayList<>(mManager.mAdded);
+        for (int opNum = 0; opNum < mOps.size(); opNum++) {
+            final Op op = mOps.get(opNum);
+            switch (op.cmd) {
+                case OP_ADD:
+                case OP_ATTACH:
+                    added.add(op.fragment);
+                break;
+                case OP_REMOVE:
+                case OP_DETACH:
+                    added.remove(op.fragment);
+                    break;
+                case OP_REPLACE: {
+                    Fragment f = op.fragment;
+                    int containerId = f.mContainerId;
+                    boolean alreadyAdded = false;
+                    for (int i = added.size() - 1; i >= 0; i--) {
+                        Fragment old = added.get(i);
+                        if (old.mContainerId == containerId) {
+                            if (old == f) {
+                                alreadyAdded = true;
+                            } else {
+                                Op removeOp = new Op();
+                                removeOp.cmd = OP_REMOVE;
+                                removeOp.fragment = old;
+                                removeOp.enterAnim = op.enterAnim;
+                                removeOp.popEnterAnim = op.popEnterAnim;
+                                removeOp.exitAnim = op.exitAnim;
+                                removeOp.popExitAnim = op.popExitAnim;
+                                mOps.add(opNum, removeOp);
+                                added.remove(old);
+                                opNum++;
+                            }
+                        }
+                    }
+                    if (alreadyAdded) {
+                        mOps.remove(opNum);
+                        opNum--;
+                    } else {
+                        op.cmd = OP_ADD;
+                        added.add(f);
+                    }
+                }
+                break;
+            }
+        }
+    }
+
     private static void setFirstOut(SparseArray<Fragment> firstOutFragments,
                             SparseArray<Fragment> lastInFragments, Fragment fragment) {
         if (fragment != null) {
@@ -891,30 +838,13 @@
         if (!mManager.mContainer.onHasView()) {
             return; // nothing to see, so no transitions
         }
-        Op op = mHead;
-        while (op != null) {
+        final int numOps = mOps.size();
+        for (int opNum = 0; opNum < numOps; opNum++) {
+            final Op op = mOps.get(opNum);
             switch (op.cmd) {
                 case OP_ADD:
                     setLastIn(firstOutFragments, lastInFragments, op.fragment);
                     break;
-                case OP_REPLACE: {
-                    Fragment f = op.fragment;
-                    if (mManager.mAdded != null) {
-                        for (int i = 0; i < mManager.mAdded.size(); i++) {
-                            Fragment old = mManager.mAdded.get(i);
-                            if (f == null || old.mContainerId == f.mContainerId) {
-                                if (old == f) {
-                                    f = null;
-                                    lastInFragments.remove(old.mContainerId);
-                                } else {
-                                    setFirstOut(firstOutFragments, lastInFragments, old);
-                                }
-                            }
-                        }
-                    }
-                    setLastIn(firstOutFragments, lastInFragments, op.fragment);
-                    break;
-                }
                 case OP_REMOVE:
                     setFirstOut(firstOutFragments, lastInFragments, op.fragment);
                     break;
@@ -931,8 +861,6 @@
                     setLastIn(firstOutFragments, lastInFragments, op.fragment);
                     break;
             }
-
-            op = op.next;
         }
     }
 
@@ -950,20 +878,13 @@
         if (!mManager.mContainer.onHasView()) {
             return; // nothing to see, so no transitions
         }
-        Op op = mTail;
-        while (op != null) {
+        final int numOps = mOps.size();
+        for (int opNum = numOps - 1; opNum >= 0; opNum--) {
+            final Op op = mOps.get(opNum);
             switch (op.cmd) {
                 case OP_ADD:
                     setFirstOut(firstOutFragments, lastInFragments, op.fragment);
                     break;
-                case OP_REPLACE:
-                    if (op.removed != null) {
-                        for (int i = op.removed.size() - 1; i >= 0; i--) {
-                            setLastIn(firstOutFragments, lastInFragments, op.removed.get(i));
-                        }
-                    }
-                    setFirstOut(firstOutFragments, lastInFragments, op.fragment);
-                    break;
                 case OP_REMOVE:
                     setLastIn(firstOutFragments, lastInFragments, op.fragment);
                     break;
@@ -980,8 +901,6 @@
                     setFirstOut(firstOutFragments, lastInFragments, op.fragment);
                     break;
             }
-
-            op = op.prev;
         }
     }
 
@@ -1691,74 +1610,44 @@
 
         bumpBackStackNesting(-1);
 
-        Op op = mTail;
-        while (op != null) {
+        final int numOps = mOps.size();
+        for (int opNum = numOps - 1; opNum >= 0; opNum--) {
+            final Op op = mOps.get(opNum);
+            Fragment f = op.fragment;
             switch (op.cmd) {
-                case OP_ADD: {
-                    Fragment f = op.fragment;
+                case OP_ADD:
                     f.mNextAnim = op.popExitAnim;
                     mManager.removeFragment(f,
                             FragmentManagerImpl.reverseTransit(mTransition),
                             mTransitionStyle);
-                }
-                break;
-                case OP_REPLACE: {
-                    Fragment f = op.fragment;
-                    if (f != null) {
-                        f.mNextAnim = op.popExitAnim;
-                        mManager.removeFragment(f,
-                                FragmentManagerImpl.reverseTransit(mTransition),
-                                mTransitionStyle);
-                    }
-                    if (op.removed != null) {
-                        for (int i = 0; i < op.removed.size(); i++) {
-                            Fragment old = op.removed.get(i);
-                            old.mNextAnim = op.popEnterAnim;
-                            mManager.addFragment(old, false);
-                        }
-                    }
-                }
-                break;
-                case OP_REMOVE: {
-                    Fragment f = op.fragment;
+                    break;
+                case OP_REMOVE:
                     f.mNextAnim = op.popEnterAnim;
                     mManager.addFragment(f, false);
-                }
-                break;
-                case OP_HIDE: {
-                    Fragment f = op.fragment;
+                    break;
+                case OP_HIDE:
                     f.mNextAnim = op.popEnterAnim;
                     mManager.showFragment(f,
                             FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
-                }
-                break;
-                case OP_SHOW: {
-                    Fragment f = op.fragment;
+                    break;
+                case OP_SHOW:
                     f.mNextAnim = op.popExitAnim;
                     mManager.hideFragment(f,
                             FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
-                }
-                break;
-                case OP_DETACH: {
-                    Fragment f = op.fragment;
+                    break;
+                case OP_DETACH:
                     f.mNextAnim = op.popEnterAnim;
                     mManager.attachFragment(f,
                             FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
-                }
-                break;
-                case OP_ATTACH: {
-                    Fragment f = op.fragment;
+                    break;
+                case OP_ATTACH:
                     f.mNextAnim = op.popExitAnim;
                     mManager.detachFragment(f,
                             FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
-                }
-                break;
-                default: {
+                    break;
+                default:
                     throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
-                }
             }
-
-            op = op.prev;
         }
 
         if (doStateMove) {
@@ -1845,7 +1734,7 @@
     }
 
     public boolean isEmpty() {
-        return mNumOp == 0;
+        return mOps.isEmpty();
     }
 
     public class TransitionState {
diff --git a/core/java/android/content/UriMatcher.java b/core/java/android/content/UriMatcher.java
index 71a035e..444edd0 100644
--- a/core/java/android/content/UriMatcher.java
+++ b/core/java/android/content/UriMatcher.java
@@ -167,7 +167,7 @@
         if (path != null) {
             String newPath = path;
             // Strip leading slash if present.
-            if (path.length() > 0 && path.charAt(0) == '/') {
+            if (path.length() > 1 && path.charAt(0) == '/') {
                 newPath = path.substring(1);
             }
             tokens = newPath.split("/");
diff --git a/core/java/android/net/ConnectivityMetricsLogger.java b/core/java/android/net/ConnectivityMetricsLogger.java
index 029c5bd..9a2d4e0 100644
--- a/core/java/android/net/ConnectivityMetricsLogger.java
+++ b/core/java/android/net/ConnectivityMetricsLogger.java
@@ -46,11 +46,12 @@
 
     public static final String DATA_KEY_EVENTS_COUNT = "count";
 
-    /** {@hide} */ protected final IConnectivityMetricsLogger mService;
+    /** {@hide} */ protected IConnectivityMetricsLogger mService;
     /** {@hide} */ protected volatile long mServiceUnblockedTimestampMillis;
     private int mNumSkippedEvents;
 
     public ConnectivityMetricsLogger() {
+        // TODO: consider not initializing mService in constructor
         this(IConnectivityMetricsLogger.Stub.asInterface(
                 ServiceManager.getService(CONNECTIVITY_METRICS_LOGGER_SERVICE)));
     }
@@ -61,6 +62,18 @@
         mService = service;
     }
 
+    /** {@hide} */
+    protected boolean checkLoggerService() {
+        if (mService != null) {
+            return true;
+        }
+        // Two threads racing here will write the same pointer because getService
+        // is idempotent once MetricsLoggerService is initialized.
+        mService = IConnectivityMetricsLogger.Stub.asInterface(
+                ServiceManager.getService(CONNECTIVITY_METRICS_LOGGER_SERVICE));
+        return mService != null;
+    }
+
     /**
      * Log a ConnectivityMetricsEvent.
      *
@@ -96,6 +109,12 @@
             // Log number of skipped events
             Bundle b = new Bundle();
             b.putInt(DATA_KEY_EVENTS_COUNT, mNumSkippedEvents);
+
+            // Log the skipped event.
+            // TODO: Note that some of the clients push all states events into the server,
+            // If we lose some states logged here, we might mess up the statistics happened at the
+            // backend. One of the options is to introduce a non-skippable flag for important events
+            // that are logged.
             skippedEventsEvent = new ConnectivityMetricsEvent(mServiceUnblockedTimestampMillis,
                     componentTag, TAG_SKIPPED_EVENTS, b);
 
diff --git a/core/java/android/net/metrics/IpConnectivityLog.java b/core/java/android/net/metrics/IpConnectivityLog.java
index a7c1d40..dd7bd1b 100644
--- a/core/java/android/net/metrics/IpConnectivityLog.java
+++ b/core/java/android/net/metrics/IpConnectivityLog.java
@@ -31,7 +31,7 @@
  */
 public class IpConnectivityLog extends ConnectivityMetricsLogger {
     private static String TAG = "IpConnectivityMetricsLogger";
-    private static final boolean DBG = false;
+    private static final boolean DBG = true;
 
     public IpConnectivityLog() {
         // mService initialized in super constructor.
@@ -52,9 +52,9 @@
      * @return true if the event was successfully logged.
      */
     public boolean log(long timestamp, Parcelable data) {
-        if (mService == null) {
+        if (!checkLoggerService()) {
             if (DBG) {
-                Log.d(TAG, CONNECTIVITY_METRICS_LOGGER_SERVICE + " service not ready");
+                Log.d(TAG, CONNECTIVITY_METRICS_LOGGER_SERVICE + " service was not ready");
             }
             return false;
         }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 08425b0..2bc1d74 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -6041,7 +6041,8 @@
                 return true;
             }
             return mEvent instanceof MotionEvent
-                    && mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER);
+                    && (mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
+                        || mEvent.isFromSource(InputDevice.SOURCE_ROTARY_ENCODER));
         }
 
         public boolean shouldSendToSynthesizer() {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index be9bcfa..91dcc16 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -1801,11 +1801,17 @@
     public abstract class OverflowArrayMap<T> {
         private static final String OVERFLOW_NAME = "*overflow*";
 
+        final int mUid;
         final ArrayMap<String, T> mMap = new ArrayMap<>();
         T mCurOverflow;
         ArrayMap<String, MutableInt> mActiveOverflow;
+        long mLastOverflowTime;
+        long mLastOverflowFinishTime;
+        long mLastClearTime;
+        long mLastCleanupTime;
 
-        public OverflowArrayMap() {
+        public OverflowArrayMap(int uid) {
+            mUid = uid;
         }
 
         public ArrayMap<String, T> getMap() {
@@ -1813,6 +1819,7 @@
         }
 
         public void clear() {
+            mLastClearTime = SystemClock.elapsedRealtime();
             mMap.clear();
             mCurOverflow = null;
             mActiveOverflow = null;
@@ -1829,6 +1836,7 @@
         }
 
         public void cleanup() {
+            mLastCleanupTime = SystemClock.elapsedRealtime();
             if (mActiveOverflow != null) {
                 if (mActiveOverflow.size() == 0) {
                     mActiveOverflow = null;
@@ -1895,6 +1903,7 @@
                     mActiveOverflow = new ArrayMap<>();
                 }
                 mActiveOverflow.put(name, new MutableInt(1));
+                mLastOverflowTime = SystemClock.elapsedRealtime();
                 return obj;
             }
 
@@ -1924,6 +1933,7 @@
                         over.value--;
                         if (over.value <= 0) {
                             mActiveOverflow.remove(name);
+                            mLastOverflowFinishTime = SystemClock.elapsedRealtime();
                         }
                         return obj;
                     }
@@ -1932,9 +1942,35 @@
 
             // Huh, they are stopping an active operation but we can't find one!
             // That's not good.
-            Slog.wtf(TAG, "Unable to find object for " + name + " mapsize="
-                    + mMap.size() + " activeoverflow=" + mActiveOverflow
-                    + " curoverflow=" + mCurOverflow);
+            StringBuilder sb = new StringBuilder();
+            sb.append("Unable to find object for ");
+            sb.append(name);
+            sb.append(" in uid ");
+            sb.append(mUid);
+            sb.append(" mapsize=");
+            sb.append(mMap.size());
+            sb.append(" activeoverflow=");
+            sb.append(mActiveOverflow);
+            sb.append(" curoverflow=");
+            sb.append(mCurOverflow);
+            long now = SystemClock.elapsedRealtime();
+            if (mLastOverflowTime != 0) {
+                sb.append(" lastOverflowTime=");
+                TimeUtils.formatDuration(mLastOverflowTime-now, sb);
+            }
+            if (mLastOverflowFinishTime != 0) {
+                sb.append(" lastOverflowFinishTime=");
+                TimeUtils.formatDuration(mLastOverflowFinishTime-now, sb);
+            }
+            if (mLastClearTime != 0) {
+                sb.append(" lastClearTime=");
+                TimeUtils.formatDuration(mLastClearTime-now, sb);
+            }
+            if (mLastCleanupTime != 0) {
+                sb.append(" lastCleanupTime=");
+                TimeUtils.formatDuration(mLastCleanupTime-now, sb);
+            }
+            Slog.wtf(TAG, sb.toString());
             return null;
         }
 
@@ -5103,18 +5139,18 @@
             mSystemCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
             mCpuPower = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
 
-            mWakelockStats = mBsi.new OverflowArrayMap<Wakelock>() {
+            mWakelockStats = mBsi.new OverflowArrayMap<Wakelock>(uid) {
                 @Override public Wakelock instantiateObject() {
                     return new Wakelock(mBsi, Uid.this);
                 }
             };
-            mSyncStats = mBsi.new OverflowArrayMap<StopwatchTimer>() {
+            mSyncStats = mBsi.new OverflowArrayMap<StopwatchTimer>(uid) {
                 @Override public StopwatchTimer instantiateObject() {
                     return new StopwatchTimer(mBsi.mClocks, Uid.this, SYNC, null,
                             mBsi.mOnBatteryTimeBase);
                 }
             };
-            mJobStats = mBsi.new OverflowArrayMap<StopwatchTimer>() {
+            mJobStats = mBsi.new OverflowArrayMap<StopwatchTimer>(uid) {
                 @Override public StopwatchTimer instantiateObject() {
                     return new StopwatchTimer(mBsi.mClocks, Uid.this, JOB, null,
                             mBsi.mOnBatteryTimeBase);
diff --git a/core/res/Android.mk b/core/res/Android.mk
index a1bef83..b066929 100644
--- a/core/res/Android.mk
+++ b/core/res/Android.mk
@@ -16,16 +16,18 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
+LOCAL_USE_AAPT2 := true
 LOCAL_NO_STANDARD_LIBRARIES := true
 LOCAL_PACKAGE_NAME := framework-res
 LOCAL_CERTIFICATE := platform
+LOCAL_MODULE_TAGS := optional
 
-# Tell aapt to create "extending (non-application)" resource IDs,
-# since these resources will be used by many apps.
-LOCAL_AAPT_FLAGS := -x
+# Generate private symbols into the com.android.internal.R class
+# so they are not accessible to 3rd party apps.
 LOCAL_AAPT_FLAGS += --private-symbols com.android.internal
 
-LOCAL_MODULE_TAGS := optional
+# Framework doesn't need versioning since it IS the platform.
+LOCAL_AAPT_FLAGS += --no-auto-version
 
 # Install this alongside the libraries.
 LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)
@@ -34,12 +36,4 @@
 # PRODUCT-agnostic resource data like IDs and type definitions.
 LOCAL_EXPORT_PACKAGE_RESOURCES := true
 
-# Include resources generated by system RenderScript files.
-framework_GENERATED_SOURCE_DIR := $(call intermediates-dir-for,JAVA_LIBRARIES,framework,,COMMON)/src
-framework_RenderScript_STAMP_FILE := $(framework_GENERATED_SOURCE_DIR)/RenderScript.stamp
-#LOCAL_RESOURCE_DIR := $(framework_GENERATED_SOURCE_DIR)/renderscript/res $(LOCAL_PATH)/res
-
 include $(BUILD_PACKAGE)
-
-# Make sure the system .rs files get compiled before building the package-export.apk.
-# $(resource_export_package): $(framework_RenderScript_STAMP_FILE)
diff --git a/core/res/res/anim/watch_switch_thumb_to_off_animation.xml b/core/res/res/anim/watch_switch_thumb_to_off_animation.xml
index cd02e0d..c300894 100644
--- a/core/res/res/anim/watch_switch_thumb_to_off_animation.xml
+++ b/core/res/res/anim/watch_switch_thumb_to_off_animation.xml
@@ -1,4 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2016 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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
@@ -17,20 +18,34 @@
         android:interpolator="@android:interpolator/linear"
         android:propertyName="pathData"
         android:valueFrom="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
+        android:valueTo="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
+        android:valueType="pathType" />
+    <objectAnimator
+        android:duration="49"
+        android:interpolator="@android:interpolator/linear"
+        android:propertyName="pathData"
+        android:valueFrom="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
         android:valueTo="M -3.0,-7.0 l 6.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l -6.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
         android:valueType="pathType" />
     <objectAnimator
-        android:duration="66"
+        android:duration="83"
         android:interpolator="@android:interpolator/linear"
         android:propertyName="pathData"
         android:valueFrom="M -3.0,-7.0 l 6.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l -6.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
         android:valueTo="M -3.0,-7.0 l 6.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l -6.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
         android:valueType="pathType" />
     <objectAnimator
-        android:duration="66"
+        android:duration="50"
         android:interpolator="@android:interpolator/linear"
         android:propertyName="pathData"
         android:valueFrom="M -3.0,-7.0 l 6.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l -6.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
         android:valueTo="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
         android:valueType="pathType" />
+    <objectAnimator
+        android:duration="33"
+        android:interpolator="@android:interpolator/linear"
+        android:propertyName="pathData"
+        android:valueFrom="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
+        android:valueTo="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
+        android:valueType="pathType" />
 </set>
diff --git a/core/res/res/anim/watch_switch_thumb_to_on_animation.xml b/core/res/res/anim/watch_switch_thumb_to_on_animation.xml
index e644217..c300894 100644
--- a/core/res/res/anim/watch_switch_thumb_to_on_animation.xml
+++ b/core/res/res/anim/watch_switch_thumb_to_on_animation.xml
@@ -18,20 +18,34 @@
         android:interpolator="@android:interpolator/linear"
         android:propertyName="pathData"
         android:valueFrom="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
+        android:valueTo="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
+        android:valueType="pathType" />
+    <objectAnimator
+        android:duration="49"
+        android:interpolator="@android:interpolator/linear"
+        android:propertyName="pathData"
+        android:valueFrom="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
         android:valueTo="M -3.0,-7.0 l 6.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l -6.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
         android:valueType="pathType" />
     <objectAnimator
-        android:duration="66"
+        android:duration="83"
         android:interpolator="@android:interpolator/linear"
         android:propertyName="pathData"
         android:valueFrom="M -3.0,-7.0 l 6.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l -6.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
         android:valueTo="M -3.0,-7.0 l 6.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l -6.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
         android:valueType="pathType" />
     <objectAnimator
-        android:duration="66"
+        android:duration="50"
         android:interpolator="@android:interpolator/linear"
         android:propertyName="pathData"
         android:valueFrom="M -3.0,-7.0 l 6.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l -6.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
         android:valueTo="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
         android:valueType="pathType" />
+    <objectAnimator
+        android:duration="33"
+        android:interpolator="@android:interpolator/linear"
+        android:propertyName="pathData"
+        android:valueFrom="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
+        android:valueTo="M 0.0,-7.0 l 0.0,0.0 c 3.8659932486,0.0 7.0,3.1340067514 7.0,7.0 l 0.0,0.0 c 0.0,3.8659932486 -3.1340067514,7.0 -7.0,7.0 l 0.0,0.0 c -3.8659932486,0.0 -7.0,-3.1340067514 -7.0,-7.0 l 0.0,0.0 c 0.0,-3.8659932486 3.1340067514,-7.0 7.0,-7.0 Z"
+        android:valueType="pathType" />
 </set>
diff --git a/core/res/res/layout-notround-watch/alert_dialog_header_micro.xml b/core/res/res/layout-notround-watch/alert_dialog_title_material.xml
similarity index 85%
rename from core/res/res/layout-notround-watch/alert_dialog_header_micro.xml
rename to core/res/res/layout-notround-watch/alert_dialog_title_material.xml
index fc840d9..307c6db 100644
--- a/core/res/res/layout-notround-watch/alert_dialog_header_micro.xml
+++ b/core/res/res/layout-notround-watch/alert_dialog_title_material.xml
@@ -30,12 +30,9 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:src="@null" />
-    <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
+    <TextView android:id="@+id/alertTitle"
             style="?android:attr/windowTitleStyle"
-            android:ellipsize="end"
-            android:layout_marginStart="8dp"
             android:layout_marginBottom="8dp"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:textAlignment="viewStart" />
+            android:layout_height="wrap_content" />
 </LinearLayout>
diff --git a/core/res/res/layout-round-watch/alert_dialog_header_micro.xml b/core/res/res/layout-round-watch/alert_dialog_title_material.xml
similarity index 84%
rename from core/res/res/layout-round-watch/alert_dialog_header_micro.xml
rename to core/res/res/layout-round-watch/alert_dialog_title_material.xml
index 6f7ae02..0279911 100644
--- a/core/res/res/layout-round-watch/alert_dialog_header_micro.xml
+++ b/core/res/res/layout-round-watch/alert_dialog_title_material.xml
@@ -27,12 +27,10 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:src="@null" />
-    <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
+    <TextView android:id="@+id/alertTitle"
             style="?android:attr/windowTitleStyle"
-            android:ellipsize="end"
             android:layout_marginTop="36dp"
-            android:layout_marginBottom="4dp"
+            android:layout_marginBottom="8dp"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:textAlignment="center" />
+            android:layout_height="wrap_content" />
 </FrameLayout>
diff --git a/core/res/res/layout-watch/alert_dialog_material.xml b/core/res/res/layout-watch/alert_dialog_material.xml
index ce8e20a..002dde8 100644
--- a/core/res/res/layout-watch/alert_dialog_material.xml
+++ b/core/res/res/layout-watch/alert_dialog_material.xml
@@ -39,7 +39,7 @@
                 <include android:id="@+id/title_template"
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content"
-                        layout="@layout/alert_dialog_header_micro"/>
+                        layout="@layout/alert_dialog_title_material"/>
             </FrameLayout>
 
             <!-- Content Panel -->
@@ -50,7 +50,8 @@
                 <TextView android:id="@+id/message"
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content"
-                        android:textAppearance="@style/TextAppearance.Material.Body1"
+                        android:gravity="@integer/config_dialogTextGravity"
+                        android:textAppearance="@style/TextAppearance.Material.Subhead"
                         android:paddingStart="?dialogPreferredPadding"
                         android:paddingEnd="?dialogPreferredPadding"
                         android:paddingTop="8dip"
@@ -77,6 +78,7 @@
                 <LinearLayout
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content"
+                        android:layout_gravity="bottom"
                         android:orientation="vertical"
                         android:minHeight="@dimen/alert_dialog_button_bar_height"
                         android:paddingBottom="?dialogPreferredPadding"
diff --git a/core/res/res/layout/alert_dialog_material.xml b/core/res/res/layout/alert_dialog_material.xml
index 6d33de6..178505c 100644
--- a/core/res/res/layout/alert_dialog_material.xml
+++ b/core/res/res/layout/alert_dialog_material.xml
@@ -20,6 +20,7 @@
     android:id="@+id/parentPanel"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:gravity="start|top"
     android:orientation="vertical">
 
     <include layout="@layout/alert_dialog_title_material" />
diff --git a/core/res/res/values-notround-watch/config_material.xml b/core/res/res/values-notround-watch/config_material.xml
new file mode 100644
index 0000000..a99674f
--- /dev/null
+++ b/core/res/res/values-notround-watch/config_material.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds, only for Material theme.  Do not translate.
+
+     NOTE: The naming convention is "config_camelCaseValue".  -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Gravity that should be used for dialog text styles. Equivalent to: Gravity.START | Gravity.TOP -->
+    <integer name="config_dialogTextGravity">0x00800033</integer>
+</resources>
diff --git a/core/res/res/values-notround-watch/styles_material.xml b/core/res/res/values-notround-watch/styles_material.xml
deleted file mode 100644
index cd8521f4..0000000
--- a/core/res/res/values-notround-watch/styles_material.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <style name="TextAppearance.Material.AlertDialogMessage" parent="TextAppearance.Material.Body1"/>
-</resources>
diff --git a/core/res/res/values-round-watch/config_material.xml b/core/res/res/values-round-watch/config_material.xml
index bf445ef..871e910 100644
--- a/core/res/res/values-round-watch/config_material.xml
+++ b/core/res/res/values-round-watch/config_material.xml
@@ -19,4 +19,7 @@
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Don't clip on round screens so the list can scroll past the rounded edges. -->
     <bool name="config_preferenceFragmentClipToPadding">false</bool>
+
+    <!-- Gravity that should be used for dialog text styles. Equivalent to: Gravity.CENTER_HORIZONTAL | Gravity.TOP -->
+    <integer name="config_dialogTextGravity">0x00000031</integer>
 </resources>
diff --git a/core/res/res/values-round-watch/styles_material.xml b/core/res/res/values-round-watch/styles_material.xml
deleted file mode 100644
index a2f3c02..0000000
--- a/core/res/res/values-round-watch/styles_material.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <style name="TextAppearance.Material.AlertDialogMessage" parent="TextAppearance.Material.Body1">
-        <item name="textAlignment">center</item>
-    </style>
-</resources>
diff --git a/core/res/res/values-w180dp-notround-watch/dimens_material.xml b/core/res/res/values-w180dp-notround-watch/dimens_material.xml
new file mode 100644
index 0000000..79acf84
--- /dev/null
+++ b/core/res/res/values-w180dp-notround-watch/dimens_material.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <dimen name="text_size_display_4_material">80sp</dimen>
+    <dimen name="text_size_display_3_material">50sp</dimen>
+    <dimen name="text_size_display_2_material">40sp</dimen>
+    <dimen name="text_size_display_1_material">30sp</dimen>
+    <dimen name="text_size_headline_material">20sp</dimen>
+    <dimen name="text_size_title_material">18sp</dimen>
+    <dimen name="text_size_subhead_material">18sp</dimen>
+    <dimen name="text_size_title_material_toolbar">18dp</dimen>
+    <dimen name="text_size_subtitle_material_toolbar">18dp</dimen>
+    <dimen name="text_size_menu_material">18sp</dimen>
+    <dimen name="text_size_menu_header_material">16sp</dimen>
+    <dimen name="text_size_body_2_material">16sp</dimen>
+    <dimen name="text_size_body_1_material">16sp</dimen>
+    <dimen name="text_size_caption_material">14sp</dimen>
+    <dimen name="text_size_button_material">16sp</dimen>
+
+    <dimen name="text_size_large_material">18sp</dimen>
+    <dimen name="text_size_medium_material">16sp</dimen>
+    <dimen name="text_size_small_material">14sp</dimen>
+</resources>
diff --git a/core/res/res/values-w210dp-round-watch/dimens_material.xml b/core/res/res/values-w210dp-round-watch/dimens_material.xml
new file mode 100644
index 0000000..79acf84
--- /dev/null
+++ b/core/res/res/values-w210dp-round-watch/dimens_material.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <dimen name="text_size_display_4_material">80sp</dimen>
+    <dimen name="text_size_display_3_material">50sp</dimen>
+    <dimen name="text_size_display_2_material">40sp</dimen>
+    <dimen name="text_size_display_1_material">30sp</dimen>
+    <dimen name="text_size_headline_material">20sp</dimen>
+    <dimen name="text_size_title_material">18sp</dimen>
+    <dimen name="text_size_subhead_material">18sp</dimen>
+    <dimen name="text_size_title_material_toolbar">18dp</dimen>
+    <dimen name="text_size_subtitle_material_toolbar">18dp</dimen>
+    <dimen name="text_size_menu_material">18sp</dimen>
+    <dimen name="text_size_menu_header_material">16sp</dimen>
+    <dimen name="text_size_body_2_material">16sp</dimen>
+    <dimen name="text_size_body_1_material">16sp</dimen>
+    <dimen name="text_size_caption_material">14sp</dimen>
+    <dimen name="text_size_button_material">16sp</dimen>
+
+    <dimen name="text_size_large_material">18sp</dimen>
+    <dimen name="text_size_medium_material">16sp</dimen>
+    <dimen name="text_size_small_material">14sp</dimen>
+</resources>
diff --git a/core/res/res/values-watch/config_material.xml b/core/res/res/values-watch/config_material.xml
index 81b53e7..104d122 100644
--- a/core/res/res/values-watch/config_material.xml
+++ b/core/res/res/values-watch/config_material.xml
@@ -29,7 +29,4 @@
 
     <!-- Always overscan by default to ensure onApplyWindowInsets will always be called. -->
     <bool name="config_windowOverscanByDefault">true</bool>
-
-    <!-- Due to the smaller screen size, have dialog titles occupy more than 1 line. -->
-    <integer name="config_dialogWindowTitleMaxLines">3</integer>
 </resources>
diff --git a/core/res/res/values-watch/dimens_material.xml b/core/res/res/values-watch/dimens_material.xml
index d579434..96e91a5 100644
--- a/core/res/res/values-watch/dimens_material.xml
+++ b/core/res/res/values-watch/dimens_material.xml
@@ -14,5 +14,25 @@
      limitations under the License.
 -->
 <resources>
+    <dimen name="text_size_display_4_material">71sp</dimen>
+    <dimen name="text_size_display_3_material">44sp</dimen>
+    <dimen name="text_size_display_2_material">36sp</dimen>
+    <dimen name="text_size_display_1_material">27sp</dimen>
+    <dimen name="text_size_headline_material">18sp</dimen>
+    <dimen name="text_size_title_material">16sp</dimen>
+    <dimen name="text_size_subhead_material">16sp</dimen>
+    <dimen name="text_size_title_material_toolbar">16dp</dimen>
+    <dimen name="text_size_subtitle_material_toolbar">16dp</dimen>
+    <dimen name="text_size_menu_material">16sp</dimen>
+    <dimen name="text_size_menu_header_material">14sp</dimen>
+    <dimen name="text_size_body_2_material">14sp</dimen>
+    <dimen name="text_size_body_1_material">14sp</dimen>
+    <dimen name="text_size_caption_material">12sp</dimen>
+    <dimen name="text_size_button_material">14sp</dimen>
+
+    <dimen name="text_size_large_material">16sp</dimen>
+    <dimen name="text_size_medium_material">14sp</dimen>
+    <dimen name="text_size_small_material">12sp</dimen>
+
     <item name="text_line_spacing_multiplier_material" format="float" type="dimen">1.2</item>
 </resources>
diff --git a/core/res/res/values-watch/styles_material.xml b/core/res/res/values-watch/styles_material.xml
index f5735e6..e8d3d74 100644
--- a/core/res/res/values-watch/styles_material.xml
+++ b/core/res/res/values-watch/styles_material.xml
@@ -61,6 +61,9 @@
         <item name="divider">@empty</item>
     </style>
 
+    <style name="TextAppearance.Material.ListItem" parent="TextAppearance.Material.Body1" />
+    <style name="TextAppearance.Material.ListItemSecondary" parent="TextAppearance.Material.Caption" />
+
     <style name="Widget.Material.TextView" parent="Widget.TextView">
         <item name="breakStrategy">balanced</item>
     </style>
@@ -89,6 +92,14 @@
         <item name="descendantFocusability">blocksDescendants</item>
     </style>
 
+    <style name="DialogWindowTitle.Material">
+        <item name="maxLines">3</item>
+        <item name="scrollHorizontally">false</item>
+        <item name="textAppearance">@style/TextAppearance.Material.DialogWindowTitle</item>
+        <item name="gravity">@integer/config_dialogTextGravity</item>
+        <item name="ellipsize">end</item>
+    </style>
+
     <!-- DO NOTE TRANSLATE Spans within this text are applied to style composing regions
     within an EditText widget. The text content is ignored and not used.
     Note: This is @color/material_deep_teal_200, cannot use @color references here. -->
diff --git a/core/res/res/values/config_material.xml b/core/res/res/values/config_material.xml
index a37be83..397635f 100644
--- a/core/res/res/values/config_material.xml
+++ b/core/res/res/values/config_material.xml
@@ -32,9 +32,6 @@
     <!-- True if windowOverscan should be on by default. -->
     <bool name="config_windowOverscanByDefault">false</bool>
 
-    <!-- Max number of lines for the dialog title. -->
-    <integer name="config_dialogWindowTitleMaxLines">1</integer>
-
     <!-- True if preference fragment should clip to padding. -->
     <bool name="config_preferenceFragmentClipToPadding">true</bool>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 77de87d..a37db7e 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2742,4 +2742,25 @@
     <public type="attr" name="showMetadataInPreview" id="0x0101052f" />
     <public type="attr" name="colorSecondary" id="0x01010530" />
 
+  <!-- ===============================================================
+       Resources added in version O of the platform
+
+       NOTE: add <public> elements within a <public-group> like so:
+
+       <public-group type="attr" first-id="0x01010531">
+           <public name="exampleAttr1" />
+           <public name="exampleAttr2" />
+       </public-group>
+       =============================================================== -->
+    <eat-comment />
+
+    <public-group type="attr" first-id="0x01010531">
+    </public-group>
+
+    <public-group type="style" first-id="0x010302e0">
+    </public-group>
+
+    <public-group type="id" first-id="0x01020041">
+    </public-group>
+
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 998dab65..77de0af 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2795,8 +2795,8 @@
     <!-- [CHAR LIMIT=NONE] Message shown in upgrading dialog when doing an fstrim. -->
     <string name="android_upgrading_fstrim">Optimizing storage.</string>
 
-    <!-- [CHAR LIMIT=40] Title of notification that is shown when performing a system upgrade. -->
-    <string name="android_upgrading_notification_title">Android is upgrading</string>
+    <!-- [CHAR LIMIT=40] Title of notification that is shown when finishing a system upgrade. -->
+    <string name="android_upgrading_notification_title">Finishing Android update\u2026</string>
     <!-- [CHAR LIMIT=200] Body of notification that is shown when performing a system upgrade. -->
     <string name="android_upgrading_notification_body">Some apps may not work properly until the upgrade finishes</string>
 
@@ -4167,7 +4167,7 @@
 
     <!-- [CHAR_LIMIT=NONE] Data saver: Feature description -->
     <string name="data_saver_description">To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them.</string>
-    <!-- [CHAR_LIMIT=30] Data saver: Title on first-time dialogFeature description -->
+    <!-- [CHAR_LIMIT=35] Data saver: Title on first-time dialog -->
     <string name="data_saver_enable_title">Turn on Data Saver?</string>
     <!-- [CHAR_LIMIT=16] Data saver: Button to turn it on on first-time dialog -->
     <string name="data_saver_enable_button">Turn on</string>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 4435537..c66bc10 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -475,6 +475,9 @@
         <item name="textColor">#66000000</item>
     </style>
 
+    <style name="TextAppearance.Material.ListItem" parent="TextAppearance.Material.Subhead" />
+    <style name="TextAppearance.Material.ListItemSecondary" parent="TextAppearance.Material.Body1" />
+
     <style name="Widget.Material.Notification.ProgressBar" parent="Widget.Material.Light.ProgressBar.Horizontal" />
 
     <style name="Widget.Material.Notification.MessagingText" parent="Widget.Material.Light.TextView">
@@ -1246,7 +1249,7 @@
     <style name="DialogWindowTitleBackground.Material.Light" />
 
     <style name="DialogWindowTitle.Material">
-        <item name="maxLines">@integer/config_dialogWindowTitleMaxLines</item>
+        <item name="maxLines">1</item>
         <item name="scrollHorizontally">true</item>
         <item name="textAppearance">@style/TextAppearance.Material.DialogWindowTitle</item>
     </style>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 7e2867d..0eb4c8d 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -114,9 +114,9 @@
         <item name="listPreferredItemHeightSmall">48dip</item>
         <item name="listPreferredItemHeightLarge">80dip</item>
         <item name="dropdownListPreferredItemHeight">?attr/listPreferredItemHeightSmall</item>
-        <item name="textAppearanceListItem">@style/TextAppearance.Material.Subhead</item>
-        <item name="textAppearanceListItemSmall">@style/TextAppearance.Material.Subhead</item>
-        <item name="textAppearanceListItemSecondary">@style/TextAppearance.Material.Body1</item>
+        <item name="textAppearanceListItem">@style/TextAppearance.Material.ListItem</item>
+        <item name="textAppearanceListItemSmall">@style/TextAppearance.Material.ListItem</item>
+        <item name="textAppearanceListItemSecondary">@style/TextAppearance.Material.ListItemSecondary</item>
         <item name="listPreferredItemPaddingLeft">@dimen/list_item_padding_horizontal_material</item>
         <item name="listPreferredItemPaddingRight">@dimen/list_item_padding_horizontal_material</item>
         <item name="listPreferredItemPaddingStart">@dimen/list_item_padding_start_material</item>
@@ -475,9 +475,9 @@
         <item name="listPreferredItemHeightSmall">48dip</item>
         <item name="listPreferredItemHeightLarge">80dip</item>
         <item name="dropdownListPreferredItemHeight">?attr/listPreferredItemHeightSmall</item>
-        <item name="textAppearanceListItem">@style/TextAppearance.Material.Subhead</item>
-        <item name="textAppearanceListItemSmall">@style/TextAppearance.Material.Subhead</item>
-        <item name="textAppearanceListItemSecondary">@style/TextAppearance.Material.Body1</item>
+        <item name="textAppearanceListItem">@style/TextAppearance.Material.ListItem</item>
+        <item name="textAppearanceListItemSmall">@style/TextAppearance.Material.ListItem</item>
+        <item name="textAppearanceListItemSecondary">@style/TextAppearance.Material.ListItemSecondary</item>
         <item name="listPreferredItemPaddingLeft">@dimen/list_item_padding_horizontal_material</item>
         <item name="listPreferredItemPaddingRight">@dimen/list_item_padding_horizontal_material</item>
         <item name="listPreferredItemPaddingStart">@dimen/list_item_padding_start_material</item>
diff --git a/core/tests/coretests/src/android/net/UriMatcherTest.java b/core/tests/coretests/src/android/net/UriMatcherTest.java
index a728d4f..dd46fa3 100644
--- a/core/tests/coretests/src/android/net/UriMatcherTest.java
+++ b/core/tests/coretests/src/android/net/UriMatcherTest.java
@@ -82,9 +82,31 @@
         checkAll(matcher);
     }
 
+    @SmallTest
+    public void testContentUrisWithLeadingSlashAndOnlySlash() {
+        UriMatcher matcher = new UriMatcher(ROOT);
+        matcher.addURI("people", "/", PEOPLE);
+        matcher.addURI("people", "/#", PEOPLE_ID);
+        matcher.addURI("people", "/#/phones", PEOPLE_PHONES);
+        matcher.addURI("people", "/#/phones/blah", PEOPLE_PHONES_ID);
+        matcher.addURI("people", "/#/phones/#", PEOPLE_PHONES_ID);
+        matcher.addURI("people", "/#/addresses", PEOPLE_ADDRESSES);
+        matcher.addURI("people", "/#/addresses/#", PEOPLE_ADDRESSES_ID);
+        matcher.addURI("people", "/#/contact-methods", PEOPLE_CONTACTMETH);
+        matcher.addURI("people", "/#/contact-methods/#", PEOPLE_CONTACTMETH_ID);
+        matcher.addURI("calls", "/", CALLS);
+        matcher.addURI("calls", "/#", CALLS_ID);
+        matcher.addURI("caller-id", "/", CALLERID);
+        matcher.addURI("caller-id", "/*", CALLERID_TEXT);
+        matcher.addURI("filter-recent", null, FILTERRECENT);
+        matcher.addURI("auth", "/another/path/segment", ANOTHER_PATH_SEGMENT);
+        checkAll(matcher);
+    }
+
     private void checkAll(UriMatcher matcher) {
         check("content://asdf", UriMatcher.NO_MATCH, matcher);
         check("content://people", PEOPLE, matcher);
+        check("content://people/", PEOPLE, matcher);
         check("content://people/1", PEOPLE_ID, matcher);
         check("content://people/asdf", UriMatcher.NO_MATCH, matcher);
         check("content://people/2/phones", PEOPLE_PHONES, matcher);
@@ -97,9 +119,11 @@
         check("content://people/2/contact-methods/3", PEOPLE_CONTACTMETH_ID, matcher);
         check("content://people/2/contact-methods/asdf", UriMatcher.NO_MATCH, matcher);
         check("content://calls", CALLS, matcher);
+        check("content://calls/", CALLS, matcher);
         check("content://calls/1", CALLS_ID, matcher);
         check("content://calls/asdf", UriMatcher.NO_MATCH, matcher);
         check("content://caller-id", CALLERID, matcher);
+        check("content://caller-id/", CALLERID, matcher);
         check("content://caller-id/asdf", CALLERID_TEXT, matcher);
         check("content://caller-id/1", CALLERID_TEXT, matcher);
         check("content://filter-recent", FILTERRECENT, matcher);
diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index 3cbfde9..f5d23e8 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -59,7 +59,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on July 11, 2016.
+<p style="clear:both"><em>Data collected during a 7-day period ending on August 1, 2016.
 <br/>Any versions with less than 0.1% distribution are not shown.</em>
 </p>
 
@@ -81,7 +81,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on July 11, 2016.
+<p style="clear:both"><em>Data collected during a 7-day period ending on August 1, 2016.
 
 <br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
 
@@ -101,7 +101,7 @@
 
 
 <img alt="" style="float:right"
-src="//chart.googleapis.com/chart?chl=GL%202.0%7CGL%203.0%7CGL%203.1&chf=bg%2Cs%2C00000000&chd=t%3A47.5%2C41.9%2C10.6&chco=c4df9b%2C6fad0c&cht=p&chs=400x250">
+src="//chart.googleapis.com/chart?chl=GL%202.0%7CGL%203.0%7CGL%203.1&chf=bg%2Cs%2C00000000&chd=t%3A46.0%2C42.6%2C11.4&chco=c4df9b%2C6fad0c&cht=p&chs=400x250">
 
 <p>To declare which version of OpenGL ES your application requires, you should use the {@code
 android:glEsVersion} attribute of the <a
@@ -119,21 +119,21 @@
 </tr>
 <tr>
 <td>2.0</td>
-<td>47.5%</td>
+<td>46.0%</td>
 </tr>
 <tr>
 <td>3.0</td>
-<td>41.9%</td>
+<td>42.6%</td>
 </tr>
 <tr>
 <td>3.1</td>
-<td>10.6%</td>
+<td>11.4%</td>
 </tr>
 </table>
 
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on July 11, 2016</em></p>
+<p style="clear:both"><em>Data collected during a 7-day period ending on August 1, 2016</em></p>
 
 
 
@@ -147,19 +147,19 @@
       "Large": {
         "hdpi": "0.5",
         "ldpi": "0.2",
-        "mdpi": "4.4",
+        "mdpi": "4.3",
         "tvdpi": "2.1",
         "xhdpi": "0.5"
       },
       "Normal": {
-        "hdpi": "40.9",
-        "mdpi": "4.1",
+        "hdpi": "40.0",
+        "mdpi": "3.8",
         "tvdpi": "0.1",
-        "xhdpi": "26.3",
-        "xxhdpi": "15.1"
+        "xhdpi": "27.3",
+        "xxhdpi": "15.5"
       },
       "Small": {
-        "ldpi": "1.9"
+        "ldpi": "1.8"
       },
       "Xlarge": {
         "hdpi": "0.3",
@@ -167,8 +167,8 @@
         "xhdpi": "0.7"
       }
     },
-    "densitychart": "//chart.googleapis.com/chart?chco=c4df9b%2C6fad0c&chd=t%3A2.1%2C11.4%2C2.2%2C41.7%2C27.5%2C15.1&chf=bg%2Cs%2C00000000&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chs=400x250&cht=p",
-    "layoutchart": "//chart.googleapis.com/chart?chco=c4df9b%2C6fad0c&chd=t%3A3.9%2C7.7%2C86.5%2C1.9&chf=bg%2Cs%2C00000000&chl=Xlarge%7CLarge%7CNormal%7CSmall&chs=400x250&cht=p"
+    "densitychart": "//chart.googleapis.com/chart?chd=t%3A2.0%2C11.0%2C2.2%2C40.8%2C28.5%2C15.5&chf=bg%2Cs%2C00000000&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&cht=p&chs=400x250&chco=c4df9b%2C6fad0c",
+    "layoutchart": "//chart.googleapis.com/chart?chd=t%3A3.9%2C7.6%2C86.7%2C1.8&chf=bg%2Cs%2C00000000&chl=Xlarge%7CLarge%7CNormal%7CSmall&cht=p&chs=400x250&chco=c4df9b%2C6fad0c"
   }
 ];
 
@@ -176,7 +176,7 @@
 var VERSION_DATA =
 [
   {
-    "chart": "//chart.googleapis.com/chart?chco=c4df9b%2C6fad0c&chd=t%3A0.1%2C1.9%2C1.7%2C17.8%2C30.2%2C35.1%2C13.3&chf=bg%2Cs%2C00000000&chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat%7CLollipop%7CMarshmallow&chs=500x250&cht=p",
+    "chart": "//chart.googleapis.com/chart?chd=t%3A0.1%2C1.7%2C1.6%2C16.7%2C29.2%2C35.5%2C15.2&chf=bg%2Cs%2C00000000&chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat%7CLollipop%7CMarshmallow&cht=p&chs=500x250&chco=c4df9b%2C6fad0c",
     "data": [
       {
         "api": 8,
@@ -186,47 +186,47 @@
       {
         "api": 10,
         "name": "Gingerbread",
-        "perc": "1.9"
+        "perc": "1.7"
       },
       {
         "api": 15,
         "name": "Ice Cream Sandwich",
-        "perc": "1.7"
+        "perc": "1.6"
       },
       {
         "api": 16,
         "name": "Jelly Bean",
-        "perc": "6.4"
+        "perc": "6.0"
       },
       {
         "api": 17,
         "name": "Jelly Bean",
-        "perc": "8.8"
+        "perc": "8.3"
       },
       {
         "api": 18,
         "name": "Jelly Bean",
-        "perc": "2.6"
+        "perc": "2.4"
       },
       {
         "api": 19,
         "name": "KitKat",
-        "perc": "30.1"
+        "perc": "29.2"
       },
       {
         "api": 21,
         "name": "Lollipop",
-        "perc": "14.3"
+        "perc": "14.1"
       },
       {
         "api": 22,
         "name": "Lollipop",
-        "perc": "20.8"
+        "perc": "21.4"
       },
       {
         "api": 23,
         "name": "Marshmallow",
-        "perc": "13.3"
+        "perc": "15.2"
       }
     ]
   }
diff --git a/docs/html/distribute/googleplay/developer-console.jd b/docs/html/distribute/googleplay/developer-console.jd
index c826e82..5a6c96fc 100644
--- a/docs/html/distribute/googleplay/developer-console.jd
+++ b/docs/html/distribute/googleplay/developer-console.jd
@@ -10,30 +10,30 @@
   <div id="qv">
     <h2>Features</h2>
     <ol>
-      <li><a href="#latest">Latest blog posts</a></li>
-      <li><a href="#publish">Publish with confidence</a></li>
-      <li><a href="#aquire-users">Acquire users</a></li>
-      <li><a href="#insights">Actionable insights</a></li>
-      <li><a href="#manage">Manage your app</a></li>
+      <li><a href="#latest">Latest Blog Posts</a></li>
+      <li><a href="#publish">Publish with Confidence</a></li>
+      <li><a href="#aquire-users">Acquire Users</a></li>
+      <li><a href="#insights">Learn about Users and App Performance</a></li>
+      <li><a href="#manage">Manage Your App</a></li>
     </ol>
   </div>
 </div>
 
 <p>
-  The <a href="https://play.google.com/apps/publish/">Google Play Developer
-  Console</a> is your home for publishing operations and tools.
+  The <a class="external-link" href="https://play.google.com/apps/publish/">Google Play Developer
+  Console</a> is your home for publishing and managing your apps.
 </p>
 
 <img src="{@docRoot}images/distribute/googleplay/gp-devconsole-home.png" style="width:480px;">
 
 <p>
-  Upload apps, build your product pages, configure prices and distribution, and
-  publish. You can manage all phases of publishing on Google Play through the
-  Developer Console, from any web browser.
+  You can manage all phases of publishing on Google Play through the Developer
+  Console. Using any web browser, you can upload apps, build product pages, set
+  prices, configure distribution, and publish apps.
 </p>
 
 <p>
-  Once you've <a href=
+  After you've <a href=
   "{@docRoot}distribute/googleplay/start.html">registered</a> and received
   verification by email, you can sign in to your Google Play Developer Console.
 </p>
@@ -44,7 +44,7 @@
 
 <div class="dynamic-grid">
 <div class="headerLine">
-<h2 id="latest">Latest blog posts</h2>
+<h2 id="latest">Latest Blog Posts</h2>
 </div>
 
 <div class="resource-widget resource-flow-layout col-13"
@@ -54,31 +54,10 @@
   data-maxResults="3"></div>
   </div>
 
-<h2 id="publish">Publish with confidence</h2>
-
+<h2 id="publish">Publish with Confidence</h2>
+<p>The Developer Console provides rich testing features and staged rollouts that help you to
+ provide apps that satisfy your users.</p>
 <div class="wrap">
-  <h3 id="alpha-beta">Alpha and beta tests</h3>
-
-  <div class="cols" style="margin-top:2em;">
-    <div class="col-3of12">
-      <p>
-        Distribute your pre-release app to users as an open beta with a
-        one-click, opt-in URL or as a closed beta using an email list, Google
-        Group, or Google+ community. Users can then provide feedback, while not
-        affecting your app’s public reviews and rating. This valuable feedback
-        will help you test features and improve the quality of your app.
-        <a href="{@docRoot}distribute/engage/beta.html">Learn more</a>.
-      </p>
-    </div>
-
-    <div class="col-8of12 col-push-1of12">
-      <img src=
-      "{@docRoot}images/distribute/googleplay/dev-console_running-a-beta-test.png"
-      srcset=
-      "{@docRoot}images/distribute/googleplay/dev-console_running-a-beta-test.png 1x, {@docRoot}images/distribute/googleplay/dev-console_running-a-beta-test_2x.png 2x"
-      width="500">
-    </div>
-  </div>
 
   <h3 id="cloud-test">Cloud Test Lab</h3>
 
@@ -87,8 +66,8 @@
       <p>
         Get free automated testing of your app on physical devices covering
         nearly every brand, model, and version of the devices your users might
-        be using. The lab will help you quickly find compatibility issues you
-        may miss using only your available test devices. Sign-up in the
+        have. The lab helps you quickly find compatibility issues that you
+        might miss using only your available test devices. Sign up in the
         Developer Console to become an early tester before this feature becomes
         more widely available. <a href=
         "https://developers.google.com/cloud-test-lab/" class=
@@ -100,57 +79,85 @@
       <img src=
       "{@docRoot}images/distribute/googleplay/dev-console_cloud-test-lab.png"
       srcset=
-      "{@docRoot}images/distribute/googleplay/dev-console_cloud-test-lab.png 1x, {@docRoot}images/distribute/googleplay/dev-console_cloud-test-lab_2x.png 2x"
+      "{@docRoot}images/distribute/googleplay/dev-console_cloud-test-lab.png 1x,
+      {@docRoot}images/distribute/googleplay/dev-console_cloud-test-lab_2x.png 2x"
       width="500">
     </div>
   </div>
 </div>
 
+  <h3 id="alpha-beta">Alpha and beta tests</h3>
+
+  <div class="cols" style="margin-top:2em;">
+    <div class="col-3of12">
+      <p>
+      Collect user feedback on early versions of your app with alpha and beta testing.
+        Distribute your pre-release app to users as an open beta with a
+        one-click, opt-in URL or as a closed beta using an email list, Google
+        Group, or Google+ community. Users can provide feedback, while not
+        affecting your app’s public reviews and rating. This valuable feedback
+        helps you test features and improve the quality of your app.
+        <a href="{@docRoot}distribute/engage/beta.html">Learn more</a>.
+      </p>
+    </div>
+
+    <div class="col-8of12 col-push-1of12">
+      <img src=
+      "{@docRoot}images/distribute/googleplay/dev-console_running-a-beta-test.png"
+      srcset=
+      "{@docRoot}images/distribute/googleplay/dev-console_running-a-beta-test.png 1x,
+      {@docRoot}images/distribute/googleplay/dev-console_running-a-beta-test_2x.png 2x"
+      width="500">
+    </div>
+  </div>
+
 <h3 id="staged-rollouts">Staged rollouts</h3>
 
 <p>
-  Release app updates progressively to an increasing portion of your users and
-  monitor for missed issues. Then take the opportunity to fix problems before
-  all your users are affected. <a href=
+Discover and fix problems with a limited user base before making a wider release.
+With staged rollouts, you can release app updates progressively to an increasing portion of
+ your users.
+You can fix problems before your app reaches the broader user community. <a href=
   "https://support.google.com/googleplay/android-developer/answer/3131213"
-  class="external-link">Learn more.</a>
+  class="external-link">Learn more</a>.
 </p>
 
-<p class="aside">
-  <strong>Tip:</strong> If you find an issue during a rollout stage you can
-  halt the rollout to further minimize the effect, and then resume rollout once
-  a fix has been made.
+<p class="note">
+  <strong>Tip:</strong> If you find an issue during a rollout stage, you can
+  halt the rollout, make the fix, and then resume.
 </p>
 
-<h2 id="aquire-users">Aquire users</h2>
-
-  <h3 id="adwords">AdWords Universal App Campaigns</h3>
+<h2 id="aquire-users">Acquire Users</h2>
+<p>Using the Developer Console, you can configure targeted ads to present your app to more users.
+ You can test variations of your Play Store listings and track user responses.</p>
+  <h3 id="adwords">Promote your app with AdWords</h3>
 
   <p>
-    Easily and conveniently buy AdWords app install ads, across Search
+    Easily and conveniently buy AdWords app install ads. AdWords Universal App Campaigns
+    appear across Search
     (including Play Search), YouTube, AdMob, and the Google Display Network.
-    Simply set a budget and cost per acquisition and Google takes care of the
+    Set a budget and cost per acquisition, and Google takes care of the
     rest. <a href="{@docRoot}distribute/users/promote-with-ads.html">Learn
     more</a>.
   </p>
 
 <div class="wrap">
-  <h3 id="listing-experiments">Store Listing Experiments</h3>
+  <h3 id="listing-experiments">Increase installs with improved store listings</h3>
 
   <div class="cols" style="margin-top:2em;">
     <div class="col-3of12">
-      <p>
-        Test variations of the images and text used to promote and describe
-        your app on your Play store listing. Then when enough data has been
-        collected, choose to make the winning combination visible on Google
+      <p>With store listing experiments,
+        you can test variations of your app's Play Store listing.
+        You can try different combinations of images and text used to promote and describe
+        your app on its Play Store listing. Collect data, choose the best combination, and make
+        it visible on Google
         Play. <a href="{@docRoot}distribute/users/experiments.html">Learn
         more</a>.
       </p>
 
-      <p class="aside">
-        <strong>Tip:</strong> You can even try out different orders for your
-        screenshots and other images to discover which grabs users’ attention
-        the best.
+      <p class="note">
+        <strong>Tip:</strong> You can reorder your screenshots and other images in different ways
+        to determine the arrangement that best attracts users.
       </p>
     </div>
 
@@ -158,20 +165,21 @@
       <img src=
       "{@docRoot}images/distribute/googleplay/dev-console_store-listing-experiment.png"
       srcset=
-      "{@docRoot}images/distribute/googleplay/dev-console_store-listing-experiment.png 1x, {@docRoot}images/distribute/googleplay/dev-console_store-listing-experiment_2x.png 2x"
+      "{@docRoot}images/distribute/googleplay/dev-console_store-listing-experiment.png 1x,
+      {@docRoot}images/distribute/googleplay/dev-console_store-listing-experiment_2x.png 2x"
       width="500">
     </div>
   </div>
 
-  <h3 id="user-perf-report">User Acquisition performance report</h3>
+  <h3 id="user-perf-report">User acquisition performance report</h3>
 
   <div class="cols" style="margin-top:2em;">
     <div class="col-3of12">
       <p>
-        Discover where visitors to your Play Store listing come from, how many
-        go on to install your app, and how many buy your in-app products in the
-        User Acquisition performance report; compare cohorts, examine
-        acquisition channels, and see details of users and buyers. <a href=
+        Discover information about visitors to your Play Store listing, such as where they come
+        from, how many go on to install your app, and how many buy your in-app products. You
+        can also compare cohorts, examine acquisition channels, and see details of users and
+        buyers. <a href=
         "{@docRoot}distribute/users/user-acquisition.html">Learn more</a>.
       </p>
     </div>
@@ -180,14 +188,16 @@
       <img src=
       "{@docRoot}images/distribute/googleplay/dev-console_conversion-funnel.png"
       srcset=
-      "{@docRoot}images/distribute/googleplay/dev-console_conversion-funnel.png 1x, {@docRoot}images/distribute/googleplay/dev-console_conversion-funnel_2x.png 2x"
+      "{@docRoot}images/distribute/googleplay/dev-console_conversion-funnel.png 1x,
+      {@docRoot}images/distribute/googleplay/dev-console_conversion-funnel_2x.png 2x"
       width="500">
     </div>
   </div>
 </div>
 
-<h2 id="insights">Actionable insights</h2>
-
+<h2 id="insights">Learn about App Users and Performance</h2>
+<p>Using the Developer console, you can gain valuable insights about app performance.
+ You can better understand user behavior and find out ways to optimize your app. </p>
 <div class="wrap">
 
 <h3 id="player-analytics">Player Analytics</h3>
@@ -195,8 +205,10 @@
   <div class="cols" style="margin-top:2em;">
     <div class="col-3of12">
       <p>
-        With Google Play game services integration, discover more about the
-        behaviour of your game players; how they play and how they buy. Also get
+        Google Play game services offers a comprehensive dashboard of player and engagement
+        statistics.
+        With Player Analytics, discover more about the
+        behavior of your game users, including how they play and how they buy. Also get
         help setting and monitoring revenue budgets. <a href=
         "{@docRoot}distribute/engage/game-services.html">Learn more</a>.
       </p>
@@ -206,7 +218,8 @@
       <img src=
       "{@docRoot}images/distribute/googleplay/dev-console_player-analytics.png"
       srcset=
-      "{@docRoot}images/distribute/googleplay/dev-console_player-analytics.png 1x, {@docRoot}images/distribute/googleplay/dev-console_player-analytics_2x.png 2x"
+      "{@docRoot}images/distribute/googleplay/dev-console_player-analytics.png 1x,
+      {@docRoot}images/distribute/googleplay/dev-console_player-analytics_2x.png 2x"
       width="500">
     </div>
   </div>
@@ -216,74 +229,77 @@
   <div class="cols" style="margin-top:2em;">
     <div class="col-3of12">
       <p>
-        Get a wide range of reports on the performance of your app and behaviour
-        of users; such as installs, revenue, crashes, and more. Turn on email
-        alerts to be notified of any sudden changes to important stats. <a href=
-        "https://support.google.com/googleplay/android-developer/topic/3450942?ref_topic=3450986"
-        class="external-link">Learn more.</a>
+        Get a wide range of reports on the performance of your app and behavior
+        of users such as installs, revenue, and crashes. Turn on email
+        alerts to receive notifications of any sudden changes to important stats. <a  href=
+    "https://support.google.com/googleplay/android-developer/topic/3450942?ref_topic=3450986"
+        class="external-link">Learn more</a>.
       </p>
     </div>
 
     <div class="col-8of12 col-push-1of12">
       <img src=
       "{@docRoot}images/distribute/googleplay/dev-console_statistics.png" srcset=
-      "{@docRoot}images/distribute/googleplay/dev-console_statistics.png 1x, {@docRoot}images/distribute/googleplay/dev-console_statistics_2x.png 2x"
+      "{@docRoot}images/distribute/googleplay/dev-console_statistics.png 1x,
+      {@docRoot}images/distribute/googleplay/dev-console_statistics_2x.png 2x"
       width="500">
     </div>
   </div>
 </div>
 
 
-<h3 id="optimization"> Optimization tips</h3>
+<h3 id="optimization">Optimization tips</h3>
 
 <p>
-  Get tips, based on automatic app scanning, on ways in which you can improve
-  your app, everything from updating old APIs to suggestions for languages you
-  should consider localizing to.
+  Automatic app scanning provides tips on ways to improve your apps&mdash;everything
+  from updating old APIs to suggested languages for localization.
 </p>
 
-<h2 id="manage">Manage your app</h2>
+<h2 id="manage">Manage Your App</h2>
 
 <h3 id="manage-apks">Manage your APKs</h3>
 
 <p>
   Upload and manage your Android application packages (APK) to the Developer
-  Console as drafts or to your Alpha, Beta, or Production channels. <a href=
+  Console as drafts or to your Alpha, Beta, or Production channels. <a  href=
   "https://support.google.com/googleplay/android-developer/answer/113469?ref_topic=3450986"
-  class="external-link">Learn more.</a>
+  class="external-link">Learn more</a>.
 </p>
 
-<p class="aside">
-  <strong>Tip:</strong> Ensure users get the best possible experience for the
+<p class="note">
+  <strong>Tip:</strong> Ensure that users get the best possible experience for the
   smallest app downloads by creating multiple APKs with just the right content
-  for device screen size, hardware features and more.
+  for hardware features such as screen size. For more information about using multiple APKs,
+  see <a href="https://developer.android.com/training/multiple-apks/index.html">
+  Maintaining Multiple APKs.</a>
 </p>
 
 <h3 id="iap">In-app products and subscriptions</h3>
 
 <p>
-  Manage your in-app products and price them for local markets accordingly.
-  Offer weekly, monthly, annual, or seasonal subscriptions and take advantage
-  of features such as grace periods and trials. <a href=
+  Manage your in-app products and price them for local markets.
+  Offer weekly, monthly, annual, or seasonal subscriptions. Attract new users
+  with features such as grace periods and trials. <a href=
   "https://support.google.com/googleplay/android-developer/topic/3452896?ref_topic=3452890"
-  class="external-link">Learn more.</a>
+  class="external-link">Learn more</a>.
 </p>
 
 <h3 id="pricing">Pricing and distribution</h3>
 
 <p>
-  Control the price of your app for each country you choose to distribute to.
-  Make your app available to new audiences — opt-in to Android Auto, Android
+  Control the price of your app for each country that you distribute to.
+  Make your app available to new audiences&mdash;opt-in to Android Auto, Android
   TV, and Android Wear, as well as Designed for Families, Google Play for Work,
   and Google Play for Education. <a href=
   "https://support.google.com/googleplay/android-developer/answer/113469#pricing"
   class="external-link">Learn more</a>.
 </p>
 
-<p class="external-link">
-  <strong>Tip:</strong> You can set prices in other countries automatically
-  based on current exchange rates using the <strong>auto-convert prices
-  now</strong> feature.
+<p  class="note">
+  <strong>Note:</strong> When you distribute your app to countries that use other currencies,
+  the Google Play Developer Console autofills country-specific prices based on current exchange
+  rates and locally-relevant pricing patterns. You can update the exchange rates manually by
+  selecting <strong>Refresh exchange rates</strong>.
 </p>
 
 <p style="clear:both">
diff --git a/docs/html/google/play/billing/billing_overview.jd b/docs/html/google/play/billing/billing_overview.jd
index a05cc8d..7d932b7 100644
--- a/docs/html/google/play/billing/billing_overview.jd
+++ b/docs/html/google/play/billing/billing_overview.jd
@@ -7,19 +7,20 @@
 <div id="qv">
   <h2>Quickview</h2>
   <ul>
-    <li>Use In-app Billing to sell digital goods, including one-time items and
+    <li>Use In-app Billing to sell digital products, including one-time products and
 recurring subscriptions.</li>
-    <li>Supported for any app published on Google Play. You only need a Google
+    <li>In-app Billing is supported for any app published on Google Play. You need only a
+    Google
 Play Developer Console account and a Google payments merchant account.</li>
-    <li>Checkout processing is automatically handled by Google Play, with the
-same look-and-feel as for app purchases.</li>
+    <li>Google Play automatically handles checkout processing with the
+same look and feel as app purchases.</li>
   </ul>
   <h2>In this document</h2>
   <ol>
     <li><a href="#api">In-app Billing API</a></li>
     <li><a href="#products">In-app Products</a>
        <ol>
-       <li><a href="#prodtypes">Product Types</a>
+       <li><a href="#prodtypes">Product types</a>
        </ol>
     </li>
     <li><a href="#console">Google Play Developer Console</a></li>
@@ -27,30 +28,33 @@
     <li><a href="#samples">Sample App</a></li>
     <li><a href="#migration">Migration Considerations</a></li>
   </ol>
-   <h2>Related Samples</h2>
+   <h2>Related samples</h2>
   <ol>
     <li><a href="{@docRoot}training/in-app-billing/preparing-iab-app.html#GetSample">Sample
       Application (V3)</a></li>
   </ol>
-   <h2>Related Videos</h2>
+   <h2>Related videos</h2>
   <ol>
-    <li><a href="https://www.youtube.com/watch?v=UvCl5Xx7Z5o">Implementing
+    <li><a class="external-link"  href="https://www.youtube.com/watch?v=UvCl5Xx7Z5o">
+    Implementing
       Freemium</a></li>
   </ol>
 </div>
 </div>
 
-<p>This documentation describes the fundamental In-app Billing components and
+<p>This document describes the fundamental In-app Billing components and
 features that you need to understand in order to add In-app
 Billing features into your application.</p>
 
-<p class="note"><b>Note</b>: Ensure that you comply with applicable laws in the countries where you
-distribute apps. For example, in EU countries, laws based on the
-<a href="http://eur-lex.europa.eu/LexUriServ/LexUriServ.do?uri=OJ:L:2005:149:0022:0039:EN:PDF">
-Unfair Commercial Practices Directive</a> prohibit direct exhortations to children to buy advertised
-products or to persuade their parents or other adults to buy advertised products for them.
-See the
-<a href="http://ec.europa.eu/consumers/enforcement/docs/common_position_on_online_games_en.pdf">
+<p class="note"><b>Note</b>: Ensure that you comply with applicable laws in the countries where
+ you distribute apps. For example, in EU countries, laws based on the
+<a class="external-link"
+ href="http://eur-lex.europa.eu/LexUriServ/LexUriServ.do?uri=OJ:L:2005:149:0022:0039:EN:PDF">
+Unfair Commercial Practices Directive</a> prohibit direct exhortations to children to buy
+  advertised products or to persuade their parents or other adults to buy advertised products
+  for them. See the
+<a class="external-link"
+ href="http://ec.europa.eu/consumers/enforcement/docs/common_position_on_online_games_en.pdf">
 position of the EU consumer protection authorities</a> for more information on this and other
 topics.
 </p>
@@ -61,75 +65,82 @@
 app then conveys billing requests and responses between your
 application and the Google Play server. In practice, your application never
 directly communicates with the Google Play server. Instead, your application
-sends billing requests to the Google Play application over interprocess
+sends billing requests to the Google Play app over interprocess
 communication (IPC) and receives responses from the Google Play app.
 Your application does not manage any network connections between itself and
 the Google Play server.</p>
-<p>In-app Billing can be implemented only in applications that you publish
+<p>You can implement In-app Billing only in applications that you publish
 through Google Play. To complete in-app purchase requests, the Google Play app
 must be able to access the Google Play server over the network.</p>
 
-<p>In-app billing Version 3 is the latest version, and maintains very broad
+<p>In-app Billing Version 3 is the latest version, and it maintains very broad
 compatibility across the range of Android devices. In-app Billing Version 3 is
-supported on devices running Android 2.2 or higher that have the latest version
-of the Google Play store installed (<a
+supported on devices running Android 2.2 (API level 8) or higher that have the latest version
+of the Google Play app installed (<a
 href="{@docRoot}about/dashboards/index.html">a vast majority</a> of active
 devices).</p>
 
 <h4>Version 3 features</h4>
+<p>In-app Billing Version 3 provides the following features:</p>
 <ul>
-<li>Requests are sent through a streamlined API that allows you to easily request
-product details from Google Play, order in-app products, and quickly restore
-items based on users' product ownership</li>
-<li>Order information is synchronously propagated to the device on purchase
-completion</li>
-<li>All purchases are “managed” (that is, Google Play keeps track of the user's
-ownership of in-app products). The user cannot own multiple copies of an in-app
-item; only one copy can be owned at any point in time</li>
-<li>Purchased items can be consumed. When consumed, the item reverts to the
-"unowned" state and can be purchased again from Google Play</li>
-<li>Provides support for <a
-  href="{@docRoot}google/play/billing/billing_subscriptions.html">subscriptions</a></li>
+<li>Your app sends requests through a streamlined API that allows users to easily request
+product details from Google Play and order in-app products. The API quickly restores
+products based on the user's ownership.</li>
+<li>The API synchronously propagates order information to the device on purchase
+completion.</li>
+<li>All purchases are <em>managed</em> (that is, Google Play keeps track of the user's
+ownership of in-app products). The user can't own multiple copies of an in-app
+product; only one copy can be owned at any point in time.</li>
+<li>Purchased products can be consumed. When consumed, the product reverts to the
+<em>unowned</em> state and can be purchased again from Google Play.</li>
+<li>The API provides support for <a
+  href="{@docRoot}google/play/billing/billing_subscriptions.html">subscriptions</a>.</li>
 </ul>
 <p>For details about other versions of In-app Billing, see the
 <a href="{@docRoot}google/play/billing/versions.html">Version Notes</a>.</p>
 
 <h2 id="products">In-app Products</h2>
-<p>In-app products are the digital goods that you offer for sale from inside your
-application to users. Examples of digital goods includes in-game currency,
+<p>In-app products are the digital products that you offer for sale to users from inside your
+application. Examples of digital products include in-game currency,
 application feature upgrades that enhance the user experience, and new content
 for your application.</p>
 <p>You can use In-app Billing to sell only digital content.
-You cannot use In-app Billing to sell physical goods, personal services, or
-anything that requires physical delivery. Unlike with priced applications, once
-the user has purchased an in-app product there is no refund window.</p>
+You can't use In-app Billing to sell physical products, personal services, or
+anything that requires physical delivery. Unlike with priced applications, there is no refund
+ window after
+the user has purchased an in-app product.</p>
 <p>Google Play does not provide any form of content delivery. You are
 responsible for delivering the digital content that you sell in your
-applications. In-app products are always explicitly associated with one and
-only one app. That is, one application cannot purchase an in-app product
-published for another app, even if they are from the same developer.</p>
+applications. In-app products are always explicitly associated with
+ only one app. That is, one application can't purchase an in-app product
+that is published for another app, even if they are from the same developer.</p>
 
 <h3 id="prodtypes">Product types</h3>
 <p>In-app Billing supports different product types to give you flexibility in
 how you monetize your application. In all cases, you define your products using
 the Google Play Developer Console.</p>
-<p>You can specify these types of products for your In-app Billing application
-— <em>managed in-app products</em> and <em>subscriptions</em>. Google Play
-handles and tracks ownership for in-app products and subscriptions on your
-application on a per user account basis.
-<a href="{@docRoot}google/play/billing/api.html#producttypes">Learn more about
-the product types supported by In-app Billing Version 3</a>.</p>
+<p>You can specify two product types for your In-app Billing application:
+ <em>managed in-app products</em> and <em>subscriptions</em>. Google Play
+handles and tracks ownership for in-app products and subscriptions for your
+application on a per-user basis.
+<a href="{@docRoot}google/play/billing/api.html#producttypes">Learn more</a> about
+the product types supported by In-app Billing Version 3.</p>
 
 <h2 id="console">Google Play Developer Console</h2>
 <p>The Developer Console is where you can publish your
 In-app Billing application and manage the various in-app products that are
 available for purchase from your application.</p>
 <p>You can create a product list of
-digital goods that are associated with your application, including items for
-one-time purchase and recurring subscriptions. For each item, you can define
-information such as the item’s unique product ID (also called its SKU), product
-type, pricing, description, and how Google Play should handle and track
-purchases for that product.</p>
+digital products that are associated with your application, including products for
+one-time purchase and recurring subscriptions. You can define
+information for each product such as the following:</p>
+<ul>
+<li>Unique product ID (also called its SKU).</li>
+<li>Product type.</li>
+<li>Pricing.</li>
+<li>Description.</li>
+<li>Google Play handling and tracking of purchases for that product.</li></p>
+</ul>
 <p>If you sell several of your apps or in-app products at the same price, you
 can add <em>pricing templates</em> to manage these price points from a
 centralized location. When using pricing templates, you can include local taxes
@@ -146,7 +157,7 @@
 In-app Billing</a>.</p>
 
 <h2 id="checkout">Google Play Purchase Flow</h2>
-<p>Google Play uses the same checkout backend service as is used for application
+<p>Google Play uses the same backend checkout service that is used for application
 purchases, so your users experience a consistent and familiar purchase flow.</p>
 <p class="note"><strong>Important:</strong> You must have a Google payments
 merchant account to use the In-app Billing service on Google Play.</p>
@@ -157,8 +168,8 @@
 <p>When the checkout process is complete,
 Google Play sends your application the purchase details, such as the order
 number, the order date and time, and the price paid. At no point does your
-application have to handle any financial transactions; that role is provided by
-Google Play.</p>
+application have to handle any financial transactions; that role belongs to
+ Google Play.</p>
 
 <h2 id="samples">Sample Application</h2>
 <p>To help you integrate In-app Billing into your application, the Android SDK
@@ -166,16 +177,16 @@
 from inside an app.</p>
 
 <p>The <a href="{@docRoot}training/in-app-billing/preparing-iab-app.html#GetSample">
-TrivialDrive sample for the Version 3 API</a> sample shows how to use the In-app
+TrivialDrive for the Version 3 API</a> sample shows how to use the In-app
 Billing Version 3 API
 to implement in-app product and subscription purchases for a driving game. The
-application demonstrates how to send In-app Billing requests, and handle
+application demonstrates how to send In-app Billing requests and handle
 synchronous responses from Google Play. The application also shows how to record
-item consumption with the API. The Version 3 sample includes convenience classes
+product consumption with the API. The Version 3 sample includes convenience classes
 for processing In-app Billing operations as well as perform automatic signature
 verification.</p>
 
-<p class="caution"><strong>Recommendation</strong>: Make sure to obfuscate the
+<p class="caution"><strong>Recommendation</strong>: Be sure to obfuscate the
 code in your application before you publish it. For more information, see
 <a href="{@docRoot}google/play/billing/billing_best_practices.html">Security
 and Design</a>.</p>
@@ -183,16 +194,17 @@
 <h2 id="migration">Migration Considerations</h2>
 <p>The In-app Billing Version 2 API was discontinued in January 2015.
 If you have an existing In-app Billing implementation that uses API Version 2 or
-earlier, you must migrate to <a href="{@docRoot}google/play/billing/api.html">In-app Billing Version
-3</a>.</p>
+earlier, you must migrate to <a href="{@docRoot}google/play/billing/api.html">
+In-app Billing Version 3</a>.</p>
 
-<p>If you have published apps selling in-app products, note that:</p>
+<p>After migration, managed and unmanaged products are handled as follows:</p>
 <ul>
-<li>Managed items and subscriptions that you have previously defined in the Developer Console will
-work with Version 3 as before.</li>
-<li>Unmanaged items that you have defined for existing applications will be
-treated as managed products if you make a purchase request for these items using
-the Version 3 API. You do not need to create a new product entry in Developer
-Console for these items, and you can use the same product IDs to purchase these
-items.
+<li>Managed products and subscriptions that you have previously defined in the
+ Developer Console
+ work with Version 3 just as before.</li>
+<li>Unmanaged products that you have defined for existing applications are
+ treated as managed products if you make a purchase request for these products using
+the Version 3 API. You don't need to create a new product entry in the Developer
+Console for these products, and you can use the same product IDs to manage these
+products.
 </ul>
diff --git a/docs/html/google/play/billing/billing_promotions.jd b/docs/html/google/play/billing/billing_promotions.jd
index ccf50fc..4fe1abf 100644
--- a/docs/html/google/play/billing/billing_promotions.jd
+++ b/docs/html/google/play/billing/billing_promotions.jd
@@ -1,7 +1,7 @@
 page.title=In-app Promotions
 parent.title=In-app Billing
 parent.link=index.html
-page.metaDescription=Support promo codes in your app, which let you give content or features away to a limited number of users free of charge.
+page.metaDescription=Support promo codes in your app, which lets you give content or features away to a limited number of users free of charge.
 page.image=/images/play_dev.jpg
 page.tags="promotions, billing, promo codes"
 meta.tags="monetization, inappbilling, promotions"
@@ -13,7 +13,7 @@
   <h2>In this document</h2>
   <ol>
     <li><a href="#workflow">Creating and Redeeming Promo Codes</a></li>
-    <li><a href="#supporting">Supporting Promo Codes In Your App</a></li>
+    <li><a href="#supporting">Supporting Promo Codes in Your App</a></li>
     <li><a href="#testing">Testing In-app Promotions</a></li>
   </ol>
   <h2>See also</h2>
@@ -27,26 +27,26 @@
 
 <p>
   Promo codes let you give content or features away to a limited number of
-  users free of charge. Once you create a promo code, you can distribute it
+  users free of charge. After you create a promo code, you can distribute it
   subject to the
   <!--TODO: Link to TOS when/if they're available as a web page --> terms of
-  service. The user enters the promo code in your app or in the Play Store app,
-  and gets the item at no cost. You can use promo codes in many ways to
-  creatively engage with users. For example:
+  service. The user enters the promo code in your app or in the Google Play Store app
+  and receives the item at no cost. You can use promo codes in many ways to
+  creatively engage with users, such as the following:
 </p>
 
 <ul>
   <li>A game could have a special item, such as a character or decoration,
   that's only available to players who attend an event. The developer could
   distribute cards with promo codes at the event, and users would enter their
-  promo code to unlock the item.
+  promo codes to unlock the item.
   </li>
 
-  <li>An app developer might distribute promo codes at local businesses, to
+  <li>An app developer might distribute promo codes at local businesses to
   encourage potential users to try the app.
   </li>
 
-  <li>An app developer might give out "friends and family" codes to its employees to
+  <li>An app developer might give <em>friends and family codes</em> to its employees to
   share with their friends.
   </li>
 </ul>
@@ -54,11 +54,11 @@
 <p>
   Every promo code is associated with a particular <em>product ID</em> (also
   known as a <em>SKU</em>). You can create promo codes for your existing in-app
-  products. You can also keep a SKU off the Play Store, so the only way to get
+  products. You can also keep an SKU off the Play Store, so that the only way to get
   that item is by entering that SKU's promo code. When a user enters the promo
-  code in the Play Store or in their app, the user gets the item, just as if
+  code in the Play Store or in an app, the user gets the item, just as if
   they paid full price for it. If your app already uses <a href=
-  "{@docRoot}google/play/billing/api.html">In-app Billing version 3</a> to
+  "{@docRoot}google/play/billing/api.html">In-app Billing Version 3</a> to
   support in-app purchases, it's easy to add support for promo codes.
 </p>
 
@@ -67,12 +67,12 @@
 <p>
   You create promo codes through the <a href=
   "https://play.google.com/apps/publish/" class="external-link">Google Play
-  Developer Console</a>. Each promo code is associated with a single product item
+  Developer Console</a>. Each promo code is associated with a single product
   registered in the developer console.
 </p>
 
 <p>
-  When a user gets a promo code, they redeem it in one of two ways:
+  A user can redeem a promo code in one of these two ways:
 </p>
 
 <ul>
@@ -85,33 +85,20 @@
 
   <li>The user can redeem the code in the Google Play Store app. Once the user
   enters the code, the Play Store prompts the user to open the app (if they have
-  the latest version installed) or to download or update it. (We do not
-  currently support redeeming promo codes from the Google Play web store.)
+  the latest version installed) or to download or update it. Google doesn't
+  currently support redeeming promo codes from the Google Play web store.
   </li>
 </ul>
 
-<p>
-  If the promo code is for a <a href=
-  "{@docRoot}google/play/billing/api.html#consumetypes">consumable product</a>,
-  the user can apply an additional code for the same product <em>after</em> the first
-  product is consumed. For example, a game might offer promo codes for a bundle
-  of extra lives. Betty has two different promo codes for that bundle. She
-  redeems a single promo code, then launches the game. When the game launches,
-  the her character receives the lives, consuming the item. She can now redeem
-  the second promo code for another bundle of lives. (She cannot redeem the
-  second promo code until after she consumes the item she purchased with the
-  first promo code.)
-</p>
-
-<h2 id="supporting">Supporting Promo Codes In Your App</h2>
+<h2 id="supporting">Supporting Promo Codes in Your App</h2>
 
 <p>
-  To support promotion codes, your app should call the <a href=
+  To support promotion codes, your app must call the <a href=
   "{@docRoot}google/play/billing/billing_reference.html#getPurchases"
   ><code>getPurchases()</code></a>
   method whenever the app starts or resumes. This method returns a bundle of all
   current, unconsumed purchases, including purchases the user made by redeeming
-  a promo code. This simplest approach is to call <a href=
+  a promo code. The simplest approach is to call <a href=
   "{@docRoot}google/play/billing/billing_reference.html#getPurchases"
   ><code>getPurchases()</code></a>
   in your activity's {@link android.app.Activity#onResume onResume()} method,
@@ -119,21 +106,21 @@
   activity is unpaused. Calling <a href=
   "{@docRoot}google/play/billing/billing_reference.html#getPurchases"
   ><code>getPurchases()</code></a>
-  on startup and resume guarantees that your app will find out about all
+  on startup and resume guarantees that your app finds out about all
   purchases and redemptions the user may have made while the app wasn't
   running. Furthermore, if a user makes a purchase while the app is running and
-  your app misses it for any reason, your app will still find out about the
+  your app misses it for any reason, your app still finds out about the
   purchase the next time the activity resumes and calls <a href=
   "{@docRoot}google/play/billing/billing_reference.html#getPurchases"
   ><code>getPurchases()</code></a>.
 </p>
 
 <p>
-  In addition, your app should allow users to redeem promo codes inside the app
+  Your app should allow users to redeem promo codes inside the app
   itself. If your app supports the in-app purchase workflow (described in
   <a href=
   "{@docRoot}google/play/billing/billing_integrate.html#billing-requests">Making
-  In-app Billing Requests</a>), your app automatically supports in-app
+  In-app Billing requests</a>), your app automatically supports in-app
   redemption of promo codes. When you launch the in-app purchase UI,
   the user has the option to pay for the purchase with
   a promo code. Your activity's {@link android.app.Activity#onActivityResult
@@ -141,9 +128,9 @@
   purchase was completed. However, your app should still call <a href=
   "{@docRoot}google/play/billing/billing_reference.html#getPurchases"
   ><code>getPurchases()</code></a>
-  on startup and resume, just in case the purchase and consumption workflow
-  didn't complete. For example, if the user successfully redeems a promo code,
-  and then your app crashes before the item is consumed, your app still gets
+  on startup and resume, in case the purchase and consumption workflow
+  didn't complete. For example, if the user successfully redeems a promo code
+  and then your app crashes before the item is consumed, your app still receives
   information about the purchase when the app calls <a href=
   "{@docRoot}google/play/billing/billing_reference.html#getPurchases"
   ><code>getPurchases()</code></a> on its next startup.
@@ -160,8 +147,8 @@
 <p>
   To listen for the <code>PURCHASES_UPDATED</code> intent, dynamically create a
   {@link android.content.BroadcastReceiver} object and register it to listen
-  for <code>"com.android.vending.billing.PURCHASES_UPDATED"</code>. Register
-  the receiver by putting code like this in your activity's {@link
+  for <code>com.android.vending.billing.PURCHASES_UPDATED</code>. Register
+  the receiver by inserting code similar to the following in your activity's {@link
   android.app.Activity#onResume onResume()} method:
 </p>
 
@@ -172,36 +159,34 @@
 <p>
   When the user makes a purchase, the system invokes your broadcast receiver's
   {@link android.content.BroadcastReceiver#onReceive onReceive()} method. That
-  method should call <a href=
+  method must call <a href=
   "{@docRoot}google/play/billing/billing_reference.html#getPurchases"
   ><code>getPurchases()</code></a>
   to see what purchases the user has made.
 </p>
 
-<p>
-  Your activity's {@link android.app.Activity#onPause onPause()} method should
-  unregister the broadcast receiver, to reduce system overhead when your app
-  isn't running:
+<p>To reduce system overhead when your app
+  isn't running, your activity's {@link android.app.Activity#onPause onPause()} method must
+  unregister the broadcast receiver:
 </p>
 
 <pre>unRegisterReceiver(myPromoReceiver);</pre>
 
 <p class="note">
-  <strong>Note:</strong> You should not register this broadcast receiver in the
+  <strong>Note:</strong> Don't register this broadcast receiver in the
   app manifest. Declaring the receiver in the manifest can cause the system to
   launch the app to handle the intent if the user makes a purchase while the app
-  isn't running. This behavior is not necessary, and may be annoying to the
-  user. Instead, your app should call <a href=
-  "{@docRoot}google/play/billing/billing_reference.html#getPurchases"
-  ><code>getPurchases()</code></a>
-  when the user launches it, to find out about any purchases the user made
-  while the app wasn't running.
+  isn't running. This behavior is not necessary and may be annoying to the
+  user.
+  To find out about any purchases the user made while the app wasn't running,
+  call <a href="{@docRoot}google/play/billing/billing_reference.html#getPurchases"
+  ><code>getPurchases()</code></a> when the user launches the app.
 </p>
 
 <h2 id="testing">Testing In-app Promotions</h2>
 
 <p>
-  If your app supports in-app promotions, you should test the following use
+  If your app supports in-app promotions, test the following use
   cases.
 </p>
 
@@ -211,18 +196,18 @@
   If the user redeems a promo code within the app's purchase flow, as described
   in <a href=
   "{@docRoot}google/play/billing/billing_integrate.html#billing-requests">Making
-  In-app Billing Requests</a>, the system invokes your activity's {@link
+  In-app Billing requests</a>, the system invokes your activity's {@link
   android.app.Activity#onActivityResult onActivityResult()} method to handle
   the purchase. Verify that {@link android.app.Activity#onActivityResult
-  onActivityResult()} handles the purchase properly, whether the user uses cash
+  onActivityResult()} handles the purchase properly, whether the user pays with money
   or a promo code.
 </p>
 
-<h3 id="test-playstore">User redeems promo code in the Play Store</h3>
+<h3 id="test-playstore">User redeems promo code in the Google Play Store</h3>
 
 <p>
   If the user redeems a promo code in the Play Store, there are several
-  possible workflows. You should verify each one of these.
+  possible workflows. Verify each one of these workflows.
 </p>
 
 <h4 id="test-app-uninstalled">App is not installed</h4>
@@ -231,16 +216,16 @@
   If the user redeems a promo code for an app that is not installed on the
   device, the Play Store prompts the user to install the app. (If the app is
   installed but not up-to-date, the Play Store prompts the user to update the
-  app.) You should test the following sequence on a device that does not
+  app.) Test the following sequence on a device that doesn't
   have your app installed.
 </p>
 
 <ol>
-  <li>User redeems a promo code for the app in the Play Store. The Play Store
+  <li>The user redeems a promo code for the app in the Play Store. The Play Store
   prompts the user to install your app.
   </li>
 
-  <li>User installs and launches your app. Verify that on startup, the app
+  <li>The user installs and launches your app. Verify that on startup, the app
   calls <a href=
   "{@docRoot}google/play/billing/billing_reference.html#getPurchases"
   ><code>getPurchases()</code></a>
@@ -252,16 +237,16 @@
 
 <p>
   If the user redeems a promo code for an app that is installed on the device,
-  the Play Store prompts the user to switch to the app.  You should test the
+  the Play Store prompts the user to switch to the app. Test the
   following sequence on a device that has your app installed but not running:
 </p>
 
 <ol>
-  <li>User redeems a promo code for the app in the Play Store. The Play Store
+  <li>The user redeems a promo code for the app in the Play Store. The Play Store
   prompts the user to switch to your app.
   </li>
 
-  <li>User launches your app. Verify that on startup, the app calls <a href=
+  <li>The user launches your app. Verify that on startup the app calls <a href=
   "{@docRoot}google/play/billing/billing_reference.html#getPurchases"
   ><code>getPurchases()</code></a>
   and correctly detects the purchase the user made with the promo code.
@@ -274,15 +259,15 @@
 <p>
   If the user redeems a promo code for an app that is currently running on the
   device, the Play Store notifies the app via a <code>PURCHASES_UPDATED</code>
-  intent. You should test the following sequence:
+  intent. Test the following sequence:
 </p>
 
 <ol>
-  <li>User launches the app. Verify that the app has properly registered itself to
+  <li>The user launches the app. Verify that the app has properly registered itself to
   receive the <code>PURCHASES_UPDATED</code> intent.
   </li>
 
-  <li>User launches the Play Store app and redeems a promo code for the app. The Play
+  <li>The user launches the Play Store app and redeems a promo code for the app. The Play
   Store fires a <code>PURCHASES_UPDATED</code> intent. Verify that your app's
   {@link android.content.BroadcastReceiver#onReceive
   BroadcastReceiver.onReceive()} callback fires to handle the intent.
@@ -291,11 +276,11 @@
   <li>Your {@link android.content.BroadcastReceiver#onReceive onReceive()}
   method should respond to the intent by calling <a href=
   "{@docRoot}google/play/billing/billing_reference.html#getPurchases"
-  ><code>getPurchases()</code></a>. Verify that it calls this method, and that
+  ><code>getPurchases()</code></a>. Verify that your app calls this method and that
   it correctly detects the purchase the user made with the promo code.
   </li>
 
-  <li>User switches back to your app. Verify that the user has the purchased
+  <li>The user switches back to your app. Verify that the user has the purchased
   item.
   </li>
 </ol>
diff --git a/docs/html/topic/libraries/data-binding/index.jd b/docs/html/topic/libraries/data-binding/index.jd
index ec6e58c..454bb59 100644
--- a/docs/html/topic/libraries/data-binding/index.jd
+++ b/docs/html/topic/libraries/data-binding/index.jd
@@ -246,21 +246,21 @@
 </pre>
 <p>
   Expressions within the layout are written in the attribute properties using
-  the “<code>&amp;commat;{}</code>” syntax. Here, the TextView’s text is set to
+  the "<code>&commat;{}</code>" syntax. Here, the TextView's text is set to
   the firstName property of user:
 </p>
 
 <pre>
 &lt;TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
-          android:text="&amp;commat;{user.firstName}"/&gt;
+          android:text="&commat;{user.firstName}"/&gt;
 </pre>
 <h3 id="data_object">
   Data Object
 </h3>
 
 <p>
-  Let’s assume for now that you have a plain-old Java object (POJO) for User:
+  Let's assume for now that you have a plain-old Java object (POJO) for User:
 </p>
 
 <pre>
@@ -296,8 +296,8 @@
 </pre>
 <p>
   From the perspective of data binding, these two classes are equivalent. The
-  expression <strong><code>&amp;commat;{user.firstName}</code></strong> used
-  for the TextView’s <strong><code>android:text</code></strong> attribute will
+  expression <strong><code>&commat;{user.firstName}</code></strong> used
+  for the TextView's <strong><code>android:text</code></strong> attribute will
   access the <strong><code>firstName</code></strong> field in the former class
   and the <code>getFirstName()</code> method in the latter class.
   Alternatively, it will also be resolved to <code>firstName()</code> if that
@@ -310,10 +310,10 @@
 
 <p>
   By default, a Binding class will be generated based on the name of the layout
-  file, converting it to Pascal case and suffixing “Binding” to it. The above
+  file, converting it to Pascal case and suffixing "Binding" to it. The above
   layout file was <code>main_activity.xml</code> so the generate class was
   <code>MainActivityBinding</code>. This class holds all the bindings from the
-  layout properties (e.g. the <code>user</code> variable) to the layout’s Views
+  layout properties (e.g. the <code>user</code> variable) to the layout's Views
   and knows how to assign values for the binding expressions.The easiest means
   for creating the bindings is to do it while inflating:
 </p>
@@ -328,7 +328,7 @@
 }
 </pre>
 <p>
-  You’re done! Run the application and you’ll see Test User in the UI.
+  You're done! Run the application and you'll see Test User in the UI.
   Alternatively, you can get the view via:
 </p>
 
@@ -434,15 +434,15 @@
 </pre>
   Then you can bind the click event to your class as follows:
 <pre>
-  &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
-  &lt;layout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;
+  &lt;?xml version="1.0" encoding="utf-8"?&gt;
+  &lt;layout xmlns:android="http://schemas.android.com/apk/res/android"&gt;
       &lt;data&gt;
-          &lt;variable name=&quot;task&quot; type=&quot;com.android.example.Task&quot; /&gt;
-          &lt;variable name=&quot;presenter&quot; type=&quot;com.android.example.Presenter&quot; /&gt;
+          &lt;variable name="task" type="com.android.example.Task" /&gt;
+          &lt;variable name="presenter" type="com.android.example.Presenter" /&gt;
       &lt;/data&gt;
-      &lt;LinearLayout android:layout_width=&quot;match_parent&quot; android:layout_height=&quot;match_parent&quot;&gt;
-          &lt;Button android:layout_width=&quot;wrap_content&quot; android:layout_height=&quot;wrap_content&quot;
-          android:onClick=&quot;@{() -&gt; presenter.onSaveClick(task)}&quot; /&gt;
+      &lt;LinearLayout android:layout_width="match_parent" android:layout_height="match_parent"&gt;
+          &lt;Button android:layout_width="wrap_content" android:layout_height="wrap_content"
+          android:onClick="@{() -&gt; presenter.onSaveClick(task)}" /&gt;
       &lt;/LinearLayout&gt;
   &lt;/layout&gt;
 </pre>
@@ -465,7 +465,7 @@
   above could be written as:
 </p>
 <pre>
-  android:onClick=&quot;@{(view) -&gt; presenter.onSaveClick(task)}&quot;
+  android:onClick="@{(view) -&gt; presenter.onSaveClick(task)}"
 </pre>
 Or if you wanted to use the parameter in the expression, it could work as follows:
 <pre>
@@ -474,7 +474,7 @@
 }
 </pre>
 <pre>
-  android:onClick=&quot;@{(theView) -&gt; presenter.onSaveClick(theView, task)}&quot;
+  android:onClick="@{(theView) -&gt; presenter.onSaveClick(theView, task)}"
 </pre>
 You can use a lambda expression with more than one parameter:
 <pre>
@@ -483,8 +483,8 @@
 }
 </pre>
 <pre>
-  &lt;CheckBox android:layout_width=&quot;wrap_content&quot; android:layout_height=&quot;wrap_content&quot;
-        android:onCheckedChanged=&quot;@{(cb, isChecked) -&gt; presenter.completeChanged(task, isChecked)}&quot; /&gt;
+  &lt;CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content"
+        android:onCheckedChanged="@{(cb, isChecked) -&gt; presenter.completeChanged(task, isChecked)}" /&gt;
 </pre>
 <p>
   If the event you are listening to returns a value whose type is not {@code
@@ -498,7 +498,7 @@
 }
 </pre>
 <pre>
-  android:onLongClick=&quot;@{(theView) -&gt; presenter.onLongClick(theView, task)}&quot;
+  android:onLongClick="@{(theView) -&gt; presenter.onLongClick(theView, task)}"
 </pre>
 <p>
 If the expression cannot be evaluated due to {@code null} objects, Data Binding returns
@@ -510,7 +510,7 @@
 {@code void} as a symbol.
 </p>
 <pre>
-  android:onClick=&quot;@{(v) -&gt; v.isVisible() ? doSomething() : void}&quot;
+  android:onClick="@{(v) -&gt; v.isVisible() ? doSomething() : void}"
 </pre>
 
 <h5>Avoid Complex Listeners</h5>
@@ -580,7 +580,7 @@
 </pre>
 <p>
   When there are class name conflicts, one of the classes may be renamed to an
-  “alias:”
+  "alias:"
 </p>
 
 <pre>
@@ -601,7 +601,7 @@
     &lt;import type="com.example.User"/&gt;
     &lt;import type="java.util.List"/&gt;
     &lt;variable name="user" type="User"/&gt;
-    &lt;variable name="userList" type="List&amp;lt;User&gt;"/&gt;
+    &lt;variable name="userList" type="List&lt;User&gt;"/&gt;
 &lt;/data&gt;
 </pre>
 <p class="caution">
@@ -695,7 +695,7 @@
 <p>
   By default, a Binding class is generated based on the name of the layout
   file, starting it with upper-case, removing underscores ( _ ) and
-  capitalizing the following letter and then suffixing “Binding”. This class
+  capitalizing the following letter and then suffixing "Binding". This class
   will be placed in a databinding package under the module package. For
   example, the layout file <code>contact_item.xml</code> will generate
   <code>ContactItemBinding</code>. If the module package is
@@ -718,7 +718,7 @@
   This generates the binding class as <code>ContactItem</code> in the
   databinding package in the module package. If the class should be generated
   in a different package within the module package, it may be prefixed with
-  “.”:
+  ".":
 </p>
 
 <pre>
@@ -741,7 +741,7 @@
 </h3>
 
 <p>
-  Variables may be passed into an included layout&apos;s binding from the
+  Variables may be passed into an included layout's binding from the
   containing layout by using the application namespace and the variable name in
   an attribute:
 </p>
@@ -855,8 +855,8 @@
 
 <pre>
 android:text="&commat;{String.valueOf(index + 1)}"
-android:visibility="&commat;{age &amp;lt; 13 ? View.GONE : View.VISIBLE}"
-android:transitionName=&apos;&commat;{"image_" + id}&apos;
+android:visibility="&commat;{age &lt; 13 ? View.GONE : View.VISIBLE}"
+android:transitionName='&commat;{"image_" + id}'
 </pre>
 <h4 id="missing_operations">
   Missing Operations
@@ -945,9 +945,9 @@
     &lt;import type="android.util.SparseArray"/&gt;
     &lt;import type="java.util.Map"/&gt;
     &lt;import type="java.util.List"/&gt;
-    &lt;variable name="list" type="List&amp;lt;String&gt;"/&gt;
-    &lt;variable name="sparse" type="SparseArray&amp;lt;String&gt;"/&gt;
-    &lt;variable name="map" type="Map&amp;lt;String, String&gt;"/&gt;
+    &lt;variable name="list" type="List&lt;String&gt;"/&gt;
+    &lt;variable name="sparse" type="SparseArray&lt;String&gt;"/&gt;
+    &lt;variable name="map" type="Map&lt;String, String&gt;"/&gt;
     &lt;variable name="index" type="int"/&gt;
     &lt;variable name="key" type="String"/&gt;
 &lt;/data&gt;
@@ -969,17 +969,17 @@
 </p>
 
 <pre>
-android:text=&apos;&commat;{map["firstName"]}&apos;
+android:text='&commat;{map["firstName"]}'
 </pre>
 <p>
   It is also possible to use double quotes to surround the attribute value.
-  When doing so, String literals should either use the &amp;quot; or back quote
+  When doing so, String literals should either use the ' or back quote
   (`).
 </p>
 
 <pre>
 android:text="&commat;{map[`firstName`}"
-android:text="&commat;{map[&amp;quot;firstName&amp;quot;]}"
+android:text="&commat;{map['firstName']}"
 </pre>
 <h4 id="resources">
   Resources
@@ -1216,7 +1216,7 @@
 }
 </pre>
 <p>
-  That&apos;s it! To access the value, use the set and get accessor methods:
+  That's it! To access the value, use the set and get accessor methods:
 </p>
 
 <pre>
@@ -1247,15 +1247,15 @@
 <pre>
 &lt;data&gt;
     &lt;import type="android.databinding.ObservableMap"/&gt;
-    &lt;variable name="user" type="ObservableMap&amp;lt;String, Object&gt;"/&gt;
+    &lt;variable name="user" type="ObservableMap&lt;String, Object&gt;"/&gt;
 &lt;/data&gt;

 &lt;TextView
-   android:text=&apos;&commat;{user["lastName"]}&apos;
+   android:text='&commat;{user["lastName"]}'
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/&gt;
 &lt;TextView
-   android:text=&apos;&commat;{String.valueOf(1 + (Integer)user["age"])}&apos;
+   android:text='&commat;{String.valueOf(1 + (Integer)user["age"])}'
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/&gt;
 </pre>
@@ -1277,15 +1277,15 @@
 &lt;data&gt;
     &lt;import type="android.databinding.ObservableList"/&gt;
     &lt;import type="com.example.my.app.Fields"/&gt;
-    &lt;variable name="user" type="ObservableList&amp;lt;Object&gt;"/&gt;
+    &lt;variable name="user" type="ObservableList&lt;Object&gt;"/&gt;
 &lt;/data&gt;

 &lt;TextView
-   android:text=&apos;&commat;{user[Fields.LAST_NAME]}&apos;
+   android:text='&commat;{user[Fields.LAST_NAME]}'
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/&gt;
 &lt;TextView
-   android:text=&apos;&commat;{String.valueOf(1 + (Integer)user[Fields.AGE])}&apos;
+   android:text='&commat;{String.valueOf(1 + (Integer)user[Fields.AGE])}'
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/&gt;
 </pre>
@@ -1428,7 +1428,7 @@
 
 <p>
   When inflating another layout, a binding must be established for the new
-  layout. Therefore, the <code>ViewStubProxy</code> must listen to the <code>ViewStub</code>&apos;s
+  layout. Therefore, the <code>ViewStubProxy</code> must listen to the <code>ViewStub</code>'s
   {@link android.view.ViewStub.OnInflateListener} and establish the binding at that time. Since
   only one can exist, the <code>ViewStubProxy</code> allows the developer to set an
   <code>OnInflateListener</code> on it that it will call after establishing the binding.
@@ -1443,9 +1443,9 @@
 </h4>
 
 <p>
-  At times, the specific binding class won&apos;t be known. For example, a
+  At times, the specific binding class won't be known. For example, a
   {@link android.support.v7.widget.RecyclerView.Adapter} operating against arbitrary layouts
-  won&apos;t know the specific binding class. It still must assign the binding value during the
+  won't know the specific binding class. It still must assign the binding value during the
   {@link android.support.v7.widget.RecyclerView.Adapter#onBindViewHolder}.
 </p>
 
@@ -1499,13 +1499,13 @@
 For an attribute, data binding tries to find the method setAttribute. The
 namespace for the attribute does not matter, only the attribute name itself.
 <p>
-  For example, an expression associated with TextView&apos;s attribute
+  For example, an expression associated with TextView's attribute
   <strong><code>android:text</code></strong> will look for a setText(String).
   If the expression returns an int, data binding will search for a setText(int)
   method. Be careful to have the expression return the correct type, casting if
   necessary. Note that data binding will work even if no attribute exists with
   the given name. You can then easily "create" attributes for any setter by
-  using data binding. For example, support DrawerLayout doesn&apos;t have any
+  using data binding. For example, support DrawerLayout doesn't have any
   attributes, but plenty of setters. You can use the automatic setters to use
   one of these.
 </p>
@@ -1522,7 +1522,7 @@
 </h3>
 
 <p>
-  Some attributes have setters that don&apos;t match by name. For these
+  Some attributes have setters that don't match by name. For these
   methods, an attribute may be associated with the setter through
   {@link android.databinding.BindingMethods} annotation. This must be associated with
   a class and contains {@link android.databinding.BindingMethod} annotations, one for
@@ -1591,8 +1591,8 @@
 }
 </pre>
 <pre>
-&lt;ImageView app:imageUrl=“&commat;{venue.imageUrl}”
-app:error=“&commat;{&commat;drawable/venueError}”/&gt;
+&lt;ImageView app:imageUrl="&commat;{venue.imageUrl}"
+app:error="&commat;{&commat;drawable/venueError}"/&gt;
 </pre>
 
 <p>
@@ -1747,7 +1747,7 @@
 
 <pre>
 &lt;TextView
-   android:text=&apos;&commat;{userMap["lastName"]}&apos;
+   android:text='&commat;{userMap["lastName"]}'
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/&gt;
 </pre>
diff --git a/docs/html/training/in-app-billing/preparing-iab-app.jd b/docs/html/training/in-app-billing/preparing-iab-app.jd
old mode 100755
new mode 100644
index 2c6e9a0..780f2f80
--- a/docs/html/training/in-app-billing/preparing-iab-app.jd
+++ b/docs/html/training/in-app-billing/preparing-iab-app.jd
@@ -31,23 +31,32 @@
 </div>
 
 <a class="notice-developers-video wide"
-href="https://www.youtube.com/watch?v=UvCl5Xx7Z5o">
+href="https://www.youtube.com/watch?v=UvCl5Xx7Z5o" class="external-link">
 <div>
     <h3>Video</h3>
     <p>Implementing Freemium</p>
   </div>
   </a>
 
-<p>Before you can start using the In-app Billing service, you'll need to add the library that contains the In-app Billing Version 3 API to your Android project. You also need to set the permissions for your application to communicate with Google Play. In addition, you'll need to establish a connection between your application and  Google Play. You should also verify that the In-app Billing API version that you are using in your application is supported by Google Play.</p>
+<p>Before you can start using the In-app Billing service, you need to add the library that
+ contains the In-app Billing Version 3 API to your Android project. You also need to set the
+ permissions for your application to communicate with Google Play. In addition, you need to
+ establish a connection between your application and  Google Play. You must also verify that
+ the In-app Billing API version that you are using in your application is supported
+ by Google Play.</p>
 
 <h2 id="GetSample">Download the Sample Application</h2>
-<p>In this training class, you will use a reference implementation for the In-app Billing Version 3 API called the {@code TrivialDrive} sample application. The sample includes convenience classes to quickly set up the In-app Billing service, marshal and unmarshal data types, and handle In-app Billing requests from the main thread of your application.</p>
-<p>To download the sample application:</p>
+<p>In this training class, you use a reference implementation for the In-app Billing
+ Version 3 API
+ called the {@code TrivialDrive} sample application. The sample includes convenience classes to
+ quickly set up the In-app Billing service, marshal and unmarshal data types, and handle In-app
+ Billing requests from the main thread of your application.</p>
+<p>To download the sample application, follow these steps:</p>
 <ol>
 <li>Open Android Studio and then close any open projects until you are
 presented with the welcome screen.</li>
-<li>Choose <strong>Import an Android code sample</strong> from the
-  <strong>Quick Start</strong> list on the right side the window.</li>
+<li>From the <strong>Quick Start</strong> list on the right side of the window, choose
+ <strong>Import an Android code sample</strong>.</li>
 <li>Type {@code Trivial Drive} into the search bar and select the
   <strong>Trivial Drive</strong> sample.</li>
 <li>Follow the rest of the instructions in the <strong>Import Sample</strong>
@@ -56,66 +65,121 @@
 </ol>
 
 <p>Alternatively, you can use {@code git} to manually clone
- the repository from <a
+ the repository from the <a
  href="https://github.com/googlesamples/android-play-billing"
- class="external-link">https://github.com/googlesamples/android-play-billing</a></p>
+ class="external-link">Google Samples</a> GitHub site.</p>
 
 <h2 id="AddToDevConsole">Add Your Application to the Developer Console</h2>
-<p>The Google Play Developer Console is where you publish your In-app Billing application and  manage the various digital goods that are available for purchase from your application. When you create a new application entry in the Developer Console, it automatically generates a public license key for your application. You will need this key to establish a trusted connection from your application to the Google Play servers. You only need to generate this key once per application, and don’t need to repeat these steps when you update the APK file for your application.</p>
-<p>To add your application to the Developer Console:</p>
+<p>The Google Play Developer Console is where you publish your In-app Billing application
+ and  manage the various digital products that are available for purchase from your
+ application.
+ When you create a new application entry in the Developer Console, it automatically generates
+ a public license key for your application. You need this key to establish a trusted connection
+ from your application to the Google Play servers. You need to generate this key only once
+ per application, and you don’t need to repeat these steps when you update the APK file for
+ your application.</p>
+<p>To add your application to the Developer Console, follow these steps:</p>
 <ol>
-<li>Go to the <a href="http://play.google.com/apps/publish">Google Play Developer Console</a> site and log in. You will need to register for a new developer account, if you have not registered previously. To sell in-app items, you also need to have a <a href="http://www.google.com/wallet/merchants.html">Google payments</a> merchant account.</li>
-<li>Click on <strong>Try the new design</strong> to access the preview version of the Developer Console, if you are not already logged on to that version. </li>
-<li>In the <strong>All Applications</strong> tab, add a new application entry.
+<li>Go to the <a href="http://play.google.com/apps/publish" class="external-link">
+Google Play Developer Console</a>
+ site and log in. If you have not registered previously, you need to register for a new
+ developer account. To sell in-app products, you also need a
+ <a href="http://www.google.com/wallet/merchants.html" class="external-link">
+ Google payments</a> merchant account.</li>
+
+<li>In the <strong>All Applications</strong> tab, complete these steps to add a new
+ application entry:
 <ol type="a">
 <li>Click <strong>Add new application</strong>.</li>
 <li>Enter a name for your new In-app Billing application.</li>
 <li>Click <strong>Prepare Store Listing</strong>.</li>
 </ol>
 </li>
-<li>In the <strong>Services & APIs</strong> tab, find and make a note of the public license key that Google Play generated for your application. This is a Base64 string that you will need to include in your application code later.</li>
+<li>In the <strong>Services & APIs</strong> tab, find and make a note of the public license key
+ that Google Play generated for your application. This is a Base64 string that you need to
+ include in your application code later.</li>
 </ol>
 <p>Your application should now appear in the list of applications in Developer Console.</p>
 
 <h2 id="AddLibrary">Add the In-app Billing Library</h2>
-<p>To use the In-app Billing Version 3 features, you must add the {@code IInAppBillingService.aidl} file to your Android project. This Android Interface Definition Language (AIDL) file defines the interface to the Google Play service.</p>
-<p>You can find the {@code IInAppBillingService.aidl} file in the provided sample app. Depending on whether you are creating a new application or modifying an existing application, follow the instructions below to add the In-app Billing Library to your project.</p>
-<h3>New Project</h3>
-<p>To add the In-app Billing Version 3 library to your new In-app Billing project:</p>
+<p>To use the In-app Billing Version 3 features, you must add the
+ {@code IInAppBillingService.aidl}
+ file to your Android project. This Android Interface Definition Language
+ (AIDL) file defines the
+ interface to the Google Play service.</p>
+<p>You can find the {@code IInAppBillingService.aidl} file in the provided sample app.
+ To add the
+ In-app Billing library to your project, follow the instructions below for a new or
+ existing project.</p>
+<h3>Adding in-app billing to a new project</h3>
+<p>To add the In-app Billing Version 3 library to a new project, follow these steps:</p>
 <ol>
 <li>Copy the {@code TrivialDrive} sample files into your Android project.</li>
-<li>Modify the package name in the files you copied to use the package name for your project. In Android Studio, you can use this shortcut: right-click the package name, then  select <strong>Refactor</strong> > <strong>Rename</strong>.</li>
-<li>Open the {@code AndroidManifest.xml} file and update the package attribute value to use the package name for your project.</li>
-<li>Fix import statements as needed so that your project compiles correctly.  In Android Studio, you can use this shortcut: press <strong>Ctrl+Shift+O</strong> in each file showing errors.</li>
-<li>Modify the sample to create your own application. Remember to copy the Base64 public license key for your application from the Developer Console over to your {@code MainActivity.java}.</li>
+<li>Modify the package name in the files that you copied to use the package name
+ for your project.
+ In Android Studio, you can right-click the package name and then
+ select <strong>Refactor</strong> > <strong>Rename</strong>.</li>
+<li>Open the {@code AndroidManifest.xml} file and update the package attribute value to
+ use the package name for your project.</li>
+<li>Fix import statements as needed so that your project compiles correctly.
+ In Android Studio, you can press <strong>Ctrl+Shift+O</strong>
+ in each file showing errors.</li>
+<li>Modify the sample to create your own application. Remember to copy the Base64
+ public license key for your application from the Developer Console to
+ your {@code MainActivity.java}.</li>
 </ol>
 
-<h3>Existing Project</h3>
-<p>To add the In-app Billing Version 3 library to your existing In-app Billing project:</p>
+<h3>Adding in-app billing to an existing project</h3>
+<p>To add the In-app Billing Version 3 library to an existing project, follow these steps:</p>
 <ol>
 <li>Copy the {@code IInAppBillingService.aidl} file to your Android project.
   <ul>
-  <li>In Android Studio: Create a directory named {@code aidl} under {@code src/main}, add a new
-  package {@code com.android.vending.billing} in this directory, and import the
+  <li>In Android Studio: Create a directory named {@code aidl} under {@code src/main},
+  add a new
+  package {@code com.android.vending.billing} in this directory, and then import the
   {@code IInAppBillingService.aidl} file into this package.</li>
-  <li>In other dev environments: Create the following directory {@code /src/com/android/vending/billing} and copy the {@code IInAppBillingService.aidl} file into this directory.</li>
+  <li>In other dev environments: Create the following directory
+  {@code /src/com/android/vending/billing} and copy the {@code IInAppBillingService.aidl}
+  file into this directory.</li>
   </ul>
 </li>
-<li>Build your application. You should see a generated file named {@code IInAppBillingService.java} in the {@code /gen} directory of your project.</li>
-<li>Add the helper classes from the {@code /util} directory of the {@code TrivialDrive} sample to your project.  Remember to change the package name declarations in those files accordingly so that your project compiles correctly.</li>
+<li>Build your application. You should see a generated file named
+ {@code IInAppBillingService.java}
+ in the {@code /gen} directory of your project.</li>
+<li>Add the helper classes from the {@code /util} directory of the {@code TrivialDrive}
+ sample to
+ your project.  Remember to change the package name declarations in those files
+ accordingly so
+ that your project compiles correctly.</li>
 </ol>
 <p>Your project should now contain the In-app Billing Version 3 library.</p>
 
 <h2 id="SetPermission">Set the Billing Permission</h2>
-<p>Your app needs to have permission to communicate request and response messages to the Google Play’s billing service. To give your app the necessary permission, add this line in your {@code AndroidManifest.xml} manifest file:</p>
+<p>Your app needs to have permission to communicate request and response messages to
+ the Google Play billing service. To give your app the necessary permission, add the following
+ line in your {@code AndroidManifest.xml} manifest file:</p>
 <pre>
 &lt;uses-permission android:name="com.android.vending.BILLING" /&gt;
 </pre>
 
 <h2 id="Connect">Initiate a Connection with Google Play</h2>
-<p>You must bind your Activity to Google Play’s In-app Billing service to send In-app Billing requests to Google Play from your application. The convenience classes provided in the sample handles the binding to the In-app Billing service, so you don’t have to manage the network connection directly.</p>
-<p>To set up synchronous communication with Google Play, create an {@code IabHelper} instance in your activity's {@code onCreate} method. In the constructor, pass in the {@code Context} for the activity, along with a string containing the public license key that was generated earlier by the Google Play Developer Console. </p>
-<p class="note"><strong>Security Recommendation:</strong> It is highly recommended that you do not hard-code the exact public license key string value as provided by Google Play. Instead, you can construct the whole public license key string at runtime from substrings, or retrieve it from an encrypted store, before passing it to the constructor. This approach makes it more difficult for malicious third-parties to modify the public license key string in your APK file.</p>
+<p>To send In-app
+ Billing requests to Google Play from your application, you must bind your Activity
+ to the Google Play In-app Billing service. The sample includes convenience classes
+ that handle the binding to the In-app Billing service, so you don’t have to
+ manage the network connection directly.</p>
+<p>To set up synchronous communication with Google Play, create an {@code IabHelper}
+ instance in your activity's {@code onCreate} method, as shown in the following example.
+ In the constructor, pass in the {@code Context} for the activity along with a string
+ containing the public license key that was generated earlier by the Google Play
+ Developer Console.
+</p>
+<p class="caution"><strong>Security Recommendation:</strong> Google highly recommends that
+ you do not hard-code the exact public license key string value as provided by Google Play.
+ Instead, construct the whole public license key string at runtime from substrings
+ or retrieve it from an encrypted store before passing it to the constructor.
+ This approach makes it more difficult for malicious third parties to modify the public
+ license key string in your APK file.</p>
 
 <pre>
 IabHelper mHelper;
@@ -130,13 +194,20 @@
 }
 </pre>
 
-<p>Next, perform the service binding by calling the {@code startSetup} method on the {@code IabHelper} instance that you created.  Pass the method an {@code OnIabSetupFinishedListener} instance, which is called once the {@code IabHelper} completes the asynchronous setup operation. As part of the setup process, the {@code IabHelper} also checks if the In-app Billing Version 3 API is supported by Google Play. If the API version is not supported, or if an error occured while establishing the service binding, the listener is notified and passed an {@code IabResult} object with the error message.</p>
+<p>Next, perform the service binding by calling the {@code startSetup} method on the
+ {@code IabHelper} instance that you created, as shown in the following example.
+ Pass the method an {@code OnIabSetupFinishedListener} instance, which is called once
+ the {@code IabHelper} completes the asynchronous setup operation. As part of the
+ setup process, the {@code IabHelper} also checks if the In-app Billing Version 3 API
+ is supported by Google Play. If the API version is not supported, or if an error occurs
+ while establishing the service binding, the listener is notified and passed an
+ {@code IabResult} object with the error message.</p>
 
 <pre>
 mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
    public void onIabSetupFinished(IabResult result) {
       if (!result.isSuccess()) {
-         // Oh noes, there was a problem.
+         // Oh no, there was a problem.
          Log.d(TAG, "Problem setting up In-app Billing: " + result);
       }
          // Hooray, IAB is fully set up!
@@ -144,9 +215,18 @@
 });
 </pre>
 
-<p>If the setup completed successfully, you can now use the {@code mHelper} reference to communicate with the Google Play service. When your application is launched, it is a good practice to query Google Play to find out what in-app items are owned by a user. This is covered further in the <a href="{@docRoot}training/in-app-billing/purchase-iab-products.html#QueryPurchases">Query Purchased Items</a> section.</p>
+<p>If the setup completed successfully, you can now use the {@code mHelper} reference
+ to communicate with the Google Play service. When your application is launched, it is
+ a good practice to query Google Play to find out what in-app items are owned by a user.
+ This is covered further in the
+ <a href="{@docRoot}training/in-app-billing/purchase-iab-products.html#QueryPurchases">
+ Query Purchased Items</a> section.</p>
 
-<p class="note"><strong>Important:</strong> Remember to unbind from the In-app Billing service when you are done with your activity. If you don’t unbind, the open service connection could cause your device’s performance to degrade. To unbind and free your system resources, call the {@code IabHelper}'s {@code dispose} method when your {@code Activity} is destroyed.</p>
+<p class="caution"><strong>Important:</strong> Remember to unbind from the In-app Billing service
+ when you are done with your activity. If you don’t unbind, the open service connection could
+ degrade device performance. To unbind and free your system resources, call the
+ {@code IabHelper}'s {@code dispose} method when your {@code Activity} is destroyed,
+ as shown in the following example.</p>
 
 <pre>
 &#64;Override
@@ -156,8 +236,3 @@
    mHelper = null;
 }
 </pre>
-
-
-
-
-
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index be31bbe..2294b86 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -800,7 +800,6 @@
      *                        Path. Typically this would be 0.5 so that
      *                        the error is less than half a pixel.
      * @return An array of components for points approximating the Path.
-     * @hide
      */
     public float[] approximate(float acceptableError) {
         return native_approximate(mNativePath, acceptableError);
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 8cbe016..513e376 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -124,6 +124,10 @@
     -DATRACE_TAG=ATRACE_TAG_VIEW -DLOG_TAG=\"OpenGLRenderer\" \
     -Wall -Wno-unused-parameter -Wunreachable-code -Werror
 
+ifeq ($(TARGET_USES_HWC2),true)
+    hwui_cflags += -DUSE_HWC2
+endif
+
 # GCC false-positives on this warning, and since we -Werror that's
 # a problem
 hwui_cflags += -Wno-free-nonheap-object
diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp
index 41e2233..09b3945 100644
--- a/libs/hwui/FrameInfo.cpp
+++ b/libs/hwui/FrameInfo.cpp
@@ -35,8 +35,14 @@
     "IssueDrawCommandsStart",
     "SwapBuffers",
     "FrameCompleted",
+    "DequeueBufferDuration",
+    "QueueBufferDuration",
 };
 
+static_assert((sizeof(FrameInfoNames)/sizeof(FrameInfoNames[0]))
+        == static_cast<int>(FrameInfoIndex::NumIndexes),
+        "size mismatch: FrameInfoNames doesn't match the enum!");
+
 void FrameInfo::importUiThreadInfo(int64_t* info) {
     memcpy(mFrameInfo, info, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
 }
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index afab84c..993b158 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -48,6 +48,9 @@
     SwapBuffers,
     FrameCompleted,
 
+    DequeueBufferDuration,
+    QueueBufferDuration,
+
     // Must be the last value!
     NumIndexes
 };
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index ebe9c42..ed6b211 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -16,6 +16,7 @@
 #include "JankTracker.h"
 
 #include "Properties.h"
+#include "utils/TimeUtils.h"
 
 #include <algorithm>
 #include <cutils/ashmem.h>
@@ -119,11 +120,27 @@
     return index;
 }
 
-JankTracker::JankTracker(nsecs_t frameIntervalNanos) {
+JankTracker::JankTracker(const DisplayInfo& displayInfo) {
     // By default this will use malloc memory. It may be moved later to ashmem
     // if there is shared space for it and a request comes in to do that.
     mData = new ProfileData;
     reset();
+    nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1_s / displayInfo.fps);
+#if USE_HWC2
+    nsecs_t sfOffset = frameIntervalNanos - (displayInfo.presentationDeadline - 1_ms);
+    nsecs_t offsetDelta = sfOffset - displayInfo.appVsyncOffset;
+    // There are two different offset cases. If the offsetDelta is positive
+    // and small, then the intention is to give apps extra time by leveraging
+    // pipelining between the UI & RT threads. If the offsetDelta is large or
+    // negative, the intention is to subtract time from the total duration
+    // in which case we can't afford to wait for dequeueBuffer blockage.
+    if (offsetDelta <= 4_ms && offsetDelta >= 0) {
+        // SF will begin composition at VSYNC-app + offsetDelta. If we are triple
+        // buffered, this is the expected time at which dequeueBuffer will
+        // return due to the staggering of VSYNC-app & VSYNC-sf.
+        mDequeueTimeForgiveness = offsetDelta + 4_ms;
+    }
+#endif
     setFrameInterval(frameIntervalNanos);
 }
 
@@ -213,6 +230,19 @@
     mData->totalFrameCount++;
     // Fast-path for jank-free frames
     int64_t totalDuration = frame.duration(sFrameStart, FrameInfoIndex::FrameCompleted);
+    if (mDequeueTimeForgiveness
+            && frame[FrameInfoIndex::DequeueBufferDuration] > 500_us) {
+        nsecs_t expectedDequeueDuration =
+                mDequeueTimeForgiveness + frame[FrameInfoIndex::Vsync]
+                - frame[FrameInfoIndex::IssueDrawCommandsStart];
+        if (expectedDequeueDuration > 0) {
+            // Forgive only up to the expected amount, but not more than
+            // the actual time spent blocked.
+            nsecs_t forgiveAmount = std::min(expectedDequeueDuration,
+                    frame[FrameInfoIndex::DequeueBufferDuration]);
+            totalDuration -= forgiveAmount;
+        }
+    }
     uint32_t framebucket = frameCountIndexForFrameTime(totalDuration);
     // Keep the fast path as fast as possible.
     if (CC_LIKELY(totalDuration < mFrameInterval)) {
diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h
index a23dd78..8b482d5 100644
--- a/libs/hwui/JankTracker.h
+++ b/libs/hwui/JankTracker.h
@@ -21,6 +21,7 @@
 #include "utils/RingBuffer.h"
 
 #include <cutils/compiler.h>
+#include <ui/DisplayInfo.h>
 
 #include <array>
 #include <memory>
@@ -56,7 +57,7 @@
 // TODO: Replace DrawProfiler with this
 class JankTracker {
 public:
-    explicit JankTracker(nsecs_t frameIntervalNanos);
+    explicit JankTracker(const DisplayInfo& displayInfo);
     ~JankTracker();
 
     void addFrame(const FrameInfo& frame);
@@ -79,6 +80,14 @@
 
     std::array<int64_t, NUM_BUCKETS> mThresholds;
     int64_t mFrameInterval;
+    // The amount of time we will erase from the total duration to account
+    // for SF vsync offsets with HWC2 blocking dequeueBuffers.
+    // (Vsync + mDequeueBlockTolerance) is the point at which we expect
+    // SF to have released the buffer normally, so we will forgive up to that
+    // point in time by comparing to (IssueDrawCommandsStart + DequeueDuration)
+    // This is only used if we are in pipelined mode and are using HWC2,
+    // otherwise it's 0.
+    nsecs_t mDequeueTimeForgiveness = 0;
     ProfileData* mData;
     bool mIsMapped = false;
 };
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 702f376c..a3004df 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -91,7 +91,7 @@
         : mRenderThread(thread)
         , mOpaque(!translucent)
         , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
-        , mJankTracker(thread.timeLord().frameIntervalNanos())
+        , mJankTracker(thread.mainDisplayInfo())
         , mProfiler(mFrames)
         , mContentDrawBounds(0, 0, 0, 0)
         , mRenderPipeline(std::move(renderPipeline)) {
@@ -283,11 +283,6 @@
     if (CC_LIKELY(mSwapHistory.size() && !Properties::forceDrawFrame)) {
         nsecs_t latestVsync = mRenderThread.timeLord().latestVsync();
         SwapHistory& lastSwap = mSwapHistory.back();
-        int durationUs;
-        mNativeSurface->query(NATIVE_WINDOW_LAST_DEQUEUE_DURATION, &durationUs);
-        lastSwap.dequeueDuration = us2ns(durationUs);
-        mNativeSurface->query(NATIVE_WINDOW_LAST_QUEUE_DURATION, &durationUs);
-        lastSwap.queueDuration = us2ns(durationUs);
         nsecs_t vsyncDelta = std::abs(lastSwap.vsyncTime - latestVsync);
         // The slight fudge-factor is to deal with cases where
         // the vsync was estimated due to being slow handling the signal.
@@ -371,6 +366,15 @@
         swap.damage = windowDirty;
         swap.swapCompletedTime = systemTime(CLOCK_MONOTONIC);
         swap.vsyncTime = mRenderThread.timeLord().latestVsync();
+        int durationUs;
+        mNativeSurface->query(NATIVE_WINDOW_LAST_DEQUEUE_DURATION, &durationUs);
+        swap.dequeueDuration = us2ns(durationUs);
+        mNativeSurface->query(NATIVE_WINDOW_LAST_QUEUE_DURATION, &durationUs);
+        swap.queueDuration = us2ns(durationUs);
+        mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration)
+                = swap.dequeueDuration;
+        mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration)
+                = swap.queueDuration;
         mHaveNewSurface = false;
         mFrameNumber = -1;
     }
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 3c1c0bc..9688340 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -190,7 +190,7 @@
     initializeDisplayEventReceiver();
     mEglManager = new EglManager(*this);
     mRenderState = new RenderState(*this);
-    mJankTracker = new JankTracker(frameIntervalNanos);
+    mJankTracker = new JankTracker(mDisplayInfo);
 }
 
 int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
diff --git a/libs/hwui/utils/TimeUtils.h b/libs/hwui/utils/TimeUtils.h
index 8d42d7e..ce181b7 100644
--- a/libs/hwui/utils/TimeUtils.h
+++ b/libs/hwui/utils/TimeUtils.h
@@ -21,10 +21,18 @@
 namespace android {
 namespace uirenderer {
 
+constexpr nsecs_t operator"" _s (unsigned long long s) {
+    return seconds_to_nanoseconds(s);
+}
+
 constexpr nsecs_t operator"" _ms (unsigned long long ms) {
     return milliseconds_to_nanoseconds(ms);
 }
 
+constexpr nsecs_t operator"" _us (unsigned long long us) {
+    return microseconds_to_nanoseconds(us);
+}
+
 } /* namespace uirenderer */
 } /* namespace android */
 
diff --git a/libs/usb/tests/accessorytest/audio.c b/libs/usb/tests/accessorytest/audio.c
index d23d9b3..36ee6b8 100644
--- a/libs/usb/tests/accessorytest/audio.c
+++ b/libs/usb/tests/accessorytest/audio.c
@@ -164,7 +164,6 @@
 static void* play_thread(void* arg)
 {
     struct pcm *pcm = arg;
-    char *buffer;
     int index, err;
 
     fprintf(stderr, "play_thread start\n");
@@ -181,7 +180,6 @@
 
     fprintf(stderr, "play_thread done\n");
     pcm_close(pcm);
-    free(buffer);
 
     return NULL;
 }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
index ab3bbdb..1bebebc 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
@@ -753,9 +753,11 @@
         public void updateInstalledServices(List<PrintServiceInfo> services) {
             mInstalledServices.clear();
 
-            final int numServices = services.size();
-            for (int i = 0; i < numServices; i++) {
-                mInstalledServices.add(services.get(i).getComponentName().getPackageName());
+            if (services != null) {
+                final int numServices = services.size();
+                for (int i = 0; i < numServices; i++) {
+                    mInstalledServices.add(services.get(i).getComponentName().getPackageName());
+                }
             }
 
             filterRecommendations();
diff --git a/packages/SettingsLib/res/layout/usage_view.xml b/packages/SettingsLib/res/layout/usage_view.xml
index aa1a046..1d56668 100644
--- a/packages/SettingsLib/res/layout/usage_view.xml
+++ b/packages/SettingsLib/res/layout/usage_view.xml
@@ -71,9 +71,11 @@
         android:id="@+id/bottom_label_group"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:paddingStart="@dimen/usage_graph_labels_width"
         android:orientation="horizontal">
-
+        <Space
+            android:id="@+id/bottom_label_space"
+            android:layout_width="@dimen/usage_graph_labels_width"
+            android:layout_height="wrap_content"/>
         <include android:id="@+id/label_start"
             layout="@layout/usage_side_label" />
 
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 920e061..5f45f15 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -290,11 +290,11 @@
         <item>highlight</item>
     </string-array>
 
-    <!-- Titles for frame time tracking preference. [CHAR LIMIT=35] -->
+    <!-- Titles for frame time tracking preference. [CHAR LIMIT=50] -->
     <string-array name="track_frame_time_entries">
         <item>Off</item>
         <item>On screen as bars</item>
-        <item>In adb shell dumpsys gfxinfo</item>
+        <item>In <xliff:g id="as_typed_command">adb shell dumpsys gfxinfo</xliff:g></item>
     </string-array>
 
     <!-- Values for frame time tracking preference. -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/UsageView.java b/packages/SettingsLib/src/com/android/settingslib/graph/UsageView.java
index ee1821d..c6a45bc 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/UsageView.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/UsageView.java
@@ -71,10 +71,11 @@
                 layout.addView(labels);
                 // Set gravity.
                 labels.setGravity(Gravity.END);
-                // Swap the bottom label padding
+                // Swap the bottom space order.
                 LinearLayout bottomLabels = (LinearLayout) findViewById(R.id.bottom_label_group);
-                bottomLabels.setPadding(bottomLabels.getPaddingRight(), bottomLabels.getPaddingTop(),
-                        bottomLabels.getPaddingLeft(), bottomLabels.getPaddingBottom());
+                View bottomSpace = bottomLabels.findViewById(R.id.bottom_label_space);
+                bottomLabels.removeView(bottomSpace);
+                bottomLabels.addView(bottomSpace);
             } else if (gravity != Gravity.START) {
                 throw new IllegalArgumentException("Unsupported gravity " + gravity);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
index 63f726b..95cb672 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -176,8 +176,18 @@
         mCurrentView = currentView.findViewById(mId);
     }
 
+    public void setCarMode(boolean carMode) {
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            final View view = mViews.get(i);
+            if (view instanceof ButtonInterface) {
+                ((ButtonInterface) view).setCarMode(carMode);
+            }
+        }
+    }
+
     /**
-     * Interface for ImageView button actions.
+     * Interface for button actions.
      */
     public interface ButtonInterface {
         void setImageResource(@DrawableRes int resId);
@@ -187,5 +197,7 @@
         void abortCurrentGesture();
 
         void setLandscape(boolean landscape);
+
+        void setCarMode(boolean carMode);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 160baaf..5bd05b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -627,6 +627,7 @@
                 mCarMode = true;
                 uiCarModeChanged = true;
             }
+            getHomeButton().setCarMode(mCarMode);
         }
         return uiCarModeChanged;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 3df7590..61bac2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -270,6 +270,11 @@
     public void setLandscape(boolean landscape) {
         //no op
     }
+
+    @Override
+    public void setCarMode(boolean carMode) {
+        // no op
+    }
 }
 
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index a1265fb..83463e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -471,6 +471,10 @@
             }
             mServiceState = state;
             mDataNetType = state.getDataNetworkType();
+            if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null &&
+                    mServiceState.isUsingCarrierAggregation()) {
+                mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA;
+            }
             updateTelephony();
         }
 
@@ -482,6 +486,10 @@
             }
             mDataState = state;
             mDataNetType = networkType;
+            if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null &&
+                    mServiceState.isUsingCarrierAggregation()) {
+                mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA;
+            }
             updateTelephony();
         }
 
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 31e5d0b..70f39db 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -479,7 +479,7 @@
         }
     }
 
-    private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
+    private final IpConnectivityLog mMetricsLog;
 
     /**
      * Implements support for the legacy "one network per network type" model.
@@ -677,8 +677,16 @@
 
     public ConnectivityService(Context context, INetworkManagementService netManager,
             INetworkStatsService statsService, INetworkPolicyManager policyManager) {
+        this(context, netManager, statsService, policyManager, new IpConnectivityLog());
+    }
+
+    @VisibleForTesting
+    protected ConnectivityService(Context context, INetworkManagementService netManager,
+            INetworkStatsService statsService, INetworkPolicyManager policyManager,
+            IpConnectivityLog logger) {
         if (DBG) log("ConnectivityService starting up");
 
+        mMetricsLog = logger;
         mDefaultRequest = createInternetRequestForTransport(-1);
         NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder());
         mNetworkRequests.put(mDefaultRequest, defaultNRI);
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
index b24edb9..f4f6b66 100644
--- a/services/core/java/com/android/server/am/PreBootBroadcaster.java
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -130,7 +130,7 @@
             switch (msg.what) {
                 case MSG_SHOW:
                     final CharSequence title = context
-                            .getText(R.string.android_upgrading_title);
+                            .getText(R.string.android_upgrading_notification_title);
 
                     final Intent intent = new Intent();
                     intent.setClassName("com.android.settings",
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 92c4577..42d80fc 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -200,7 +200,7 @@
     private final WifiManager mWifiManager;
     private final AlarmManager mAlarmManager;
     private final NetworkRequest mDefaultRequest;
-    private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
+    private final IpConnectivityLog mMetricsLog;
 
     private boolean mIsCaptivePortalCheckEnabled;
     private boolean mUseHttps;
@@ -226,10 +226,17 @@
 
     public NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo,
             NetworkRequest defaultRequest) {
+        this(context, handler, networkAgentInfo, defaultRequest, new IpConnectivityLog());
+    }
+
+    @VisibleForTesting
+    protected NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo,
+            NetworkRequest defaultRequest, IpConnectivityLog logger) {
         // Add suffix indicating which NetworkMonitor we're talking about.
         super(TAG + networkAgentInfo.name());
 
         mContext = context;
+        mMetricsLog = logger;
         mConnectivityServiceHandler = handler;
         mNetworkAgentInfo = networkAgentInfo;
         mNetId = mNetworkAgentInfo.network.netId;
diff --git a/services/core/java/com/android/server/job/controllers/ContentObserverController.java b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
index a42d0cd..5d209fc 100644
--- a/services/core/java/com/android/server/job/controllers/ContentObserverController.java
+++ b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
@@ -16,6 +16,7 @@
 
 package com.android.server.job.controllers;
 
+import android.annotation.UserIdInt;
 import android.app.job.JobInfo;
 import android.content.Context;
 import android.database.ContentObserver;
@@ -23,6 +24,7 @@
 import android.os.Handler;
 import android.os.UserHandle;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.TimeUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -35,6 +37,7 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Controller for monitoring changes to content URIs through a ContentObserver.
@@ -59,7 +62,11 @@
     private static volatile ContentObserverController sController;
 
     final private List<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
-    ArrayMap<JobInfo.TriggerContentUri, ObserverInstance> mObservers = new ArrayMap<>();
+    /**
+     * Per-userid {@link JobInfo.TriggerContentUri} keyed ContentObserver cache.
+     */
+    SparseArray<ArrayMap<JobInfo.TriggerContentUri, ObserverInstance>> mObservers =
+            new SparseArray<>();
     final Handler mHandler;
 
     public static ContentObserverController get(JobSchedulerService taskManagerService) {
@@ -203,18 +210,21 @@
 
     final class ObserverInstance extends ContentObserver {
         final JobInfo.TriggerContentUri mUri;
+        final @UserIdInt int mUserId;
         final ArraySet<JobInstance> mJobs = new ArraySet<>();
 
-        public ObserverInstance(Handler handler, JobInfo.TriggerContentUri uri) {
+        public ObserverInstance(Handler handler, JobInfo.TriggerContentUri uri,
+                @UserIdInt int userId) {
             super(handler);
             mUri = uri;
+            mUserId = userId;
         }
 
         @Override
         public void onChange(boolean selfChange, Uri uri) {
             if (DEBUG) {
                 Slog.i(TAG, "onChange(self=" + selfChange + ") for " + uri
-                        + " when mUri=" + mUri);
+                        + " when mUri=" + mUri + " mUserId=" + mUserId);
             }
             synchronized (mLock) {
                 final int N = mJobs.size();
@@ -258,27 +268,38 @@
 
         boolean mTriggerPending;
 
+        // This constructor must be called with the master job scheduler lock held.
         JobInstance(JobStatus jobStatus) {
             mJobStatus = jobStatus;
             mExecuteRunner = new TriggerRunnable(this);
             mTimeoutRunner = new TriggerRunnable(this);
             final JobInfo.TriggerContentUri[] uris = jobStatus.getJob().getTriggerContentUris();
+            final int sourceUserId = jobStatus.getSourceUserId();
+            ArrayMap<JobInfo.TriggerContentUri, ObserverInstance> observersOfUser =
+                    mObservers.get(sourceUserId);
+            if (observersOfUser == null) {
+                observersOfUser = new ArrayMap<>();
+                mObservers.put(sourceUserId, observersOfUser);
+            }
             if (uris != null) {
                 for (JobInfo.TriggerContentUri uri : uris) {
-                    ObserverInstance obs = mObservers.get(uri);
+                    ObserverInstance obs = observersOfUser.get(uri);
                     if (obs == null) {
-                        obs = new ObserverInstance(mHandler, uri);
-                        mObservers.put(uri, obs);
+                        obs = new ObserverInstance(mHandler, uri, jobStatus.getSourceUserId());
+                        observersOfUser.put(uri, obs);
                         final boolean andDescendants = (uri.getFlags() &
                                 JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS) != 0;
                         if (DEBUG) {
                             Slog.v(TAG, "New observer " + obs + " for " + uri.getUri()
-                                    + " andDescendants=" + andDescendants);
+                                    + " andDescendants=" + andDescendants
+                                    + " sourceUserId=" + sourceUserId);
                         }
                         mContext.getContentResolver().registerContentObserver(
                                 uri.getUri(),
                                 andDescendants,
-                                obs);
+                                obs,
+                                sourceUserId
+                        );
                     } else {
                         if (DEBUG) {
                             final boolean andDescendants = (uri.getFlags() &
@@ -342,7 +363,11 @@
                         Slog.i(TAG, "Unregistering observer " + obs + " for " + obs.mUri.getUri());
                     }
                     mContext.getContentResolver().unregisterContentObserver(obs);
-                    mObservers.remove(obs.mUri);
+                    ArrayMap<JobInfo.TriggerContentUri, ObserverInstance> observerOfUser =
+                            mObservers.get(obs.mUserId);
+                    if (observerOfUser !=  null) {
+                        observerOfUser.remove(obs.mUri);
+                    }
                 }
             }
         }
@@ -366,60 +391,66 @@
         int N = mObservers.size();
         if (N > 0) {
             pw.println("  Observers:");
-            for (int i = 0; i < N; i++) {
-                ObserverInstance obs = mObservers.valueAt(i);
-                int M = obs.mJobs.size();
-                boolean shouldDump = false;
-                for (int j=0; j<M; j++) {
-                    JobInstance inst = obs.mJobs.valueAt(j);
-                    if (inst.mJobStatus.shouldDump(filterUid)) {
-                        shouldDump = true;
-                        break;
+            for (int userIdx = 0; userIdx < N; userIdx++) {
+                final int userId = mObservers.keyAt(userIdx);
+                ArrayMap<JobInfo.TriggerContentUri, ObserverInstance> observersOfUser =
+                        mObservers.get(userId);
+                int numbOfObserversPerUser = observersOfUser.size();
+                for (int observerIdx = 0 ; observerIdx < numbOfObserversPerUser; observerIdx++) {
+                    ObserverInstance obs = observersOfUser.valueAt(observerIdx);
+                    int M = obs.mJobs.size();
+                    boolean shouldDump = false;
+                    for (int j = 0; j < M; j++) {
+                        JobInstance inst = obs.mJobs.valueAt(j);
+                        if (inst.mJobStatus.shouldDump(filterUid)) {
+                            shouldDump = true;
+                            break;
+                        }
                     }
-                }
-                if (!shouldDump) {
-                    continue;
-                }
-                pw.print("    ");
-                JobInfo.TriggerContentUri trigger = mObservers.keyAt(i);
-                pw.print(trigger.getUri());
-                pw.print(" 0x");
-                pw.print(Integer.toHexString(trigger.getFlags()));
-                pw.print(" (");
-                pw.print(System.identityHashCode(obs));
-                pw.println("):");
-                pw.println("      Jobs:");
-                for (int j=0; j<M; j++) {
-                    JobInstance inst = obs.mJobs.valueAt(j);
-                    pw.print("        #");
-                    inst.mJobStatus.printUniqueId(pw);
-                    pw.print(" from ");
-                    UserHandle.formatUid(pw, inst.mJobStatus.getSourceUid());
-                    if (inst.mChangedAuthorities != null) {
-                        pw.println(":");
-                        if (inst.mTriggerPending) {
-                            pw.print("          Trigger pending: update=");
-                            TimeUtils.formatDuration(
-                                    inst.mJobStatus.getTriggerContentUpdateDelay(), pw);
-                            pw.print(", max=");
-                            TimeUtils.formatDuration(
-                                    inst.mJobStatus.getTriggerContentMaxDelay(), pw);
+                    if (!shouldDump) {
+                        continue;
+                    }
+                    pw.print("    ");
+                    JobInfo.TriggerContentUri trigger = observersOfUser.keyAt(observerIdx);
+                    pw.print(trigger.getUri());
+                    pw.print(" 0x");
+                    pw.print(Integer.toHexString(trigger.getFlags()));
+                    pw.print(" (");
+                    pw.print(System.identityHashCode(obs));
+                    pw.println("):");
+                    pw.println("      Jobs:");
+                    for (int j = 0; j < M; j++) {
+                        JobInstance inst = obs.mJobs.valueAt(j);
+                        pw.print("        #");
+                        inst.mJobStatus.printUniqueId(pw);
+                        pw.print(" from ");
+                        UserHandle.formatUid(pw, inst.mJobStatus.getSourceUid());
+                        if (inst.mChangedAuthorities != null) {
+                            pw.println(":");
+                            if (inst.mTriggerPending) {
+                                pw.print("          Trigger pending: update=");
+                                TimeUtils.formatDuration(
+                                        inst.mJobStatus.getTriggerContentUpdateDelay(), pw);
+                                pw.print(", max=");
+                                TimeUtils.formatDuration(
+                                        inst.mJobStatus.getTriggerContentMaxDelay(), pw);
+                                pw.println();
+                            }
+                            pw.println("          Changed Authorities:");
+                            for (int k = 0; k < inst.mChangedAuthorities.size(); k++) {
+                                pw.print("          ");
+                                pw.println(inst.mChangedAuthorities.valueAt(k));
+                            }
+                            if (inst.mChangedUris != null) {
+                                pw.println("          Changed URIs:");
+                                for (int k = 0; k < inst.mChangedUris.size(); k++) {
+                                    pw.print("          ");
+                                    pw.println(inst.mChangedUris.valueAt(k));
+                                }
+                            }
+                        } else {
                             pw.println();
                         }
-                        pw.println("          Changed Authorities:");
-                        for (int k=0; k<inst.mChangedAuthorities.size(); k++) {
-                            pw.print("          ");
-                            pw.println(inst.mChangedAuthorities.valueAt(k));
-                        }
-                        if (inst.mChangedUris != null) {
-                            pw.println("          Changed URIs:");
-                            for (int k = 0; k<inst.mChangedUris.size(); k++) {
-                                pw.print("          ");
-                                pw.println(inst.mChangedUris.valueAt(k));
-                            }
-                        }
-                    } else {
-                        pw.println();
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index d02424b..2f77f93 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -239,7 +239,8 @@
         synchronized (mLock) {
             UserManager manager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
             int currentUser = ActivityManager.getCurrentUser();
-            int[] userIds = manager.getEnabledProfileIds(currentUser);
+            // Include all profiles even though they aren't yet enabled to handle work profile case.
+            int[] userIds = manager.getProfileIdsWithDisabled(currentUser);
             mCurrentUserIdList.clear();
             if (userIds != null && userIds.length > 0) {
                 for (int userId : userIds) {
@@ -440,6 +441,12 @@
     private MediaSessionRecord createSessionLocked(int callerPid, int callerUid, int userId,
             String callerPackageName, ISessionCallback cb, String tag) {
 
+        UserRecord user = mUserRecords.get(userId);
+        if (user == null) {
+            Log.wtf(TAG, "Request from invalid user: " +  userId);
+            throw new RuntimeException("Session request from invalid user.");
+        }
+
         final MediaSessionRecord session = new MediaSessionRecord(callerPid, callerUid, userId,
                 callerPackageName, cb, tag, this, mHandler);
         try {
@@ -450,8 +457,6 @@
 
         mAllSessions.add(session);
         mPriorityStack.addSession(session, mCurrentUserIdList.contains(userId));
-
-        UserRecord user = mUserRecords.get(userId);
         user.addSessionLocked(session);
 
         mHandler.post(MessageHandler.MSG_SESSIONS_CHANGED, userId, 0);
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 77c69c9..c5f3cfd3b 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -56,16 +56,9 @@
     // TODO: Evaluate the need for WeakReferences here.
 
     /**
-     * The list of packages to dexopt.
+     * The list of dexopt invocations for all work.
      */
-    private List<PackageParser.Package> mDexoptPackages;
-
-    /**
-     * The list of dexopt invocations for the current package (which will no longer be in
-     * mDexoptPackages). This can be more than one as a package may have multiple code paths,
-     * e.g., in the split-APK case.
-     */
-    private List<String> mCommandsForCurrentPackage;
+    private List<String> mDexoptCommands;
 
     private int completeSize;
 
@@ -94,15 +87,43 @@
 
     @Override
     public synchronized void prepare() throws RemoteException {
-        if (mDexoptPackages != null) {
+        if (mDexoptCommands != null) {
             throw new IllegalStateException("already called prepare()");
         }
         synchronized (mPackageManagerService.mPackages) {
-            mDexoptPackages = PackageManagerServiceUtils.getPackagesForDexopt(
+            // Important: the packages we need to run with ab-ota compiler-reason.
+            List<PackageParser.Package> important = PackageManagerServiceUtils.getPackagesForDexopt(
                     mPackageManagerService.mPackages.values(), mPackageManagerService);
+            // Others: we should optimize this with the (first-)boot compiler-reason.
+            List<PackageParser.Package> others =
+                    new ArrayList<>(mPackageManagerService.mPackages.values());
+            others.removeAll(important);
+
+            // Pre-size the array list by over-allocating by a factor of 1.5.
+            mDexoptCommands = new ArrayList<>(3 * mPackageManagerService.mPackages.size() / 2);
+
+            for (PackageParser.Package p : important) {
+                // Make sure that core apps are optimized according to their own "reason".
+                // If the core apps are not preopted in the B OTA, and REASON_AB_OTA is not speed
+                // (by default is speed-profile) they will be interepreted/JITed. This in itself is
+                // not a problem as we will end up doing profile guided compilation. However, some
+                // core apps may be loaded by system server which doesn't JIT and we need to make
+                // sure we don't interpret-only
+                int compilationReason = p.coreApp
+                        ? PackageManagerService.REASON_CORE_APP
+                        : PackageManagerService.REASON_AB_OTA;
+                mDexoptCommands.addAll(generatePackageDexopts(p, compilationReason));
+            }
+            for (PackageParser.Package p : others) {
+                // We assume here that there are no core apps left.
+                if (p.coreApp) {
+                    throw new IllegalStateException("Found a core app that's not important");
+                }
+                mDexoptCommands.addAll(
+                        generatePackageDexopts(p, PackageManagerService.REASON_FIRST_BOOT));
+            }
         }
-        completeSize = mDexoptPackages.size();
-        mCommandsForCurrentPackage = null;
+        completeSize = mDexoptCommands.size();
     }
 
     @Override
@@ -110,87 +131,52 @@
         if (DEBUG_DEXOPT) {
             Log.i(TAG, "Cleaning up OTA Dexopt state.");
         }
-        mDexoptPackages = null;
-        mCommandsForCurrentPackage = null;
+        mDexoptCommands = null;
     }
 
     @Override
     public synchronized boolean isDone() throws RemoteException {
-        if (mDexoptPackages == null) {
+        if (mDexoptCommands == null) {
             throw new IllegalStateException("done() called before prepare()");
         }
 
-        return mDexoptPackages.isEmpty() && (mCommandsForCurrentPackage == null);
+        return mDexoptCommands.isEmpty();
     }
 
     @Override
     public synchronized float getProgress() throws RemoteException {
-        // We approximate by number of packages here. We could track all compiles, if we
-        // generated them ahead of time. Right now we're trying to conserve memory.
+        // Approximate the progress by the amount of already completed commands.
         if (completeSize == 0) {
             return 1f;
         }
-        int packagesLeft = mDexoptPackages.size() + (mCommandsForCurrentPackage != null ? 1 : 0);
-        return (completeSize - packagesLeft) / ((float)completeSize);
-    }
-
-    /**
-     * Return the next dexopt command for the current package. Enforces the invariant
-     */
-    private String getNextPackageDexopt() {
-        if (mCommandsForCurrentPackage != null) {
-            String next = mCommandsForCurrentPackage.remove(0);
-            if (mCommandsForCurrentPackage.isEmpty()) {
-                mCommandsForCurrentPackage = null;
-            }
-            return next;
-        }
-        return null;
+        int commandsLeft = mDexoptCommands.size();
+        return (completeSize - commandsLeft) / ((float)completeSize);
     }
 
     @Override
     public synchronized String nextDexoptCommand() throws RemoteException {
-        if (mDexoptPackages == null) {
+        if (mDexoptCommands == null) {
             throw new IllegalStateException("dexoptNextPackage() called before prepare()");
         }
 
-        // Get the next command.
-        for (;;) {
-            // Check whether there's one for the current package.
-            String next = getNextPackageDexopt();
-            if (next != null) {
-                return next;
-            }
+        if (mDexoptCommands.isEmpty()) {
+            return "(all done)";
+        }
 
-            // Move to the next package, if possible.
-            if (mDexoptPackages.isEmpty()) {
-                return "Nothing to do";
-            }
+        String next = mDexoptCommands.remove(0);
 
-            PackageParser.Package nextPackage = mDexoptPackages.remove(0);
-
-            if (DEBUG_DEXOPT) {
-                Log.i(TAG, "Processing " + nextPackage.packageName + " for OTA dexopt.");
-            }
-
-            // Generate the next mPackageDexopts state. Ignore errors, this loop is strongly
-            // monotonically increasing, anyways.
-            generatePackageDexopts(nextPackage);
-
-            // Invariant check: mPackageDexopts is null or not empty.
-            if (mCommandsForCurrentPackage != null && mCommandsForCurrentPackage.isEmpty()) {
-                cleanup();
-                throw new IllegalStateException("mPackageDexopts empty for " + nextPackage);
-            }
+        if (IsFreeSpaceAvailable()) {
+            return next;
+        } else {
+            mDexoptCommands.clear();
+            return "(no free space)";
         }
     }
 
     /**
-     * Generate all dexopt commands for the given package and place them into mPackageDexopts.
-     * Returns true on success, false in an error situation like low disk space.
+     * Check for low space. Returns true if there's space left.
      */
-    private synchronized boolean generatePackageDexopts(PackageParser.Package nextPackage) {
-        // Check for low space.
+    private boolean IsFreeSpaceAvailable() {
         // TODO: If apps are not installed in the internal /data partition, we should compare
         //       against that storage's free capacity.
         File dataDir = Environment.getDataDirectory();
@@ -200,12 +186,14 @@
             throw new IllegalStateException("Invalid low memory threshold");
         }
         long usableSpace = dataDir.getUsableSpace();
-        if (usableSpace < lowThreshold) {
-            Log.w(TAG, "Not running dexopt on " + nextPackage.packageName + " due to low memory: " +
-                    usableSpace);
-            return false;
-        }
+        return (usableSpace >= lowThreshold);
+    }
 
+    /**
+     * Generate all dexopt commands for the given package.
+     */
+    private synchronized List<String> generatePackageDexopts(PackageParser.Package pkg,
+            int compilationReason) {
         // Use our custom connection that just collects the commands.
         RecordingInstallerConnection collectingConnection = new RecordingInstallerConnection();
         Installer collectingInstaller = new Installer(mContext, collectingConnection);
@@ -213,71 +201,22 @@
         // Use the package manager install and install lock here for the OTA dex optimizer.
         PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer(
                 collectingInstaller, mPackageManagerService.mInstallLock, mContext);
-        // Make sure that core apps are optimized according to their own "reason".
-        // If the core apps are not preopted in the B OTA, and REASON_AB_OTA is not speed
-        // (by default is speed-profile) they will be interepreted/JITed. This in itself is not a
-        // problem as we will end up doing profile guided compilation. However, some core apps may
-        // be loaded by system server which doesn't JIT and we need to make sure we don't
-        // interpret-only
-        int compilationReason = nextPackage.coreApp
-                ? PackageManagerService.REASON_CORE_APP
-                : PackageManagerService.REASON_AB_OTA;
 
-        optimizer.performDexOpt(nextPackage, nextPackage.usesLibraryFiles,
+        optimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
                 null /* ISAs */, false /* checkProfiles */,
                 getCompilerFilterForReason(compilationReason),
                 null /* CompilerStats.PackageStats */);
 
-        mCommandsForCurrentPackage = collectingConnection.commands;
-        if (mCommandsForCurrentPackage.isEmpty()) {
-            mCommandsForCurrentPackage = null;
-        }
-
-        return true;
+        return collectingConnection.commands;
     }
 
     @Override
     public synchronized void dexoptNextPackage() throws RemoteException {
-        if (mDexoptPackages == null) {
-            throw new IllegalStateException("dexoptNextPackage() called before prepare()");
-        }
-        if (mDexoptPackages.isEmpty()) {
-            // Tolerate repeated calls.
-            return;
-        }
-
-        PackageParser.Package nextPackage = mDexoptPackages.remove(0);
-
-        if (DEBUG_DEXOPT) {
-            Log.i(TAG, "Processing " + nextPackage.packageName + " for OTA dexopt.");
-        }
-
-        // Check for low space.
-        // TODO: If apps are not installed in the internal /data partition, we should compare
-        //       against that storage's free capacity.
-        File dataDir = Environment.getDataDirectory();
-        @SuppressWarnings("deprecation")
-        long lowThreshold = StorageManager.from(mContext).getStorageLowBytes(dataDir);
-        if (lowThreshold == 0) {
-            throw new IllegalStateException("Invalid low memory threshold");
-        }
-        long usableSpace = dataDir.getUsableSpace();
-        if (usableSpace < lowThreshold) {
-            Log.w(TAG, "Not running dexopt on " + nextPackage.packageName + " due to low memory: " +
-                    usableSpace);
-            return;
-        }
-
-        PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer(
-                mPackageManagerService.mInstaller, mPackageManagerService.mInstallLock, mContext);
-        optimizer.performDexOpt(nextPackage, nextPackage.usesLibraryFiles, null /* ISAs */,
-                false /* checkProfiles */,
-                getCompilerFilterForReason(PackageManagerService.REASON_AB_OTA),
-                mPackageManagerService.getOrCreateCompilerPackageStats(nextPackage));
+        throw new UnsupportedOperationException();
     }
 
     private void moveAbArtifacts(Installer installer) {
-        if (mDexoptPackages != null) {
+        if (mDexoptCommands != null) {
             throw new IllegalStateException("Should not be ota-dexopting when trying to move.");
         }
 
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 85b6be7..e17d243 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -553,7 +553,7 @@
     public List<UserInfo> getProfiles(int userId, boolean enabledOnly) {
         boolean returnFullInfo = true;
         if (userId != UserHandle.getCallingUserId()) {
-            checkManageUsersPermission("getting profiles related to user " + userId);
+            checkManageOrCreateUsersPermission("getting profiles related to user " + userId);
         } else {
             returnFullInfo = hasManageUsersPermission();
         }
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 7fed802..ed275ad 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -60,6 +60,7 @@
             secure = true;
             deviceHasKeyguard = true;
             enabled = true;
+            currentUser = UserHandle.USER_NULL;
         }
         boolean showing;
         boolean showingAndNotOccluded;
@@ -158,6 +159,10 @@
             if (mKeyguardState.systemIsReady) {
                 // If the system is ready, it means keyguard crashed and restarted.
                 mKeyguardService.onSystemReady();
+                if (mKeyguardState.currentUser != UserHandle.USER_NULL) {
+                    // There has been a user switch earlier
+                    mKeyguardService.setCurrentUser(mKeyguardState.currentUser);
+                }
                 // This is used to hide the scrim once keyguard displays.
                 if (mKeyguardState.interactiveState == INTERACTIVE_STATE_AWAKE) {
                     mKeyguardService.onStartedWakingUp();
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 8d13b0d..ced84f6 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -2086,7 +2086,12 @@
             float screenAutoBrightnessAdjustment = 0.0f;
             boolean autoBrightness = (mScreenBrightnessModeSetting ==
                     Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
-            if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
+            if (!mBootCompleted) {
+                // Keep the brightness steady during boot. This requires the
+                // bootloader brightness and the default brightness to be identical.
+                autoBrightness = false;
+                brightnessSetByUser = false;
+            } else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
                 screenBrightness = mScreenBrightnessOverrideFromWindowManager;
                 autoBrightness = false;
                 brightnessSetByUser = false;
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 1d6cc32..2d60f43 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -1081,14 +1081,15 @@
                                 Region.Op.REVERSE_DIFFERENCE);
                     }
 
-                    // We figured out what is touchable for the entire screen - done.
-                    if (unaccountedSpace.isEmpty()) {
-                        break;
-                    }
-
                     // If a window is modal it prevents other windows from being touched
                     if ((flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                             | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
+                        // Account for all space in the task, whether the windows in it are
+                        // touchable or not. The modal window blocks all touches from the task's
+                        // area.
+                        unaccountedSpace.op(windowState.getDisplayFrameLw(), unaccountedSpace,
+                                Region.Op.REVERSE_DIFFERENCE);
+
                         if (task != null) {
                             // If the window is associated with a particular task, we can skip the
                             // rest of the windows for that task.
@@ -1100,6 +1101,10 @@
                             break;
                         }
                     }
+                    // We figured out what is touchable for the entire screen - done.
+                    if (unaccountedSpace.isEmpty()) {
+                        break;
+                    }
                 }
 
                 // Always report the focused window.
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 3cde274..6b0edad 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -282,10 +282,10 @@
 
     WindowState findMainWindow() {
         WindowState candidate = null;
-        int j = windows.size();
+        int j = allAppWindows.size();
         while (j > 0) {
             j--;
-            WindowState win = windows.get(j);
+            WindowState win = allAppWindows.get(j);
             if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION
                     || win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
                 // In cases where there are multiple windows, we prefer the non-exiting window. This
@@ -548,7 +548,7 @@
         clearVisibleBeforeClientHidden();
 
         if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG,
-                "restoreSavedSurfaces: " + appWindowToken + " allDrawn=" + allDrawn
+                "restoreSavedSurfaces: " + this + " allDrawn=" + allDrawn
                 + " numInteresting=" + numInteresting + " numDrawn=" + numDrawn);
     }
 
@@ -615,8 +615,8 @@
     }
 
     void setReplacingWindows(boolean animate) {
-        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + appWindowToken
-                + " with replacing windows.");
+        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
+                "Marking app token " + this + " with replacing windows.");
 
         for (int i = allAppWindows.size() - 1; i >= 0; i--) {
             final WindowState w = allAppWindows.get(i);
@@ -633,7 +633,7 @@
     }
 
     void setReplacingChildren() {
-        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + appWindowToken
+        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + this
                 + " with replacing child windows.");
         for (int i = allAppWindows.size() - 1; i >= 0; i--) {
             final WindowState w = allAppWindows.get(i);
@@ -644,8 +644,8 @@
     }
 
     void resetReplacingWindows() {
-        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Resetting app token " + appWindowToken
-                + " of replacing window marks.");
+        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
+                "Resetting app token " + this + " of replacing window marks.");
 
         for (int i = allAppWindows.size() - 1; i >= 0; i--) {
             final WindowState w = allAppWindows.get(i);
@@ -775,8 +775,8 @@
         if (!mFrozenMergedConfig.isEmpty()) {
             mFrozenMergedConfig.remove();
         }
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            final WindowState win = windows.get(i);
+        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
+            final WindowState win = allAppWindows.get(i);
             if (!win.mHasSurface) {
                 continue;
             }
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 25f6c27..7b6f9e3 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -246,7 +246,10 @@
 
     boolean updateWallpaperOffset(WindowState wallpaperWin, int dw, int dh, boolean sync) {
         boolean rawChanged = false;
-        float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : 0.5f;
+        // Set the default wallpaper x-offset to either edge of the screen (depending on RTL), to
+        // match the behavior of most Launchers
+        float defaultWallpaperX = wallpaperWin.isRtl() ? 1f : 0f;
+        float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : defaultWallpaperX;
         float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f;
         int availw = wallpaperWin.mFrame.right - wallpaperWin.mFrame.left - dw;
         int offset = availw > 0 ? -(int)(availw * wpx + .5f) : 0;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 292561a..0493084 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1621,7 +1621,6 @@
     void addInputMethodWindowToListLocked(WindowState win) {
         int pos = findDesiredInputMethodWindowIndexLocked(true);
         if (pos >= 0) {
-            win.mTargetAppToken = mInputMethodTarget.mAppToken;
             if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(
                     TAG_WM, "Adding input method window " + win + " at " + pos);
             // TODO(multidisplay): IMEs are only supported on the default display.
@@ -1630,7 +1629,6 @@
             moveInputMethodDialogsLocked(pos + 1);
             return;
         }
-        win.mTargetAppToken = null;
         addWindowToListInOrderLocked(win, true);
         moveInputMethodDialogsLocked(pos);
     }
@@ -1674,7 +1672,6 @@
         }
 
         if (pos >= 0) {
-            final AppWindowToken targetAppToken = mInputMethodTarget.mAppToken;
             // Skip windows owned by the input method.
             if (mInputMethodWindow != null) {
                 while (pos < windows.size()) {
@@ -1689,7 +1686,6 @@
             if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Adding " + N + " dialogs at pos=" + pos);
             for (int i=0; i<N; i++) {
                 WindowState win = dialogs.get(i);
-                win.mTargetAppToken = targetAppToken;
                 pos = win.reAddWindowLocked(pos);
             }
             if (DEBUG_INPUT_METHOD) {
@@ -1700,7 +1696,6 @@
         }
         for (int i=0; i<N; i++) {
             WindowState win = dialogs.get(i);
-            win.mTargetAppToken = null;
             reAddWindowToListInOrderLocked(win);
             if (DEBUG_INPUT_METHOD) {
                 Slog.v(TAG_WM, "No IM target, final list:");
@@ -1756,11 +1751,6 @@
                     pos++;
                 }
                 if (pos >= N) {
-                    // Z order is good.
-                    // The IM target window may be changed, so update the mTargetAppToken.
-                    if (imWin != null) {
-                        imWin.mTargetAppToken = mInputMethodTarget.mAppToken;
-                    }
                     return false;
                 }
             }
@@ -1775,7 +1765,6 @@
                     Slog.v(TAG_WM, "List after removing with new pos " + imPos + ":");
                     logWindowList(windows, "  ");
                 }
-                imWin.mTargetAppToken = mInputMethodTarget.mAppToken;
                 imWin.reAddWindowLocked(imPos);
                 if (DEBUG_INPUT_METHOD) {
                     Slog.v(TAG_WM, "List after moving IM to " + imPos + ":");
@@ -1793,7 +1782,6 @@
             if (imWin != null) {
                 if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Moving IM from " + imPos);
                 imWin.removeFromWindowList(0);
-                imWin.mTargetAppToken = null;
                 reAddWindowToListInOrderLocked(imWin);
                 if (DEBUG_INPUT_METHOD) {
                     Slog.v(TAG_WM, "List with no IM target:");
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index beb7e2b..d20529d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -158,7 +158,6 @@
     WindowToken mToken;
     WindowToken mRootToken;
     AppWindowToken mAppToken;
-    AppWindowToken mTargetAppToken;
 
     // mAttrs.flags is tested in animation without being locked. If the bits tested are ever
     // modified they will need to be locked.
@@ -619,17 +618,17 @@
         }
         mIsFloatingLayer = mIsImWindow || mIsWallpaper;
 
-        final WindowState appWin = getTopParentWindow();
-        WindowToken appToken = appWin.mToken;
-        while (appToken.appWindowToken == null) {
-            WindowToken parent = mService.mTokenMap.get(appToken.token);
-            if (parent == null || appToken == parent) {
+        final WindowState topParentWindow = getTopParentWindow();
+        WindowToken rootToken = topParentWindow.mToken;
+        while (rootToken.appWindowToken == null) {
+            WindowToken parent = mService.mTokenMap.get(rootToken.token);
+            if (parent == null || rootToken == parent) {
                 break;
             }
-            appToken = parent;
+            rootToken = parent;
         }
-        mRootToken = appToken;
-        mAppToken = appToken.appWindowToken;
+        mRootToken = rootToken;
+        mAppToken = rootToken.appWindowToken;
         if (mAppToken != null) {
             final DisplayContent appDisplay = getDisplayContent();
             mNotOnAppsDisplay = displayContent != appDisplay;
@@ -1495,14 +1494,21 @@
     }
 
     int getAnimLayerAdjustment() {
-        if (mTargetAppToken != null) {
-            return mTargetAppToken.mAppAnimator.animLayerAdjustment;
-        } else if (mAppToken != null) {
-            return mAppToken.mAppAnimator.animLayerAdjustment;
-        } else {
-            // Nothing is animating, so there is no animation adjustment.
-            return 0;
+        final boolean isImeType =
+                mAttrs.type == TYPE_INPUT_METHOD || mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
+        if (isImeType && mService.mInputMethodTarget != null) {
+            final AppWindowToken appToken = mService.mInputMethodTarget.mAppToken;
+            if (appToken != null) {
+                return appToken.mAppAnimator.animLayerAdjustment;
+            }
         }
+
+        if (mAppToken != null) {
+            return mAppToken.mAppAnimator.animLayerAdjustment;
+        }
+
+        // Nothing is animating, so there is no animation adjustment.
+        return 0;
     }
 
     void scheduleAnimationIfDimming() {
@@ -2580,9 +2586,7 @@
             pw.print(prefix); pw.print("mBaseLayer="); pw.print(mBaseLayer);
                     pw.print(" mSubLayer="); pw.print(mSubLayer);
                     pw.print(" mAnimLayer="); pw.print(mLayer); pw.print("+");
-                    pw.print((mTargetAppToken != null ?
-                            mTargetAppToken.mAppAnimator.animLayerAdjustment
-                          : (mAppToken != null ? mAppToken.mAppAnimator.animLayerAdjustment : 0)));
+                    pw.print(getAnimLayerAdjustment());
                     pw.print("="); pw.print(mWinAnimator.mAnimLayer);
                     pw.print(" mLastLayer="); pw.println(mWinAnimator.mLastLayer);
         }
@@ -2595,9 +2599,6 @@
                 pw.print(isAnimatingWithSavedSurface());
                 pw.print(" mAppDied=");pw.println(mAppDied);
             }
-            if (mTargetAppToken != null) {
-                pw.print(prefix); pw.print("mTargetAppToken="); pw.println(mTargetAppToken);
-            }
             pw.print(prefix); pw.print("mViewVisibility=0x");
             pw.print(Integer.toHexString(mViewVisibility));
             pw.print(" mHaveFrame="); pw.print(mHaveFrame);
@@ -3205,4 +3206,8 @@
         mAnimatingExit = false;
         mService.mWallpaperControllerLocked.hideWallpapers(this);
     }
+
+    public boolean isRtl() {
+        return mMergedConfiguration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+    }
 }
diff --git a/services/retaildemo/java/com/android/server/retaildemo/PreloadAppsInstaller.java b/services/retaildemo/java/com/android/server/retaildemo/PreloadAppsInstaller.java
index c0bf9b3..7a3b461 100644
--- a/services/retaildemo/java/com/android/server/retaildemo/PreloadAppsInstaller.java
+++ b/services/retaildemo/java/com/android/server/retaildemo/PreloadAppsInstaller.java
@@ -130,6 +130,10 @@
                     // Install on user 0 so that the package is cached when demo user is re-created
                     installExistingPackage(basePackageName, UserHandle.USER_SYSTEM, counter);
                 } else if (returnCode == PackageManager.INSTALL_FAILED_ALREADY_EXISTS) {
+                    // This can only happen in first session after a reboot
+                    if (!mApkToPackageMap.containsKey(apkName)) {
+                        mApkToPackageMap.put(apkName, basePackageName);
+                    }
                     installExistingPackage(basePackageName, userId, counter);
                 }
             }
diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
index c6078fd..8d5971f 100644
--- a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
+++ b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
@@ -224,8 +224,7 @@
             if (mDeviceDemoModeUri.equals(uri)) {
                 mDeviceInDemoMode = UserManager.isDeviceInDemoMode(getContext());
                 if (mDeviceInDemoMode) {
-                    SystemProperties.set(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, "1");
-                    mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
+                    putDeviceInDemoMode();
                 } else {
                     SystemProperties.set(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, "0");
                     if (mWakeLock.isHeld()) {
@@ -287,7 +286,6 @@
         synchronized (mActivityLock) {
             mFirstUserActivityTime = mLastUserActivityTime = SystemClock.uptimeMillis();
         }
-        mPreloadAppsInstaller = new PreloadAppsInstaller(context);
     }
 
     private Notification createResetNotification() {
@@ -465,6 +463,11 @@
         return mSystemUserConfiguration;
     }
 
+    private void putDeviceInDemoMode() {
+        SystemProperties.set(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, "1");
+        mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
+    }
+
     @Override
     public void onStart() {
         if (DEBUG) {
@@ -479,26 +482,31 @@
 
     @Override
     public void onBootPhase(int bootPhase) {
-        if (bootPhase != PHASE_THIRD_PARTY_APPS_CAN_START) {
-            return;
+        switch (bootPhase) {
+            case PHASE_THIRD_PARTY_APPS_CAN_START:
+                mPreloadAppsInstaller = new PreloadAppsInstaller(getContext());
+                mPm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
+                mAmi = LocalServices.getService(ActivityManagerInternal.class);
+                mWakeLock = mPm
+                        .newWakeLock(
+                                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP,
+                                TAG);
+                mNm = NotificationManager.from(getContext());
+                mCameraManager = (CameraManager) getContext()
+                        .getSystemService(Context.CAMERA_SERVICE);
+                mCameraIdsWithFlash = getCameraIdsWithFlash();
+                SettingsObserver settingsObserver = new SettingsObserver(mHandler);
+                settingsObserver.register();
+                settingsObserver.refreshTimeoutConstants();
+                registerBroadcastReceiver();
+                break;
+            case PHASE_BOOT_COMPLETED:
+                if (UserManager.isDeviceInDemoMode(getContext())) {
+                    mDeviceInDemoMode = true;
+                    putDeviceInDemoMode();
+                }
+                break;
         }
-        mPm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
-        mAmi = LocalServices.getService(ActivityManagerInternal.class);
-        mWakeLock = mPm
-                .newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, TAG);
-        mNm = NotificationManager.from(getContext());
-        mCameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
-        mCameraIdsWithFlash = getCameraIdsWithFlash();
-
-        if (UserManager.isDeviceInDemoMode(getContext())) {
-            mDeviceInDemoMode = true;
-            SystemProperties.set(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, "1");
-            mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
-        }
-        SettingsObserver settingsObserver = new SettingsObserver(mHandler);
-        settingsObserver.register();
-        settingsObserver.refreshTimeoutConstants();
-        registerBroadcastReceiver();
     }
 
     @Override
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index f2a9315..59ccbd9 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -51,6 +51,7 @@
 import android.net.NetworkMisc;
 import android.net.NetworkRequest;
 import android.net.RouteInfo;
+import android.net.metrics.IpConnectivityLog;
 import android.os.ConditionVariable;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -585,8 +586,9 @@
         public String gen204ProbeRedirectUrl = null;
 
         public WrappedNetworkMonitor(Context context, Handler handler,
-            NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest) {
-            super(context, handler, networkAgentInfo, defaultRequest);
+                NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest,
+                IpConnectivityLog log) {
+            super(context, handler, networkAgentInfo, defaultRequest, log);
         }
 
         @Override
@@ -599,8 +601,9 @@
         private WrappedNetworkMonitor mLastCreatedNetworkMonitor;
 
         public WrappedConnectivityService(Context context, INetworkManagementService netManager,
-                INetworkStatsService statsService, INetworkPolicyManager policyManager) {
-            super(context, netManager, statsService, policyManager);
+                INetworkStatsService statsService, INetworkPolicyManager policyManager,
+                IpConnectivityLog log) {
+            super(context, netManager, statsService, policyManager, log);
             mLingerDelayMs = TEST_LINGER_DELAY_MS;
         }
 
@@ -639,8 +642,8 @@
         @Override
         public NetworkMonitor createNetworkMonitor(Context context, Handler handler,
                 NetworkAgentInfo nai, NetworkRequest defaultRequest) {
-            final WrappedNetworkMonitor monitor = new WrappedNetworkMonitor(context, handler, nai,
-                    defaultRequest);
+            final WrappedNetworkMonitor monitor = new WrappedNetworkMonitor(
+                    context, handler, nai, defaultRequest, mock(IpConnectivityLog.class));
             mLastCreatedNetworkMonitor = monitor;
             return monitor;
         }
@@ -705,7 +708,8 @@
         mService = new WrappedConnectivityService(mServiceContext,
                 mock(INetworkManagementService.class),
                 mock(INetworkStatsService.class),
-                mock(INetworkPolicyManager.class));
+                mock(INetworkPolicyManager.class),
+                mock(IpConnectivityLog.class));
 
         mService.systemReady();
         mCm = new WrappedConnectivityManager(getContext(), mService);
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index f437a92..11d84c1 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -240,6 +240,8 @@
 
     private boolean mIsDataRoamingFromRegistration;
 
+    private boolean mIsUsingCarrierAggregation;
+
     /**
      * get String description of roaming type
      * @hide
@@ -318,6 +320,7 @@
         mCdmaEriIconMode = s.mCdmaEriIconMode;
         mIsEmergencyOnly = s.mIsEmergencyOnly;
         mIsDataRoamingFromRegistration = s.mIsDataRoamingFromRegistration;
+        mIsUsingCarrierAggregation = s.mIsUsingCarrierAggregation;
     }
 
     /**
@@ -346,6 +349,7 @@
         mCdmaEriIconMode = in.readInt();
         mIsEmergencyOnly = in.readInt() != 0;
         mIsDataRoamingFromRegistration = in.readInt() != 0;
+        mIsUsingCarrierAggregation = in.readInt() != 0;
     }
 
     public void writeToParcel(Parcel out, int flags) {
@@ -371,6 +375,7 @@
         out.writeInt(mCdmaEriIconMode);
         out.writeInt(mIsEmergencyOnly ? 1 : 0);
         out.writeInt(mIsDataRoamingFromRegistration ? 1 : 0);
+        out.writeInt(mIsUsingCarrierAggregation ? 1 : 0);
     }
 
     public int describeContents() {
@@ -680,7 +685,8 @@
                 && equalsHandlesNulls(mCdmaDefaultRoamingIndicator,
                         s.mCdmaDefaultRoamingIndicator)
                 && mIsEmergencyOnly == s.mIsEmergencyOnly
-                && mIsDataRoamingFromRegistration == s.mIsDataRoamingFromRegistration);
+                && mIsDataRoamingFromRegistration == s.mIsDataRoamingFromRegistration
+                && mIsUsingCarrierAggregation == s.mIsUsingCarrierAggregation);
     }
 
     /**
@@ -788,7 +794,8 @@
                 + " RoamInd=" + mCdmaRoamingIndicator
                 + " DefRoamInd=" + mCdmaDefaultRoamingIndicator
                 + " EmergOnly=" + mIsEmergencyOnly
-                + " IsDataRoamingFromRegistration=" + mIsDataRoamingFromRegistration);
+                + " IsDataRoamingFromRegistration=" + mIsDataRoamingFromRegistration
+                + " IsUsingCarrierAggregation=" + mIsUsingCarrierAggregation);
     }
 
     private void setNullState(int state) {
@@ -815,6 +822,7 @@
         mCdmaEriIconMode = -1;
         mIsEmergencyOnly = false;
         mIsDataRoamingFromRegistration = false;
+        mIsUsingCarrierAggregation = false;
     }
 
     public void setStateOutOfService() {
@@ -988,6 +996,7 @@
         mCdmaDefaultRoamingIndicator = m.getInt("cdmaDefaultRoamingIndicator");
         mIsEmergencyOnly = m.getBoolean("emergencyOnly");
         mIsDataRoamingFromRegistration = m.getBoolean("isDataRoamingFromRegistration");
+        mIsUsingCarrierAggregation = m.getBoolean("isUsingCarrierAggregation");
     }
 
     /**
@@ -1017,21 +1026,42 @@
         m.putInt("cdmaDefaultRoamingIndicator", mCdmaDefaultRoamingIndicator);
         m.putBoolean("emergencyOnly", mIsEmergencyOnly);
         m.putBoolean("isDataRoamingFromRegistration", mIsDataRoamingFromRegistration);
+        m.putBoolean("isUsingCarrierAggregation", mIsUsingCarrierAggregation);
     }
 
     /** @hide */
     public void setRilVoiceRadioTechnology(int rt) {
+        if (rt == RIL_RADIO_TECHNOLOGY_LTE_CA) {
+            rt = RIL_RADIO_TECHNOLOGY_LTE;
+        }
+
         this.mRilVoiceRadioTechnology = rt;
     }
 
     /** @hide */
     public void setRilDataRadioTechnology(int rt) {
+        if (rt == RIL_RADIO_TECHNOLOGY_LTE_CA) {
+            rt = RIL_RADIO_TECHNOLOGY_LTE;
+            this.mIsUsingCarrierAggregation = true;
+        } else {
+            this.mIsUsingCarrierAggregation = false;
+        }
         this.mRilDataRadioTechnology = rt;
         if (VDBG) Rlog.d(LOG_TAG, "[ServiceState] setRilDataRadioTechnology=" +
                 mRilDataRadioTechnology);
     }
 
     /** @hide */
+    public boolean isUsingCarrierAggregation() {
+        return mIsUsingCarrierAggregation;
+    }
+
+    /** @hide */
+    public void setIsUsingCarrierAggregation(boolean ca) {
+        mIsUsingCarrierAggregation = ca;
+    }
+
+    /** @hide */
     public void setCssIndicator(int css) {
         this.mCssIndicator = (css != 0);
     }
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index ef09535..1203db7 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -211,9 +211,11 @@
 
     // Provider actions.
     applicationAction["provider"].action(requiredNameIsJavaClassName);
-    applicationAction["provider"]["grant-uri-permissions"];
+    applicationAction["provider"]["intent-filter"] = intentFilterAction;
     applicationAction["provider"]["meta-data"] = metaDataAction;
+    applicationAction["provider"]["grant-uri-permissions"];
     applicationAction["provider"]["path-permissions"];
+
     return true;
 }
 
diff --git a/tools/aapt2/remove-duplicates.py b/tools/aapt2/remove-duplicates.py
new file mode 100644
index 0000000..fb98bb7
--- /dev/null
+++ b/tools/aapt2/remove-duplicates.py
@@ -0,0 +1,181 @@
+#!/usr/bin/env python
+
+import os
+import os.path
+import sys
+import tempfile
+import xml.parsers.expat
+
+"""
+Scans each resource file in res/values/ looking for duplicates.
+All but the last occurrence of resource definition are removed.
+This creates no semantic changes, the resulting APK when built
+should contain the same definition.
+"""
+
+class Duplicate:
+    """A small struct to maintain the positions of a Duplicate resource definition."""
+    def __init__(self, name, product, depth, start, end):
+        self.name = name
+        self.product = product
+        self.depth = depth
+        self.start = start
+        self.end = end
+
+class ResourceDefinitionLocator:
+    """Callback class for xml.parsers.expat which records resource definitions and their
+    locations.
+    """
+    def __init__(self, parser):
+        self.resource_definitions = {}
+        self._parser = parser
+        self._depth = 0
+        self._current_resource = None
+
+    def start_element(self, tag_name, attrs):
+        self._depth += 1
+        if self._depth == 2 and tag_name not in ["public", "java-symbol", "eat-comment", "skip"]:
+            resource_name = None
+            product = ""
+            try:
+                product = attrs["product"]
+            except KeyError:
+                pass
+
+            if tag_name == "item":
+                resource_name = "{0}/{1}".format(attrs["type"], attrs["name"])
+            else:
+                resource_name = "{0}/{1}".format(tag_name, attrs["name"])
+            self._current_resource = Duplicate(
+                    resource_name,
+                    product,
+                    self._depth,
+                    (self._parser.CurrentLineNumber - 1, self._parser.CurrentColumnNumber),
+                    None)
+
+    def end_element(self, tag_name):
+        if self._current_resource and self._depth == self._current_resource.depth:
+            # Record the end position of the element, which is the length of the name
+            # plus the </> symbols (len("</>") == 3).
+            self._current_resource.end = (self._parser.CurrentLineNumber - 1,
+                    self._parser.CurrentColumnNumber + 3 + len(tag_name))
+            key_name = "{0}:{1}".format(self._current_resource.name,
+                    self._current_resource.product)
+            try:
+                self.resource_definitions[key_name] += [self._current_resource]
+            except KeyError:
+                self.resource_definitions[key_name] = [self._current_resource]
+            self._current_resource = None
+        self._depth -= 1
+
+def remove_duplicates(xml_path):
+    """Reads the input file and generates an output file with any duplicate
+    resources removed, keeping the last occurring definition and removing
+    the others. The output is written to a temporary and then renamed
+    to the original file name.
+    """
+    input = ""
+    with open(xml_path) as fin:
+        input = fin.read()
+
+    parser = xml.parsers.expat.ParserCreate("utf-8")
+    parser.returns_unicode = True
+    tracker = ResourceDefinitionLocator(parser)
+    parser.StartElementHandler = tracker.start_element
+    parser.EndElementHandler = tracker.end_element
+    parser.Parse(input)
+
+    # Treat the input as UTF-8 or else column numbers will be wrong.
+    input_lines = input.decode('utf-8').splitlines(True)
+
+    # Extract the duplicate resource definitions, ignoring the last definition
+    # which will take precedence and be left intact.
+    duplicates = []
+    for res_name, entries in tracker.resource_definitions.iteritems():
+        if len(entries) > 1:
+            duplicates += entries[:-1]
+
+    # Sort the duplicates so that they are in order. That way we only do one pass.
+    duplicates = sorted(duplicates, key=lambda x: x.start)
+
+    last_line_no = 0
+    last_col_no = 0
+    output_lines = []
+    current_line = ""
+    for definition in duplicates:
+        print "{0}:{1}:{2}: removing duplicate resource '{3}'".format(
+                xml_path, definition.start[0] + 1, definition.start[1], definition.name)
+
+        if last_line_no < definition.start[0]:
+            # The next definition is on a new line, so write what we have
+            # to the output.
+            new_line = current_line + input_lines[last_line_no][last_col_no:]
+            if not new_line.isspace():
+                output_lines.append(new_line)
+            current_line = ""
+            last_col_no = 0
+            last_line_no += 1
+
+        # Copy all the lines up until this one.
+        for line_to_copy in xrange(last_line_no, definition.start[0]):
+            output_lines.append(input_lines[line_to_copy])
+
+        # Add to the existing line we're building, by including the prefix of this line
+        # and skipping the lines and characters until the end of this duplicate definition.
+        last_line_no = definition.start[0]
+        current_line += input_lines[last_line_no][last_col_no:definition.start[1]]
+        last_line_no = definition.end[0]
+        last_col_no = definition.end[1]
+
+    new_line = current_line + input_lines[last_line_no][last_col_no:]
+    if not new_line.isspace():
+        output_lines.append(new_line)
+    current_line = ""
+    last_line_no += 1
+    last_col_no = 0
+
+    for line_to_copy in xrange(last_line_no, len(input_lines)):
+        output_lines.append(input_lines[line_to_copy])
+
+    if len(duplicates) > 0:
+        print "{0}: writing deduped copy...".format(xml_path)
+
+        # Write the lines to a temporary file.
+        dirname, basename = os.path.split(xml_path)
+        temp_name = ""
+        with tempfile.NamedTemporaryFile(prefix=basename, dir=dirname, delete=False) as temp:
+            temp_name = temp.name
+            for line in output_lines:
+                temp.write(line.encode('utf-8'))
+
+        # Now rename that file to the original so we have an atomic write that is consistent.
+        os.rename(temp.name, xml_path)
+
+def enumerate_files(res_path):
+    """Enumerates all files in the resource directory that are XML files and
+       within a values-* subdirectory. These types of files end up compiled
+       in the resources.arsc table of an APK.
+    """
+    values_directories = os.listdir(res_path)
+    values_directories = filter(lambda f: f.startswith('values'), values_directories)
+    values_directories = map(lambda f: os.path.join(res_path, f), values_directories)
+    all_files = []
+    for dir in values_directories:
+        files = os.listdir(dir)
+        files = filter(lambda f: f.endswith('.xml'), files)
+        files = map(lambda f: os.path.join(dir, f), files)
+        all_files += files
+    return all_files
+
+if __name__ == '__main__':
+    if len(sys.argv) < 2:
+        print >> sys.stderr, "please specify a path to a resource directory"
+        sys.exit(1)
+
+    res_path = os.path.abspath(sys.argv[1])
+    print "looking in {0} ...".format(res_path)
+
+    for f in enumerate_files(res_path):
+        print "checking {0} ...".format(f)
+        remove_duplicates(f)
+
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 3bf88b7..a64bfe5 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -806,7 +806,7 @@
          * Quality network selection status String (for debug purpose). Use Quality network
          * selection status value as index to extec the corresponding debug string
          */
-        private static final String[] QUALITY_NETWORK_SELECTION_STATUS = {
+        public static final String[] QUALITY_NETWORK_SELECTION_STATUS = {
                 "NETWORK_SELECTION_ENABLED",
                 "NETWORK_SELECTION_TEMPORARY_DISABLED",
                 "NETWORK_SELECTION_PERMANENTLY_DISABLED"};
@@ -868,7 +868,7 @@
         /**
          * Quality network selection disable reason String (for debug purpose)
          */
-        private static final String[] QUALITY_NETWORK_SELECTION_DISABLE_REASON = {
+        public static final String[] QUALITY_NETWORK_SELECTION_DISABLE_REASON = {
                 "NETWORK_SELECTION_ENABLE",
                 "NETWORK_SELECTION_DISABLED_BAD_LINK",
                 "NETWORK_SELECTION_DISABLED_ASSOCIATION_REJECTION ",