Merge "Add misc apct perf tests"
diff --git a/Android.mk b/Android.mk
index c5b3b6b..b644a17 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1194,20 +1194,45 @@
 
 LOCAL_DROIDDOC_OPTIONS:= \
 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
-		-devsite \
-		-hdf devsite true \
 		-toroot / \
 		-hdf android.whichdoc online \
+		-devsite \
 		$(sample_groups) \
-		-useUpdatedTemplates \
 		-hdf android.hasSamples true \
-		-yaml _book.yaml \
 		-samplesdir $(samples_dir)
 
 LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
 
 include $(BUILD_DROIDDOC)
 
+# ==== docs for the web (on the devsite app engine server) =======================
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
+LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
+LOCAL_STATIC_JAVA_LIBRARIES:=$(framework_docs_LOCAL_STATIC_JAVA_LIBRARIES)
+LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
+LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
+LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
+LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR)
+LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR)
+LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
+# specify a second html input dir and an output path relative to OUT_DIR)
+LOCAL_ADDITIONAL_HTML_DIR:=docs/html-intl /
+
+LOCAL_MODULE := ds-static
+
+LOCAL_DROIDDOC_OPTIONS:= \
+		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+		-hdf android.whichdoc online \
+		-staticonly \
+		-toroot / \
+		-devsite \
+		-ignoreJdLinks
+
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
+
+include $(BUILD_DROIDDOC)
+
 # ==== site updates for docs (on the androiddevdocs app engine server) =======================
 include $(CLEAR_VARS)
 
diff --git a/apct-tests/perftests/multiuser/Android.mk b/apct-tests/perftests/multiuser/Android.mk
new file mode 100644
index 0000000..f670043
--- /dev/null
+++ b/apct-tests/perftests/multiuser/Android.mk
@@ -0,0 +1,31 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-test \
+    apct-perftests-utils
+
+LOCAL_PACKAGE_NAME := MultiUserPerfTests
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
diff --git a/apct-tests/perftests/multiuser/AndroidManifest.xml b/apct-tests/perftests/multiuser/AndroidManifest.xml
new file mode 100644
index 0000000..ace7106
--- /dev/null
+++ b/apct-tests/perftests/multiuser/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.multiuser.frameworks.perftests">
+
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+            android:targetPackage="com.android.multiuser.frameworks.perftests"/>
+
+</manifest>
\ No newline at end of file
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java
new file mode 100644
index 0000000..bd0139f
--- /dev/null
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ */
+package android.multiuser;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.app.SynchronousUserSwitchObserver;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class UserLifecycleTest {
+    private final int MIN_REPEAT_TIMES = 4;
+
+    private final int TIMEOUT_REMOVE_USER_SEC = 4;
+    private final int CHECK_USER_REMOVED_INTERVAL_MS = 200; // 0.2 sec
+
+    private final int TIMEOUT_USER_START_SEC = 4; // 4 sec
+
+    private final int TIMEOUT_USER_SWITCH_SEC = 8; // 8 sec
+
+    private UserManager mUm;
+    private ActivityManager mAm;
+    private IActivityManager mIam;
+    private BenchmarkState mState;
+    private ArrayList<Integer> mUsersToRemove;
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Before
+    public void setUp() {
+        final Context context = InstrumentationRegistry.getContext();
+        mUm = UserManager.get(context);
+        mAm = context.getSystemService(ActivityManager.class);
+        mIam = ActivityManagerNative.getDefault();
+        mState = mPerfStatusReporter.getBenchmarkState();
+        mState.setMinRepeatTimes(MIN_REPEAT_TIMES);
+        mUsersToRemove = new ArrayList<>();
+    }
+
+    @After
+    public void tearDown() {
+        for (int userId : mUsersToRemove) {
+            mUm.removeUser(userId);
+        }
+    }
+
+    @Test
+    public void createAndStartUserPerf() throws Exception {
+        while (mState.keepRunning()) {
+            final UserInfo userInfo = mUm.createUser("TestUser", 0);
+
+            final CountDownLatch latch = new CountDownLatch(1);
+            InstrumentationRegistry.getContext().registerReceiverAsUser(new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    if (Intent.ACTION_USER_STARTED.equals(intent.getAction())) {
+                        latch.countDown();
+                    }
+                }
+            }, UserHandle.ALL, new IntentFilter(Intent.ACTION_USER_STARTED), null, null);
+            mIam.startUserInBackground(userInfo.id);
+            latch.await(TIMEOUT_USER_START_SEC, TimeUnit.SECONDS);
+
+            mState.pauseTiming();
+            removeUser(userInfo.id);
+            mState.resumeTiming();
+        }
+    }
+
+    @Test
+    public void switchUserPerf() throws Exception {
+        while (mState.keepRunning()) {
+            mState.pauseTiming();
+            final int startUser = mAm.getCurrentUser();
+            final UserInfo userInfo = mUm.createUser("TestUser", 0);
+            mState.resumeTiming();
+
+            switchUser(userInfo.id);
+
+            mState.pauseTiming();
+            switchUser(startUser);
+            removeUser(userInfo.id);
+            mState.resumeTiming();
+        }
+    }
+
+    private void switchUser(int userId) throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        registerUserSwitchObserver(latch);
+        mAm.switchUser(userId);
+        latch.await(TIMEOUT_USER_SWITCH_SEC, TimeUnit.SECONDS);
+    }
+
+    private void registerUserSwitchObserver(final CountDownLatch latch) throws Exception {
+        ActivityManagerNative.getDefault().registerUserSwitchObserver(
+                new SynchronousUserSwitchObserver() {
+                    @Override
+                    public void onUserSwitching(int newUserId) throws RemoteException {
+                    }
+
+                    @Override
+                    public void onUserSwitchComplete(int newUserId) throws RemoteException {
+                        latch.countDown();
+                    }
+
+                    @Override
+                    public void onForegroundProfileSwitch(int newProfileId) throws RemoteException {
+                    }
+                }, "UserLifecycleTest");
+    }
+
+    private void removeUser(int userId) throws Exception {
+        mUm.removeUser(userId);
+        final long startTime = System.currentTimeMillis();
+        while (mUm.getUserInfo(userId) != null &&
+                System.currentTimeMillis() - startTime < TIMEOUT_REMOVE_USER_SEC) {
+            Thread.sleep(CHECK_USER_REMOVED_INTERVAL_MS);
+        }
+        if (mUm.getUserInfo(userId) != null) {
+            mUsersToRemove.add(userId);
+        }
+    }
+}
\ No newline at end of file
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
index 4213e4a..b27d71b 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
@@ -48,7 +48,6 @@
     private static final int RUNNING = 2;  // The benchmark is running.
     private static final int RUNNING_PAUSED = 3;  // The benchmark is temporary paused.
     private static final int FINISHED = 4;  // The benchmark has stopped.
-    private static final int MIN_REPEAT_TIMES = 16;
 
     private int mState = NOT_STARTED;  // Current benchmark state.
 
@@ -64,10 +63,20 @@
     private double mMean = 0.0;
     private double mStandardDeviation = 0.0;
 
+    // Number of iterations needed for calculating the stats.
+    private int mMinRepeatTimes = 16;
+
     // Individual duration in nano seconds.
     private ArrayList<Long> mResults = new ArrayList<>();
 
     /**
+     * Sets the number of iterations needed for calculating the stats. Default is 16.
+     */
+    public void setMinRepeatTimes(int minRepeatTimes) {
+        mMinRepeatTimes = minRepeatTimes;
+    }
+
+    /**
      * Calculates statistics.
      */
     private void calculateSatistics() {
@@ -133,7 +142,7 @@
                 mNanoPausedDuration = 0;
 
                 // To calculate statistics, needs two or more samples.
-                if (mResults.size() > MIN_REPEAT_TIMES && currentTime > mNanoFinishTime) {
+                if (mResults.size() > mMinRepeatTimes && currentTime > mNanoFinishTime) {
                     calculateSatistics();
                     mState = FINISHED;
                     return false;
@@ -181,7 +190,7 @@
         sb.append("sigma=").append(standardDeviation()).append(", ");
         sb.append("iteration=").append(mResults.size()).append(", ");
         // print out the first few iterations' number for double checking.
-        int sampleNumber = Math.min(mResults.size(), MIN_REPEAT_TIMES);
+        int sampleNumber = Math.min(mResults.size(), mMinRepeatTimes);
         for (int i = 0; i < sampleNumber; i++) {
             sb.append("No ").append(i).append(" result is ").append(mResults.get(i)).append(", ");
         }
diff --git a/api/current.txt b/api/current.txt
index d496bb8..3e015ab 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -43176,6 +43176,7 @@
     method public int getScaledOverscrollDistance();
     method public int getScaledPagingTouchSlop();
     method public int getScaledScrollBarSize();
+    method public int getScaledScrollFactor();
     method public int getScaledTouchSlop();
     method public int getScaledWindowTouchSlop();
     method public static int getScrollBarFadeDuration();
@@ -43999,6 +44000,7 @@
     field public static final int TYPE_APPLICATION_SUB_PANEL = 1002; // 0x3ea
     field public static final int TYPE_BASE_APPLICATION = 1; // 0x1
     field public static final int TYPE_CHANGED = 2; // 0x2
+    field public static final int TYPE_DRAWN_APPLICATION = 4; // 0x4
     field public static final int TYPE_INPUT_METHOD = 2011; // 0x7db
     field public static final int TYPE_INPUT_METHOD_DIALOG = 2012; // 0x7dc
     field public static final int TYPE_KEYGUARD_DIALOG = 2009; // 0x7d9
@@ -56417,6 +56419,7 @@
     ctor public MGF1ParameterSpec(java.lang.String);
     method public java.lang.String getDigestAlgorithm();
     field public static final java.security.spec.MGF1ParameterSpec SHA1;
+    field public static final java.security.spec.MGF1ParameterSpec SHA224;
     field public static final java.security.spec.MGF1ParameterSpec SHA256;
     field public static final java.security.spec.MGF1ParameterSpec SHA384;
     field public static final java.security.spec.MGF1ParameterSpec SHA512;
@@ -59027,9 +59030,17 @@
     ctor public HashMap();
     ctor public HashMap(java.util.Map<? extends K, ? extends V>);
     method public java.lang.Object clone();
+    method public V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+    method public V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
+    method public V computeIfPresent(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
     method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+    method public V getOrDefault(java.lang.Object, V);
+    method public V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
+    method public V putIfAbsent(K, V);
+    method public boolean remove(java.lang.Object, java.lang.Object);
     method public boolean replace(K, V, V);
+    method public V replace(K, V);
     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
   }
 
@@ -63475,7 +63486,7 @@
     field protected byte[] encodedParams;
   }
 
-  public abstract interface SecretKey implements java.security.Key {
+  public abstract interface SecretKey implements javax.security.auth.Destroyable java.security.Key {
     field public static final long serialVersionUID = -4795878709595146952L; // 0xbd719db928b8f538L
   }
 
@@ -63486,7 +63497,7 @@
     method public static final javax.crypto.SecretKeyFactory getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
     method public static final javax.crypto.SecretKeyFactory getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
     method public static final javax.crypto.SecretKeyFactory getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
-    method public final java.security.spec.KeySpec getKeySpec(javax.crypto.SecretKey, java.lang.Class) throws java.security.spec.InvalidKeySpecException;
+    method public final java.security.spec.KeySpec getKeySpec(javax.crypto.SecretKey, java.lang.Class<?>) throws java.security.spec.InvalidKeySpecException;
     method public final java.security.Provider getProvider();
     method public final javax.crypto.SecretKey translateKey(javax.crypto.SecretKey) throws java.security.InvalidKeyException;
   }
@@ -63494,7 +63505,7 @@
   public abstract class SecretKeyFactorySpi {
     ctor public SecretKeyFactorySpi();
     method protected abstract javax.crypto.SecretKey engineGenerateSecret(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
-    method protected abstract java.security.spec.KeySpec engineGetKeySpec(javax.crypto.SecretKey, java.lang.Class) throws java.security.spec.InvalidKeySpecException;
+    method protected abstract java.security.spec.KeySpec engineGetKeySpec(javax.crypto.SecretKey, java.lang.Class<?>) throws java.security.spec.InvalidKeySpecException;
     method protected abstract javax.crypto.SecretKey engineTranslateKey(javax.crypto.SecretKey) throws java.security.InvalidKeyException;
   }
 
@@ -63612,7 +63623,9 @@
 
   public class PBEParameterSpec implements java.security.spec.AlgorithmParameterSpec {
     ctor public PBEParameterSpec(byte[], int);
+    ctor public PBEParameterSpec(byte[], int, java.security.spec.AlgorithmParameterSpec);
     method public int getIterationCount();
+    method public java.security.spec.AlgorithmParameterSpec getParameterSpec();
     method public byte[] getSalt();
   }
 
diff --git a/api/removed.txt b/api/removed.txt
index 94ba452..239eab6 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -179,6 +179,10 @@
     ctor public BatteryManager();
   }
 
+  public class Build {
+    field public static final boolean PERMISSIONS_REVIEW_REQUIRED;
+  }
+
   public final class PowerManager {
     method public void goToSleep(long);
     method public deprecated void userActivity(long, boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index 6db91c6..3e47ac7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -46346,6 +46346,7 @@
     method public int getScaledOverscrollDistance();
     method public int getScaledPagingTouchSlop();
     method public int getScaledScrollBarSize();
+    method public int getScaledScrollFactor();
     method public int getScaledTouchSlop();
     method public int getScaledWindowTouchSlop();
     method public static int getScrollBarFadeDuration();
@@ -47172,6 +47173,7 @@
     field public static final int TYPE_APPLICATION_SUB_PANEL = 1002; // 0x3ea
     field public static final int TYPE_BASE_APPLICATION = 1; // 0x1
     field public static final int TYPE_CHANGED = 2; // 0x2
+    field public static final int TYPE_DRAWN_APPLICATION = 4; // 0x4
     field public static final int TYPE_INPUT_METHOD = 2011; // 0x7db
     field public static final int TYPE_INPUT_METHOD_DIALOG = 2012; // 0x7dc
     field public static final int TYPE_KEYGUARD_DIALOG = 2009; // 0x7d9
@@ -59944,6 +59946,7 @@
     ctor public MGF1ParameterSpec(java.lang.String);
     method public java.lang.String getDigestAlgorithm();
     field public static final java.security.spec.MGF1ParameterSpec SHA1;
+    field public static final java.security.spec.MGF1ParameterSpec SHA224;
     field public static final java.security.spec.MGF1ParameterSpec SHA256;
     field public static final java.security.spec.MGF1ParameterSpec SHA384;
     field public static final java.security.spec.MGF1ParameterSpec SHA512;
@@ -62554,9 +62557,17 @@
     ctor public HashMap();
     ctor public HashMap(java.util.Map<? extends K, ? extends V>);
     method public java.lang.Object clone();
+    method public V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+    method public V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
+    method public V computeIfPresent(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
     method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+    method public V getOrDefault(java.lang.Object, V);
+    method public V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
+    method public V putIfAbsent(K, V);
+    method public boolean remove(java.lang.Object, java.lang.Object);
     method public boolean replace(K, V, V);
+    method public V replace(K, V);
     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
   }
 
@@ -67002,7 +67013,7 @@
     field protected byte[] encodedParams;
   }
 
-  public abstract interface SecretKey implements java.security.Key {
+  public abstract interface SecretKey implements javax.security.auth.Destroyable java.security.Key {
     field public static final long serialVersionUID = -4795878709595146952L; // 0xbd719db928b8f538L
   }
 
@@ -67013,7 +67024,7 @@
     method public static final javax.crypto.SecretKeyFactory getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
     method public static final javax.crypto.SecretKeyFactory getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
     method public static final javax.crypto.SecretKeyFactory getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
-    method public final java.security.spec.KeySpec getKeySpec(javax.crypto.SecretKey, java.lang.Class) throws java.security.spec.InvalidKeySpecException;
+    method public final java.security.spec.KeySpec getKeySpec(javax.crypto.SecretKey, java.lang.Class<?>) throws java.security.spec.InvalidKeySpecException;
     method public final java.security.Provider getProvider();
     method public final javax.crypto.SecretKey translateKey(javax.crypto.SecretKey) throws java.security.InvalidKeyException;
   }
@@ -67021,7 +67032,7 @@
   public abstract class SecretKeyFactorySpi {
     ctor public SecretKeyFactorySpi();
     method protected abstract javax.crypto.SecretKey engineGenerateSecret(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
-    method protected abstract java.security.spec.KeySpec engineGetKeySpec(javax.crypto.SecretKey, java.lang.Class) throws java.security.spec.InvalidKeySpecException;
+    method protected abstract java.security.spec.KeySpec engineGetKeySpec(javax.crypto.SecretKey, java.lang.Class<?>) throws java.security.spec.InvalidKeySpecException;
     method protected abstract javax.crypto.SecretKey engineTranslateKey(javax.crypto.SecretKey) throws java.security.InvalidKeyException;
   }
 
@@ -67139,7 +67150,9 @@
 
   public class PBEParameterSpec implements java.security.spec.AlgorithmParameterSpec {
     ctor public PBEParameterSpec(byte[], int);
+    ctor public PBEParameterSpec(byte[], int, java.security.spec.AlgorithmParameterSpec);
     method public int getIterationCount();
+    method public java.security.spec.AlgorithmParameterSpec getParameterSpec();
     method public byte[] getSalt();
   }
 
diff --git a/api/test-current.txt b/api/test-current.txt
index 5293a04..eca6fb9 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -43257,6 +43257,7 @@
     method public int getScaledOverscrollDistance();
     method public int getScaledPagingTouchSlop();
     method public int getScaledScrollBarSize();
+    method public int getScaledScrollFactor();
     method public int getScaledTouchSlop();
     method public int getScaledWindowTouchSlop();
     method public static int getScrollBarFadeDuration();
@@ -44080,6 +44081,7 @@
     field public static final int TYPE_APPLICATION_SUB_PANEL = 1002; // 0x3ea
     field public static final int TYPE_BASE_APPLICATION = 1; // 0x1
     field public static final int TYPE_CHANGED = 2; // 0x2
+    field public static final int TYPE_DRAWN_APPLICATION = 4; // 0x4
     field public static final int TYPE_INPUT_METHOD = 2011; // 0x7db
     field public static final int TYPE_INPUT_METHOD_DIALOG = 2012; // 0x7dc
     field public static final int TYPE_KEYGUARD_DIALOG = 2009; // 0x7d9
@@ -56506,6 +56508,7 @@
     ctor public MGF1ParameterSpec(java.lang.String);
     method public java.lang.String getDigestAlgorithm();
     field public static final java.security.spec.MGF1ParameterSpec SHA1;
+    field public static final java.security.spec.MGF1ParameterSpec SHA224;
     field public static final java.security.spec.MGF1ParameterSpec SHA256;
     field public static final java.security.spec.MGF1ParameterSpec SHA384;
     field public static final java.security.spec.MGF1ParameterSpec SHA512;
@@ -59116,9 +59119,17 @@
     ctor public HashMap();
     ctor public HashMap(java.util.Map<? extends K, ? extends V>);
     method public java.lang.Object clone();
+    method public V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
+    method public V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
+    method public V computeIfPresent(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
     method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+    method public V getOrDefault(java.lang.Object, V);
+    method public V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
+    method public V putIfAbsent(K, V);
+    method public boolean remove(java.lang.Object, java.lang.Object);
     method public boolean replace(K, V, V);
+    method public V replace(K, V);
     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
   }
 
@@ -63564,7 +63575,7 @@
     field protected byte[] encodedParams;
   }
 
-  public abstract interface SecretKey implements java.security.Key {
+  public abstract interface SecretKey implements javax.security.auth.Destroyable java.security.Key {
     field public static final long serialVersionUID = -4795878709595146952L; // 0xbd719db928b8f538L
   }
 
@@ -63575,7 +63586,7 @@
     method public static final javax.crypto.SecretKeyFactory getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
     method public static final javax.crypto.SecretKeyFactory getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
     method public static final javax.crypto.SecretKeyFactory getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
-    method public final java.security.spec.KeySpec getKeySpec(javax.crypto.SecretKey, java.lang.Class) throws java.security.spec.InvalidKeySpecException;
+    method public final java.security.spec.KeySpec getKeySpec(javax.crypto.SecretKey, java.lang.Class<?>) throws java.security.spec.InvalidKeySpecException;
     method public final java.security.Provider getProvider();
     method public final javax.crypto.SecretKey translateKey(javax.crypto.SecretKey) throws java.security.InvalidKeyException;
   }
@@ -63583,7 +63594,7 @@
   public abstract class SecretKeyFactorySpi {
     ctor public SecretKeyFactorySpi();
     method protected abstract javax.crypto.SecretKey engineGenerateSecret(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
-    method protected abstract java.security.spec.KeySpec engineGetKeySpec(javax.crypto.SecretKey, java.lang.Class) throws java.security.spec.InvalidKeySpecException;
+    method protected abstract java.security.spec.KeySpec engineGetKeySpec(javax.crypto.SecretKey, java.lang.Class<?>) throws java.security.spec.InvalidKeySpecException;
     method protected abstract javax.crypto.SecretKey engineTranslateKey(javax.crypto.SecretKey) throws java.security.InvalidKeyException;
   }
 
@@ -63701,7 +63712,9 @@
 
   public class PBEParameterSpec implements java.security.spec.AlgorithmParameterSpec {
     ctor public PBEParameterSpec(byte[], int);
+    ctor public PBEParameterSpec(byte[], int, java.security.spec.AlgorithmParameterSpec);
     method public int getIterationCount();
+    method public java.security.spec.AlgorithmParameterSpec getParameterSpec();
     method public byte[] getSalt();
   }
 
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 94ba452..239eab6 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -179,6 +179,10 @@
     ctor public BatteryManager();
   }
 
+  public class Build {
+    field public static final boolean PERMISSIONS_REVIEW_REQUIRED;
+  }
+
   public final class PowerManager {
     method public void goToSleep(long);
     method public deprecated void userActivity(long, boolean);
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 72a21e3..80af5ea 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -17,7 +17,6 @@
 #include <binder/ProcessState.h>
 #include <utils/Log.h>
 #include <cutils/memory.h>
-#include <cutils/process_name.h>
 #include <cutils/properties.h>
 #include <cutils/trace.h>
 #include <android_runtime/AndroidRuntime.h>
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 59d2f18..26e7dac 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.GET_ACCOUNTS;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.Size;
@@ -28,6 +29,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.IntentSender;
 import android.content.res.Resources;
 import android.database.SQLException;
 import android.os.Build;
@@ -261,6 +263,15 @@
             "android.accounts.AccountAuthenticator";
     public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
 
+    /**
+     * Token for the special case where a UID has access only to an account
+     * but no authenticator specific auth tokens.
+     *
+     * @hide
+     */
+    public static final String ACCOUNT_ACCESS_TOKEN =
+            "com.android.abbfd278-af8b-415d-af8b-7571d5dab133";
+
     private final Context mContext;
     private final IAccountManager mService;
     private final Handler mMainHandler;
@@ -2785,8 +2796,6 @@
      *         <ul>
      *         <li>{@link #KEY_ACCOUNT_SESSION_BUNDLE} - encrypted Bundle for
      *         adding the the to the device later.
-     *         <li>{@link #KEY_PASSWORD} - optional, the password or password
-     *         hash of the account.
      *         <li>{@link #KEY_ACCOUNT_STATUS_TOKEN} - optional, token to check
      *         status of the account
      *         </ul>
@@ -2872,8 +2881,6 @@
      *         <ul>
      *         <li>{@link #KEY_ACCOUNT_SESSION_BUNDLE} - encrypted Bundle for
      *         updating the local credentials on device later.
-     *         <li>{@link #KEY_PASSWORD} - optional, the password or password
-     *         hash of the account
      *         <li>{@link #KEY_ACCOUNT_STATUS_TOKEN} - optional, token to check
      *         status of the account
      *         </ul>
@@ -3063,4 +3070,49 @@
             }
         }.start();
     }
+
+    /**
+     * Gets whether a given package under a user has access to an account.
+     * Can be called only from the system UID.
+     *
+     * @param account The account for which to check.
+     * @param packageName The package for which to check.
+     * @param userHandle The user for which to check.
+     * @return True if the package can access the account.
+     *
+     * @hide
+     */
+    public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
+            @NonNull UserHandle userHandle) {
+        try {
+            return mService.hasAccountAccess(account, packageName, userHandle);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Creates an intent to request access to a given account for a UID.
+     * The returned intent should be stated for a result where {@link
+     * Activity#RESULT_OK} result means access was granted whereas {@link
+     * Activity#RESULT_CANCELED} result means access wasn't granted. Can
+     * be called only from the system UID.
+     *
+     * @param account The account for which to request.
+     * @param packageName The package name which to request.
+     * @param userHandle The user for which to request.
+     * @return The intent to request account access or null if the package
+     *     doesn't exist.
+     *
+     * @hide
+     */
+    public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
+            @NonNull String packageName, @NonNull UserHandle userHandle) {
+        try {
+            return mService.createRequestAccountAccessIntentSenderAsUser(account, packageName,
+                    userHandle);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/accounts/AccountManagerInternal.java b/core/java/android/accounts/AccountManagerInternal.java
new file mode 100644
index 0000000..d777643
--- /dev/null
+++ b/core/java/android/accounts/AccountManagerInternal.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+package android.accounts;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.os.RemoteCallback;
+
+/**
+ * Account manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class AccountManagerInternal {
+
+    /**
+     * Requests that a given package is given access to an account.
+     * The provided callback will be invoked with a {@link android.os.Bundle}
+     * containing the result which will be a boolean value mapped to the
+     * {@link AccountManager#KEY_BOOLEAN_RESULT} key.
+     *
+     * @param account The account for which to request.
+     * @param packageName The package name for which to request.
+     * @param userId Concrete user id for which to request.
+     * @param callback A callback for receiving the result.
+     */
+    public abstract void requestAccountAccess(@NonNull  Account account,
+            @NonNull String packageName, @IntRange(from = 0) int userId,
+            @NonNull RemoteCallback callback);
+}
diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
index 12b2b9c..8d0ce58 100644
--- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java
+++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
@@ -35,12 +35,10 @@
  */
 public class GrantCredentialsPermissionActivity extends Activity implements View.OnClickListener {
     public static final String EXTRAS_ACCOUNT = "account";
-    public static final String EXTRAS_AUTH_TOKEN_LABEL = "authTokenLabel";
     public static final String EXTRAS_AUTH_TOKEN_TYPE = "authTokenType";
     public static final String EXTRAS_RESPONSE = "response";
-    public static final String EXTRAS_ACCOUNT_TYPE_LABEL = "accountTypeLabel";
-    public static final String EXTRAS_PACKAGES = "application";
     public static final String EXTRAS_REQUESTING_UID = "uid";
+
     private Account mAccount;
     private String mAuthTokenType;
     private int mUid;
@@ -109,7 +107,11 @@
                 }
             }
         };
-        AccountManager.get(this).getAuthTokenLabel(mAccount.type, mAuthTokenType, callback, null);
+
+        if (!AccountManager.ACCOUNT_ACCESS_TOKEN.equals(mAuthTokenType)) {
+            AccountManager.get(this).getAuthTokenLabel(mAccount.type,
+                    mAuthTokenType, callback, null);
+        }
 
         findViewById(R.id.allow_button).setOnClickListener(this);
         findViewById(R.id.deny_button).setOnClickListener(this);
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index c52faeb..e5183b2 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -19,7 +19,10 @@
 import android.accounts.IAccountManagerResponse;
 import android.accounts.Account;
 import android.accounts.AuthenticatorDescription;
+import android.content.IntentSender;
 import android.os.Bundle;
+import android.os.RemoteCallback;
+import android.os.UserHandle;
 
 /**
  * Central application service that provides account management.
@@ -115,4 +118,10 @@
     boolean removeAccountVisibility(in Account a, in int uid);
     boolean makeAccountVisible(in Account a, in int uid);
     boolean isAccountVisible(in Account a, in int uid);
+
+    /* Check if the package in a user can access an account */
+    boolean hasAccountAccess(in Account account, String packageName, in UserHandle userHandle);
+    /* Crate an intent to request account access for package and a given user id */
+    IntentSender createRequestAccountAccessIntentSenderAsUser(in Account account,
+        String packageName, in UserHandle userHandle);
 }
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 30e72e5..a904f9d 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -635,12 +635,12 @@
         boolean setIsEmpty = false;
         if (mStartDelay > 0) {
             start(mRootNode);
-        } else if (mNodes.size() > 1) {
+        } else if (isEmptySet(this)) {
+            // Set is empty or contains only empty animator sets. Skip to end in this case.
+            setIsEmpty = true;
+        } else {
             // No delay, but there are other animators in the set
             onChildAnimatorEnded(mDelayAnim);
-        } else {
-            // Set is empty, no delay, no other animation. Skip to end in this case
-            setIsEmpty = true;
         }
 
         if (mListeners != null) {
@@ -657,6 +657,25 @@
         }
     }
 
+    // Returns true if set is empty or contains nothing but animator sets with no start delay.
+    private static boolean isEmptySet(AnimatorSet set) {
+        if (set.getStartDelay() > 0) {
+            return false;
+        }
+        for (int i = 0; i < set.getChildAnimations().size(); i++) {
+            Animator anim = set.getChildAnimations().get(i);
+            if (!(anim instanceof AnimatorSet)) {
+                // Contains non-AnimatorSet, not empty.
+                return false;
+            } else {
+                if (!isEmptySet((AnimatorSet) anim)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
     private void updateAnimatorsDuration() {
         if (mDuration >= 0) {
             // If the duration was set on this AnimatorSet, pass it along to all child animations
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index 2219238..aef1d0c 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -337,11 +337,12 @@
     }
 
     public void startExitOutTransition(Activity activity, Bundle options) {
-        if (!activity.getWindow().hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)) {
+        mEnterTransitionCoordinator = null;
+        if (!activity.getWindow().hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) ||
+                mExitTransitionCoordinators == null) {
             return;
         }
         ActivityOptions activityOptions = new ActivityOptions(options);
-        mEnterTransitionCoordinator = null;
         if (activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
             int key = activityOptions.getExitCoordinatorKey();
             int index = mExitTransitionCoordinators.indexOfKey(key);
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index f4f8d69..a4b1a1f 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -669,10 +669,9 @@
         bumpBackStackNesting(1);
 
         if (mManager.mCurState >= Fragment.CREATED) {
-            SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
-            SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
-            calculateFragments(firstOutFragments, lastInFragments);
-            beginTransition(firstOutFragments, lastInFragments, false);
+            SparseArray<FragmentContainerTransition> transitioningFragments = new SparseArray<>();
+            calculateFragments(transitioningFragments);
+            beginTransition(transitioningFragments);
         }
 
         final int numOps = mOps.size();
@@ -783,32 +782,44 @@
         }
     }
 
-    private static void setFirstOut(SparseArray<Fragment> firstOutFragments,
-                            SparseArray<Fragment> lastInFragments, Fragment fragment) {
+    private static void setFirstOut(SparseArray<FragmentContainerTransition> transitioningFragments,
+                            Fragment fragment, boolean isPop) {
         if (fragment != null) {
             int containerId = fragment.mContainerId;
             if (containerId != 0 && !fragment.isHidden()) {
-                if (fragment.isAdded() && fragment.getView() != null
-                        && firstOutFragments.get(containerId) == null) {
-                    firstOutFragments.put(containerId, fragment);
+                FragmentContainerTransition fragments = transitioningFragments.get(containerId);
+                if (fragment.isAdded() && fragment.getView() != null && (fragments == null ||
+                        fragments.firstOut == null)) {
+                    if (fragments == null) {
+                        fragments = new FragmentContainerTransition();
+                        transitioningFragments.put(containerId, fragments);
+                    }
+                    fragments.firstOut = fragment;
+                    fragments.firstOutIsPop = isPop;
                 }
-                if (lastInFragments.get(containerId) == fragment) {
-                    lastInFragments.remove(containerId);
+                if (fragments != null && fragments.lastIn == fragment) {
+                    fragments.lastIn = null;
                 }
             }
         }
     }
 
-    private void setLastIn(SparseArray<Fragment> firstOutFragments,
-            SparseArray<Fragment> lastInFragments, Fragment fragment) {
+    private void setLastIn(SparseArray<FragmentContainerTransition> transitioningFragments,
+            Fragment fragment, boolean isPop) {
         if (fragment != null) {
             int containerId = fragment.mContainerId;
             if (containerId != 0) {
+                FragmentContainerTransition fragments = transitioningFragments.get(containerId);
                 if (!fragment.isAdded()) {
-                    lastInFragments.put(containerId, fragment);
+                    if (fragments == null) {
+                        fragments = new FragmentContainerTransition();
+                        transitioningFragments.put(containerId, fragments);
+                    }
+                    fragments.lastIn = fragment;
+                    fragments.lastInIsPop = isPop;
                 }
-                if (firstOutFragments.get(containerId) == fragment) {
-                    firstOutFragments.remove(containerId);
+                if (fragments != null && fragments.firstOut == fragment) {
+                    fragments.firstOut = null;
                 }
             }
             /**
@@ -828,13 +839,12 @@
      * Finds the first removed fragment and last added fragments when going forward.
      * If none of the fragments have transitions, then both lists will be empty.
      *
-     * @param firstOutFragments The list of first fragments to be removed, keyed on the
-     *                          container ID. This list will be modified by the method.
-     * @param lastInFragments The list of last fragments to be added, keyed on the
-     *                        container ID. This list will be modified by the method.
+     * @param transitioningFragments Keyed on the container ID, the first fragments to be removed,
+     *                               and last fragments to be added. This will be modified by
+     *                               this method.
      */
-    private void calculateFragments(SparseArray<Fragment> firstOutFragments,
-            SparseArray<Fragment> lastInFragments) {
+    private void calculateFragments(
+            SparseArray<FragmentContainerTransition> transitioningFragments) {
         if (!mManager.mContainer.onHasView()) {
             return; // nothing to see, so no transitions
         }
@@ -843,22 +853,14 @@
             final Op op = mOps.get(opNum);
             switch (op.cmd) {
                 case OP_ADD:
-                    setLastIn(firstOutFragments, lastInFragments, op.fragment);
+                case OP_SHOW:
+                case OP_ATTACH:
+                    setLastIn(transitioningFragments, op.fragment, false);
                     break;
                 case OP_REMOVE:
-                    setFirstOut(firstOutFragments, lastInFragments, op.fragment);
-                    break;
                 case OP_HIDE:
-                    setFirstOut(firstOutFragments, lastInFragments, op.fragment);
-                    break;
-                case OP_SHOW:
-                    setLastIn(firstOutFragments, lastInFragments, op.fragment);
-                    break;
                 case OP_DETACH:
-                    setFirstOut(firstOutFragments, lastInFragments, op.fragment);
-                    break;
-                case OP_ATTACH:
-                    setLastIn(firstOutFragments, lastInFragments, op.fragment);
+                    setFirstOut(transitioningFragments, op.fragment, false);
                     break;
             }
         }
@@ -868,13 +870,12 @@
      * Finds the first removed fragment and last added fragments when popping the back stack.
      * If none of the fragments have transitions, then both lists will be empty.
      *
-     * @param firstOutFragments The list of first fragments to be removed, keyed on the
-     *                          container ID. This list will be modified by the method.
-     * @param lastInFragments The list of last fragments to be added, keyed on the
-     *                        container ID. This list will be modified by the method.
+     * @param transitioningFragments Keyed on the container ID, the first fragments to be removed,
+     *                               and last fragments to be added. This will be modified by
+     *                               this method.
      */
-    public void calculateBackFragments(SparseArray<Fragment> firstOutFragments,
-            SparseArray<Fragment> lastInFragments) {
+    public void calculateBackFragments(
+            SparseArray<FragmentContainerTransition> transitioningFragments) {
         if (!mManager.mContainer.onHasView()) {
             return; // nothing to see, so no transitions
         }
@@ -883,22 +884,14 @@
             final Op op = mOps.get(opNum);
             switch (op.cmd) {
                 case OP_ADD:
-                    setFirstOut(firstOutFragments, lastInFragments, op.fragment);
+                case OP_SHOW:
+                case OP_ATTACH:
+                    setFirstOut(transitioningFragments, op.fragment, true);
                     break;
                 case OP_REMOVE:
-                    setLastIn(firstOutFragments, lastInFragments, op.fragment);
-                    break;
                 case OP_HIDE:
-                    setLastIn(firstOutFragments, lastInFragments, op.fragment);
-                    break;
-                case OP_SHOW:
-                    setFirstOut(firstOutFragments, lastInFragments, op.fragment);
-                    break;
                 case OP_DETACH:
-                    setLastIn(firstOutFragments, lastInFragments, op.fragment);
-                    break;
-                case OP_ATTACH:
-                    setFirstOut(firstOutFragments, lastInFragments, op.fragment);
+                    setLastIn(transitioningFragments, op.fragment, true);
                     break;
             }
         }
@@ -925,18 +918,12 @@
      * outgoing fragment's return shared element transition is used. Shared element
      * transitions only operate if there is both an incoming and outgoing fragment.</p>
      *
-     * @param firstOutFragments The list of first fragments to be removed, keyed on the
-     *                          container ID.
-     * @param lastInFragments The list of last fragments to be added, keyed on the
-     *                        container ID.
-     * @param isBack true if this is popping the back stack or false if this is a
-     *               forward operation.
+     * @param containers The first in and last out fragments that are transitioning.
      * @return The TransitionState used to complete the operation of the transition
      * in {@link #setNameOverrides(android.app.BackStackRecord.TransitionState, java.util.ArrayList,
      * java.util.ArrayList)}.
      */
-    private TransitionState beginTransition(SparseArray<Fragment> firstOutFragments,
-            SparseArray<Fragment> lastInFragments, boolean isBack) {
+    private TransitionState beginTransition(SparseArray<FragmentContainerTransition> containers) {
         TransitionState state = new TransitionState();
 
         // Adding a non-existent target view makes sure that the transitions don't target
@@ -944,20 +931,11 @@
         // add any, then no views will be targeted.
         state.nonExistentView = new View(mManager.mHost.getContext());
 
-        // Go over all leaving fragments.
-        for (int i = 0; i < firstOutFragments.size(); i++) {
-            int containerId = firstOutFragments.keyAt(i);
-            configureTransitions(containerId, state, isBack, firstOutFragments,
-                    lastInFragments);
-        }
-
-        // Now go over all entering fragments that didn't have a leaving fragment.
-        for (int i = 0; i < lastInFragments.size(); i++) {
-            int containerId = lastInFragments.keyAt(i);
-            if (firstOutFragments.get(containerId) == null) {
-                configureTransitions(containerId, state, isBack, firstOutFragments,
-                        lastInFragments);
-            }
+        final int numContainers = containers.size();
+        for (int i = 0; i < numContainers; i++) {
+            int containerId = containers.keyAt(i);
+            FragmentContainerTransition containerTransition = containers.valueAt(i);
+            configureTransitions(containerId, state, containerTransition);
         }
         return state;
     }
@@ -1225,24 +1203,21 @@
      *
      * @param containerId The container ID of the fragments to configure the transition for.
      * @param state The Transition State keeping track of the executing transitions.
-     * @param firstOutFragments The list of first fragments to be removed, keyed on the
-     *                          container ID.
-     * @param lastInFragments The list of last fragments to be added, keyed on the
-     *                        container ID.
-     * @param isBack true if this is popping the back stack or false if this is a
-     *               forward operation.
+     * @param transitioningFragments The first out and last in fragments for the fragment container.
      */
-    private void configureTransitions(int containerId, TransitionState state, boolean isBack,
-            SparseArray<Fragment> firstOutFragments, SparseArray<Fragment> lastInFragments) {
+    private void configureTransitions(int containerId, TransitionState state,
+            FragmentContainerTransition transitioningFragments) {
         ViewGroup sceneRoot = (ViewGroup) mManager.mContainer.onFindViewById(containerId);
         if (sceneRoot != null) {
-            Fragment inFragment = lastInFragments.get(containerId);
-            Fragment outFragment = firstOutFragments.get(containerId);
+            final Fragment inFragment = transitioningFragments.lastIn;
+            final Fragment outFragment = transitioningFragments.firstOut;
 
-            Transition enterTransition = getEnterTransition(inFragment, isBack);
-            TransitionSet sharedElementTransition =
-                    getSharedElementTransition(inFragment, outFragment, isBack);
-            Transition exitTransition = getExitTransition(outFragment, isBack);
+            Transition enterTransition =
+                    getEnterTransition(inFragment, transitioningFragments.lastInIsPop);
+            TransitionSet sharedElementTransition = getSharedElementTransition(inFragment,
+                    outFragment, transitioningFragments.lastInIsPop);
+            Transition exitTransition =
+                    getExitTransition(outFragment, transitioningFragments.firstOutIsPop);
 
             if (enterTransition == null && sharedElementTransition == null &&
                     exitTransition == null) {
@@ -1254,12 +1229,13 @@
             ArrayMap<String, View> namedViews = null;
             ArrayList<View> sharedElementTargets = new ArrayList<View>();
             if (sharedElementTransition != null) {
-                namedViews = remapSharedElements(state, outFragment, isBack);
+                namedViews = remapSharedElements(state, outFragment,
+                        transitioningFragments.firstOutIsPop);
                 setSharedElementTargets(sharedElementTransition,
                         state.nonExistentView, namedViews, sharedElementTargets);
 
                 // Notify the start of the transition.
-                SharedElementCallback callback = isBack ?
+                SharedElementCallback callback = transitioningFragments.lastInIsPop ?
                         outFragment.mEnterTransitionCallback :
                         inFragment.mEnterTransitionCallback;
                 ArrayList<String> names = new ArrayList<String>(namedViews.keySet());
@@ -1290,13 +1266,14 @@
             }
 
             Transition transition = mergeTransitions(enterTransition, exitTransition,
-                    sharedElementTransition, inFragment, isBack);
+                    sharedElementTransition, inFragment, transitioningFragments.lastInIsPop);
 
             if (transition != null) {
                 ArrayList<View> hiddenFragments = new ArrayList<View>();
                 ArrayList<View> enteringViews = addTransitionTargets(state, enterTransition,
                         sharedElementTransition, exitTransition, transition, sceneRoot, inFragment,
-                        outFragment, hiddenFragments, isBack, sharedElementTargets);
+                        outFragment, hiddenFragments, transitioningFragments.lastInIsPop,
+                        sharedElementTargets);
 
                 transition.setNameOverrides(state.nameOverrides);
                 // We want to exclude hidden views later, so we need a non-null list in the
@@ -1589,7 +1566,7 @@
     }
 
     public TransitionState popFromBackStack(boolean doStateMove, TransitionState state,
-            SparseArray<Fragment> firstOutFragments, SparseArray<Fragment> lastInFragments) {
+            SparseArray<FragmentContainerTransition> transitioningFragments) {
         if (FragmentManagerImpl.DEBUG) {
             Log.v(TAG, "popFromBackStack: " + this);
             LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
@@ -1600,8 +1577,8 @@
 
         if (mManager.mCurState >= Fragment.CREATED) {
             if (state == null) {
-                if (firstOutFragments.size() != 0 || lastInFragments.size() != 0) {
-                    state = beginTransition(firstOutFragments, lastInFragments, true);
+                if (transitioningFragments.size() != 0) {
+                    state = beginTransition(transitioningFragments);
                 }
             } else if (!doStateMove) {
                 setNameOverrides(state, mSharedElementTargetNames, mSharedElementSourceNames);
@@ -1742,4 +1719,30 @@
         public View enteringEpicenterView;
         public View nonExistentView;
     }
+
+    /**
+     * Tracks the last fragment added and first fragment removed for fragment transitions.
+     * This also tracks which fragments are changed by push or pop transactions.
+     */
+    public static class FragmentContainerTransition {
+        /**
+         * The last fragment added/attached/shown in its container
+         */
+        public Fragment lastIn;
+
+        /**
+         * true when lastIn was added during a pop transaction or false if added with a push
+         */
+        public boolean lastInIsPop;
+
+        /**
+         * The first fragment with a View that was removed/detached/hidden in its container.
+         */
+        public Fragment firstOut;
+
+        /**
+         * true when firstOut was removed during a pop transaction or false otherwise
+         */
+        public boolean firstOutIsPop;
+    }
 }
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 7394c7f..099bae4 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1635,12 +1635,12 @@
                 return false;
             }
             final BackStackRecord bss = mBackStack.remove(last);
-            SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
-            SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
+            SparseArray<BackStackRecord.FragmentContainerTransition> transitioningFragments =
+                    new SparseArray<>();
             if (mCurState >= Fragment.CREATED) {
-                bss.calculateBackFragments(firstOutFragments, lastInFragments);
+                bss.calculateBackFragments(transitioningFragments);
             }
-            bss.popFromBackStack(true, null, firstOutFragments, lastInFragments);
+            bss.popFromBackStack(true, null, transitioningFragments);
             reportBackStackChanged();
         } else {
             int index = -1;
@@ -1684,18 +1684,17 @@
                 states.add(mBackStack.remove(i));
             }
             final int LAST = states.size()-1;
-            SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
-            SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
+            SparseArray<BackStackRecord.FragmentContainerTransition> transitioningFragments =
+                    new SparseArray<>();
             if (mCurState >= Fragment.CREATED) {
                 for (int i = 0; i <= LAST; i++) {
-                    states.get(i).calculateBackFragments(firstOutFragments, lastInFragments);
+                    states.get(i).calculateBackFragments(transitioningFragments);
                 }
             }
             BackStackRecord.TransitionState state = null;
             for (int i=0; i<=LAST; i++) {
                 if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i));
-                state = states.get(i).popFromBackStack(i == LAST, state,
-                        firstOutFragments, lastInFragments);
+                state = states.get(i).popFromBackStack(i == LAST, state, transitioningFragments);
             }
             reportBackStackChanged();
         }
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index ec22ff6..75a5bf7 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -44,7 +44,7 @@
      */
     ParcelFileDescriptor setWallpaper(String name, in String callingPackage,
             in Rect cropHint, boolean allowBackup, out Bundle extras, int which,
-            IWallpaperManagerCallback completion);
+            IWallpaperManagerCallback completion, int userId);
 
     /**
      * Set the live wallpaper. This only affects the system wallpaper.
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 1778ca7..2d46495 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -511,12 +511,15 @@
             }});
 
         registerService(Context.WIFI_NAN_SERVICE, WifiNanManager.class,
-                new StaticServiceFetcher<WifiNanManager>() {
+                new CachedServiceFetcher<WifiNanManager>() {
             @Override
-            public WifiNanManager createService() throws ServiceNotFoundException {
-                IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_NAN_SERVICE);
+            public WifiNanManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+                IBinder b = ServiceManager.getService(Context.WIFI_NAN_SERVICE);
                 IWifiNanManager service = IWifiNanManager.Stub.asInterface(b);
-                return new WifiNanManager(service);
+                if (service == null) {
+                    return null;
+                }
+                return new WifiNanManager(ctx.getOuterContext(), service);
             }});
 
         registerService(Context.WIFI_SCANNING_SERVICE, WifiScanner.class,
@@ -828,7 +831,7 @@
                         service = createService(ctx);
                         cache[mCacheIndex] = service;
                     } catch (ServiceNotFoundException e) {
-                        Log.w(TAG, e.getMessage(), e);
+                        Log.wtf(TAG, e.getMessage(), e);
                     }
                 }
                 return (T)service;
@@ -852,7 +855,7 @@
                     try {
                         mCachedInstance = createService();
                     } catch (ServiceNotFoundException e) {
-                        Log.w(TAG, e.getMessage(), e);
+                        Log.wtf(TAG, e.getMessage(), e);
                     }
                 }
                 return mCachedInstance;
@@ -885,7 +888,7 @@
                     try {
                         mCachedInstance = createService(appContext != null ? appContext : ctx);
                     } catch (ServiceNotFoundException e) {
-                        Log.w(TAG, e.getMessage(), e);
+                        Log.wtf(TAG, e.getMessage(), e);
                     }
                 }
                 return mCachedInstance;
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 6e44662..219afea 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -48,6 +48,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
@@ -939,7 +940,8 @@
             /* Set the wallpaper to the default values */
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(
                     "res:" + resources.getResourceName(resid),
-                    mContext.getOpPackageName(), null, false, result, which, completion);
+                    mContext.getOpPackageName(), null, false, result, which, completion,
+                    UserHandle.myUserId());
             if (fd != null) {
                 FileOutputStream fos = null;
                 boolean ok = false;
@@ -1040,6 +1042,19 @@
     public int setBitmap(Bitmap fullImage, Rect visibleCropHint,
             boolean allowBackup, @SetWallpaperFlags int which)
             throws IOException {
+        return setBitmap(fullImage, visibleCropHint, allowBackup, which,
+                UserHandle.myUserId());
+    }
+
+    /**
+     * Like {@link #setBitmap(Bitmap, Rect, boolean, int)}, but allows to pass in an explicit user
+     * id. If the user id doesn't match the user id the process is running under, calling this
+     * requires permission {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
+     * @hide
+     */
+    public int setBitmap(Bitmap fullImage, Rect visibleCropHint,
+            boolean allowBackup, @SetWallpaperFlags int which, int userId)
+            throws IOException {
         validateRect(visibleCropHint);
         if (sGlobals.mService == null) {
             Log.w(TAG, "WallpaperService not running");
@@ -1050,7 +1065,7 @@
         try {
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
                     mContext.getOpPackageName(), visibleCropHint, allowBackup,
-                    result, which, completion);
+                    result, which, completion, userId);
             if (fd != null) {
                 FileOutputStream fos = null;
                 try {
@@ -1176,7 +1191,7 @@
         try {
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
                     mContext.getOpPackageName(), visibleCropHint, allowBackup,
-                    result, which, completion);
+                    result, which, completion, UserHandle.myUserId());
             if (fd != null) {
                 FileOutputStream fos = null;
                 try {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 6ac7132..ae9b169 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2341,8 +2341,10 @@
     public static final int WIPE_RESET_PROTECTION_DATA = 0x0002;
 
     /**
-     * Ask the user data be wiped. Wiping the primary user will cause the device to reboot, erasing
-     * all user data while next booting up.
+     * Ask that all user data be wiped. If called as a secondary user, the user will be removed and
+     * other users will remain unaffected. Calling from the primary user will cause the device to
+     * reboot, erasing all device data - including all the secondary users and their data - while
+     * booting up.
      * <p>
      * The calling device admin must have requested {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} to
      * be able to call this method; if it has not, a security exception will be thrown.
@@ -6463,6 +6465,18 @@
         }
     }
 
+    /**
+     * @hide
+     * Force update user setup completed status
+     */
+    public void forceUpdateUserSetupComplete() {
+        try {
+            mService.forceUpdateUserSetupComplete();
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
     private void throwIfParentInstance(String functionName) {
         if (mParentInstance) {
             throw new SecurityException(functionName + " cannot be called on the parent instance");
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 1036f04..8d06ef1 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -305,4 +305,6 @@
     boolean isDeviceProvisioned();
     boolean isDeviceProvisioningConfigApplied();
     void setDeviceProvisioningConfigApplied();
+
+    void forceUpdateUserSetupComplete();
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 467eb89..e9b6041 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3156,7 +3156,7 @@
     /**
      * Use with {@link #getSystemService} to retrieve a
      * {@link android.net.wifi.nan.WifiNanManager} for handling management of
-     * Wi-Fi NAN discovery and connections.
+     * Wi-Fi NAN.
      *
      * @see #getSystemService
      * @see android.net.wifi.nan.WifiNanManager
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d537739..70010b2 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1448,7 +1448,7 @@
     /**
      * Activity Action: Launch application installer.
      * <p>
-     * Input: The data must be a content: or file: URI at which the application
+     * Input: The data must be a content: URI at which the application
      * can be retrieved.  As of {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1},
      * you can also use "package:<package-name>" to install an application for the
      * current user that is already installed for another user. You can optionally supply
diff --git a/core/java/android/content/SyncAdapterType.java b/core/java/android/content/SyncAdapterType.java
index 8a16ac9..6ef7fd2 100644
--- a/core/java/android/content/SyncAdapterType.java
+++ b/core/java/android/content/SyncAdapterType.java
@@ -16,6 +16,7 @@
 
 package android.content;
 
+import android.annotation.Nullable;
 import android.text.TextUtils;
 import android.os.Parcelable;
 import android.os.Parcel;
@@ -33,6 +34,7 @@
     private final boolean isAlwaysSyncable;
     private final boolean allowParallelSyncs;
     private final String settingsActivity;
+    private final String packageName;
 
     public SyncAdapterType(String authority, String accountType, boolean userVisible,
             boolean supportsUploading) {
@@ -50,6 +52,7 @@
         this.allowParallelSyncs = false;
         this.settingsActivity = null;
         this.isKey = false;
+        this.packageName = null;
     }
 
     /** @hide */
@@ -57,7 +60,8 @@
             boolean supportsUploading,
             boolean isAlwaysSyncable,
             boolean allowParallelSyncs,
-            String settingsActivity) {
+            String settingsActivity,
+            String packageName) {
         if (TextUtils.isEmpty(authority)) {
             throw new IllegalArgumentException("the authority must not be empty: " + authority);
         }
@@ -72,6 +76,7 @@
         this.allowParallelSyncs = allowParallelSyncs;
         this.settingsActivity = settingsActivity;
         this.isKey = false;
+        this.packageName = packageName;
     }
 
     private SyncAdapterType(String authority, String accountType) {
@@ -89,6 +94,7 @@
         this.allowParallelSyncs = false;
         this.settingsActivity = null;
         this.isKey = true;
+        this.packageName = null;
     }
 
     public boolean supportsUploading() {
@@ -148,6 +154,16 @@
         return settingsActivity;
     }
 
+    /**
+     * The package hosting the sync adapter.
+     * @return The package name.
+     *
+     * @hide
+     */
+    public @Nullable String getPackageName() {
+        return packageName;
+    }
+
     public static SyncAdapterType newKey(String authority, String accountType) {
         return new SyncAdapterType(authority, accountType);
     }
@@ -181,6 +197,7 @@
                     + ", isAlwaysSyncable=" + isAlwaysSyncable
                     + ", allowParallelSyncs=" + allowParallelSyncs
                     + ", settingsActivity=" + settingsActivity
+                    + ", packageName=" + packageName
                     + "}";
         }
     }
@@ -201,6 +218,7 @@
         dest.writeInt(isAlwaysSyncable ? 1 : 0);
         dest.writeInt(allowParallelSyncs ? 1 : 0);
         dest.writeString(settingsActivity);
+        dest.writeString(packageName);
     }
 
     public SyncAdapterType(Parcel source) {
@@ -211,6 +229,7 @@
                 source.readInt() != 0,
                 source.readInt() != 0,
                 source.readInt() != 0,
+                source.readString(),
                 source.readString());
     }
 
diff --git a/core/java/android/content/SyncAdaptersCache.java b/core/java/android/content/SyncAdaptersCache.java
index 6704b75..ddbdb8a 100644
--- a/core/java/android/content/SyncAdaptersCache.java
+++ b/core/java/android/content/SyncAdaptersCache.java
@@ -81,7 +81,7 @@
                     sa.getString(com.android.internal.R.styleable
                             .SyncAdapter_settingsActivity);
             return new SyncAdapterType(authority, accountType, userVisible, supportsUploading,
-                    isAlwaysSyncable, allowParallelSyncs, settingsActivity);
+                    isAlwaysSyncable, allowParallelSyncs, settingsActivity, packageName);
         } finally {
             sa.recycle();
         }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e8f0845..a6f6220 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2040,8 +2040,7 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
-     * {@link #hasSystemFeature}: The device supports Wi-Fi Aware (NAN)
-     * networking.
+     * {@link #hasSystemFeature}: The device supports Wi-Fi NAN.
      *
      * @hide PROPOSED_NAN_API
      */
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 5c31f79..201ada1 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2295,11 +2295,7 @@
             b.append(cls);
             return b.toString().intern();
         }
-        if (c >= 'a' && c <= 'z') {
-            return cls.intern();
-        }
-        outError[0] = "Bad class name " + cls + " in package " + pkg;
-        return null;
+        return cls.intern();
     }
 
     private static String buildCompoundName(String pkg,
@@ -2760,12 +2756,7 @@
         }
 
         if (ai.name != null) {
-            ai.className = buildClassName(pkgName, ai.name, outError);
-            if (ai.className == null) {
-                sa.recycle();
-                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
-                return false;
-            }
+            ai.className = ai.name;
         }
 
         String manageSpaceActivity = sa.getNonConfigurationString(
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 8f62d3f..7669635 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2595,7 +2595,8 @@
 
         /**
          * Called if no network is found in the given timeout time.  If no timeout is given,
-         * this will not be called.
+         * this will not be called. The associated {@link NetworkRequest} will have already
+         * been removed and released, as if {@link #unregisterNetworkCallback} had been called.
          * @hide
          */
         public void onUnavailable() {}
@@ -2668,6 +2669,26 @@
     /** @hide */
     public static final int CALLBACK_RESUMED             = BASE + 12;
 
+    /** @hide */
+    public static String getCallbackName(int whichCallback) {
+        switch (whichCallback) {
+            case CALLBACK_PRECHECK:     return "CALLBACK_PRECHECK";
+            case CALLBACK_AVAILABLE:    return "CALLBACK_AVAILABLE";
+            case CALLBACK_LOSING:       return "CALLBACK_LOSING";
+            case CALLBACK_LOST:         return "CALLBACK_LOST";
+            case CALLBACK_UNAVAIL:      return "CALLBACK_UNAVAIL";
+            case CALLBACK_CAP_CHANGED:  return "CALLBACK_CAP_CHANGED";
+            case CALLBACK_IP_CHANGED:   return "CALLBACK_IP_CHANGED";
+            case CALLBACK_RELEASED:     return "CALLBACK_RELEASED";
+            case CALLBACK_EXIT:         return "CALLBACK_EXIT";
+            case EXPIRE_LEGACY_REQUEST: return "EXPIRE_LEGACY_REQUEST";
+            case CALLBACK_SUSPENDED:    return "CALLBACK_SUSPENDED";
+            case CALLBACK_RESUMED:      return "CALLBACK_RESUMED";
+            default:
+                return Integer.toString(whichCallback);
+        }
+    }
+
     private class CallbackHandler extends Handler {
         private final HashMap<NetworkRequest, NetworkCallback>mCallbackMap;
         private final AtomicInteger mRefCount;
@@ -2834,7 +2855,7 @@
     private final static int REQUEST = 2;
 
     private NetworkRequest sendRequestForNetwork(NetworkCapabilities need,
-            NetworkCallback networkCallback, int timeoutSec, int action,
+            NetworkCallback networkCallback, int timeoutMs, int action,
             int legacyType) {
         if (networkCallback == null) {
             throw new IllegalArgumentException("null NetworkCallback");
@@ -2850,7 +2871,7 @@
                             new Messenger(sCallbackHandler), new Binder());
                 } else {
                     networkCallback.networkRequest = mService.requestNetwork(need,
-                            new Messenger(sCallbackHandler), timeoutSec, new Binder(), legacyType);
+                            new Messenger(sCallbackHandler), timeoutMs, new Binder(), legacyType);
                 }
                 if (networkCallback.networkRequest != null) {
                     sNetworkCallback.put(networkCallback.networkRequest, networkCallback);
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 11b861a..3a436de 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -41,13 +41,13 @@
  */
 public class NetworkPolicyManager {
 
-    /* POLICY_* are masks and can be ORed */
+    /* POLICY_* are masks and can be ORed, although currently they are not.*/
     /** No specific network policy, use system default. */
     public static final int POLICY_NONE = 0x0;
     /** Reject network usage on metered networks when application in background. */
     public static final int POLICY_REJECT_METERED_BACKGROUND = 0x1;
-    /** Allow network use (metered or not) in the background in battery save mode. */
-    public static final int POLICY_ALLOW_BACKGROUND_BATTERY_SAVE = 0x2;
+    /** Allow metered network use in the background even when in data usage save mode. */
+    public static final int POLICY_ALLOW_METERED_BACKGROUND = 0x4;
 
     /*
      * Rules defining whether an uid has access to a network given its type (metered / non-metered).
@@ -126,8 +126,8 @@
     /**
      * Set policy flags for specific UID.
      *
-     * @param policy {@link #POLICY_NONE} or combination of flags like
-     * {@link #POLICY_REJECT_METERED_BACKGROUND} or {@link #POLICY_ALLOW_BACKGROUND_BATTERY_SAVE}.
+     * @param policy should be {@link #POLICY_NONE} or any combination of {@code POLICY_} flags,
+     *     although it is not validated.
      */
     public void setUidPolicy(int uid, int policy) {
         try {
@@ -138,9 +138,12 @@
     }
 
     /**
-     * Add policy flags for specific UID.  The given policy bits will be set for
-     * the uid.  Policy flags may be either
-     * {@link #POLICY_REJECT_METERED_BACKGROUND} or {@link #POLICY_ALLOW_BACKGROUND_BATTERY_SAVE}.
+     * Add policy flags for specific UID.
+     *
+     * <p>The given policy bits will be set for the uid.
+     *
+     * @param policy should be {@link #POLICY_NONE} or any combination of {@code POLICY_} flags,
+     *     although it is not validated.
      */
     public void addUidPolicy(int uid, int policy) {
         try {
@@ -151,9 +154,12 @@
     }
 
     /**
-     * Clear/remove policy flags for specific UID.  The given policy bits will be set for
-     * the uid.  Policy flags may be either
-     * {@link #POLICY_REJECT_METERED_BACKGROUND} or {@link #POLICY_ALLOW_BACKGROUND_BATTERY_SAVE}.
+     * Clear/remove policy flags for specific UID.
+     *
+     * <p>The given policy bits will be set for the uid.
+     *
+     * @param policy should be {@link #POLICY_NONE} or any combination of {@code POLICY_} flags,
+     *     although it is not validated.
      */
     public void removeUidPolicy(int uid, int policy) {
         try {
@@ -344,7 +350,7 @@
         return true;
     }
 
-    /*
+    /**
      * @hide
      */
     public static String uidRulesToString(int uidRules) {
@@ -357,4 +363,19 @@
         string.append(")");
         return string.toString();
     }
+
+    /**
+     * @hide
+     */
+    public static String uidPoliciesToString(int uidPolicies) {
+        final StringBuilder string = new StringBuilder().append(uidPolicies).append(" (");
+        if (uidPolicies == POLICY_NONE) {
+            string.append("NONE");
+        } else {
+            string.append(DebugUtils.flagsToString(NetworkPolicyManager.class,
+                    "POLICY_", uidPolicies));
+        }
+        string.append(")");
+        return string.toString();
+    }
 }
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 25806fa..f65a50f 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -904,7 +904,8 @@
         if (pool.isEmpty()) {
             return true;
         }
-        Entry moved = addTrafficToApplications(tunIface,  underlyingIface, tunIfaceTotal, pool);
+        Entry moved =
+                addTrafficToApplications(tunUid, tunIface, underlyingIface, tunIfaceTotal, pool);
         deductTrafficFromVpnApp(tunUid, underlyingIface, moved);
 
         if (!moved.isEmpty()) {
@@ -919,9 +920,9 @@
      * Initializes the data used by the migrateTun() method.
      *
      * This is the first pass iteration which does the following work:
-     * (1) Adds up all the traffic through tun0.
-     * (2) Adds up all the traffic through the tunUid's underlyingIface
+     * (1) Adds up all the traffic through the tunUid's underlyingIface
      *     (both foreground and background).
+     * (2) Adds up all the traffic through tun0 excluding traffic from the vpn app itself.
      */
     private void tunAdjustmentInit(int tunUid, String tunIface, String underlyingIface,
             Entry tunIfaceTotal, Entry underlyingIfaceTotal) {
@@ -941,8 +942,9 @@
                 underlyingIfaceTotal.add(recycle);
             }
 
-            if (recycle.tag == TAG_NONE && Objects.equals(tunIface, recycle.iface)) {
-                // Add up all tunIface traffic.
+            if (recycle.uid != tunUid && recycle.tag == TAG_NONE
+                    && Objects.equals(tunIface, recycle.iface)) {
+                // Add up all tunIface traffic excluding traffic from the vpn app itself.
                 tunIfaceTotal.add(recycle);
             }
         }
@@ -958,13 +960,15 @@
         return pool;
     }
 
-    private Entry addTrafficToApplications(String tunIface, String underlyingIface,
+    private Entry addTrafficToApplications(int tunUid, String tunIface, String underlyingIface,
             Entry tunIfaceTotal, Entry pool) {
         Entry moved = new Entry();
         Entry tmpEntry = new Entry();
         tmpEntry.iface = underlyingIface;
         for (int i = 0; i < size; i++) {
-            if (Objects.equals(iface[i], tunIface)) {
+            // the vpn app is excluded from the redistribution but all moved traffic will be
+            // deducted from the vpn app (see deductTrafficFromVpnApp below).
+            if (Objects.equals(iface[i], tunIface) && uid[i] != tunUid) {
                 if (tunIfaceTotal.rxBytes > 0) {
                     tmpEntry.rxBytes = pool.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes;
                 } else {
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index c180c7f..5b51002 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -847,6 +847,7 @@
      * is installed.
      *
      * @hide
+     * @removed
      */
     @SystemApi
     public static final boolean PERMISSIONS_REVIEW_REQUIRED =
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 8d6d9ed..4616af8 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -372,6 +372,14 @@
     }
 
     /**
+     * @see #getDataPreloadsDirectory()
+     * {@hide}
+     */
+    public static File getDataPreloadsMediaDirectory() {
+        return new File(getDataPreloadsDirectory(), "media");
+    }
+
+    /**
      * Return the primary shared/external storage directory. This directory may
      * not currently be accessible if it has been mounted by the user on their
      * computer, has been removed from the device, or some other problem has
diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java
index 4e705e0..dd85e15 100644
--- a/core/java/android/os/FileObserver.java
+++ b/core/java/android/os/FileObserver.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.Nullable;
 import android.util.Log;
 
 import java.lang.ref.WeakReference;
@@ -204,7 +205,8 @@
      *
      * @param event The type of event which happened
      * @param path The path, relative to the main monitored file or directory,
-     *     of the file or directory which triggered the event
+     *     of the file or directory which triggered the event.  This value can
+     *     be {@code null} for certain events, such as {@link #MOVE_SELF}.
      */
-    public abstract void onEvent(int event, String path);
+    public abstract void onEvent(int event, @Nullable String path);
 }
diff --git a/core/java/android/os/IHwBinder.java b/core/java/android/os/IHwBinder.java
index 88af4fb..76e881e 100644
--- a/core/java/android/os/IHwBinder.java
+++ b/core/java/android/os/IHwBinder.java
@@ -18,8 +18,9 @@
 
 /** @hide */
 public interface IHwBinder {
-    // MUST match libhwbinder/IBinder.h definition !!!
+    // These MUST match their corresponding libhwbinder/IBinder.h definition !!!
     public static final int FIRST_CALL_TRANSACTION = 1;
+    public static final int FLAG_ONEWAY = 1;
 
     public void transact(
             int code, HwParcel request, HwParcel reply, int flags);
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index d7a7296..f050d76 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -237,6 +237,15 @@
             ZygoteState zygoteState, ArrayList<String> args)
             throws ZygoteStartFailedEx {
         try {
+            // Throw early if any of the arguments are malformed. This means we can
+            // avoid writing a partial response to the zygote.
+            int sz = args.size();
+            for (int i = 0; i < sz; i++) {
+                if (args.get(i).indexOf('\n') >= 0) {
+                    throw new ZygoteStartFailedEx("embedded newlines not allowed");
+                }
+            }
+
             /**
              * See com.android.internal.os.SystemZygoteInit.readArgumentList()
              * Presently the wire format to the zygote process is:
@@ -253,13 +262,8 @@
             writer.write(Integer.toString(args.size()));
             writer.newLine();
 
-            int sz = args.size();
             for (int i = 0; i < sz; i++) {
                 String arg = args.get(i);
-                if (arg.indexOf('\n') >= 0) {
-                    throw new ZygoteStartFailedEx(
-                            "embedded newlines not allowed");
-                }
                 writer.write(arg);
                 writer.newLine();
             }
@@ -268,11 +272,16 @@
 
             // Should there be a timeout on this?
             Process.ProcessStartResult result = new Process.ProcessStartResult();
+
+            // Always read the entire result from the input stream to avoid leaving
+            // bytes in the stream for future process starts to accidentally stumble
+            // upon.
             result.pid = inputStream.readInt();
+            result.usingWrapper = inputStream.readBoolean();
+
             if (result.pid < 0) {
                 throw new ZygoteStartFailedEx("fork() failed");
             }
-            result.usingWrapper = inputStream.readBoolean();
             return result;
         } catch (IOException ex) {
             zygoteState.close();
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index 5a98482..7399b7b 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -443,7 +443,6 @@
         // false permits advanced to be shown based on user preferences.
         intent.putExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, isPrimary());
         intent.putExtra(DocumentsContract.EXTRA_FANCY_FEATURES, true);
-        intent.putExtra(DocumentsContract.EXTRA_SHOW_FILESIZE, true);
         return intent;
     }
 
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index c51a613..6ddaf3b 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -96,9 +96,6 @@
     public static final String EXTRA_SHOW_ADVANCED = "android.content.extra.SHOW_ADVANCED";
 
     /** {@hide} */
-    public static final String EXTRA_SHOW_FILESIZE = "android.content.extra.SHOW_FILESIZE";
-
-    /** {@hide} */
     public static final String EXTRA_FANCY_FEATURES = "android.content.extra.FANCY";
 
     /** {@hide} */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bff4d7d..a7ff552 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3817,6 +3817,26 @@
         }
 
         /**
+         * These entries should be cloned from this profile's parent only if the dependency's
+         * value is true ("1")
+         *
+         * Note: the dependencies must be Secure settings
+         *
+         * @hide
+         */
+        public static final Map<String, String> CLONE_FROM_PARENT_ON_VALUE = new ArrayMap<>();
+        static {
+            CLONE_FROM_PARENT_ON_VALUE.put(RINGTONE, Secure.SYNC_PARENT_SOUNDS);
+            CLONE_FROM_PARENT_ON_VALUE.put(NOTIFICATION_SOUND, Secure.SYNC_PARENT_SOUNDS);
+            CLONE_FROM_PARENT_ON_VALUE.put(ALARM_ALERT, Secure.SYNC_PARENT_SOUNDS);
+        }
+
+        /** @hide */
+        public static void getCloneFromParentOnValueSettings(Map<String, String> outMap) {
+            outMap.putAll(CLONE_FROM_PARENT_ON_VALUE);
+        }
+
+        /**
          * When to use Wi-Fi calling
          *
          * @see android.telephony.TelephonyManager.WifiCallingChoices
@@ -5846,6 +5866,8 @@
         /**
          * If nonzero, ANRs in invisible background processes bring up a dialog.
          * Otherwise, the process will be silently killed.
+         *
+         * Also prevents ANRs and crash dialogs from being suppressed.
          * @hide
          */
         public static final String ANR_SHOW_BACKGROUND = "anr_show_background";
@@ -6061,6 +6083,17 @@
         public static final String VOLUME_CONTROLLER_SERVICE_COMPONENT
                 = "volume_controller_service_component";
 
+        /**
+         * Defines whether managed profile ringtones should be synced from it's parent profile
+         * <p>
+         * 0 = ringtones are not synced
+         * 1 = ringtones are synced from the profile's parent (default)
+         * <p>
+         * This value is only used for managed profiles.
+         * @hide
+         */
+        public static final String SYNC_PARENT_SOUNDS = "sync_parent_sounds";
+
         /** @hide */
         public static final String IMMERSIVE_MODE_CONFIRMATIONS = "immersive_mode_confirmations";
 
@@ -6432,7 +6465,8 @@
             NIGHT_DISPLAY_CUSTOM_START_TIME,
             NIGHT_DISPLAY_CUSTOM_END_TIME,
             NIGHT_DISPLAY_AUTO_MODE,
-            NIGHT_DISPLAY_ACTIVATED
+            NIGHT_DISPLAY_ACTIVATED,
+            SYNC_PARENT_SOUNDS
         };
 
         /**
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 27b0a8b..5099eeb 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -30,7 +30,6 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.Voicemail;
-
 import java.util.List;
 
 /**
@@ -123,22 +122,36 @@
             "android.intent.action.VOICEMAIL_SMS_RECEIVED";
 
     /**
-     * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate the
-     * event type of the SMS. Common values are "SYNC" or "STATUS"
+     * Optional extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to
+     * indicate the event type of the SMS. Common values are "SYNC" or "STATUS". The extra will not
+     * exist if the framework cannot parse the SMS as voicemail but the carrier pattern indicates
+     * it is.
      */
     /** @hide */
     public static final String EXTRA_VOICEMAIL_SMS_PREFIX =
             "com.android.voicemail.extra.VOICEMAIL_SMS_PREFIX";
 
     /**
-     * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate the
-     * fields sent by the SMS
+     * Optional extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to
+     * indicate the fields sent by the SMS. The extra will not exist if the framework cannot
+     * parse the SMS as voicemail but the carrier pattern indicates it is.
      */
     /** @hide */
     public static final String EXTRA_VOICEMAIL_SMS_FIELDS =
             "com.android.voicemail.extra.VOICEMAIL_SMS_FIELDS";
 
     /**
+     * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate the
+     * message body of the SMS. This extra is included if the framework cannot
+     * parse the SMS as voicemail but the carrier pattern indicates it is.
+     */
+    /**
+     * @hide
+     */
+    public static final String EXTRA_VOICEMAIL_SMS_MESSAGE_BODY =
+        "com.android.voicemail.extra.VOICEMAIL_SMS_MESSAGE_BODY";
+
+    /**
      * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate he
      * subscription ID of the phone account that received the SMS.
      */
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index 1e765b6..f93e548 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -64,10 +64,10 @@
      * The first entry in the array is a pointer to the next array in the
      * list; the second entry is a pointer to the int[] hash code array for it.
      */
-    static Object[] mBaseCache;
-    static int mBaseCacheSize;
-    static Object[] mTwiceBaseCache;
-    static int mTwiceBaseCacheSize;
+    static Object[] sBaseCache;
+    static int sBaseCacheSize;
+    static Object[] sTwiceBaseCache;
+    static int sTwiceBaseCacheSize;
 
     final boolean mIdentityHashCode;
     int[] mHashes;
@@ -152,31 +152,35 @@
     }
 
     private void allocArrays(final int size) {
-        if (size == (BASE_SIZE*2)) {
+        if (size == (BASE_SIZE * 2)) {
             synchronized (ArraySet.class) {
-                if (mTwiceBaseCache != null) {
-                    final Object[] array = mTwiceBaseCache;
+                if (sTwiceBaseCache != null) {
+                    final Object[] array = sTwiceBaseCache;
                     mArray = array;
-                    mTwiceBaseCache = (Object[])array[0];
-                    mHashes = (int[])array[1];
+                    sTwiceBaseCache = (Object[]) array[0];
+                    mHashes = (int[]) array[1];
                     array[0] = array[1] = null;
-                    mTwiceBaseCacheSize--;
-                    if (DEBUG) Log.d(TAG, "Retrieving 2x cache " + mHashes
-                            + " now have " + mTwiceBaseCacheSize + " entries");
+                    sTwiceBaseCacheSize--;
+                    if (DEBUG) {
+                        Log.d(TAG, "Retrieving 2x cache " + mHashes + " now have "
+                                + sTwiceBaseCacheSize + " entries");
+                    }
                     return;
                 }
             }
         } else if (size == BASE_SIZE) {
             synchronized (ArraySet.class) {
-                if (mBaseCache != null) {
-                    final Object[] array = mBaseCache;
+                if (sBaseCache != null) {
+                    final Object[] array = sBaseCache;
                     mArray = array;
-                    mBaseCache = (Object[])array[0];
-                    mHashes = (int[])array[1];
+                    sBaseCache = (Object[]) array[0];
+                    mHashes = (int[]) array[1];
                     array[0] = array[1] = null;
-                    mBaseCacheSize--;
-                    if (DEBUG) Log.d(TAG, "Retrieving 1x cache " + mHashes
-                            + " now have " + mBaseCacheSize + " entries");
+                    sBaseCacheSize--;
+                    if (DEBUG) {
+                        Log.d(TAG, "Retrieving 1x cache " + mHashes + " now have " + sBaseCacheSize
+                                + " entries");
+                    }
                     return;
                 }
             }
@@ -187,32 +191,36 @@
     }
 
     private static void freeArrays(final int[] hashes, final Object[] array, final int size) {
-        if (hashes.length == (BASE_SIZE*2)) {
+        if (hashes.length == (BASE_SIZE * 2)) {
             synchronized (ArraySet.class) {
-                if (mTwiceBaseCacheSize < CACHE_SIZE) {
-                    array[0] = mTwiceBaseCache;
+                if (sTwiceBaseCacheSize < CACHE_SIZE) {
+                    array[0] = sTwiceBaseCache;
                     array[1] = hashes;
-                    for (int i=size-1; i>=2; i--) {
+                    for (int i = size - 1; i >= 2; i--) {
                         array[i] = null;
                     }
-                    mTwiceBaseCache = array;
-                    mTwiceBaseCacheSize++;
-                    if (DEBUG) Log.d(TAG, "Storing 2x cache " + array
-                            + " now have " + mTwiceBaseCacheSize + " entries");
+                    sTwiceBaseCache = array;
+                    sTwiceBaseCacheSize++;
+                    if (DEBUG) {
+                        Log.d(TAG, "Storing 2x cache " + array + " now have " + sTwiceBaseCacheSize
+                                + " entries");
+                    }
                 }
             }
         } else if (hashes.length == BASE_SIZE) {
             synchronized (ArraySet.class) {
-                if (mBaseCacheSize < CACHE_SIZE) {
-                    array[0] = mBaseCache;
+                if (sBaseCacheSize < CACHE_SIZE) {
+                    array[0] = sBaseCache;
                     array[1] = hashes;
-                    for (int i=size-1; i>=2; i--) {
+                    for (int i = size - 1; i >= 2; i--) {
                         array[i] = null;
                     }
-                    mBaseCache = array;
-                    mBaseCacheSize++;
-                    if (DEBUG) Log.d(TAG, "Storing 1x cache " + array
-                            + " now have " + mBaseCacheSize + " entries");
+                    sBaseCache = array;
+                    sBaseCacheSize++;
+                    if (DEBUG) {
+                        Log.d(TAG, "Storing 1x cache " + array + " now have "
+                                + sBaseCacheSize + " entries");
+                    }
                 }
             }
         }
@@ -321,7 +329,7 @@
      * @return Returns the value stored at the given index.
      */
     public E valueAt(int index) {
-        return (E)mArray[index];
+        return (E) mArray[index];
     }
 
     /**
@@ -358,8 +366,8 @@
 
         index = ~index;
         if (mSize >= mHashes.length) {
-            final int n = mSize >= (BASE_SIZE*2) ? (mSize+(mSize>>1))
-                    : (mSize >= BASE_SIZE ? (BASE_SIZE*2) : BASE_SIZE);
+            final int n = mSize >= (BASE_SIZE * 2) ? (mSize + (mSize >> 1))
+                    : (mSize >= BASE_SIZE ? (BASE_SIZE * 2) : BASE_SIZE);
 
             if (DEBUG) Log.d(TAG, "add: grow from " + mHashes.length + " to " + n);
 
@@ -377,8 +385,9 @@
         }
 
         if (index < mSize) {
-            if (DEBUG) Log.d(TAG, "add: move " + index + "-" + (mSize-index)
-                    + " to " + (index+1));
+            if (DEBUG) {
+                Log.d(TAG, "add: move " + index + "-" + (mSize - index) + " to " + (index + 1));
+            }
             System.arraycopy(mHashes, index, mHashes, index + 1, mSize - index);
             System.arraycopy(mArray, index, mArray, index + 1, mSize - index);
         }
@@ -432,7 +441,7 @@
                 mSize = N;
             }
         } else {
-            for (int i=0; i<N; i++) {
+            for (int i = 0; i < N; i++) {
                 add(array.valueAt(i));
             }
         }
@@ -469,11 +478,11 @@
             mArray = EmptyArray.OBJECT;
             mSize = 0;
         } else {
-            if (mHashes.length > (BASE_SIZE*2) && mSize < mHashes.length/3) {
+            if (mHashes.length > (BASE_SIZE * 2) && mSize < mHashes.length / 3) {
                 // Shrunk enough to reduce size of arrays.  We don't allow it to
                 // shrink smaller than (BASE_SIZE*2) to avoid flapping between
                 // that and BASE_SIZE.
-                final int n = mSize > (BASE_SIZE*2) ? (mSize + (mSize>>1)) : (BASE_SIZE*2);
+                final int n = mSize > (BASE_SIZE * 2) ? (mSize + (mSize >> 1)) : (BASE_SIZE * 2);
 
                 if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to " + n);
 
@@ -488,23 +497,26 @@
                     System.arraycopy(oarray, 0, mArray, 0, index);
                 }
                 if (index < mSize) {
-                    if (DEBUG) Log.d(TAG, "remove: copy from " + (index+1) + "-" + mSize
-                            + " to " + index);
+                    if (DEBUG) {
+                        Log.d(TAG, "remove: copy from " + (index + 1) + "-" + mSize
+                                + " to " + index);
+                    }
                     System.arraycopy(ohashes, index + 1, mHashes, index, mSize - index);
                     System.arraycopy(oarray, index + 1, mArray, index, mSize - index);
                 }
             } else {
                 mSize--;
                 if (index < mSize) {
-                    if (DEBUG) Log.d(TAG, "remove: move " + (index+1) + "-" + mSize
-                            + " to " + index);
+                    if (DEBUG) {
+                        Log.d(TAG, "remove: move " + (index + 1) + "-" + mSize + " to " + index);
+                    }
                     System.arraycopy(mHashes, index + 1, mHashes, index, mSize - index);
                     System.arraycopy(mArray, index + 1, mArray, index, mSize - index);
                 }
                 mArray[mSize] = null;
             }
         }
-        return (E)old;
+        return (E) old;
     }
 
     /**
@@ -545,8 +557,8 @@
     @Override
     public <T> T[] toArray(T[] array) {
         if (array.length < mSize) {
-            @SuppressWarnings("unchecked") T[] newArray
-                = (T[]) Array.newInstance(array.getClass().getComponentType(), mSize);
+            @SuppressWarnings("unchecked") T[] newArray =
+                    (T[]) Array.newInstance(array.getClass().getComponentType(), mSize);
             array = newArray;
         }
         System.arraycopy(mArray, 0, array, 0, mSize);
@@ -577,7 +589,7 @@
             }
 
             try {
-                for (int i=0; i<mSize; i++) {
+                for (int i = 0; i < mSize; i++) {
                     E mine = valueAt(i);
                     if (!set.contains(mine)) {
                         return false;
@@ -621,7 +633,7 @@
 
         StringBuilder buffer = new StringBuilder(mSize * 14);
         buffer.append('{');
-        for (int i=0; i<mSize; i++) {
+        for (int i = 0; i < mSize; i++) {
             if (i > 0) {
                 buffer.append(", ");
             }
@@ -759,7 +771,7 @@
     @Override
     public boolean retainAll(Collection<?> collection) {
         boolean removed = false;
-        for (int i=mSize-1; i>=0; i--) {
+        for (int i = mSize - 1; i >= 0; i--) {
             if (!collection.contains(mArray[i])) {
                 removeAt(i);
                 removed = true;
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index b705cf1..27c1dcb 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -583,10 +583,11 @@
 
             if (mIsLongpressEnabled) {
                 mHandler.removeMessages(LONG_PRESS);
-                mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime()
-                        + TAP_TIMEOUT + LONGPRESS_TIMEOUT);
+                mHandler.sendEmptyMessageAtTime(LONG_PRESS,
+                        mCurrentDownEvent.getDownTime() + LONGPRESS_TIMEOUT);
             }
-            mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT);
+            mHandler.sendEmptyMessageAtTime(SHOW_PRESS,
+                    mCurrentDownEvent.getDownTime() + TAP_TIMEOUT);
             handled |= mListener.onDown(ev);
             break;
 
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index bb77100..7e19562 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -379,9 +379,9 @@
             if (createNewSurface) {
                 // Create a new SurfaceTexture for the layer.
                 mSurface = new SurfaceTexture(false);
-                mLayer.setSurfaceTexture(mSurface);
                 nCreateNativeWindow(mSurface);
             }
+            mLayer.setSurfaceTexture(mSurface);
             mSurface.setDefaultBufferSize(getWidth(), getHeight());
             mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5a7f0ff..d351371 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -830,7 +830,6 @@
      */
     protected static boolean sPreserveMarginParamsInLayoutParamConversion;
 
-
     /**
      * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when
      * calling setFlags.
@@ -9856,6 +9855,18 @@
     }
 
     /**
+     * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()}
+     * and {@link #onFinishTemporaryDetach()}.
+     *
+     * <p>This method always returns {@code true} when called directly or indirectly from
+     * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from
+     * {@link #onFinishTemporaryDetach()}, however, depends on the OS version.
+     * <ul>
+     *     <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li>
+     *     <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li>
+     * </ul>
+     * </p>
+     *
      * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()}
      * and {@link #onFinishTemporaryDetach()}.
      */
@@ -9890,8 +9901,8 @@
      */
     @CallSuper
     public void dispatchFinishTemporaryDetach() {
-        onFinishTemporaryDetach();
         mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH;
+        onFinishTemporaryDetach();
         if (hasWindowFocus() && hasFocus()) {
             InputMethodManager.getInstance().focusIn(this);
         }
@@ -20273,8 +20284,14 @@
                 // remove it from the transparent region.
                 final int[] location = attachInfo.mTransparentLocation;
                 getLocationInWindow(location);
-                region.op(location[0], location[1], location[0] + mRight - mLeft,
-                        location[1] + mBottom - mTop, Region.Op.DIFFERENCE);
+                // When a view has Z value, then it will be better to leave some area below the view
+                // for drawing shadow. The shadow outset is proportional to the Z value. Note that
+                // the bottom part needs more offset than the left, top and right parts due to the
+                // spot light effects.
+                int shadowOffset = getZ() > 0 ? (int) getZ() : 0;
+                region.op(location[0] - shadowOffset, location[1] - shadowOffset,
+                        location[0] + mRight - mLeft + shadowOffset,
+                        location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE);
             } else {
                 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) {
                     // The SKIP_DRAW flag IS set and the background drawable exists, we remove
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 9a73d0b..33b488f 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -219,6 +219,12 @@
     private static final int OVERFLING_DISTANCE = 6;
 
     /**
+     * Amount to scroll in response to a {@link MotionEvent#ACTION_SCROLL} event, in dips per
+     * axis value.
+     */
+    private static final int SCROLL_FACTOR = 64;
+
+    /**
      * Default duration to hide an action mode for.
      */
     private static final long ACTION_MODE_HIDE_DURATION_DEFAULT = 2000;
@@ -246,6 +252,7 @@
     private final int mOverflingDistance;
     private final boolean mFadingMarqueeEnabled;
     private final long mGlobalActionsKeyTimeout;
+    private final int mScrollFactor;
 
     private boolean sHasPermanentMenuKey;
     private boolean sHasPermanentMenuKeySet;
@@ -274,6 +281,7 @@
         mOverflingDistance = OVERFLING_DISTANCE;
         mFadingMarqueeEnabled = true;
         mGlobalActionsKeyTimeout = GLOBAL_ACTIONS_KEY_TIMEOUT;
+        mScrollFactor = SCROLL_FACTOR;
     }
 
     /**
@@ -357,6 +365,8 @@
                 com.android.internal.R.dimen.config_viewMaxFlingVelocity);
         mGlobalActionsKeyTimeout = res.getInteger(
                 com.android.internal.R.integer.config_globalActionsKeyTimeout);
+        mScrollFactor = res.getDimensionPixelSize(
+                com.android.internal.R.dimen.config_scrollFactor);
     }
 
     /**
@@ -669,6 +679,14 @@
     }
 
     /**
+     * @return Amount to scroll in response to a {@link MotionEvent#ACTION_SCROLL} event. Multiply
+     * this by the event's axis value to obtain the number of pixels to be scrolled.
+     */
+    public int getScaledScrollFactor() {
+        return mScrollFactor;
+    }
+
+    /**
      * The maximum drawing cache size expressed in bytes.
      *
      * @return the maximum size of View's drawing cache expressed in bytes
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index c682d09..2a52b53 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -6415,16 +6415,28 @@
             return true;
         }
         super.gatherTransparentRegion(region);
-        final View[] children = mChildren;
-        final int count = mChildrenCount;
+        // Instead of naively traversing the view tree, we have to traverse according to the Z
+        // order here. We need to go with the same order as dispatchDraw().
+        // One example is that after surfaceView punch a hole, we will still allow other views drawn
+        // on top of that hole. In this case, those other views should be able to cut the
+        // transparent region into smaller area.
+        final int childrenCount = mChildrenCount;
         boolean noneOfTheChildrenAreTransparent = true;
-        for (int i = 0; i < count; i++) {
-            final View child = children[i];
-            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
-                if (!child.gatherTransparentRegion(region)) {
-                    noneOfTheChildrenAreTransparent = false;
+        if (childrenCount > 0) {
+            final ArrayList<View> preorderedList = buildOrderedChildList();
+            final boolean customOrder = preorderedList == null
+                    && isChildrenDrawingOrderEnabled();
+            final View[] children = mChildren;
+            for (int i = 0; i < childrenCount; i++) {
+                final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
+                final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
+                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
+                    if (!child.gatherTransparentRegion(region)) {
+                        noneOfTheChildrenAreTransparent = false;
+                    }
                 }
             }
+            if (preorderedList != null) preorderedList.clear();
         }
         return meOpaque || noneOfTheChildrenAreTransparent;
     }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 757727b..d0c9234 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -52,6 +52,7 @@
 import android.media.AudioManager;
 import android.os.Binder;
 import android.os.Build;
+import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Handler;
@@ -1540,7 +1541,15 @@
         if (viewVisibilityChanged) {
             mAttachInfo.mWindowVisibility = viewVisibility;
             host.dispatchWindowVisibilityChanged(viewVisibility);
-            host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE);
+
+            // Prior to N we didn't have dispatchVisibilityAggregated to give a more accurate
+            // view into when views are visible to the user or not. ImageView never dealt with
+            // telling its drawable about window visibility, among other things. Some apps cause
+            // an additional crossfade animation when windows become visible if they get this
+            // additional call, so only send it to new apps to avoid new visual jank.
+            if (host.getContext().getApplicationInfo().targetSdkVersion >= VERSION_CODES.N) {
+                host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE);
+            }
             if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
                 endDragResizing();
                 destroyHardwareResources();
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index eb6b17e..0dbf00d 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -221,6 +221,7 @@
          * @see #TYPE_BASE_APPLICATION
          * @see #TYPE_APPLICATION
          * @see #TYPE_APPLICATION_STARTING
+         * @see #TYPE_DRAWN_APPLICATION
          * @see #TYPE_APPLICATION_PANEL
          * @see #TYPE_APPLICATION_MEDIA
          * @see #TYPE_APPLICATION_SUB_PANEL
@@ -244,6 +245,7 @@
             @ViewDebug.IntToString(from = TYPE_BASE_APPLICATION, to = "TYPE_BASE_APPLICATION"),
             @ViewDebug.IntToString(from = TYPE_APPLICATION, to = "TYPE_APPLICATION"),
             @ViewDebug.IntToString(from = TYPE_APPLICATION_STARTING, to = "TYPE_APPLICATION_STARTING"),
+            @ViewDebug.IntToString(from = TYPE_DRAWN_APPLICATION, to = "TYPE_DRAWN_APPLICATION"),
             @ViewDebug.IntToString(from = TYPE_APPLICATION_PANEL, to = "TYPE_APPLICATION_PANEL"),
             @ViewDebug.IntToString(from = TYPE_APPLICATION_MEDIA, to = "TYPE_APPLICATION_MEDIA"),
             @ViewDebug.IntToString(from = TYPE_APPLICATION_SUB_PANEL, to = "TYPE_APPLICATION_SUB_PANEL"),
@@ -315,6 +317,13 @@
         public static final int TYPE_APPLICATION_STARTING = 3;
 
         /**
+         * Window type: a variation on TYPE_APPLICATION that ensures the window
+         * manager will wait for this window to be drawn before the app is shown.
+         * In multiuser systems shows only on the owning user's window.
+         */
+        public static final int TYPE_DRAWN_APPLICATION = 4;
+
+        /**
          * End of types of application windows.
          */
         public static final int LAST_APPLICATION_WINDOW = 99;
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 2dfa8cd..44f6fac 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
 import android.content.pm.ServiceInfo;
 import android.os.Binder;
 import android.os.Handler;
@@ -91,6 +92,9 @@
     /** @hide */
     public static final int AUTOCLICK_DELAY_DEFAULT = 600;
 
+    /** @hide */
+    public static final int MAX_A11Y_EVENTS_PER_SERVICE_CALL = 20;
+
     static final Object sInstanceSync = new Object();
 
     private static AccessibilityManager sInstance;
@@ -99,6 +103,8 @@
 
     private IAccessibilityManager mService;
 
+    private EventDispatchThread mEventDispatchThread;
+
     final int mUserId;
 
     final Handler mHandler;
@@ -170,7 +176,7 @@
     private final IAccessibilityManagerClient.Stub mClient =
             new IAccessibilityManagerClient.Stub() {
         public void setState(int state) {
-            // We do not want to change this immediately as the applicatoin may
+            // We do not want to change this immediately as the application may
             // have already checked that accessibility is on and fired an event,
             // that is now propagating up the view tree, Hence, if accessibility
             // is now off an exception will be thrown. We want to have the exception
@@ -297,47 +303,32 @@
      * their descendants.
      */
     public void sendAccessibilityEvent(AccessibilityEvent event) {
-        final IAccessibilityManager service;
-        final int userId;
-        synchronized (mLock) {
-            service = getServiceLocked();
-            if (service == null) {
+        if (!isEnabled()) {
+            Looper myLooper = Looper.myLooper();
+            if (myLooper == Looper.getMainLooper()) {
+                throw new IllegalStateException(
+                        "Accessibility off. Did you forget to check that?");
+            } else {
+                // If we're not running on the thread with the main looper, it's possible for
+                // the state of accessibility to change between checking isEnabled and
+                // calling this method. So just log the error rather than throwing the
+                // exception.
+                Log.e(LOG_TAG, "AccessibilityEvent sent with accessibility disabled");
                 return;
             }
-            if (!mIsEnabled) {
-                Looper myLooper = Looper.myLooper();
-                if (myLooper == Looper.getMainLooper()) {
-                    throw new IllegalStateException(
-                            "Accessibility off. Did you forget to check that?");
-                } else {
-                    // If we're not running on the thread with the main looper, it's possible for
-                    // the state of accessibility to change between checking isEnabled and
-                    // calling this method. So just log the error rather than throwing the
-                    // exception.
-                    Log.e(LOG_TAG, "AccessibilityEvent sent with accessibility disabled");
-                    return;
-                }
-            }
-            userId = mUserId;
         }
-        boolean doRecycle = false;
-        try {
-            event.setEventTime(SystemClock.uptimeMillis());
-            // it is possible that this manager is in the same process as the service but
-            // client using it is called through Binder from another process. Example: MMS
-            // app adds a SMS notification and the NotificationManagerService calls this method
-            long identityToken = Binder.clearCallingIdentity();
-            doRecycle = service.sendAccessibilityEvent(event, userId);
-            Binder.restoreCallingIdentity(identityToken);
-            if (DEBUG) {
-                Log.i(LOG_TAG, event + " sent");
+        event.setEventTime(SystemClock.uptimeMillis());
+
+        getEventDispatchThread().scheduleEvent(event);
+    }
+
+    private EventDispatchThread getEventDispatchThread() {
+        synchronized (mLock) {
+            if (mEventDispatchThread == null) {
+                mEventDispatchThread = new EventDispatchThread(mService, mUserId);
+                mEventDispatchThread.start();
             }
-        } catch (RemoteException re) {
-            Log.e(LOG_TAG, "Error during sending " + event + " ", re);
-        } finally {
-            if (doRecycle) {
-                event.recycle();
-            }
+            return mEventDispatchThread;
         }
     }
 
@@ -620,7 +611,7 @@
         }
     }
 
-    private  IAccessibilityManager getServiceLocked() {
+    private IAccessibilityManager getServiceLocked() {
         if (mService == null) {
             tryConnectToServiceLocked(null);
         }
@@ -722,4 +713,99 @@
             }
         }
     }
+
+    private static class EventDispatchThread extends Thread {
+        // Second lock used to keep UI thread performant. Never try to grab mLock when holding
+        // this one, or the UI thread will block in send AccessibilityEvent.
+        private final Object mEventQueueLock = new Object();
+
+        // Two lists to hold events. The app thread fills one while we empty the other.
+        private final ArrayList<AccessibilityEvent> mEventLists0 =
+                new ArrayList<>(MAX_A11Y_EVENTS_PER_SERVICE_CALL);
+        private final ArrayList<AccessibilityEvent> mEventLists1 =
+                new ArrayList<>(MAX_A11Y_EVENTS_PER_SERVICE_CALL);
+
+        private boolean mPingPongListToggle;
+
+        private final IAccessibilityManager mService;
+
+        private final int mUserId;
+
+        EventDispatchThread(IAccessibilityManager service, int userId) {
+            mService = service;
+            mUserId = userId;
+        }
+
+        @Override
+        public void run() {
+            while (true) {
+                ArrayList<AccessibilityEvent> listBeingDrained;
+                synchronized (mEventQueueLock) {
+                    ArrayList<AccessibilityEvent> listBeingFilled = getListBeingFilledLocked();
+                    if (listBeingFilled.isEmpty()) {
+                        try {
+                            mEventQueueLock.wait();
+                        } catch (InterruptedException e) {
+                            // Treat as a notify
+                        }
+                    }
+                    // Swap buffers
+                    mPingPongListToggle = !mPingPongListToggle;
+                    listBeingDrained = listBeingFilled;
+                }
+                dispatchEvents(listBeingDrained);
+            }
+        }
+
+        public void scheduleEvent(AccessibilityEvent event) {
+            synchronized (mEventQueueLock) {
+                getListBeingFilledLocked().add(event);
+                mEventQueueLock.notifyAll();
+            }
+        }
+
+        private ArrayList<AccessibilityEvent> getListBeingFilledLocked() {
+            return (mPingPongListToggle) ? mEventLists0 : mEventLists1;
+        }
+
+        private void dispatchEvents(ArrayList<AccessibilityEvent> events) {
+            int eventListCapacityLowerBound = events.size();
+            while (events.size() > 0) {
+                // We don't want to consume extra memory if an app sends a lot of events in a
+                // one-off event. Cap the list length at double the max events per call.
+                // We'll end up with extra GC for apps that send huge numbers of events, but
+                // sending that many events will lead to bad performance in any case.
+                if ((eventListCapacityLowerBound > 2 * MAX_A11Y_EVENTS_PER_SERVICE_CALL)
+                        && (events.size() <= 2 * MAX_A11Y_EVENTS_PER_SERVICE_CALL)) {
+                    events.trimToSize();
+                    eventListCapacityLowerBound = events.size();
+                }
+                // We only expect this loop to run once, as the app shouldn't be sending
+                // huge numbers of events.
+                // The clear in the called method will remove the sent events
+                dispatchOneBatchOfEvents(events.subList(0,
+                        Math.min(events.size(), MAX_A11Y_EVENTS_PER_SERVICE_CALL)));
+            }
+        }
+
+        private void dispatchOneBatchOfEvents(List<AccessibilityEvent> events) {
+            if (events.isEmpty()) {
+                return;
+            }
+            long identityToken = Binder.clearCallingIdentity();
+            try {
+                mService.sendAccessibilityEvents(new ParceledListSlice<>(events),
+                        mUserId);
+            } catch (RemoteException re) {
+                Log.e(LOG_TAG, "Error sending multiple events");
+            }
+            Binder.restoreCallingIdentity(identityToken);
+            if (DEBUG) {
+                Log.i(LOG_TAG, events.size() + " events sent");
+            }
+            for (int i = events.size() - 1; i >= 0; i--) {
+                events.remove(i).recycle();
+            }
+        }
+    }
 }
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 7f44bac..aa9cb39 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -21,6 +21,7 @@
 import android.accessibilityservice.IAccessibilityServiceConnection;
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.content.ComponentName;
+import android.content.pm.ParceledListSlice;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.IAccessibilityInteractionConnection;
@@ -37,7 +38,9 @@
 
     int addClient(IAccessibilityManagerClient client, int userId);
 
-    boolean sendAccessibilityEvent(in AccessibilityEvent uiEvent, int userId);
+    void sendAccessibilityEvent(in AccessibilityEvent uiEvent, int userId);
+
+    void sendAccessibilityEvents(in ParceledListSlice events, int userId);
 
     List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId);
 
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 15eb8de..4bfc718 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -42,6 +42,7 @@
 
 import dalvik.system.VMRuntime;
 
+import java.lang.reflect.Method;
 import java.io.File;
 import java.io.IOException;
 import java.util.Arrays;
@@ -59,6 +60,8 @@
     private static final String CHROMIUM_WEBVIEW_FACTORY =
             "com.android.webview.chromium.WebViewChromiumFactoryProvider";
 
+    private static final String CHROMIUM_WEBVIEW_FACTORY_METHOD = "create";
+
     private static final String NULL_WEBVIEW_FACTORY =
             "com.android.webview.nullwebview.NullWebViewFactoryProvider";
 
@@ -192,11 +195,25 @@
             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()");
             try {
                 Class<WebViewFactoryProvider> providerClass = getProviderClass();
+                Method staticFactory = null;
+                try {
+                    staticFactory = providerClass.getMethod(
+                        CHROMIUM_WEBVIEW_FACTORY_METHOD, WebViewDelegate.class);
+                } catch (Exception e) {
+                    if (DEBUG) {
+                        Log.w(LOGTAG, "error instantiating provider with static factory method", e);
+                    }
+                }
 
                 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "providerClass.newInstance()");
                 try {
-                    sProviderInstance = providerClass.getConstructor(WebViewDelegate.class)
-                            .newInstance(new WebViewDelegate());
+                    if (staticFactory != null) {
+                        sProviderInstance = (WebViewFactoryProvider)
+                                staticFactory.invoke(null, new WebViewDelegate());
+                    } else {
+                        sProviderInstance = providerClass.getConstructor(WebViewDelegate.class)
+                                .newInstance(new WebViewDelegate());
+                    }
                     if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);
                     return sProviderInstance;
                 } catch (Exception e) {
diff --git a/core/java/android/widget/ForwardingListener.java b/core/java/android/widget/ForwardingListener.java
index a5fcbc7..8b82c06 100644
--- a/core/java/android/widget/ForwardingListener.java
+++ b/core/java/android/widget/ForwardingListener.java
@@ -279,7 +279,9 @@
         @Override
         public void run() {
             final ViewParent parent = mSrc.getParent();
-            parent.requestDisallowInterceptTouchEvent(true);
+            if (parent != null) {
+                parent.requestDisallowInterceptTouchEvent(true);
+            }
         }
     }
 
@@ -289,4 +291,4 @@
             onLongPress();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 6dafe34..64779a2 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -651,7 +651,7 @@
      */
     private Editor mEditor;
 
-    private final GestureDetector mClickableSpanOnClickGestureDetector;
+    private GestureDetector mClickableSpanOnClickGestureDetector;
 
     private static final int DEVICE_PROVISIONED_UNKNOWN = 0;
     private static final int DEVICE_PROVISIONED_NO = 1;
@@ -1491,24 +1491,6 @@
         if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
             setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
         }
-
-        mClickableSpanOnClickGestureDetector = new GestureDetector(context,
-                new GestureDetector.SimpleOnGestureListener() {
-                    @Override
-                    public boolean onSingleTapConfirmed(MotionEvent e) {
-                        if (mLinksClickable && (mMovement != null) &&
-                                (mMovement instanceof LinkMovementMethod
-                                || (mAutoLinkMask != 0 && isTextSelectable()))) {
-                            ClickableSpan[] links = ((Spannable) mText).getSpans(
-                                    getSelectionStart(), getSelectionEnd(), ClickableSpan.class);
-                            if (links.length > 0) {
-                                links[0].onClick(TextView.this);
-                                return true;
-                            }
-                        }
-                        return false;
-                    }
-                });
     }
 
     private int[] parseDimensionArray(TypedArray dimens) {
@@ -8536,7 +8518,23 @@
             if (mMovement != null) {
                 handled |= mMovement.onTouchEvent(this, (Spannable) mText, event);
             }
-            handled |= mClickableSpanOnClickGestureDetector.onTouchEvent(event);
+
+            // Lazily create the clickable span gesture detector only if it looks like it
+            // might be useful.
+            if (action == MotionEvent.ACTION_DOWN && mClickableSpanOnClickGestureDetector == null
+                    && shouldUseClickableSpanOnClickGestureDetector()) {
+                ClickableSpan[] links = ((Spannable) mText).getSpans(
+                        getSelectionStart(), getSelectionEnd(),
+                        ClickableSpan.class);
+                if (links.length > 0) {
+                    mClickableSpanOnClickGestureDetector =
+                            createClickableSpanOnClickGestureDetector();
+                }
+            }
+
+            if (mClickableSpanOnClickGestureDetector != null) {
+                handled |= mClickableSpanOnClickGestureDetector.onTouchEvent(event);
+            }
 
             final boolean textIsSelectable = isTextSelectable();
             if (touchIsFinished && (isTextEditable() || textIsSelectable)) {
@@ -8937,6 +8935,31 @@
         mEditor.onLocaleChanged();
     }
 
+    private GestureDetector createClickableSpanOnClickGestureDetector() {
+        return new GestureDetector(mContext,
+                new GestureDetector.SimpleOnGestureListener() {
+                    @Override
+                    public boolean onSingleTapConfirmed(MotionEvent e) {
+                        if (shouldUseClickableSpanOnClickGestureDetector()) {
+                            ClickableSpan[] links = ((Spannable) mText).getSpans(
+                                    getSelectionStart(), getSelectionEnd(),
+                                    ClickableSpan.class);
+                            if (links.length > 0) {
+                                links[0].onClick(TextView.this);
+                                return true;
+                            }
+                        }
+                        return false;
+                    }
+                });
+    }
+
+    private boolean shouldUseClickableSpanOnClickGestureDetector() {
+        return mLinksClickable && (mMovement != null) &&
+                (mMovement instanceof LinkMovementMethod
+                        || (mAutoLinkMask != 0 && isTextSelectable()));
+    }
+
     /**
      * This method is used by the ArrowKeyMovementMethod to jump from one word to the other.
      * Made available to achieve a consistent behavior.
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 1308f28..eb143e8 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -101,6 +101,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
 import static com.android.internal.policy.PhoneWindow.FEATURE_OPTIONS_PANEL;
 
 /** @hide */
@@ -1860,7 +1861,7 @@
         }
         final WindowManager.LayoutParams attrs = mWindow.getAttributes();
         final boolean isApplication = attrs.type == TYPE_BASE_APPLICATION ||
-                attrs.type == TYPE_APPLICATION;
+                attrs.type == TYPE_APPLICATION || attrs.type == TYPE_DRAWN_APPLICATION;
         // Only a non floating application window on one of the allowed workspaces can get a caption
         if (!mWindow.isFloating() && isApplication && StackId.hasWindowDecor(mStackId)) {
             // Dependent on the brightness of the used title we either use the
diff --git a/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl b/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl
index 419b1f8..8e454db 100644
--- a/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl
@@ -20,4 +20,5 @@
     void onSimSecureStateChanged(boolean simSecure);
     void onInputRestrictedStateChanged(boolean inputRestricted);
     void onTrustedChanged(boolean trusted);
+    void onHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper);
 }
\ No newline at end of file
diff --git a/core/java/com/android/internal/widget/WatchHeaderListView.java b/core/java/com/android/internal/widget/WatchHeaderListView.java
index 3d32d86..4fd19c3 100644
--- a/core/java/com/android/internal/widget/WatchHeaderListView.java
+++ b/core/java/com/android/internal/widget/WatchHeaderListView.java
@@ -103,7 +103,8 @@
 
     @Override
     public int getHeaderViewsCount() {
-        return mTopPanel == null ? super.getHeaderViewsCount() : super.getHeaderViewsCount() + 1;
+        return mTopPanel == null ? super.getHeaderViewsCount()
+                : super.getHeaderViewsCount() + (mTopPanel.getVisibility() == GONE ? 0 : 1);
     }
 
     private void wrapAdapterIfNecessary() {
@@ -133,7 +134,7 @@
         }
 
         private int getTopPanelCount() {
-            return mTopPanel == null ? 0 : 1;
+            return (mTopPanel == null || mTopPanel.getVisibility() == GONE) ? 0 : 1;
         }
 
         @Override
@@ -143,33 +144,19 @@
 
         @Override
         public boolean areAllItemsEnabled() {
-            return mTopPanel == null && super.areAllItemsEnabled();
+            return getTopPanelCount() == 0 && super.areAllItemsEnabled();
         }
 
         @Override
         public boolean isEnabled(int position) {
-            if (mTopPanel != null) {
-                if (position == 0) {
-                    return false;
-                } else {
-                    return super.isEnabled(position - 1);
-                }
-            }
-
-            return super.isEnabled(position);
+            int topPanelCount = getTopPanelCount();
+            return position < topPanelCount ? false : super.isEnabled(position - topPanelCount);
         }
 
         @Override
         public Object getItem(int position) {
-            if (mTopPanel != null) {
-                if (position == 0) {
-                    return null;
-                } else {
-                    return super.getItem(position - 1);
-                }
-            }
-
-            return super.getItem(position);
+            int topPanelCount = getTopPanelCount();
+            return position < topPanelCount ? null : super.getItem(position - topPanelCount);
         }
 
         @Override
@@ -187,15 +174,9 @@
 
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
-            if (mTopPanel != null) {
-                if (position == 0) {
-                    return mTopPanel;
-                } else {
-                    return super.getView(position - 1, convertView, parent);
-                }
-            }
-
-            return super.getView(position, convertView, parent);
+            int topPanelCount = getTopPanelCount();
+            return position < topPanelCount
+                    ? mTopPanel : super.getView(position - topPanelCount, convertView, parent);
         }
 
         @Override
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 2a9498c..462d103 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -264,6 +264,7 @@
     libradio_metadata \
     libnativeloader \
     libmemunreachable \
+    libhidl \
     libhwbinder \
 
 LOCAL_SHARED_LIBRARIES += \
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index ef16ef5..4976002 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -20,13 +20,14 @@
 #define LOG_TAG "AudioSystem-JNI"
 #include <utils/Log.h>
 
+#include <sstream>
 #include <jni.h>
 #include <JNIHelp.h>
 #include "core_jni_helpers.h"
 
 #include <media/AudioSystem.h>
 #include <media/AudioPolicy.h>
-
+#include <nativehelper/ScopedLocalRef.h>
 #include <system/audio.h>
 #include <system/audio_policy.h>
 #include "android_media_AudioFormat.h"
@@ -903,6 +904,12 @@
     return false; // not found
 }
 
+// TODO: pull out to separate file
+template <typename T, size_t N>
+static constexpr size_t array_size(const T (&)[N]) {
+    return N;
+}
+
 static jint convertAudioPortFromNative(JNIEnv *env,
                                            jobject *jAudioPort, const struct audio_port *nAudioPort)
 {
@@ -923,6 +930,38 @@
     ALOGV("convertAudioPortFromNative id %d role %d type %d name %s",
         nAudioPort->id, nAudioPort->role, nAudioPort->type, nAudioPort->name);
 
+    // Verify audio port array count info.
+    if (nAudioPort->num_sample_rates > array_size(nAudioPort->sample_rates)
+            || nAudioPort->num_channel_masks > array_size(nAudioPort->channel_masks)
+            || nAudioPort->num_formats > array_size(nAudioPort->formats)
+            || nAudioPort->num_gains > array_size(nAudioPort->gains)) {
+
+        std::stringstream ss;
+        ss << "convertAudioPortFromNative array count out of bounds:"
+                << " num_sample_rates " << nAudioPort->num_sample_rates
+                << " num_channel_masks " << nAudioPort->num_channel_masks
+                << " num_formats " << nAudioPort->num_formats
+                << " num_gains " << nAudioPort->num_gains
+                ;
+        std::string s = ss.str();
+
+        // Prefer to log through Java wtf instead of native ALOGE.
+        ScopedLocalRef<jclass> jLogClass(env, env->FindClass("android/util/Log"));
+        jmethodID jWtfId = (jLogClass.get() == nullptr)
+                ? nullptr
+                : env->GetStaticMethodID(jLogClass.get(), "wtf",
+                        "(Ljava/lang/String;Ljava/lang/String;)I");
+        if (jWtfId != nullptr) {
+            ScopedLocalRef<jstring> jMessage(env, env->NewStringUTF(s.c_str()));
+            ScopedLocalRef<jstring> jTag(env, env->NewStringUTF(LOG_TAG));
+            (void)env->CallStaticIntMethod(jLogClass.get(), jWtfId, jTag.get(), jMessage.get());
+        } else {
+            ALOGE("%s", s.c_str());
+        }
+        jStatus = (jint)AUDIO_JAVA_ERROR;
+        goto exit;
+    }
+
     jSamplingRates = env->NewIntArray(nAudioPort->num_sample_rates);
     if (jSamplingRates == NULL) {
         jStatus = (jint)AUDIO_JAVA_ERROR;
@@ -1066,7 +1105,7 @@
                                                        &jAudioPortConfig,
                                                        &nAudioPort->active_config);
     if (jStatus != AUDIO_JAVA_SUCCESS) {
-        return jStatus;
+        goto exit;
     }
 
     env->SetObjectField(*jAudioPort, gAudioPortFields.mActiveConfig, jAudioPortConfig);
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index a45e1ee..132ed95 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -25,7 +25,7 @@
 
 #include <JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
-#include <hwbinder/IServiceManager.h>
+#include <hidl/IServiceManager.h>
 #include <hwbinder/ProcessState.h>
 #include <hwbinder/Status.h>
 #include <nativehelper/ScopedLocalRef.h>
diff --git a/core/jni/android_os_HwRemoteBinder.cpp b/core/jni/android_os_HwRemoteBinder.cpp
index 23d4fced..81ba368 100644
--- a/core/jni/android_os_HwRemoteBinder.cpp
+++ b/core/jni/android_os_HwRemoteBinder.cpp
@@ -24,7 +24,7 @@
 
 #include <JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
-#include <hwbinder/IServiceManager.h>
+#include <hidl/IServiceManager.h>
 #include <hwbinder/Status.h>
 #include <nativehelper/ScopedLocalRef.h>
 
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index ffa7107..1cfbd97 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -22,7 +22,6 @@
 #include <utils/Log.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
-#include <cutils/process_name.h>
 #include <cutils/sched_policy.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
diff --git a/core/jni/hwbinder/EphemeralStorage.h b/core/jni/hwbinder/EphemeralStorage.h
index 1273003..b02ed9f 100644
--- a/core/jni/hwbinder/EphemeralStorage.h
+++ b/core/jni/hwbinder/EphemeralStorage.h
@@ -19,7 +19,7 @@
 #define EPHEMERAL_STORAGE_H_
 
 #include <android-base/macros.h>
-#include <hwbinder/HidlSupport.h>
+#include <hidl/HidlSupport.h>
 #include <jni.h>
 #include <utils/Vector.h>
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3ceba08..40ffb74 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -181,8 +181,13 @@
     <protected-broadcast
         android:name="android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast
+        android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_SENT" />
+    <protected-broadcast
+        android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY" />
+    <protected-broadcast
         android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.pbap.intent.action.PBAP_STATE_CHANGED" />
+    <protected-broadcast android:name="android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast android:name="android.btopp.intent.action.INCOMING_FILE_NOTIFICATION" />
     <protected-broadcast android:name="android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT" />
     <protected-broadcast android:name="android.btopp.intent.action.LIST" />
@@ -199,6 +204,8 @@
     <protected-broadcast android:name="com.android.bluetooth.pbap.userconfirmtimeout" />
     <protected-broadcast android:name="com.android.bluetooth.pbap.authresponse" />
     <protected-broadcast android:name="com.android.bluetooth.pbap.authcancelled" />
+    <protected-broadcast android:name="com.android.bluetooth.sap.USER_CONFIRM_TIMEOUT" />
+    <protected-broadcast android:name="com.android.bluetooth.sap.action.DISCONNECT_ACTION" />
 
     <protected-broadcast android:name="android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED" />
 
@@ -395,6 +402,8 @@
 
     <protected-broadcast android:name="android.bluetooth.adapter.action.BLE_STATE_CHANGED" />
     <protected-broadcast android:name="com.android.bluetooth.map.USER_CONFIRM_TIMEOUT" />
+    <protected-broadcast android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_SENT" />
+    <protected-broadcast android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY" />
     <protected-broadcast android:name="android.content.jobscheduler.JOB_DELAY_EXPIRED" />
     <protected-broadcast android:name="android.content.syncmanager.SYNC_ALARM" />
     <protected-broadcast android:name="android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION" />
@@ -1312,6 +1321,7 @@
         android:protectionLevel="dangerous"
         android:description="@string/permdesc_getAccounts"
         android:label="@string/permlab_getAccounts" />
+    <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
 
     <!-- @SystemApi Allows applications to call into AccountAuthenticators.
     <p>Not for use by third-party applications. -->
diff --git a/core/res/assets/images/android-logo-mask.png b/core/res/assets/images/android-logo-mask.png
index ad40645..5512c0ad 100644
--- a/core/res/assets/images/android-logo-mask.png
+++ b/core/res/assets/images/android-logo-mask.png
Binary files differ
diff --git a/core/res/assets/images/android-logo-shine.png b/core/res/assets/images/android-logo-shine.png
index cb65f22..c5d1263 100644
--- a/core/res/assets/images/android-logo-shine.png
+++ b/core/res/assets/images/android-logo-shine.png
Binary files differ
diff --git a/core/res/assets/images/clock64.png b/core/res/assets/images/clock64.png
index 493a1ea..2e01e38 100644
--- a/core/res/assets/images/clock64.png
+++ b/core/res/assets/images/clock64.png
Binary files differ
diff --git a/core/res/assets/sounds/bootanim0.raw b/core/res/assets/sounds/bootanim0.raw
deleted file mode 100644
index 46b8c0f..0000000
--- a/core/res/assets/sounds/bootanim0.raw
+++ /dev/null
Binary files differ
diff --git a/core/res/assets/sounds/bootanim1.raw b/core/res/assets/sounds/bootanim1.raw
deleted file mode 100644
index ce69944..0000000
--- a/core/res/assets/sounds/bootanim1.raw
+++ /dev/null
Binary files differ
diff --git a/core/res/assets/webkit/hyph_en_US.dic b/core/res/assets/webkit/hyph_en_US.dic
deleted file mode 100644
index d91204b..0000000
--- a/core/res/assets/webkit/hyph_en_US.dic
+++ /dev/null
@@ -1,9784 +0,0 @@
-ISO8859-1
-LEFTHYPHENMIN 2
-RIGHTHYPHENMIN 3
-.a2ch4
-.ad4der
-.a2d
-.ad1d4
-.a2f1t
-.a2f
-.a4l3t
-.am5at
-.4a1ma
-.an5c
-.a2n
-.2ang4
-.an1i5m
-.an1t4
-.an3te
-.anti5s
-.ant2i
-.a4r5s2
-.2a2r
-.ar4t2ie4
-.ar1ti
-.ar4ty
-.as3c
-.as1p
-.a2s1s
-.aster5
-.a2tom5
-.a1to
-.au1d
-.av4i
-.awn4
-.ba4g
-.ba5na
-.ba2n
-.bas4e
-.ber4
-.be5r1a
-.be3s1m
-.4bes4
-.b4e5s2to
-.bri2
-.but4ti
-.bu4t3t2
-.cam4pe
-.1ca
-.ca4m1p
-.can5c
-.ca2n
-.capa5b
-.ca1pa
-.car5ol
-.c2a2r
-.ca4t
-.ce4la
-.2ch4
-.chill5i
-.ch4il2
-.chil1l
-.1ci2
-.cit5r
-.2c1it
-.co3e2
-.1co
-.co4r
-.cor5n1er
-.corn2e
-.de4moi2
-.d4em
-.de1mo
-.de3o
-.de3r1a
-.de3r1i
-.de1s4c
-.des2
-.dic1t2io5
-.3di2c1t
-.do4t
-.1do
-.du4c
-.1du
-.du4m1b5
-.earth5
-.ear2t
-.e2a2r
-.eas3i
-.2e1b4
-.eer4
-.eg2
-.e2l5d
-.el3em
-.enam3
-.e1na
-.en3g
-.e2n3s2
-.eq5ui5t
-.e1q
-.equ2
-.eq2ui2
-.er4ri
-.er1r4
-.es3
-.4eu3
-.eye5
-.fes3
-.for5mer
-.1fo
-.fo2r
-.for1m
-.for2me
-.1ga2
-.ge2
-.gen3t4
-.1gen
-.ge5o2g
-.1geo
-.1g2i5a
-.gi4b
-.go4r
-.1go
-.hand5i
-.ha2n
-.h4and
-.ha4n5k2
-.he2
-.hero5i2
-.h2ero
-.h1es3
-.he4t3
-.hi3b
-.hi3er
-.h2ie4
-.hon5ey
-.ho2n
-.hon3o
-.hov5
-.id4l
-.2id
-.idol3
-.i1do
-.im3m
-.im5p1i2n
-.i4m1p
-.im2pi
-.in1
-.in3ci
-.2ine2
-.4i4n2k2
-.2i2n3s2
-.ir5r4
-.4ir
-.is4i
-.ju3r
-.la4cy
-.la4m
-.lat5er
-.l4ath5
-.le2
-.leg5e
-.len4
-.lep5
-.lev1
-.l2i4g
-.li1g5a
-.li2n
-.l2i3o
-.l1i4t
-.ma1g5a5
-.1ma
-.mal5o
-.ma1n5a
-.ma2n
-.mar5ti
-.m2a2r
-.me2
-.mer3c
-.me5ter
-.me1te
-.m2is1
-.mis4t5i
-.mon3e
-.1mo
-.mo2n
-.mo3ro
-.mo2r
-.mu5ta
-.1mu
-.mu2ta5b
-.ni4c
-.od2
-.od1d5
-.of5te
-.o2ft
-.or5a1to
-.o1ra
-.or3c
-.or1d
-.or3t
-.os3
-.os4tl
-.4oth3
-.out3
-.ou2
-.ped5al
-.2p2ed
-.p2e2d2a
-.pe5te
-.pe2t
-.pe5tit
-.p2i4e4
-.pio5n4
-.3p2i1o
-.pi2t
-.pre3m
-.pr2
-.ra4c
-.ran4t
-.ra2n
-.ratio5n1a
-.ratio2n4
-.ra1t2io
-.ree2
-.re5mit
-.res2
-.re5stat
-.res2t
-.res1ta
-.r2i4g
-.ri2t5u
-.ro4q
-.ros5t
-.row5d
-.ru4d
-.3s4c2i3e4
-.s1ci
-.5se2l2f5
-.sel1l5
-.se2n
-.se5r2ie4
-.ser1i
-.s2h2
-.si2
-.s3ing4
-.2s1in
-.st4
-.sta5b2l2
-.s1ta
-.s2tab
-.s4y2
-.1ta4
-.te4
-.3ten5a2n
-.te1na
-.th2
-.ti2
-.til4
-.ti1m5o5
-.1tim
-.ting4
-.2t1in
-.t4i4n5k2
-.to1n4a
-.1to
-.to2n
-.to4p
-.top5i
-.to2u5s
-.tou2
-.trib5ut
-.tr4ib
-.u1n1a
-.un3ce
-.under5
-.un1de
-.u2n1e
-.u4n5k2
-.un5o
-.un3u4
-.up3
-.ure3
-.us5a2
-.2us
-.ven4de
-.ve5r1a
-.wil5i
-.wi2
-.wil2
-.ye4
-4ab.
-a5bal
-a5ba2n
-abe2
-ab5erd
-ab2i5a
-ab5i2t5ab
-abi2t
-abi1ta
-ab5lat
-ab2l2
-ab5o5l1iz
-abol2i
-4abr
-ab5rog
-ab3ul
-a4c2a2r
-a1ca
-ac5ard
-ac5aro
-a5ceou2
-ac1er
-a5che4t
-a2ch
-ache2
-4a2ci
-a3c2ie4
-a2c1in
-a3c2io
-ac5rob
-act5if2
-a2c1t
-ac3ul
-ac4um
-a2d
-ad4d1in
-ad1d4
-ad5er.
-2adi
-a3d4i3a
-ad3i1ca
-adi4er
-ad2ie4
-a3d2io
-a3dit
-a5di1u
-ad4le
-ad3ow
-a1do
-ad5ra2n
-a1dr
-ad4su
-a2d1s2
-4a1du
-a3du2c
-ad5um
-ae4r
-aer2i4e4
-aer1i
-a2f
-a4f1f4
-a4gab
-a1ga
-aga4n
-ag5el1l
-a1ge4o
-4ag4eu
-ag1i
-4ag4l2
-ag1n
-a2go
-3a3g4o4g
-ag3o3ni
-ago2n2
-a5guer
-a2gue
-ag5ul
-a4gy
-a3ha
-a3he
-a4h4l4
-a3ho
-ai2
-a5i1a
-a3ic.
-ai5ly
-a4i4n
-ain5in
-a2ini
-a2i1n5o
-ait5en
-a2ite
-a1j
-ak1en
-al5ab
-al3a2d
-a4l2a2r
-4aldi4
-a2ld
-2ale
-al3end
-a4lent2i
-a1len1t
-a5le5o
-al1i
-al4ia.
-al2i1a
-al2i4e4
-al5lev
-al1l
-al2le
-4allic
-all2i
-4a2lm
-a5log.
-a4ly.
-a1ly
-4a2lys4
-5a5lys1t
-5alyt
-3alyz
-4a1ma
-a2m5ab
-am3ag
-ama5ra
-am2a2r
-am5asc
-a4ma3tis
-a4m5a1to
-am5er1a
-am3ic
-am5if
-am5i1ly
-am1in
-am2i4no
-a2mo
-a5mo2n
-amor5i
-amo2r
-amp5en
-a4m1p
-a2n
-an3age
-a1na
-3ana1ly
-a3n2a2r
-an3ar3c
-anar4i
-a3nati
-an2at
-4and
-ande4s2
-an1de
-an3dis1
-an1dl
-an4dow
-an1do
-a5nee
-a3nen
-an5e2st.
-a1nes
-a2nest
-a3n4eu
-2ang
-ang5ie4
-an1gl2
-a4n1ic
-a3nies
-an2ie4
-an3i3f
-an4ime
-an1im
-a5nim1i
-a5n2ine
-an1in
-an3i4o
-a3n2ip
-an3is2h
-an3it
-a3ni1u
-an4kli
-a4nk2
-an1k1l
-5anniz
-a4n1n2
-ano4
-an5ot
-an4oth5
-an2sa2
-a2n1s2
-an4s1co
-ans4c
-an4s1n4
-an2sp
-ans3po
-an4st
-an4su2r
-an1su
-anta2l4
-an1t
-an1ta
-an4t2ie4
-ant2i
-4an1to
-an2tr
-an4tw4
-an3u1a
-an3ul
-a5nur
-4ao
-ap2a2r4
-a1pa
-ap5at
-ap5er3o
-a3ph4er
-4aphi
-a4pilla
-apil1l
-ap5ill2a2r
-ap3i2n
-ap3i1ta
-a3pi2tu
-a2p2l2
-apo4c5
-ap5o1la
-apor5i
-a1p4or
-apos3t
-a1pos
-aps5e4s
-a2p1s2
-ap2se
-a3pu
-aque5
-aqu2
-2a2r
-ar3a2c1t
-a5rade
-ara2d
-ar5adis1
-ar2adi
-ar3al
-a5rame1te
-aram3et
-ar2an4g
-ara2n
-ara3p
-ar4at
-a5ra1t2io
-ar5a1t2iv
-a5rau
-ar5av4
-araw4
-arbal4
-ar1b
-ar4cha2n
-ar1c
-ar3cha
-ar2ch
-ar5d2ine
-ard2i
-ard1in4
-ar4dr
-ar5eas
-a3ree
-ar3en1t
-a5r2e2ss
-ar4fi
-ar1f
-ar4f4l2
-ar1i
-ar5i2al
-ar2i3a
-ar3i2a2n
-a3ri5et
-ar2ie4
-ar4im
-ar5in2at
-ar2i1na
-ar3i1o
-ar2iz
-ar2mi
-ar1m
-ar5o5d
-a5roni
-aro2n
-a3roo2
-ar2p
-ar3q
-arre4
-ar1r4
-ar4sa2
-a4rs2
-ar2s2h
-4as.
-a2s4ab
-asa2
-as3an1t
-asa2n
-ashi4
-as2h
-a5sia.
-as2i1a
-a3si1b
-a3sic
-5a5si4t
-ask3i
-ask2
-as4l2
-a4soc
-a1so
-as5ph
-as4s2h
-a2ss
-as3ten
-as1t4r
-asu1r5a
-a1su
-asu2r
-a2ta
-at3ab2l2
-a2tab
-at5ac
-at3alo
-ata2l
-at5ap
-ate5c
-at5e2ch
-at3e1go
-ateg4
-at3en.
-at3er1a
-ater5n
-a5ter1na
-at3est
-at5ev
-4ath
-ath5em
-ath2e
-a5the2n
-at4ho
-ath5om
-4ati.
-a5t2i1a
-a2t5i5b
-at1ic
-at3if2
-ation5a2r
-a1t2io
-atio2n
-atio1n1a
-at3i1tu
-a4tog
-a1to
-a2tom
-at5om2iz
-a4top
-a4tos2
-a1tr
-at5rop
-at4sk2
-a4t1s2
-at4tag
-a4t3t2
-at1ta
-at5te
-at4th
-a2tu
-at5u1a
-a4t5ue
-at3ul
-at3u1ra
-a2ty
-au4b
-augh3
-au3gu
-au4l2
-aun5d
-au3r
-au5si1b
-a2us
-a4ut5en
-au1th
-a2va
-av3ag4
-a5va2n
-av4e4no
-av3er1a
-av5ern
-av5ery
-av1i
-avi4er
-av2ie4
-av3ig
-av5oc
-a1vor
-3away
-aw3i2
-aw4ly
-aws4
-ax4i5c
-ax3i
-ax4id
-ay5al
-aye4
-ays4
-azi4er
-a2z1i
-az2ie4
-az2z5i
-a4z1z2
-5ba.
-bad5ger
-ba2d
-ba4ge
-bal1a
-ban5dag
-ba2n
-b4and
-ban1d2a
-ban4e
-ban3i
-barbi5
-b2a2r
-bar1b
-bar2i4a
-bar1i
-bas4si
-ba2ss
-1bat
-ba4z
-2b1b
-b2be
-b3ber
-bbi4na
-4b1d
-4be.
-beak4
-bea2t3
-4be2d
-b2e3d2a
-be3de
-b4e3di
-be3gi
-be5gu
-1bel
-be1l2i
-be3lo
-4be5m
-be5n2ig
-be5nu
-4bes4
-be3sp
-b2e5st4r
-3bet
-be1t5iz
-be5tr
-be3tw4
-be3w
-be5y1o4
-2bf
-4b3h
-bi2b
-b2i4d
-3b2ie4
-bi5en
-bi4er
-2b3if
-1bil
-bi3l2iz
-bil1i
-bin2a5r4
-bi1na
-b4in4d
-bi5net
-b2ine
-bi3o2gr
-b2io
-bi5ou2
-bi2t
-3b2i3t2io
-bi1ti
-bi3tr
-3bit5u1a
-bi1tu
-b5i4tz
-b1j
-bk4
-b2l2
-bl4ath5
-b4le.
-blen4
-5ble1sp
-bles2
-b3lis
-b4lo
-blun4t
-4b1m
-4b3n
-bne5g
-3bod
-bod3i
-bo4e
-bol3ic
-bol2i
-bom4bi
-bo4m1b
-bo1n4a
-bo2n
-bon5at
-3boo2
-5bor.
-4b1o1ra
-bor5d
-5bore
-5bori
-5bos4
-b5o1ta
-b4oth5
-bo4to
-boun2d3
-bou2
-4bp
-4brit
-br4oth3
-2b5s2
-bsor4
-b1so
-2bt
-b2t4l
-b4to
-b3tr
-buf4fer1
-bu4f1f
-bu4ga
-bu3l2i
-bu1mi4
-bu4n
-bunt4i
-bun1t
-bu3re
-bus5ie4
-b2us
-buss4e
-bu2ss
-5bust
-4bu1ta
-3bu1t2io
-b4u1t2i
-b5u1to
-b1v
-4b5w
-5by.
-bys4
-1ca
-cab3in
-ca1b2l2
-ca2ch4
-ca5den
-ca2d
-4cag4
-2c5ah
-ca3lat
-cal4la
-cal1l
-cal2l5in4
-call2i
-4calo
-c4an5d
-ca2n
-can4e
-ca4n4ic
-can5is
-can3iz
-can4ty
-can1t
-cany4
-ca5per
-car5om
-c2a2r
-cast5er
-cas5t2ig
-cast2i
-4cas4y
-c4a4th
-4ca1t2iv
-cav5al
-ca2va
-c3c
-ccha5
-c2ch
-c3c2i4a
-c1ci
-ccom1pa5
-c1co
-cco4m1p
-cco2n4
-ccou3t
-ccou2
-2ce.
-4ced.
-4ce1den
-3cei2
-5cel.
-3cel1l
-1cen
-3cenc
-2cen4e
-4ceni
-3cen1t
-3cep
-ce5ram
-cer1a
-4ce1s4a2
-3ces1si
-c2e2ss
-ces5si5b
-ces5t
-cet4
-c5e4ta
-cew4
-2ch
-4ch.
-4ch3ab
-5cha4n1ic
-cha2n
-ch5a5nis
-che2
-cheap3
-4ch4ed
-ch5e5lo
-3chemi
-ch5ene
-che2n
-ch3er.
-ch3e4r1s2
-4ch1in
-5chi2ne.
-ch2ine
-ch5i5n2e2ss
-chi1nes
-5ch2ini
-5ch2io
-3chit
-chi2z
-3cho2
-ch4ti
-1ci
-3c2i1a
-ci2a5b
-ci2a5r
-ci5c
-4cier
-c2ie4
-5c4i2f3ic.
-ci1fi
-4c4i5i4
-ci4la
-3cil1i
-2cim
-2cin
-c4i1na
-3cin2at
-cin3em
-c2ine
-c1ing
-c5ing.
-5c2i1no
-cio2n4
-c2io
-4cipe4
-c2ip
-ci3ph
-4cip4ic
-cip3i
-4cis1ta
-4cis1t2i
-2c1it
-ci1t3iz
-ci1ti
-5ciz
-ck1
-ck3i
-1c4l4
-4cl2a2r
-c5la5ra1t2io
-clar4at
-5clare
-cle4m
-4clic
-clim4
-c1ly4
-c5n
-1co
-co5ag
-c4oa
-coe2
-2cog
-co4gr
-coi4
-co3inc
-col5i
-5colo
-col3o4r
-com5er
-co2me
-co1n4a
-co2n
-c4one
-con3g
-con5t
-co3pa
-cop3ic
-co4p2l2
-4cor1b
-coro3n
-cos4e
-cov1
-cove4
-cow5a
-co2z5e
-co5z1i
-c1q
-cras5t
-cr2as
-5crat.
-5crat1ic
-cre3a2t
-5c2r2ed
-4c3re1ta
-cre4v2
-cri2
-cri5f
-c4rin
-cr2is4
-5cri1ti
-cro4p2l2
-crop5o
-cros4e
-cru4d
-4c3s2
-2c1t
-c2ta4b
-c1ta
-ct5ang
-cta2n
-c5tan1t
-c2te
-c3ter
-c4t4ic1u
-ctim3i
-c1tim
-ctu4r
-c1tu
-c4tw4
-cud5
-c4uf
-c4ui2
-cu5i1ty
-5cul2i
-cul4tis4
-cul1ti
-cu4lt
-3c4ul1tu2
-cu2ma
-c3ume
-cu4mi
-3cun
-cu3pi
-cu5py
-cu2r5a4b
-cu1ra
-cu5r2i3a
-1c2us
-cus1s4i
-cu2ss
-3c4ut
-cu4t2ie4
-c4u1t2i
-4c5u1t2iv
-4cutr
-1cy
-c2ze4
-1d2a
-5da.
-2d3a4b
-da2ch4
-4da2f
-2dag
-da2m2
-d2an3g
-da2n
-dard5
-d2a2r
-dark5
-4dary
-3dat
-4da1t2iv
-4da1to
-5dav4
-dav5e
-5day
-d1b
-d5c
-d1d4
-2de.
-dea2f5
-de4b5i2t
-d2e1b
-de4bo2n
-deca2n4
-de1ca
-de4cil
-de1c2i
-de5com
-de1co
-2d1ed
-4dee.
-de5if
-dei2
-del2i4e4
-del2i
-de4l5i5q
-de5lo
-d4em
-5dem.
-3demic
-dem5ic.
-de5mil
-de4mo2n3s2
-de1mo
-demo2n
-demo2r5
-1den
-de4n2a2r
-de1na
-d4e3no
-denti5f2
-den1t
-dent2i
-de3nu
-de1p
-de3pa
-depi4
-de2pu
-d3e1q
-d4er1h4
-5der3m4
-d5ern5iz
-de4r5s2
-des2
-d2es.
-de1s2c
-de2s5o
-des3t2i
-d2e3st4r
-de4su
-de1t
-de2to
-de1v
-de2v3i4l
-de1vi
-4dey
-4d1f
-d4ga
-d3ge4t
-dg1i
-d2gy
-d1h2
-5di.
-1d4i3a
-dia5b
-d4i4cam
-di1ca
-d4ice
-3di2c1t
-3d2id
-5di3en
-d2ie4
-d1if
-di3ge
-d2ig
-di4la1to
-di1la
-d1in
-1di1na
-3di2ne.
-d2ine
-5d2ini
-di5niz
-1d2io
-dio5g
-di4p2l2
-d2ip
-d4ir2
-di1re
-dir1t5i
-dis1
-5disi
-d4is3t
-d2i1ti
-1d2i1v
-d1j
-d5k2
-4d5la
-3dle.
-3dled
-3dles.
-dles2
-4d3l2e2ss
-2d3lo
-4d5lu
-2d1ly
-d1m
-4d1n4
-1do
-3do.
-do5de
-5doe
-2d5of
-d4og
-do4la
-dol2i4
-do5lo4r
-dom5iz
-do3n2at
-do2n
-do1n1a
-doni4
-doo3d
-doo2
-do4p4p
-d4or
-3dos
-4d5out
-dou2
-do4v
-3dox
-d1p
-1dr
-drag5o2n2
-dra2go
-4dr2ai2
-dre4
-dre2a5r
-5dren
-dr4i4b
-dril4
-dro4p
-4drow
-5drupli
-dru3p2l2
-4dry
-2d1s2
-ds4p
-d4sw2
-d4s4y
-d2th
-1du
-d1u1a
-du2c
-d1u3ca
-duc5er
-4duct.
-du2c1t
-4duc4t1s2
-du5el
-du4g
-d3ul4e
-dum4be
-du4m1b
-du4n
-4dup
-du4pe
-d1v
-d1w
-d2y
-5dyn
-dy4s2e
-dys5p
-e1a4b
-e3a2c1t
-ea2d1
-ead5ie4
-e2adi
-ea4ge
-ea5ger
-ea4l
-eal5er
-e2ale
-eal3ou2
-eam3er
-e5and
-ea2n
-ear3a
-e2a2r
-ear4c
-ear5es
-ear4ic
-ear1i
-ear4il
-ear5k
-ear2t
-eart3e
-ea5sp
-e3a2ss
-east3
-ea2t
-eat5en
-eath3i
-e4ath
-e5at3if2
-e4a3tu
-ea2v
-eav3en
-eav5i
-eav5o
-2e1b
-e4bel.
-e1bel
-e4be2l1s2
-e4ben
-e4bi2t
-e3br
-e4ca2d
-e1ca
-ecan5c
-eca2n
-ec1ca5
-ec3c
-e1ce
-ec5es1sa2
-ec2e2ss
-e1c2i
-e4cib
-ec5ificat
-eci1fi
-ecifi1ca
-ec5i3f2ie4
-ec5i1fy
-e2c3im
-e2c1i4t
-e5c2ite
-e4clam
-e1c4l4
-e4cl2us
-e2col
-e1co
-e4com1m
-e4compe
-eco4m1p
-e4con1c
-eco2n
-e2cor
-ec3o1ra
-eco5ro
-e1cr
-e4crem
-ec4ta2n
-e2c1t
-ec1ta
-ec4te
-e1cu
-e4cul
-ec3u1la
-2e2d2a
-4ed3d4
-e4d1er
-ede4s2
-4edi
-e3d4i3a
-ed3ib
-ed3i1ca
-ed3im
-ed1it
-edi5z
-4e1do
-e4dol
-edo2n2
-e4dri
-e1dr
-e4dul
-e1du
-ed5u1l4o
-ee2c
-e4ed3i
-ee2f
-eel3i
-ee4ly
-ee2m
-ee4na
-ee4p1
-ee2s4
-eest4
-ee4ty
-e5ex
-e1f
-e4f3ere
-efer1
-1e4f1f
-e4fic
-e1fi
-5ef2i1c4i
-efil4
-e3f2i2ne
-e2fin
-ef5i5n2ite
-ef2ini
-efin2it
-3efit
-efor5es
-e1fo
-efo2r
-e4fu4se.
-e3fu
-ef2us
-4egal
-e1ga
-eger4
-eg5ib
-eg4ic
-eg5ing
-e5git5
-eg5n
-e4go.
-e1go
-e4gos
-eg1ul
-e5gur
-5e1gy
-e1h4
-eher4
-ei2
-e5ic
-e2i5d
-e2ig2
-ei5g4l2
-e3i4m1b
-e3in3f
-e1ing
-e5inst
-e2i2n1s2
-eir4d
-e4ir
-e2it3e
-e2i3th
-e5i1ty
-e1j
-e4jud
-ej5udi
-eki4n
-ek1i
-ek4la
-ek1l
-e1la
-e4la.
-e4lac
-e3l4an4d
-ela2n
-e4l5a1t2iv
-e4law
-elax1a4
-e3le2a
-el5ebra
-el2e1b
-ele3br
-5elec
-e4led
-el3e1ga
-e5len
-e4l1er
-e1les2
-e2l2f
-el2i
-e3libe4
-e4l5ic.
-el3i1ca
-e3lier
-el2ie4
-el5i3gib
-el2ig
-el4igi
-e5lim
-e4l3ing
-e3l2io
-e2lis
-el5is2h
-e3l2iv3
-4ella
-el1l
-el4lab
-ell4o4
-e5loc
-el5og
-el3op.
-el2s2h
-e2l1s2
-el4ta
-e4lt
-e5lud
-el5ug
-e4mac
-e1ma
-e4mag
-e5ma2n
-em5a1na
-e4m5b
-e1me
-e2mel
-e4met
-em3i1ca
-em2i4e4
-em5igra
-em2ig4
-emi1gr
-em1in2
-em5ine
-em3i3ni
-e4m2is
-em5is2h
-e5m4i2s1s
-em3iz
-5emniz
-e4m1n
-emo4g
-e1mo
-emo3n2i5o
-emo2n
-em3pi
-e4m1p
-e4mul
-e1mu
-em5u1la
-emu3n2
-e3my
-en5a2mo
-e1na
-e4nan1t
-en2a2n
-ench4er
-en2ch
-enche2
-en3dic
-e5nea
-e5nee
-en3em
-en5ero
-en1er
-en5e1si
-e1nes
-e2n5est
-en3etr
-e3ne4w
-en5i4c3s2
-e5n2ie4
-e5nil
-e3n2i4o
-en3is2h
-en3it
-e5ni1u
-5eniz
-4e4n1n2
-4eno
-e4no4g
-e4nos
-en3ov
-en4sw2
-e2n1s2
-ent5age
-en1t
-en1ta
-4enth1es
-enth2e
-en3u1a
-en5uf
-e3ny.
-4e4n3z
-e5of
-eo2g
-e4oi4
-e3ol
-eop3a2r
-eo2pa
-e1or
-eo3re
-eo5rol
-eos4
-e4ot
-eo4to
-e5out
-eou2
-e5ow
-e2pa
-e3p4ai2
-ep5anc
-epa2n
-e5pel
-e3pen1t
-ep5e5t2i1t2io
-epe2t
-epeti1ti
-ephe4
-e4pli
-e1p2l2
-e1po
-e4prec
-epr2
-ep5re1ca
-e4p2r2ed
-ep3re1h4
-e3pro
-e4prob
-ep4s4h
-e2p1s2
-ep5ti5b
-e2p1t
-e4pu2t
-ep5u1ta
-e1q
-equi3l
-equ2
-eq2ui2
-e4q3ui3s
-er1a
-e2ra4b
-4er4and
-era2n
-er3a2r
-4er4ati.
-2er1b
-er4b2l2
-er3ch
-er1c
-er4che2
-2e2re.
-e3re1a4l
-ere5co
-ere3in
-erei2
-er5el.
-er3e1mo
-er5e1na
-er5ence
-4erene
-er3en1t
-ere4q
-er5e2ss
-er3es2t
-eret4
-er1h4
-er1i
-e1r2i3a4
-5erick1
-e3rien
-er2ie4
-eri4er
-er3in4e
-e1r2i1o
-4erit
-er4i1u
-er2i4v
-e4ri1va
-er3m4
-er4nis4
-4er3n2it
-5erniz
-er3no4
-2ero
-er5ob
-e5r2oc
-ero4r
-er1ou2
-e4r1s2
-er3set
-er2se
-ert3er
-4er2tl
-er3tw4
-4eru
-eru4t
-5erwau
-er1w
-e1s4a2
-e4sa2ge.
-e4sages
-es2c
-e2s1ca
-es5ca2n
-e3scr
-es5cu
-e1s2e
-e2sec
-es5e1cr
-e4s5enc
-e4sert.
-e4ser4t1s2
-e4ser1va
-4es2h
-e3sha
-esh5e2n
-e1si
-e2sic
-e2s2id
-es5i1den
-e4s5ig1n4a
-es2ig
-e2s5im
-e2s4i4n
-esis4te
-e1sis
-e5si4u
-e5skin
-esk2
-esk1i
-es4mi
-e2s1m
-e2sol
-e1so
-es3olu
-e2so2n
-es5o1n1a4
-e1sp
-e2s3per
-es5pi1ra
-esp4ir
-es4pre
-espr2
-2e2ss
-es4si4b
-es1si
-esta2n4
-es1ta
-es3t2ig
-est2i
-es5tim
-4es2to
-e3sto2n
-2est4r
-e5stro
-estruc5
-e2su2r
-e1su
-es5ur1r4
-es4w2
-e2ta4b
-e1ta
-e3ten4d
-e3teo
-ethod3
-et1ic
-e5tide
-et2id
-e2t1in4
-et2i4no
-e5t4ir
-e5t2i1t2io
-eti1ti
-et5i1t2iv
-4e2t1n2
-et5o1n1a
-e1to
-eto2n
-e3tra
-e3tre
-et3ric
-et5rif
-et3rog
-et5ros
-et3u1a
-e1tu
-et5ym
-e1ty
-e4t5z
-4eu
-e5un
-e3up
-eu3ro
-e2us4
-eute4
-euti5l
-e4u1t2i
-eu5tr
-eva2p5
-e1va
-e2vas
-ev5ast
-e5vea
-ev3el1l
-eve4l3o
-e5veng
-even4i
-ev1er
-e5v2er1b
-e1vi
-ev3id
-e2vi4l
-e4v1in
-e3v2i4v
-e5voc
-e5vu
-e1wa
-e4wag
-e5wee
-e3wh
-ewil5
-ewi2
-ew3in4g
-e3wit
-1ex3p
-5ey1c
-5eye.
-eys4
-1fa
-fa3b2l2
-f4ab3r
-fa4ce
-4fag
-fa4i4n4
-fai2
-fal2l5e
-fal1l
-4f4a4ma
-fam5is
-5f2a2r
-far5th
-fa3ta
-fa3th2e
-f4ath
-4fa1to
-fau4lt5
-fau4l2
-4f5b
-4fd
-4fe.
-feas4
-fe4ath3
-fea2t
-f2e4b
-4fe1ca
-5fe2c1t
-2fed
-fe3l2i
-fe4mo
-fen2d
-fen1d5e
-fer1
-5fer1r4
-fev4
-4f1f
-f4fes
-f4f2ie4
-f1fi
-f5f2in.
-f2fin
-f2f5is
-f4f2ly5
-ff4l2
-f2fy
-4fh
-1fi
-f2i3a
-2f3ic.
-4f3ical
-fi1ca
-f3ica2n
-4ficate
-f3i1cen
-fi3cer
-f2i1c4i
-5fi3c2i1a
-5fic2ie4
-4fi4c3s2
-fi3cu
-fi5del
-f2id
-fight5
-f2ig
-fil5i
-fil2l5in4
-fil1l
-fill2i
-4fi1ly
-2fin
-5fi1na
-f4in2d5
-f2i2ne
-f1in3g
-f2i4n4n2
-fis4t2i
-f4l2
-f5l2e2ss
-fles2
-flin4
-flo3re
-f2ly5
-4fm
-4fn
-1fo
-5fo2n
-fon4de
-f2ond
-fon4t
-fo2r
-fo5rat
-fo1ra
-for5ay
-fore5t
-for4i
-for1t5a
-fos5
-4f5p
-fra4t
-f5rea
-fres5c
-fri2
-fril4
-frol5
-2f3s
-2ft
-f4to
-f2ty
-3fu
-fu5el
-4fug
-fu4min
-fu1mi
-fu5ne
-fu3ri
-fusi4
-f2us
-fu2s4s
-4fu1ta
-1fy
-1ga
-ga2f4
-5gal.
-3gal1i
-ga3lo
-2gam
-ga5met
-g5a2mo
-gan5is
-ga2n
-ga3niz
-gani5za1
-4gano4
-gar5n4
-g2a2r
-ga2ss4
-g4ath3
-4ga1t2iv
-4gaz
-g3b
-gd4
-2ge.
-2ged
-geez4
-gel4in
-gel2i
-ge5lis
-ge5l1iz
-4ge1ly
-1gen
-ge4n2at
-ge1na
-g5e5niz
-4g4eno
-4geny
-1geo
-ge3om
-g4ery
-5ge1si
-geth5
-4ge1to
-ge4ty
-ge4v
-4g1g2
-g2ge
-g3ger
-gglu5
-ggl2
-g1go4
-gh3in
-gh5out
-ghou2
-gh4to
-5gi.
-1g2i4a
-gi2a5r
-g1ic
-5gi3c2i1a
-g2i1ci
-g4i1co
-gien5
-g2ie4
-5gies.
-gil4
-g3i1men
-3g4in.
-g4in5ge
-5g4i2n1s2
-5g2io
-3g4ir
-gir4l
-g3is1l2
-gi4u
-5g2iv
-3giz
-gl2
-gla4
-gl2ad5i
-gla2d
-5glas
-1gle
-gli4b
-g3l2ig
-3glo
-glo3r
-g1m
-g4my
-g1n4a
-g4na.
-gne4t4t2
-g1ni
-g2n1in
-g4n2i4o
-g1no
-g4no4n
-1go
-3go.
-gob5
-5goe
-3g4o4g
-go3is
-goi2
-go2n2
-4g3o3n1a
-gon5do5
-g2ond
-go3ni
-5goo2
-go5riz
-gor5ou2
-5gos.
-gov1
-g3p
-1gr
-4gra1d2a
-gra2d
-g4r2ai2
-gra2n2
-5gra4ph.
-g5ra3ph4er
-5graph1ic
-gr4aphi
-4g3ra1phy
-4gray
-gre4n
-4gress.
-gr2e2ss
-4grit
-g4ro
-gruf4
-gs2
-g5ste
-gth3
-gu4a
-3guar2d
-gu2a2r
-2gue
-5gui5t
-g2ui2
-3gun
-3g2us
-4gu4t
-g3w
-1gy
-2g5y3n
-gy5ra
-h3ab4l2
-ha2ch4
-hae4m
-hae4t
-h5agu
-ha3la
-hala3m
-ha4m
-han4ci
-ha2n
-han4cy
-5hand.
-h4and
-h2an4g
-hang5er
-han1g5o
-h5a5niz
-ha4n4k2
-han4te
-han1t
-ha2p3l2
-ha2p5t
-ha3ra2n
-h2a2r
-ha5r2as
-har2d
-hard3e
-har4le4
-har1l
-harp5en
-har2p
-har5ter
-ha2s5s
-haun4
-5haz
-haz3a1
-h1b
-1hea2d1
-3he2a2r
-he4ca2n
-he1ca
-h5ecat
-h4ed
-h4e5do5
-he3l4i
-hel4lis
-hel1l
-hell2i
-hel4ly
-h5elo
-he4m4p
-he2n
-he1na4
-hen5at
-he1o5r
-hep5
-h4er1a
-hera3p
-her4ba
-h2er1b
-here5a
-h3ern
-h5er1ou2
-h2ero
-h3ery
-h1es
-he2s5p
-he4t
-he2t4ed
-h4eu4
-h1f
-h1h
-hi5a2n
-h2i1a
-hi4co
-high5
-h2ig
-h4il2
-himer4
-h4i1na
-hion4e
-h2io
-hio2n
-h2i4p
-hir4l
-h4ir
-hi3ro
-hir4p
-hir4r4
-his3el
-h4ise
-h4i2s4s
-hith5er
-h2ith
-hith2e
-h2i2v
-4hk
-4h1l4
-hla2n4
-h2lo
-hlo3ri
-4h1m
-hmet4
-2h1n
-h5odiz
-h5o2d1s2
-ho4g
-ho1ge4
-hol5a2r
-ho1la
-3hol4e
-ho4ma
-ho2me3
-ho1n4a
-ho2n
-ho5ny
-3hood
-hoo2
-hoo2n4
-hor5at
-ho1ra
-ho5r2is
-hort3e
-ho5ru
-hos4e
-ho5sen
-hos1p
-1ho2us
-hou2
-house3
-hov5el
-4h5p
-4hr4
-hree5
-hro5niz
-hro2n
-hro3po
-4h1s2
-h4s2h
-h4t2a2r
-h1ta
-ht1en
-ht5es
-h4ty
-hu4g
-hu4min
-hu1mi
-hun5ke
-hu4nk2
-hun4t
-hus3t4
-h2us
-hu4t
-h1w
-h4war4t
-hw2a2r
-hy3pe
-hy3ph
-hy2s
-2i1a
-i2al
-iam4
-iam5e1te
-i2a2n
-4ianc
-ian3i
-4ian4t
-ia5pe
-ia2ss4
-i4a1t2iv
-ia4tric
-ia1tr
-i4a2tu
-ibe4
-ib3er1a
-ib5ert
-ib5i1a
-ib3in
-ib5it.
-ibi2t
-ib5ite
-i1b2l2
-ib3li
-i5bo
-i1br
-i2b5ri
-i5bu4n
-4icam
-i1ca
-5icap
-4ic2a2r
-i4car.
-i4cara
-icas5
-i4cay
-iccu4
-ic3c
-4iceo
-4i2ch
-2i1ci
-i5c2id
-ic5i1na
-i2cin
-i2c2ip
-ic3i1pa
-i4c1ly4
-i1c4l4
-i2c5oc
-i1co
-4i1cr
-5icra
-i4cry
-ic4te
-i2c1t
-ic1tu2
-ic4t3u1a
-ic3u1la
-ic4um
-ic5uo
-i3cur
-2id
-i4dai2
-i1d2a
-id5anc
-ida2n
-id5d4
-ide3a4l
-ide4s2
-i2di
-id5i2a2n
-i1d4i3a
-idi4a2r
-i5d2ie4
-i1d3io
-idi5ou2
-id1it
-id5i1u
-i3dle
-i4dom
-i1do
-id3ow
-i4dr
-i2du
-id5uo
-2ie4
-ied4e
-5ie5ga
-ie2ld3
-ie1n5a4
-ien4e
-i5e4n1n2
-i3ent2i
-ien1t
-i1er.
-i3es2c
-i1est
-i3et
-4if.
-if5ero
-ifer1
-iff5en
-i4f1f
-if4fr
-4i2f3ic.
-i1fi
-i3f2ie4
-i3f4l2
-4i2ft
-2ig
-iga5b
-i1ga
-ig3er1a
-ight3i
-4igi
-i3gib
-ig3il4
-ig3in
-ig3it
-i4g4l2
-i2go
-ig3or
-ig5ot
-i5gre
-i1gr
-ig2u5i2
-ig1ur
-i3h
-4i5i4
-i3j
-4ik
-i1la
-il3a4b
-i4l4ade
-ila2d
-i2l5am
-ila5ra
-il2a2r
-i3leg
-il1er
-ilev4
-i2l5f
-il1i
-il3i1a
-il2ib
-il3io
-il4ist
-2il1it
-il2iz
-ill5ab
-il1l
-4i2l1n2
-il3o1q
-il4ty
-i4lt
-il5ur
-il3v
-i4mag
-i1ma
-im3age
-ima5ry
-im2a2r
-iment2a5r
-i1men
-i3men1t
-imen1ta
-4imet
-im1i
-im5i1d4a
-im2id
-imi5le
-i5m2ini
-4imit
-im4ni
-i4m1n
-i3mo2n
-i1mo
-i2mu
-im3u1la
-2in.
-i4n3au
-i1na
-4inav
-incel4
-in3cer
-4ind
-in5dling
-2ine
-i3nee
-in4er4a2r
-in1er
-iner1a
-i5n2e2ss
-i1nes
-4in1ga
-4inge
-in5gen
-4ingi
-in5gling
-ingl2
-4in1go
-4in1gu
-2ini
-i5ni.
-i4n4i1a
-in3i4o
-in1is
-i5ni4te.
-in2it
-in2ite
-5i3n2i1t2io
-ini1ti
-in3i1ty
-4i4nk2
-4i4n1l
-2i4n1n2
-2i1no
-i4no4c
-ino4s
-i4not
-2i2n1s2
-in3se
-insu1r5a
-in1su
-insu2r
-2int.
-in1t
-2in4th
-in1u
-i5n2us
-4iny
-2io
-4io.
-io1ge4
-io2gr
-i1ol
-io4m
-ion3at
-io2n
-io1n1a
-ion4ery
-ion1er
-ion3i
-i2o5ph
-ior3i
-i4os
-i4o5th
-i5oti
-io4to
-i4our
-iou2
-2ip
-ipe4
-iphr2as4
-ip4hr4
-ip3i
-ip4ic
-ip4re4
-ipr2
-ip3ul
-i3qua
-iqu2
-iq5ue1f
-iq3u2id
-iq2ui2
-iq3ui3t
-4ir
-i1ra
-i2ra4b
-i4rac
-ird5e
-ire4de
-i2r2ed
-i4re1f
-i4rel4
-i4res
-ir5gi
-irg2
-ir1i
-iri5de
-ir2id
-ir4is
-iri3tu
-5i5r2iz
-ir4min
-ir1m
-iro4g
-5iron.
-iro2n
-ir5ul
-2is.
-is5ag
-isa2
-is3a2r
-isas5
-2is1c
-is3ch2
-4ise
-is3er
-3i4s3f
-is5ha2n
-is2h
-is3ho2n3
-isho4
-ish5op
-is3i1b
-is2i4d
-i5sis
-is5i1t2iv
-isi1ti
-4is4k2
-isla2n4
-is1l2
-4is4m1s2
-i2s1m
-i2so
-iso5mer
-i3som
-iso2me
-is1p
-is2pi
-is4py
-4i2s1s
-is4sal
-is1sa2
-issen4
-is4s1e4s
-is4ta.
-is1ta
-is1te
-is1t2i
-ist4ly
-is2tl
-4istral
-ist4r
-is1tra
-i2su
-is5us
-4i3ta.
-i1ta
-ita4bi
-i2tab
-i4tag
-4ita5m
-i3ta2n
-i3tat
-2ite
-it3er1a
-i5ter1i
-it4es
-2ith
-i1ti
-4i1t2i1a
-4i2tic
-it3i1ca
-5i5tick1
-i2t3ig
-it5il1l
-i2tim
-2i1t2io
-4itis
-i4ti2s4m
-i2t5o5m
-i1to
-4ito2n
-i4tram
-i1tra
-it5ry
-4i4t3t2
-it3u1at
-i1tu
-itu1a
-i5tud2
-it3ul
-4itz.
-i4tz
-i1u
-2iv
-iv3el1l
-iv3en.
-i4v3er.
-i4vers.
-ive4r1s2
-iv5il.
-i2vil
-iv5io
-iv1it
-i5vore
-iv3o3ro
-i4v3ot
-4i5w
-ix4o
-4iy
-4iz2a2r2
-iza1
-i2z1i4
-5izon1t
-i1zo
-izo2n
-5ja
-jac4q
-ja4p
-1je
-je4r5s2
-4jes4t2ie4
-jest2i
-4jes2ty
-jew3
-jo4p
-5judg
-3ka.
-k3ab
-k5ag
-kais4
-kai2
-kal4
-k1b
-k2ed
-1kee
-ke4g
-ke5l2i
-k3en4d
-k1er
-kes4
-k3e2st.
-ke4ty
-k3f
-kh4
-k1i
-5ki.
-5k2ic
-k4il1l
-kilo5
-k4im
-k4in.
-kin4de
-k4ind
-k5i5n2e2ss
-k2ine
-ki1nes
-kin4g
-k2i4p
-kis4
-k5is2h
-kk4
-k1l
-4k3ley
-4k1ly
-k1m
-k5nes
-1k2no
-ko5r
-kos2h4
-k3ou2
-kro5n
-4k1s2
-k4sc
-ks4l2
-k4s4y
-k5t
-k1w
-lab3ic
-l4abo
-l4a2ci4
-l4ade
-la2d
-la3d2y
-lag4n
-la2m3o
-3l4and
-la2n
-lan4dl
-lan5et
-lan4te
-lan1t
-lar4g2
-l2a2r
-lar3i
-las4e
-la5ta2n
-la2ta
-4latel2i4
-4la1t2iv
-4lav
-la4v4a
-2l1b
-lbin4
-4l1c2
-lce4
-l3ci
-2ld
-l2de
-ld4ere
-ld4er1i
-ldi4
-ld5is1
-l3dr
-l4dri
-le2a
-le4bi
-l2e1b
-le2ft5
-le1f
-5leg.
-5le4g1g2
-le4mat
-le1ma
-lem5at1ic
-4len.
-3lenc
-5le2ne.
-1len1t
-le3ph
-le4pr2
-le2ra5b
-ler1a
-ler4e
-3lerg2
-3l4er1i
-l4ero
-les2
-le5s1co
-les2c
-5lesq
-3l2e2ss
-5less.
-l3e1va
-lev4er.
-lev1er
-lev4er1a
-lev4e4r1s2
-3ley
-4leye
-2lf
-l5fr
-4l1g4
-l5ga
-lg2a2r3
-l4ges
-l1go3
-2l3h
-li4ag
-l2i1a
-li2am4
-liar5iz
-li2a2r
-liar1i
-li4as
-li4a1to
-li5bi
-5lic2io
-l2i1ci
-li4cor
-li1co
-4li4c3s2
-4lict.
-li2c1t
-l4icu
-l3i1cy
-l3i1d2a
-l2id
-lid5er
-3li2di
-lif3er1
-l4i4f1f
-li4f4l2
-5ligate
-l2ig
-li1ga
-3ligh
-li4gra
-li1gr
-3l4ik
-4l4i4l
-lim4b2l2
-li4m1b
-lim3i
-li4mo
-l4i4m4p
-l4i1na
-1l4ine
-lin3ea
-l2in3i
-link5er
-l4i4nk2
-li5og
-l2io
-4l4iq
-lis4p
-l1it
-l2it.
-5lit3i1ca
-li1ti
-l4i2tic
-l5i5ti4c3s2
-liv3er
-l2iv
-l1iz
-4lj
-lka3
-l3kal4
-lka4t
-l1l
-l4law
-l2le
-l5le2a
-l3lec
-l3leg
-l3lel
-l3le4n
-l3le4t
-ll2i
-l2lin4
-l5l4i1na
-ll4o
-lloq2ui5
-llo1q
-lloqu2
-l2l5out
-llou2
-l5low
-2lm
-l5met
-lm3ing
-l4mo2d1
-l1mo
-lmo2n4
-2l1n2
-3lo.
-lob5al
-lo4ci
-4lof
-3log1ic
-l5o1go
-3logu
-lom3er
-lo2me
-5long
-lo2n
-lon4i
-l3o3niz
-lood5
-loo2
-5lo4pe.
-lop3i
-l3o4p1m
-lo1ra4
-lo4ra1to
-lo5r2ie4
-lor5ou2
-5los.
-los5et
-5los5o3phiz
-lo2so
-los4op
-los2oph
-5los5o1phy
-los4t
-lo4ta
-loun5d
-lou2
-2lout
-4lov
-2lp
-lpa5b
-l1pa
-l3pha
-l5phi
-lp5ing
-lpi2n
-l3pit
-l4p2l2
-l5pr2
-4l1r
-2l1s2
-l4sc
-l2se
-l4s2ie4
-4lt
-lt5ag
-l1ta
-ltane5
-lta2n
-l1te
-lten4
-lter1a4
-lth3i
-l5ties.
-lt2ie4
-ltis4
-l1tr
-l1tu2
-ltu1r3a
-lu5a
-lu3br
-lu2ch4
-lu3ci
-lu3en
-luf4
-lu5id
-l2ui2
-lu4ma
-5lu1mi
-l5umn.
-lu4m1n
-5lum3n4i1a
-lu3o
-luo3r
-4lup
-lu2ss4
-l2us
-lus3te
-1lut
-l5ven
-l5vet4
-2l1w
-1ly
-4lya
-4ly1b
-ly5me4
-ly3no
-2lys4
-l5y3s2e
-1ma
-2mab
-ma2ca
-ma5ch2ine
-ma2ch
-ma4ch1in
-ma4c4l4
-mag5in
-mag1i
-5mag1n
-2mah
-ma2id5
-mai2
-4ma2ld
-ma3l2ig
-mal1i
-ma5lin
-mal4l2i
-mal1l
-mal4ty
-ma4lt
-5ma3n4i1a
-ma2n
-man5is
-man3iz
-4map
-ma5ri2ne.
-m2a2r
-mar1i
-mar2in4e
-ma5r2iz
-mar4ly
-mar1l
-mar3v
-ma5sce
-mas4e
-mas1t
-5mate
-m4ath3
-ma3tis
-4mati3za1
-ma1tiz
-4m1b
-m1ba4t5
-m5bil
-m4b3ing
-mb2i4v
-4m5c
-4me.
-2med
-4med.
-5me3d4i3a
-m4edi
-me3d2ie4
-m5e5d2y
-me2g
-mel5o2n
-me4l4t
-me2m
-me1m1o3
-1men
-me1n4a
-men5ac
-men4de
-4mene
-men4i
-me2n1s4
-men1su5
-3men1t
-men4te
-me5o2n
-m5er1sa2
-me4r1s2
-2mes
-3mest2i
-me4ta
-met3a2l
-me1te
-me5thi
-m4etr
-5met3ric
-me5tr2ie4
-me3try
-me4v
-4m1f
-2mh
-5mi.
-m2i3a
-mi1d4a
-m2id
-mid4g
-m2ig4
-3mil3i1a
-mil1i
-m5i5l2ie4
-m4il1l
-mi1n4a
-3m4ind
-m5i3nee
-m2ine
-m4ingl2
-min5gli
-m5ing1ly
-min4t
-m4in1u
-miot4
-m2io
-m2is
-mi4s4er.
-m4ise
-mis3er
-mis5l2
-mis4t2i
-m5i4stry
-mist4r
-4m2ith
-m2iz
-4mk
-4m1l
-m1m
-mma5ry
-m1ma
-mm2a2r
-4m1n
-m1n4a
-m4n1in
-mn4o
-1mo
-4mocr
-5moc5ra1tiz
-mo2d1
-mo4go
-mois2
-moi2
-mo4i5se
-4m2ok
-mo5lest
-moles2
-mo3me
-mon5et
-mo2n
-mon5ge
-mo3n4i3a
-mon4i2s1m
-mon1is
-mon4ist
-mo3niz
-monol4
-mo3ny.
-mo2r
-4mo5ra.
-mo1ra
-mos2
-mo5sey
-mo3sp
-m4oth3
-m5ouf
-mou2
-3mo2us
-mo2v
-4m1p
-mpara5
-m1pa
-mp2a2r
-mpa5rab
-mp4a4r5i
-m3pe2t
-mphas4
-m2pi
-mp2i4a
-mp5ies
-mp2ie4
-m4p1i2n
-m5p4ir
-mp5is
-mpo3ri
-m1p4or
-mpos5ite
-m1pos
-m4po2us
-mpou2
-mpov5
-mp4tr
-m2p1t
-m2py
-4m3r
-4m1s2
-m4s2h
-m5si
-4mt
-1mu
-mul2a5r4
-mu1la
-5mu4lt
-mul1ti3
-3mum
-mun2
-4mup
-mu4u
-4mw
-1na
-2n1a2b
-n4abu
-4nac.
-na4ca
-n5a2c1t
-nag5er.
-nak4
-na4l1i
-na5l2i1a
-4na4lt
-na5mit
-n2a2n
-nan1ci4
-nan4it
-na4nk4
-nar3c
-n2a2r
-4nare
-nar3i
-nar4l
-n5ar1m
-n4as
-nas4c
-nas5t2i
-n2at
-na3ta2l
-na2ta
-nat5o5m2iz
-na2tom
-na1to
-n2au
-nau3se
-na2us
-3naut
-nav4e
-4n1b4
-nc2a2r5
-n1ca
-n4ces.
-n3cha
-n2ch
-n5cheo
-nche2
-n5ch4il2
-n3chis
-n2c1in
-n1ci
-n2c4it
-ncou1r5a
-n1co
-ncou2
-n1cr
-n1cu
-n4dai2
-n1d2a
-n5da2n
-n1de
-nd5e2st.
-ndes2
-ndi4b
-n5d2if
-n1dit
-n3diz
-n5du2c
-n1du
-ndu4r
-nd2we
-nd1w
-2ne.
-n3e2a2r
-n2e2b
-neb3u
-ne2c
-5neck1
-2ned
-ne4gat
-ne1ga
-ne4g5a1t2iv
-5nege
-ne4la
-nel5iz
-nel2i
-ne5mi
-ne4mo
-1nen
-4nene
-3neo
-ne4po
-ne2q
-n1er
-ne2ra5b
-ner1a
-n4er3a2r
-n2ere
-n4er5i
-ner4r4
-1nes
-2nes.
-4ne1sp
-2nest
-4nes4w2
-3net1ic
-ne4v
-n5eve
-ne4w
-n3f
-n4gab
-n1ga
-n3gel
-nge4n4e
-n1gen
-n5gere
-n3ger1i
-ng5ha
-n3gib
-ng1in
-n5git
-n4gla4
-ngl2
-ngov4
-n1go
-ng5s2h
-ngs2
-n1gu
-n4gum
-n2gy
-4n1h4
-nha4
-nhab3
-nhe4
-3n4i1a
-ni3a2n
-ni4ap
-ni3ba
-ni4b2l2
-n2i4d
-ni5di
-ni4er
-n2ie4
-ni2fi
-ni5ficat
-nifi1ca
-n5i1gr
-n2ig
-n4ik4
-n1im
-ni3m2iz
-nim1i
-n1in
-5ni2ne.
-n2ine
-nin4g
-n2i4o
-5n2is.
-nis4ta
-n2it
-n4ith
-3n2i1t2io
-ni1ti
-n3itor
-ni1to
-ni3tr
-n1j
-4nk2
-n5k2ero
-nk1er
-n3ket
-nk3in
-nk1i
-n1k1l
-4n1l
-n5m
-nme4
-nmet4
-4n1n2
-nne4
-nni3al
-n3n4i1a
-nn2i4v
-nob4l2
-no3ble
-n5o1c4l4
-4n3o2d
-3noe
-4nog
-no1ge4
-nois5i
-noi2
-no5l4i
-5nol1o1gis
-3nomic
-n5o5m2iz
-no4mo
-no3my
-no4n
-non4ag
-no1n1a
-non5i
-n5oniz
-4nop
-5nop5o5l2i
-no2r5ab
-no1ra
-no4rary
-nor2a2r
-4nos2c
-nos4e
-nos5t
-no5ta
-1nou2
-3noun
-nov3el3
-nowl3
-n1p4
-npi4
-npre4c
-npr2
-n1q
-n1r
-nru4
-2n1s2
-n2s5ab
-nsa2
-nsati4
-ns4c
-n2se
-n4s3e4s
-ns2id1
-ns2ig4
-n2s1l2
-n2s3m
-n4soc
-n1so
-ns4pe
-n5spi
-nsta5b2l2
-ns1ta
-ns2tab
-n1t
-n2ta4b
-n1ta
-nte4r3s2
-nt2i
-n5ti2b
-nti4er
-nt2ie4
-nti2f2
-n3t2ine
-n2t1in
-n4t3ing
-nt2i4p
-ntrol5l2i
-ntrol1l
-n4t4s2
-ntu3me
-n1tu
-n3tum
-nu1a
-nu4d
-nu5en
-nuf4fe
-nu4f1f
-n3ui4n
-n2ui2
-3nu3it
-n4um
-nu1me
-n5u1mi
-3nu4n
-n3uo
-nu3tr
-n1v2
-n1w4
-nym4
-nyp4
-4nz
-n3za1
-4oa
-oa2d3
-o5a5les2
-o2ale
-oard3
-o2a2r
-oas4e
-oast5e
-oat5i
-ob3a3b
-o5b2a2r
-o1be4l
-o1bi
-o2bin
-ob5ing
-o3br
-ob3ul
-o1ce
-o2ch4
-o3che4t
-oche2
-ocif3
-o1ci
-o4cil
-o4clam
-o1c4l4
-o4cod
-o1co
-oc3rac
-oc5ra1tiz
-ocre3
-5ocrit
-ocri2
-octo2r5a
-o2c1t
-oc1to
-oc3u1la
-o5cure
-od5d1ed
-od1d4
-od3ic
-o1d2i3o
-o2do4
-od4or3
-o4d5uct.
-o1du
-odu2c
-odu2c1t
-o4d5uc4t1s2
-o4el
-o5eng
-o3er
-oe4ta
-o3ev
-o2fi
-of5ite
-of4i4t4t2
-o2g5a5r
-o1ga
-o4g5a1t2iv
-o4ga1to
-o1ge
-o5gene
-o1gen
-o5geo
-o4ger
-o3g2ie4
-1o1gis
-og3it
-o4gl2
-o5g2ly
-3ogniz
-og1ni
-o4g4ro
-o1gr
-og2u5i2
-1o1gy
-2o2g5y3n
-o1h2
-ohab5
-oi2
-oic3es
-oi3der
-o2id
-oi4f1f4
-o2ig4
-oi5let
-o3ing
-oint5er
-oin1t
-o5i2s1m
-oi5so2n
-oi2so
-oist5en
-ois1te
-oi3ter
-o2ite
-o5j
-2ok
-o3ken
-ok5ie4
-ok1i
-o1la
-o4la2n
-ola2ss4
-o2l2d
-ol2d1e
-ol3er
-o3les2c
-oles2
-o3let
-ol4fi
-o2lf
-ol2i
-o3l2i1a
-o3lice
-ol5id.
-ol2id
-o3li4f
-o5l4i4l
-ol3ing
-o5l2io
-o5l2is.
-ol3is2h
-o5l2ite
-ol1it
-o5l2i1t2io
-oli1ti
-o5l2iv
-oll2i4e4
-ol1l
-oll2i
-ol5o3giz
-olo4r
-ol5p2l2
-o2lp
-o4l2t
-ol3ub
-ol3ume
-ol3un
-o5l2us
-ol2v
-o2ly
-o2m5ah
-o1ma
-oma5l
-om5a1tiz
-om2be
-o4m1b
-om4b2l2
-o2me
-om3e1n4a
-o1men
-om5er2se
-ome4r1s2
-o4met
-om5e3try
-om4etr
-o3m2i3a
-om3ic.
-om3i1ca
-o5m2id
-om1in
-o5m2ini
-5ommend
-om1m
-om1men
-omo4ge
-o1mo
-o4mo2n
-om3pi
-o4m1p
-ompro5
-ompr2
-o2n
-o1n1a
-on4ac
-o3n2a2n
-on1c
-3oncil
-on1ci
-2ond
-on5do
-o3nen
-o2n5est
-o1nes
-on4gu
-on1ic
-o3n2i4o
-on1is
-o5ni1u
-on3key
-o4nk2
-on4odi
-o4n3o2d
-on3o3my
-o2n3s2
-on5spi4
-onspi1r5a
-onsp4ir
-on1su4
-onten4
-on1t
-on3t4i
-onti2f5
-on5um
-on1va5
-on1v2
-oo2
-ood5e
-ood5i
-o2o4k
-oop3i
-o3ord
-oost5
-o2pa
-o2p2e5d
-op1er
-3oper1a
-4op4erag
-2oph
-o5pha2n
-o5ph4er
-op3ing
-opi2n
-o3pit
-o5po2n
-o4posi
-o1pos
-o1pr2
-op1u
-opy5
-o1q
-o1ra
-o5ra.
-o4r3ag
-or5al1iz
-oral1i
-or5an4ge
-ora2n
-or2ang
-ore5a
-o5re1a4l
-or3ei2
-or4e5s2h
-or5e2st.
-ores2t
-orew4
-or4gu
-org2
-4o5r2i3a
-or3i1ca
-o5ril
-or1in
-o1r2i1o
-or3i1ty
-o3ri1u
-or2mi
-or1m
-orn2e
-o5rof
-or3oug
-orou2
-or5pe
-or1p
-3orrh4
-or1r4
-or4se
-o4rs2
-ors5en
-orst4
-or3thi
-or3thy
-or4ty
-o5rum
-o1ry
-os3al
-osa2
-os2c
-os4ce
-o3scop
-os1co
-4oscopi
-o5scr
-os4i4e4
-os5i1t2iv
-osi1ti
-os3i1to
-os3i1ty
-o5si4u
-os4l2
-o2so
-o2s4pa
-os4po
-os2ta
-o5stati
-os5til
-ost2i
-os5tit
-o4ta2n
-o1ta
-otele4g
-ot3er.
-ot5e4r1s2
-o4tes
-4oth
-oth5e1si
-oth2e
-oth1es
-oth3i4
-ot3ic.
-ot5i1ca
-o3tice
-o3tif2
-o3tis
-oto5s2
-o1to
-ou2
-ou3b2l2
-ouch5i
-ou2ch
-ou5et
-ou4l
-ounc5er
-oun2d
-ou5v2
-ov4en
-over4ne
-ove4r3s2
-ov4ert
-o3vis
-o4vi1ti4
-o5v4ol
-ow3der
-ow3el
-ow5est3
-ow1i2
-own5i
-o4wo2
-oy1a
-1pa
-pa4ca
-pa4ce
-pa2c4t
-p4a2d
-5paga4n
-pa1ga
-p3agat
-p4ai2
-pa4i4n4
-p4al
-pa1n4a
-pa2n
-pan3el
-pan4ty
-pan1t
-pa3ny
-pa1p
-pa4pu
-para5b2l2
-p2a2r
-pa2rab
-par5age
-par5d2i
-3pare
-par5el
-p4a4r1i
-par4is
-pa2te
-pa5ter
-5pathic
-p4ath
-pa5thy
-pa4tric
-pa1tr
-pav4
-3pay
-4p1b
-pd4
-4pe.
-3pe4a
-pear4l
-pe2a2r
-pe2c
-2p2ed
-3pede
-3p4edi
-pe3d4i3a4
-ped4ic
-p4ee
-pee4d
-pek4
-pe4la
-pel2i4e4
-pel2i
-pe4n2a2n
-pe1na
-p4enc
-pen4th
-pen1t
-pe5o2n
-p4era.
-per1a
-pera5b2l2
-pe2ra4b
-p4erag
-p4er1i
-peri5st
-per2is
-per4mal
-per3m4
-per1ma
-per2me5
-p4ern
-p2er3o
-per3ti
-p4e5ru
-per1v
-pe2t
-pe5ten
-pe5tiz
-4pf
-4pg
-4ph.
-phar5i
-ph2a2r
-ph4e3no
-phe2n
-ph4er
-ph4es.
-ph1es
-ph1ic
-5ph2ie4
-ph5ing
-5phis1t2i
-3phiz
-p4h2l4
-3phob
-3phone
-pho2n
-5phoni
-pho4r
-4p4h1s2
-ph3t
-5phu
-1phy
-p2i3a
-pi2a2n4
-pi4c2ie4
-p2i1ci
-pi4cy
-p4id
-p5i1d2a
-pi3de
-5pi2di
-3piec
-p2ie4
-pi3en
-pi4grap
-p2ig
-pi1gr
-pi3lo
-pi2n
-p4in.
-p4ind4
-p4i1no
-3p2i1o
-pio2n4
-p3ith
-pi5tha
-pi2tu
-2p3k2
-1p2l2
-3pla2n
-plas5t
-pl2i3a
-pli5er
-pl2ie4
-4pl2ig
-pli4n
-ploi4
-plu4m
-plu4m4b
-4p1m
-2p3n
-po4c
-5pod.
-po5em
-po3et5
-5po4g
-poin2
-poi2
-5poin1t
-poly5t
-po2ly
-po4ni
-po2n
-po4p
-1p4or
-po4ry
-1pos
-po2s1s
-p4ot
-po4ta
-5poun
-pou2
-4p1p
-ppa5ra
-p1pa
-pp2a2r
-p2pe
-p4p2ed
-p5pel
-p3pen
-p3per
-p3pe2t
-ppo5s2ite
-p1pos
-pr2
-pray4e4
-5pre1c2i
-pre5co
-pre3e2m
-pre4f5ac
-pre1f
-pre1fa
-pre4la
-pr1e3r4
-p3re1s2e
-3pr2e2ss
-pre5ten
-pre3v2
-5pr2i4e4
-prin4t3
-pr2i4s
-pri2s3o
-p3ro1ca
-pr2oc
-prof5it
-pro2fi
-pro3l
-pros3e
-pro1t
-2p1s2
-p2se
-ps4h
-p4si1b
-2p1t
-p2t5a4b
-p1ta
-p2te
-p2th
-p1ti3m
-ptu4r
-p1tu
-p4tw4
-pub3
-pue4
-puf4
-pu4l3c2
-pu4m
-pu2n
-pur4r4
-5p2us
-pu2t
-5pute
-put3er
-pu3tr
-put4t1ed
-pu4t3t2
-put4t1in
-p3w
-qu2
-qua5v4
-2que.
-3quer
-3quet
-2rab
-ra3bi
-rach4e2
-ra2ch
-r5a1c4l4
-raf5fi
-ra2f
-ra4f1f4
-ra2f4t
-r2ai2
-ra4lo
-ram3et
-r2ami
-ra3ne5o
-ra2n
-ran4ge
-r2ang
-r4ani
-ra5no4
-rap3er
-3ra1phy
-rar5c
-r2a2r
-rare4
-rar5e1f
-4raril
-rar1i
-r2as
-ratio2n4
-ra1t2io
-rau4t
-ra5vai2
-ra2va
-rav3el
-ra5z2ie4
-ra2z1i
-r1b
-r4bab
-r4bag
-rbi2
-r2b3i4f
-r2bin
-r5b2ine
-rb5ing.
-rb4o
-r1c
-r2ce
-r1cen4
-r3cha
-r2ch
-rch4er
-rche2
-r4ci4b
-r1ci
-r2c4it
-rcum3
-r4dal
-r1d2a
-rd2i
-r1d4i4a
-rdi4er
-rd2ie4
-rd1in4
-rd3ing
-2re.
-re1a4l
-re3a2n
-re5ar1r4
-re2a2r
-5rea2v
-re4aw
-r5ebrat
-r2e1b
-re3br
-rec5ol1l
-re2col
-re1co
-re4c5ompe
-reco4m1p
-re4cre
-re1cr
-2r2ed
-re1de
-re3dis1
-r4edi
-red5it
-re4fac
-re1f
-re1fa
-re2fe
-re5fer.
-refer1
-re3fi
-re4fy
-reg3is
-re5it
-rei2
-re1l2i
-re5lu
-r4en4ta
-ren1t
-ren4te
-re1o
-re5pi2n
-re4posi
-re1po
-re1pos
-re1pu
-r1er4
-r4er1i
-r2ero4
-r4e5ru
-r4es.
-re4spi
-re1sp
-res4s5i4b
-r2e2ss
-res1si
-res2t
-re5s2ta2l
-res1ta
-r2e3st4r
-re4ter
-re4ti4z
-re3tri
-r4eu2
-re5u1t2i
-rev2
-re4val
-re1va
-rev3el
-r5ev5er.
-rev1er
-re5ve4r1s2
-re5vert
-re5vi4l
-re1vi
-rev5olu
-re4wh
-r1f
-r3fu4
-r4fy
-rg2
-rg3er
-r3get
-r3g1ic
-rgi4n
-rg3ing
-r5gis
-r5git
-r1gl2
-rgo4n2
-r1go
-r3gu
-rh4
-4rh.
-4rhal
-r2i3a
-ria4b
-ri4ag
-r4ib
-rib3a
-ric5as5
-ri1ca
-r4ice
-4r2i1ci
-5ri5c2id
-ri4c2ie4
-r4i1co
-rid5er
-r2id
-ri3enc
-r2ie4
-ri3en1t
-ri1er
-ri5et
-rig5a2n
-r2ig
-ri1ga
-5r4igi
-ril3iz
-ril1i
-5rima2n
-ri1ma
-rim5i
-3ri1mo
-rim4pe
-ri4m1p
-r2i1na
-5rina.
-r4in4d
-r2in4e
-rin4g
-r2i1o
-5riph
-r2ip
-riph5e
-ri2p2l2
-rip5lic
-r4iq
-r2is
-r4is.
-r2is4c
-r3is2h
-ris4p
-ri3ta3b
-ri1ta
-r5ited.
-r2ite
-ri2t1ed
-rit5er.
-rit5e4r1s2
-r4i2t3ic
-ri1ti
-ri2tu
-rit5ur
-riv5el
-r2iv
-riv3et
-riv3i
-r3j
-r3ket
-rk4le
-rk1l
-rk4lin
-r1l
-rle4
-r2led
-r4l2ig
-r4lis
-rl5is2h
-r3lo4
-r1m
-rma5c
-r1ma
-r2me
-r3men
-rm5e4r1s2
-rm3ing
-r4ming.
-r4m2io
-r3mit
-r4my
-r4n2a2r
-r1na
-r3nel
-r4n1er
-r5net
-r3ney
-r5nic
-r1nis4
-r3n2it
-r3n2iv
-rno4
-r4nou2
-r3nu
-rob3l2
-r2oc
-ro3cr
-ro4e
-ro1fe
-ro5fil
-ro2fi
-r2ok2
-ro5k1er
-5role.
-rom5e1te
-ro2me
-ro4met
-rom4i
-ro4m4p
-ron4al
-ro2n
-ro1n1a
-ron4e
-ro5n4is
-ron4ta
-ron1t
-1room
-roo2
-5root
-ro3pel
-rop3ic
-ror3i
-ro5ro
-ro2s5per
-ro2s4s
-ro4th2e
-r4oth
-ro4ty
-ro4va
-rov5el
-rox5
-r1p
-r4pe4a
-r5pen1t
-rp5er.
-r3pe2t
-rp4h4
-rp3ing
-rpi2n
-r3po
-r1r4
-rre4c
-rre4f
-r4re1o
-rre4s2t
-rr2i4o
-rr2i4v
-rro2n4
-rros4
-rrys4
-4rs2
-r1sa2
-rsa5ti
-rs4c
-r2se
-r3sec
-rse4cr
-r4s5er.
-rs3e4s
-r5se5v2
-r1s2h
-r5sha
-r1si
-r4si4b
-rso2n3
-r1so
-r1sp
-r5sw2
-rta2ch4
-r1ta
-r4tag
-r3t2e1b
-r3ten4d
-r1te5o
-r1ti
-r2t5i2b
-rt2i4d
-r4tier
-rt2ie4
-r3t2ig
-rtil3i
-rtil4l
-r4ti1ly
-r4tist
-r4t2iv
-r3tri
-rtr2oph4
-rt4s2h4
-r4t1s2
-ru3a
-ru3e4l
-ru3en
-ru4gl2
-ru3i4n
-r2ui2
-rum3p2l2
-ru4m2p
-ru2n
-ru4nk5
-run4ty
-run1t
-r5usc2
-r2us
-ru2t1i5n
-r4u1t2i
-rv4e
-rvel4i
-r3ven
-rv5er.
-r5vest
-rv4e2s
-r3vey
-r3vic
-r3v2i4v
-r3vo
-r1w
-ry4c
-5rynge
-ryn5g
-ry3t
-sa2
-2s1ab
-5sack1
-sac3ri2
-s3a2c1t
-5sai2
-sa4l2a2r4
-s4a2l4m
-sa5lo
-sa4l4t
-3sanc
-sa2n
-san4de
-s4and
-s1ap
-sa5ta
-5sa3t2io
-sa2t3u
-sau4
-sa5vor
-5saw
-4s5b
-scan4t5
-s1ca
-sca2n
-sca4p
-scav5
-s4ced
-4s3cei2
-s4ces
-s2ch2
-s4cho2
-3s4c2ie4
-s1ci
-5sc4in4d
-s2cin
-scle5
-s1c4l4
-s4cli
-scof4
-s1co
-4scopy5
-scou1r5a
-scou2
-s1cu
-4s5d
-4se.
-se4a
-seas4
-sea5w
-se2c3o
-3se2c1t
-4s4ed
-se4d4e
-s5edl
-se2g
-se1g3r
-5sei2
-se1le
-5se2l2f
-5selv
-4se1me
-se4mol
-se1mo
-sen5at
-se1na
-4senc
-sen4d
-s5e2ned
-sen5g
-s5en1in
-4sen4t1d
-sen1t
-4sen2tl
-se2p3a3
-4s1er.
-s4er1l
-s2er4o
-4ser3vo
-s1e4s
-s4e5s2h
-ses5t
-5se5um
-s4eu
-5sev
-sev3en
-sew4i2
-5sex
-4s3f
-2s3g
-s2h
-2sh.
-sh1er
-5shev
-sh1in
-sh3io
-3sh2i4p
-sh2i2v5
-sho4
-sh5o2l2d
-sho2n3
-shor4
-short5
-4sh1w
-si1b
-s5ic3c
-3si2de.
-s2id
-5side4s2
-5si2di
-si5diz
-4sig1n4a
-s2ig
-sil4e
-4si1ly
-2s1in
-s2i1na
-5si2ne.
-s2ine
-s3ing
-1s2io
-5sio2n
-sio1n5a
-s4i2r
-si1r5a
-1sis
-3s2i1t2io
-si1ti
-5si1u
-1s2iv
-5siz
-sk2
-4ske
-s3ket
-sk5ine
-sk1i
-sk5in4g
-s1l2
-s3lat
-s2le
-sl2ith5
-sl1it
-2s1m
-s3ma
-smal1l3
-sma2n3
-smel4
-s5men
-5s4m2ith
-smo2l5d4
-s1mo
-s1n4
-1so
-so4ce
-so2ft3
-so4lab
-so1la
-so2l3d2
-so3lic
-sol2i
-5sol2v
-3som
-3s4on.
-so2n
-so1n1a4
-son4g
-s4op
-5soph1ic
-s2oph
-s5o3phiz
-s5o1phy
-sor5c
-sor5d
-4sov
-so5vi
-2s1pa
-5sp4ai2
-spa4n
-spen4d
-2s5peo
-2sper
-s2phe
-3sph4er
-spho5
-spil4
-sp5ing
-spi2n
-4s3p2i1o
-s4p1ly
-s1p2l2
-s4po2n
-s1p4or4
-4sp4ot
-squal4l
-squ2
-s1r
-2ss
-s1sa2
-ssas3
-s2s5c
-s3sel
-s5sen5g
-s4ses.
-ss1e4s
-s5set
-s1si
-s4s2ie4
-ssi4er
-s4s5i1ly
-s4s1l2
-ss4li
-s4s1n4
-sspen4d4
-ss2t
-ssu1r5a
-s1su
-ssu2r
-ss5w2
-2st.
-s2tag
-s1ta
-s2ta2l
-stam4i
-5st4and
-sta2n
-s4ta4p
-5stat.
-s4t1ed
-stern5i
-s5t2ero
-ste2w
-ste1w5a
-s3th2e
-st2i
-s4ti.
-s5t2i1a
-s1tic
-5s4tick1
-s4t2ie4
-s3tif2
-st3ing
-s2t1in
-5st4ir
-s1tle
-s2tl
-5stock1
-s1to
-sto2m3a
-5stone
-sto2n
-s4top
-3store
-st4r
-s4tra2d
-s1tra
-5stra2tu
-s4tray
-s4tr2id
-4stry
-4st3w4
-s2ty
-1su
-su1al
-su4b3
-su2g3
-su5is
-s2ui2
-suit3
-s4ul
-su2m
-su1m3i
-su2n
-su2r
-4sv
-sw2
-4s1wo2
-s4y
-4sy1c
-3syl
-syn5o
-sy5rin
-1ta
-3ta.
-2tab
-ta5bles2
-tab2l2
-5tab5o5l1iz
-tabol2i
-4t4a2ci
-ta5do
-ta2d
-4ta2f4
-tai5lo
-tai2
-ta2l
-ta5la
-tal5en
-t2ale
-tal3i
-4talk
-tal4lis
-tal1l
-tall2i
-ta5log
-ta5mo
-tan4de
-ta2n
-t4and
-1tan1ta3
-tan1t
-ta5per
-ta5p2l2
-tar4a
-t2a2r
-4tar1c
-4tare
-ta3r2iz
-tar1i
-tas4e
-ta5s4y
-4tat1ic
-ta4tur
-ta2tu
-taun4
-tav4
-2taw
-tax4is
-tax3i
-2t1b
-4tc
-t4ch
-tch5e4t
-tche2
-4t1d
-4te.
-te2ad4i
-tea2d1
-4tea2t
-te1ce4
-5te2c1t
-2t1ed
-t4e5di
-1tee
-teg4
-te5ger4
-te5gi
-3tel.
-tel2i4
-5te2l1s2
-te2ma2
-tem3at
-3ten2a2n
-te1na
-3tenc
-3tend
-4te1nes
-1ten1t
-ten4tag
-ten1ta
-1teo
-te4p
-te5pe
-ter3c
-5ter3d
-1ter1i
-ter5ies
-ter2ie4
-ter3is
-teri5za1
-5t4er3n2it
-ter5v
-4tes.
-4t2e2ss
-t3ess.
-teth5e
-3t4eu
-3tex
-4tey
-2t1f
-4t1g
-2th.
-tha2n4
-th2e
-4thea
-th3eas
-the5a2t
-the3is
-thei2
-3the4t
-th5ic.
-th5i1ca
-4th4il2
-5th4i4nk2
-4t4h1l4
-th5ode
-5thod3ic
-4thoo2
-thor5it
-tho5riz
-2t4h1s2
-1t2i1a
-ti4ab
-ti4a1to
-2ti2b
-4tick1
-t4i1co
-t4ic1u
-5ti2di
-t2id
-3tien
-t2ie4
-tif2
-ti5fy
-2t2ig
-5tigu
-til2l5in4
-til1l
-till2i
-1tim
-4ti4m1p
-tim5ul
-ti2mu
-2t1in
-t2i1na
-3ti2ne.
-t2ine
-3t2ini
-1t2io
-ti5oc
-tion5ee
-tio2n
-5tiq
-ti3sa2
-3t4ise
-ti2s4m
-ti5so
-tis4p
-5tisti1ca
-tis1t2i
-tis1tic
-ti3tl
-ti4u
-1t2iv
-ti1v4a
-1tiz
-ti3za1
-ti3ze4n
-ti2ze
-2tl
-t5la
-tla2n4
-3tle.
-3tled
-3tles.
-tles2
-t5let.
-t5lo
-4t1m
-tme4
-2t1n2
-1to
-to3b
-to5crat
-4to2do4
-2tof
-to2gr
-to5ic
-toi2
-to2ma
-to4m4b
-to3my
-ton4a4l1i
-to2n
-to1n1a
-to3n2at
-4tono
-4tony
-to2ra
-to3r2ie4
-tor5iz
-tos2
-5tour
-tou2
-4tout
-to3w2a2r
-4t1p
-1tra
-t2ra3b
-tra5ch
-tr4a2ci4
-tra2c4it
-trac4te
-tra2c1t
-tr2as4
-tra5ven
-trav5e2s5
-tre5f
-tre4m
-trem5i
-5tr2i3a
-tri5ces
-tr4ice
-5tri3c2i1a
-t4r2i1ci
-4tri4c3s2
-2trim
-tr2i4v
-tro5m4i
-tron5i
-tro2n
-4trony
-tro5phe
-tr2oph
-tro3sp
-tro3v
-tr2u5i2
-tr2us4
-4t1s2
-t4sc
-ts2h4
-t4sw2
-4t3t2
-t4tes
-t5to
-t1tu4
-1tu
-tu1a
-tu3a2r
-tu4b4i
-tud2
-4tue
-4tuf4
-5t2u3i2
-3tum
-tu4nis
-tu1ni
-2t3up.
-3ture
-5turi
-tur3is
-tur5o
-tu5ry
-3t2us
-4tv
-tw4
-4t1wa
-twis4
-twi2
-4t1wo2
-1ty
-4tya
-2tyl
-type3
-ty5ph
-4tz
-t2z4e
-4uab
-uac4
-ua5na
-ua2n
-uan4i
-uar5an1t
-u2a2r
-uara2n
-uar2d
-uar3i
-uar3t
-u1at
-uav4
-ub4e
-u4bel
-u3ber
-u4b2ero
-u1b4i
-u4b5ing
-u3b4le.
-ub2l2
-u3ca
-uci4b
-u1ci
-u2c4it
-ucle3
-u1c4l4
-u3cr
-u3cu
-u4cy
-ud5d4
-ud3er
-ud5est
-udes2
-ude1v4
-u1dic
-ud3ied
-ud2ie4
-ud3ies
-ud5is1
-u5dit
-u4do2n
-u1do
-ud4si
-u2d1s2
-u4du
-u4ene
-ue2n1s4
-uen4te
-uen1t
-uer4il
-uer1i
-3u1fa
-u3f4l2
-ugh3e2n
-ug5in
-2ui2
-uil5iz
-uil1i
-ui4n
-u1ing
-uir4m
-u4ir
-ui1ta4
-u2iv3
-ui4v4er.
-u5j
-4uk
-u1la
-ula5b
-u5lati
-ul2ch4
-u4l1c2
-5ulche2
-ul3der
-u2ld
-ul2de
-ul4e
-u1len
-ul4gi
-u4l1g4
-ul2i
-u5l2i1a
-ul3ing
-ul5is2h
-ul4l2a2r
-ul1l
-ul4li4b
-ull2i
-ul4lis
-4u2l3m
-u1l4o
-4u2l1s2
-uls5e4s
-ul2se
-ul1ti
-u4lt
-ul1tra3
-ul1tr
-4ul1tu2
-u3lu
-ul5ul
-ul5v
-u2m5ab
-u1ma
-um4bi
-u4m1b
-um4b1ly
-umb2l2
-u1mi
-u4m3ing
-umor5o
-u1mo
-umo2r
-u4m2p
-un2at4
-u1na
-u2ne
-un4er
-u1ni
-un4im
-u2n1in
-un5is2h
-un2i3v
-u2n3s4
-un4sw2
-un2t3a4b
-un1t
-un1ta
-un4ter.
-un4tes
-unu4
-un5y
-u4n5z
-u4o4rs2
-u5os
-u1ou2
-u1pe
-upe4r5s2
-u5p2i3a
-up3ing
-upi2n
-u3p2l2
-u4p3p
-upport5
-up1p4or
-up2t5i2b
-u2p1t
-up1tu4
-u1ra
-4ura.
-u4rag
-u4r2as
-ur4be
-ur1b
-ur1c4
-ur1d
-ure5a2t
-ur4fer1
-ur1f
-ur4fr
-u3rif
-uri4fic
-uri1fi
-ur1in
-u3r2i1o
-u1rit
-ur3iz
-ur2l
-url5ing.
-ur4no4
-uros4
-ur4pe
-ur1p
-ur4pi
-urs5er
-u4rs2
-ur2se
-ur5tes
-ur3th2e
-ur1ti4
-ur4t2ie4
-u3ru
-2us
-u5sa2d
-usa2
-u5sa2n
-us4ap
-usc2
-us3ci
-use5a
-u5s2i1a
-u3sic
-us4lin
-us1l2
-us1p
-us5s1l2
-u2ss
-us5tere
-us1t4r
-u2su
-usu2r4
-u2ta4b
-u1ta
-u3tat
-4u4te.
-4utel
-4uten
-uten4i
-4u1t2i
-uti5l2iz
-util1i
-u3t2ine
-u2t1in
-ut3ing
-utio1n5a
-u1t2io
-utio2n
-u4tis
-5u5tiz
-u4t1l
-u2t5of
-u1to
-uto5g
-uto5mat1ic
-uto2ma
-u5to2n
-u4tou2
-u4t1s4
-u3u
-uu4m
-u1v2
-ux1u3
-u2z4e
-1va
-5va.
-2v1a4b
-vac5il
-v4a2ci
-vac3u
-vag4
-va4ge
-va5l2i4e4
-val1i
-val5o
-val1u
-va5mo
-va5niz
-va2n
-va5pi
-var5ied
-v2a2r
-var1i
-var2ie4
-3vat
-4ve.
-4ved
-veg3
-v3el.
-vel3l2i
-vel1l
-ve4lo
-v4e1ly
-ven3om
-v4eno
-v5enue
-v4erd
-5v2e2re.
-v4erel
-v3eren
-ver5enc
-v4eres
-ver3ie4
-ver1i
-vermi4n
-ver3m4
-3ver2se
-ve4r1s2
-ver3th
-v4e2s
-4ves.
-ves4te
-ve4te
-vet3er
-ve4ty
-vi5al1i
-v2i1a
-vi2al
-5vi2a2n
-5vi2de.
-v2id
-5vi2d1ed
-4v3i1den
-5vide4s2
-5vi2di
-v3if
-vi5gn
-v2ig
-v4ik4
-2vil
-5v2il1it
-vil1i
-v3i3l2iz
-v1in
-4vi4na
-v2inc
-v4in5d
-4ving
-vi1o3l
-v2io
-v3io4r
-vi1ou2
-v2i4p
-vi5ro
-v4ir
-vis3it
-vi3so
-vi3su
-4vi1ti
-vit3r
-4vi1ty
-3v2iv
-5vo.
-voi4
-3v2ok
-vo4la
-v5ole
-5vo4l2t
-3vol2v
-vom5i
-vo2r5ab
-vo1ra
-vori4
-vo4ry
-vo4ta
-4vo1tee
-4vv4
-v4y
-w5ab2l2
-2wac
-wa5ger
-wa2g5o
-wait5
-wai2
-w5al.
-wam4
-war4t
-w2a2r
-was4t
-wa1te
-wa5ver
-w1b
-wea5r2ie4
-we2a2r
-wear1i
-we4ath3
-wea2t
-we4d4n4
-weet3
-wee5v
-wel4l
-w1er
-west3
-w3ev
-whi4
-wi2
-wil2
-wil2l5in4
-wil1l
-will2i
-win4de
-w4ind
-win4g
-w4ir4
-3w4ise
-w2ith3
-wiz5
-w4k
-wl4es2
-wl3in
-w4no
-1wo2
-wom1
-wo5v4en
-w5p
-wra4
-wri4
-wri1ta4
-w3s2h
-ws4l2
-ws4pe
-w5s4t
-4wt
-wy4
-x1a
-xac5e
-x4a2go
-xam3
-x4ap
-xas5
-x3c2
-x1e
-xe4cu1to
-xe1cu
-xe3c4ut
-x2ed
-xer4i
-x2e5ro
-x1h
-xhi2
-xh4il5
-xhu4
-x3i
-x2i5a
-xi5c
-xi5di
-x2id
-x4ime
-xi5m2iz
-xim1i
-x3o
-x4ob
-x3p
-xp4an4d
-x1pa
-xpa2n
-xpec1to5
-xpe2c
-xpe2c1t
-x2p2e3d
-x1t2
-x3ti
-x1u
-xu3a
-xx4
-y5ac
-3y2a2r4
-y5at
-y1b
-y1c
-y2ce
-yc5er
-y3ch
-ych4e2
-ycom4
-y1co
-ycot4
-y1d
-y5ee
-y1er
-y4er1f
-yes4
-ye4t
-y5gi
-4y3h
-y1i
-y3la
-ylla5b2l2
-yl1l
-y3lo
-y5lu
-ymbol5
-y4m1b
-yme4
-ym1pa3
-y4m1p
-yn3c4hr4
-yn2ch
-yn5d
-yn5g
-yn5ic
-5ynx
-y1o4
-yo5d
-y4o5g
-yom4
-yo5net
-yo2n
-y4o2n3s2
-y4os
-y4p2ed
-yper5
-yp3i
-y3po
-y4po4c
-yp2ta
-y2p1t
-y5pu
-yra5m
-yr5i3a
-y3ro
-yr4r4
-ys4c
-y3s2e
-ys3i1ca
-y1s3io
-3y1sis
-y4so
-y2ss4
-ys1t
-ys3ta
-ysu2r4
-y1su
-y3thin
-yt3ic
-y1w
-za1
-z5a2b
-z2a2r2
-4zb
-2ze
-ze4n
-ze4p
-z1er
-z2e3ro
-zet4
-2z1i
-z4il
-z4is
-5zl
-4zm
-1zo
-zo4m
-zo5ol
-zoo2
-zte4
-4z1z2
-z4zy
-.as9s8o9c8i8a8te.
-.as1so
-.asso1ci
-.asso3c2i1a
-.as9s8o9c8i8a8t8es.
-.de8c9l8i9n8a9t8i8on.
-.de1c4l4
-.decl4i1na
-.declin2at
-.declina1t2io
-.declinatio2n
-.ob8l8i8g9a9t8o8ry.
-.ob2l2
-.obl2ig
-.obli1ga
-.obliga1to
-.obligato1ry
-.ph8i8l9a8n9t8h8r8o8p8ic.
-.ph4il2
-.phi1la
-.phila2n
-.philan1t
-.philant4hr4
-.philanthrop3ic
-.pr8e8s8e8nt.
-.p3re1s2e
-.presen1t
-.pr8e8s8e8n8ts.
-.presen4t4s2
-.pr8o8j8e8ct.
-.pro5j
-.pro1je
-.proje2c1t
-.pr8o8j8e8c8ts.
-.projec4t1s2
-.re8c9i9p8r8o8c9i9t8y.
-.re1c2i
-.rec2ip
-.recipr2
-.recipr2oc
-.re1cipro1ci
-.recipro2c1it
-.reciproci1ty
-.re9c8o8g9n8i9z8a8n8ce.
-.re1co
-.re2cog
-.rec3ogniz
-.recog1ni
-.recogniza1
-.recogniza2n
-.re8f9o8r9m8a9t8i8on.
-.re1f
-.re1fo
-.refo2r
-.refor1m
-.refor1ma
-.reforma1t2io
-.reformatio2n
-.re8t9r8i9b8u9t8i8on.
-.re3tri
-.retr4ib
-.retri3bu1t2io
-.retrib4u1t2i
-.retributio2n
-.ta9b8le.
-.2tab
-.tab2l2
-.ac8a8d9e9m8y.
-.a1ca
-.aca2d
-.acad4em
-.acade3my
-.ac8a8d9e9m8i8e8s.
-.academ2i4e4
-.ac9c8u9s8a9t8i8v8e.
-.ac3c
-.ac1c2us
-.accusa2
-.accusa1t2iv
-.ac8r8o9n8y8m.
-.acro2n
-.acronym4
-.ac8r8y8l9a8m8i8d8e.
-.acry3la
-.acrylam2id
-.ac8r8y8l9a8m8i8d8e8s.
-.acrylamide4s2
-.ac8r8y8l9a8l8d8e9h8y8d8e.
-.acryla2ld
-.acrylal2de
-.acrylalde1h4
-.acrylaldehy1d
-.ad8d9a9b8l8e.
-.ad1d2a
-.ad2d3a4b
-.addab2l2
-.ad8d9i9b8l8e.
-.addi1b2l2
-.ad8r8e8n9a9l8i8n8e.
-.a1dr
-.adre4
-.a5dren
-.adre1na
-.adrena4l1i
-.adrena1l4ine
-.ae8r8o9s8p8a8c8e.
-.ae4r
-.a2ero
-.aero2s4pa
-.aerospa4ce
-.af9t8e8r9t8h8o8u8g8h8t.
-.afterthou2
-.af9t8e8r9t8h8o8u8g8h8t8s.
-.afterthough4t1s2
-.ag8r8o8n9o9m8i8s8t.
-.a1gr
-.ag4ro
-.agro2n
-.agronom2is
-.ag8r8o8n9o9m8i8s8t8s.
-.agronomis4t1s2
-.al9g8e9b8r8a9i9c8a8l9l8y.
-.a4l1g4
-.alg2e1b
-.alge3br
-.algebr2ai2
-.algebrai1ca
-.algebraical1l
-.algebraical1ly
-.am9p8h8e8t9a9m8i8n8e.
-.a4m1p
-.amphe4t
-.amphe1ta
-.amphetam1in
-.amphetam2ine
-.am9p8h8e8t9a9m8i8n8e8s.
-.amphetami1nes
-.an9a9l8y8s8e.
-.3ana1ly
-.a1na
-.an4a2lys4
-.anal5y3s2e
-.an9a9l8y8s8e8d.
-.analy4s4ed
-.an8a8l8y9s8e8s.
-.analys1e4s
-.an9i8s8o9t8r8o8p9i8c.
-.ani2so
-.anisotrop3ic
-.an9i8s8o9t8r8o8p9i9c8a8l9l8y.
-.anisotropi1ca
-.anisotropical1l
-.anisotropical1ly
-.an9i8s8o8t9r8o9p8i8s8m.
-.anisotropi2s1m
-.an9i8s8o8t9r8o8p8y.
-.anisotropy5
-.an8o8m9a8l8y.
-.ano4
-.anoma5l
-.ano1ma
-.anoma1ly
-.an8o8m9a8l8i8e8s.
-.anomal1i
-.anomal2i4e4
-.an8t8i9d8e8r8i8v9a9t8i8v8e.
-.ant2id
-.antider1i
-.antider2i4v
-.antide4ri1va
-.antideri3vat
-.antider2iva1t2iv
-.an8t8i9d8e8r8i8v9a9t8i8v8e8s.
-.antiderivativ4e2s
-.an8t8i9h8o8l8o9m8o8r9p8h8i8c.
-.anti3h
-.antiholo1mo
-.antiholomo2r
-.antiholomor1p
-.antiholomorp4h4
-.antiholomorph1ic
-.an9t8i8n9o9m8y.
-.an2t1in
-.ant2i1no
-.antino3my
-.an9t8i8n9o9m8i8e8s.
-.antinom2ie4
-.an9t8i9n8u9c8l8e8a8r.
-.antin1u
-.antinucle3
-.antinu1c4l4
-.antinucle2a
-.antinucle2a2r
-.an9t8i9n8u9c8l8e9o8n.
-.antinucleo2n
-.an9t8i9r8e8v9o9l8u9t8i8o8n9a8r8y.
-.ant4ir
-.antirev2
-.antirev5olu
-.antirevo1lut
-.antirevol4u1t2i
-.antirevolutio1n5a
-.antirevolu1t2io
-.antirevolutio2n
-.antirevolution2a2r
-.ap8o8t8h9e9o9s8e8s.
-.ap4ot
-.ap4oth
-.apoth2e
-.apotheos4
-.apotheos1e4s
-.ap8o8t8h9e9o9s8i8s.
-.apotheo1sis
-.ap9p8e8n9d8i8x.
-.a4p1p
-.ap2pe
-.ap3pen
-.ar9c8h8i9m8e9d8e8a8n.
-.ar1c
-.ar2ch
-.archi2med
-.archimedea2n
-.ar9c8h8i9p8e8l9a8g8o.
-.arch2i4p
-.archipe4
-.archipe4la
-.archipela2go
-.ar9c8h8i9p8e8l9a9g8o8s.
-.ar9c8h8i8v8e.
-.arch2i2v
-.ar9c8h8i8v8e8s.
-.archiv4e2s
-.ar9c8h8i8v9i8n8g.
-.archiv1in
-.archi4ving
-.ar9c8h8i8v9i8s8t.
-.ar9c8h8i8v9i8s8t8s.
-.archivis4t1s2
-.ar9c8h8e9t8y8p9a8l.
-.arche2
-.arche4t
-.arche1ty
-.archety1pa
-.archetyp4al
-.ar9c8h8e9t8y8p9i9c8a8l.
-.archetyp3i
-.archetypi1ca
-.ar8c9t8a8n9g8e8n8t.
-.ar2c1t
-.arct5ang
-.arc1ta
-.arcta2n
-.arctan1gen
-.arctangen1t
-.ar8c9t8a8n9g8e8n8t8s.
-.arctangen4t4s2
-.as9s8i8g8n9a9b8l8e.
-.as1si
-.as4sig1n4a
-.ass2ig
-.assig2n1a2b
-.assignab2l2
-.as9s8i8g8n9o8r.
-.assig1no
-.as9s8i8g8n9o8r8s.
-.assigno4rs2
-.as9s8i8s8t9a8n8t9s8h8i8p.
-.as1sis
-.assis1ta
-.assista2n
-.assistan1t
-.assistan4t4s2
-.assistants2h4
-.assistant3sh2i4p
-.as9s8i8s8t9a8n8t9s8h8i8p8s.
-.assistantshi2p1s2
-.as8y8m8p9t8o9m8a8t8i8c.
-.as4y
-.asy4m1p
-.asym2p1t
-.asymp1to
-.asympto2ma
-.asymptomat1ic
-.as9y8m8p9t8o8t9i8c.
-.as8y8n9c8h8r8o9n8o8u8s.
-.asyn3c4hr4
-.asyn2ch
-.asynchro2n
-.asynchro1nou2
-.asynchrono2us
-.at8h9e8r9o9s8c8l8e9r8o9s8i8s.
-.4ath
-.ath2e
-.ath2ero
-.atheros2c
-.atheroscle5
-.atheros1c4l4
-.ath2eroscl4ero
-.atherosclero1sis
-.at9m8o8s9p8h8e8r8e.
-.a4t1m
-.at1mo
-.atmos2
-.atmo3sp
-.atmos2phe
-.atmo3sph4er
-.at9m8o8s9p8h8e8r8e8s.
-.at9t8r8i8b9u8t8e8d.
-.a4t3t2
-.attr4ib
-.attribu2t1ed
-.at9t8r8i8b9u8t9a8b8l8e.
-.attri4bu1ta
-.attribu2ta4b
-.attributab2l2
-.au9t8o9m8a9t8i8o8n.
-.au1to
-.auto2ma
-.automa1t2io
-.automatio2n
-.au9t8o8m9a9t8o8n.
-.automa1to
-.automato2n
-.au9t8o8m9a9t8a.
-.automa2ta
-.au9t8o9n8u8m9b8e8r9i8n8g.
-.au5to2n
-.auton5um
-.autonu4m1b
-.autonumber1i
-.autonumberin4g
-.au9t8o8n9o9m8o8u8s.
-.au4tono
-.autono4mo
-.autono3mo2us
-.autonomou2
-.au8t8o9r8o8u8n8d9i8n8g.
-.autorou2
-.autoroun2d
-.autoround1in
-.av9o8i8r9d8u9p8o8i8s.
-.avoi4
-.avo4ir
-.avoir1du
-.avoir4dup
-.avoirdupoi2
-.ba8n8d9l8e8a8d8e8r.
-.b4and
-.ban1dl
-.bandle2a
-.bandlea2d1
-.ba8n8d9l8e8a8d8e8r8s.
-.bandleade4r5s2
-.ba8n8k9r8u8p8t.
-.ba4nk2
-.bankru2p1t
-.ba8n8k9r8u8p8t9c8y.
-.bankrup4tc
-.bankrupt1cy
-.ba8n8k9r8u8p8t9c8i8e8s.
-.bankrupt1ci
-.bankruptc2ie4
-.ba8r9o8n8i8e8s.
-.b2a2r
-.ba5roni
-.baro2n
-.baron2ie4
-.ba8s8e9l8i8n8e9s8k8i8p.
-.basel2i
-.base1l4ine
-.baseli1nes
-.baselinesk2
-.baselinesk1i
-.baselinesk2i4p
-.ba9t8h8y8m9e9t8r8y.
-.1bat
-.b4ath
-.bathyme4
-.bathym4etr
-.bathyme3try
-.ba8t8h8y9s8c8a8p8h8e.
-.bathy2s
-.bathys4c
-.bathysca4p
-.bathys1ca
-.be8a8n9i8e8s.
-.bea2n
-.bea3nies
-.bean2ie4
-.be9h8a8v9i8o8u8r.
-.be1h4
-.behav1i
-.behavi1ou2
-.behav2io
-.behavi4our
-.be9h8a8v9i8o8u8r8s.
-.behaviou4rs2
-.be8v8i8e8s.
-.be1vi
-.bev2ie4
-.bi8b9l8i9o8g9r8a9p8h8y9s8t8y8l8e.
-.bi2b
-.bi1b2l2
-.bib3li
-.bibli5og
-.bibl2io
-.biblio2gr
-.biblio4g3ra1phy
-.bibliography2s
-.bibliographys1t
-.bibliographys2ty
-.bibliographys2tyl
-.bi9d8i8f9f8e8r9e8n9t8i8a8l.
-.b2i4d
-.bi2di
-.bid1if
-.bidi4f1f
-.bidiffer1
-.bidiffer3en1t
-.bidifferent2i
-.bidifferen1t2i1a
-.bidifferenti2al
-.bi8g9g8e8s8t.
-.b2ig
-.bi4g1g2
-.big2ge
-.bi8l8l9a8b8l8e.
-.1bil
-.bill5ab
-.bil1l
-.billab2l2
-.bi8o9m8a8t8h9e9m8a8t9i8c8s.
-.b2io
-.bio4m
-.bio1ma
-.biom4ath3
-.biomath5em
-.biomath2e
-.biomathe1ma
-.biomathemat1ic
-.biomathemati4c3s2
-.bi8o9m8e8d9i9c8a8l.
-.bio2me
-.bio2med
-.biom4edi
-.biomed3i1ca
-.bi8o9m8e8d9i9c8i8n8e.
-.biomed2i1ci
-.biomedi2cin
-.biomedic2ine
-.bi8o9r8h8y8t8h8m8s.
-.biorh4
-.biorhyt4h1m
-.biorhyth4m1s2
-.bi8t9m8a8p.
-.bi2t
-.bi4t1m
-.bit1ma
-.bit4map
-.bi8t9m8a8p8s.
-.bitma2p1s2
-.bl8a8n8d9e8r.
-.b2l2
-.b3l4and
-.bla2n
-.blan1de
-.bl8a8n8d9e8s8t.
-.blande4s2
-.bl8i8n8d9e8r.
-.bl4ind
-.blin1de
-.bl8o8n8d8e8s.
-.b4lo
-.blo2n
-.bl2ond
-.blon1de
-.blondes2
-.bl8u8e9p8r8i8n8t.
-.bluepr2
-.blueprin4t3
-.bl8u8e9p8r8i8n8t8s.
-.blueprin4t4s2
-.bo9l8o8m9e9t8e8r.
-.bolo2me
-.bolo4met
-.bolome1te
-.bo8o8k9s8e8l8l9e8r.
-.3boo2
-.bo2o4k
-.boo4k1s2
-.booksel1l
-.booksel2le
-.bo8o8k9s8e8l8l9e8r8s.
-.bookselle4r1s2
-.bo8o8l9e8a8n.
-.boole2a
-.boolea2n
-.bo8o8l9e8a8n8s.
-.boolea2n1s2
-.bo8r9n8o9l8o8g9i9c8a8l.
-.borno4
-.borno3log1ic
-.bornologi1ca
-.bo8t9u9l8i8s8m.
-.bo1tu
-.botul2i
-.botuli2s1m
-.br8u8s8q8u8e8r.
-.br2us
-.brusqu2
-.brus3quer
-.bu8f9f8e8r.
-.buf4fer1
-.bu4f1f
-.bu8f9f8e8r8s.
-.buffe4r1s2
-.bu8s8i8e8r.
-.bus5ie4
-.b2us
-.bu8s8i8e8s8t.
-.busi1est
-.bu8s8s8i8n8g.
-.bu2ss
-.bus1si
-.bus2s1in
-.buss3ing
-.bu8t8t8e8d.
-.but2t1ed
-.bu8z8z9w8o8r8d.
-.bu4z1z2
-.buzz1wo2
-.bu8z8z9w8o8r8d8s.
-.buzzwor2d1s2
-.ca9c8o8p8h9o9n8y.
-.ca1co
-.cac2oph
-.cacopho5ny
-.cacopho2n
-.ca9c8o8p8h9o9n8i8e8s.
-.caco5phoni
-.cacophon2ie4
-.ca8l8l9e8r.
-.cal1l
-.cal2le
-.ca8l8l9e8r8s.
-.calle4r1s2
-.ca8m9e8r8a9m8e8n.
-.cam5er1a
-.camera1men
-.ca8r8t9w8h8e8e8l.
-.cartw4
-.ca8r8t9w8h8e8e8l8s.
-.cartwhee2l1s2
-.ca9t8a8r8r8h8s.
-.ca2ta
-.cat2a2r
-.catar1r4
-.catarrh4
-.catarr4h1s2
-.ca8t9a9s8t8r8o8p8h9i8c.
-.catas1t4r
-.catastr2oph
-.catastroph1ic
-.ca8t9a9s8t8r8o8p8h9i9c8a8l8l8y.
-.catastrophi1ca
-.catastrophical1l
-.catastrophical1ly
-.ca8t9e9n8o8i8d.
-.cat4eno
-.catenoi2
-.cateno2id
-.ca8t9e9n8o8i8d8s.
-.catenoi2d1s2
-.ca8u9l8i9f8l8o8w9e8r.
-.cau4l2
-.caul2i
-.cauli4f4l2
-.cauliflow1er
-.ch8a8p9a8r9r8a8l.
-.chap2a2r4
-.cha1pa
-.chapar1r4
-.ch8a8r9t8r8e8u8s8e.
-.ch2a2r
-.chartr4eu2
-.chartre2us4
-.ch8e8m8o9t8h8e8r9a8p8y.
-.che2
-.che1mo
-.chem4oth3
-.chemoth2e
-.chemoth4er1a
-.chemothera3p
-.ch8e8m8o9t8h8e8r9a9p8i8e8s.
-.chemotherap2ie4
-.ch8l8o8r8o9m8e8t8h9a8n8e.
-.c4h1l4
-.ch2lo
-.chloro2me
-.chloro4met
-.chlorometha2n4
-.ch8l8o8r8o9m8e8t8h9a8n8e8s.
-.chlorometha1nes
-.ch8o9l8e8s9t8e8r8i8c.
-.3cho2
-.c3hol4e
-.choles2
-.choles1ter1i
-.ci8g9a9r8e8t8t8e.
-.c2ig
-.ci1ga
-.cig2a2r
-.cigare4t3t2
-.ci8g9a9r8e8t8t8e8s.
-.cigaret4tes
-.ci8n8q8u8e9f8o8i8l.
-.2cin
-.cin1q
-.cinqu2
-.cinque1f
-.cinque1fo
-.cinquefoi2
-.co9a8s8s8o9c8i8a9t8i8v8e.
-.c4oa
-.coa2ss
-.coas1so
-.coasso1ci
-.coasso3c2i1a
-.coassoci4a1t2iv
-.co9g8n8a8c.
-.2cog
-.cog1n4a
-.co9g8n8a8c8s.
-.cogna4c3s2
-.co9k8e8r9n8e8l.
-.c2ok
-.cok1er
-.coker3nel
-.co9k8e8r9n8e8l8s.
-.cokerne2l1s2
-.co8l9l8i8n9e8a9t8i8o8n.
-.col1l
-.coll2i
-.col2lin4
-.col1l4ine
-.collin3ea
-.collinea2t
-.collinea1t2io
-.collineatio2n
-.co8l9u8m8n8s.
-.colu4m1n
-.colum2n1s2
-.co8m9p8a8r9a8n8d.
-.co4m1p
-.compara5
-.com1pa
-.comp2a2r
-.compara2n
-.compar4and
-.co8m9p8a8r9a8n8d8s.
-.comparan2d1s2
-.co8m9p8e8n9d8i8u8m.
-.compendi1u
-.co8m9p8o9n8e8n8t9w8i8s8e.
-.compo2n
-.compo3nen
-.componen1t
-.componentw4
-.componentwis4
-.componentwi2
-.component3w4ise
-.co8m8p9t8r8o8l9l8e8r.
-.comp4tr
-.com2p1t
-.comptrol1l
-.comptrol2le
-.co8m8p9t8r8o8l9l8e8r8s.
-.comptrolle4r1s2
-.co8n9f8o8r8m9a8b8l8e.
-.co2n
-.con3f
-.con1fo
-.confo2r
-.confor1m
-.confor1ma
-.confor2mab
-.conformab2l2
-.co8n9f8o8r8m9i8s8t.
-.confor2mi
-.conform2is
-.co8n9f8o8r8m9i8s8t8s.
-.conformis4t1s2
-.co8n9f8o8r8m9i8t8y.
-.confor3mit
-.conformi1ty
-.co8n9g8r8e8s8s.
-.con3g
-.con1gr
-.congr2e2ss
-.co8n9g8r8e8s8s8e8s.
-.congress1e4s
-.co8n9t8r8i8b9u8t8e.
-.con5t
-.contr4ib
-.co8n9t8r8i8b9u8t8e8s.
-.co8n9t8r8i8b9u8t8e8d.
-.contribu2t1ed
-.co9r8e9l8a9t8i8o8n.
-.core1la
-.corela1t2io
-.corelatio2n
-.co9r8e9l8a9t8i8o8n8s.
-.corelatio2n3s2
-.co9r8e9l8i9g8i8o8n9i8s8t.
-.core1l2i
-.corel2ig
-.corel4igi
-.coreli5g2io
-.coreligion3i
-.coreligio2n
-.coreligion1is
-.co9r8e9l8i9g8i8o8n9i8s8t8s.
-.coreligionis4t1s2
-.co9r8e9o8p9s8i8s.
-.core1o
-.coreo2p1s2
-.coreop1sis
-.co9r8e9s8p8o8n9d8e8n8t.
-.core1sp
-.cores4po2n
-.coresp2ond
-.corespon1de
-.corespon1den
-.coresponden1t
-.co9r8e9s8p8o8n9d8e8n8t8s.
-.coresponden4t4s2
-.co9s8e9c8a8n8t.
-.cos4e
-.cose1ca
-.coseca2n
-.cosecan1t
-.co9t8a8n9g8e8n8t.
-.co4ta2n
-.co1ta
-.cot2ang
-.cotan1gen
-.cotangen1t
-.co8u8r9s8e8s.
-.cou2
-.cou4rs2
-.cour2se
-.cours3e4s
-.co9w8o8r8k9e8r.
-.co4wo2
-.cowork1er
-.co9w8o8r8k9e8r8s.
-.coworke4r1s2
-.cr8a8n8k9c8a8s8e.
-.cra2n
-.cra4nk2
-.crank1ca
-.cr8a8n8k9s8h8a8f8t.
-.cran4k1s2
-.cranks2h
-.cranksha2f
-.cranksha2ft
-.cr8o8c9o9d8i8l8e.
-.cr2oc
-.cro4cod
-.cro1co
-.cr8o8c9o9d8i8l8e8s.
-.crocodiles2
-.cr8o8s8s9h8a8t8c8h.
-.cro2s4s
-.cross2h
-.crossha4tc
-.crosshat4ch
-.cr8o8s8s9h8a8t8c8h8e8d.
-.crosshatche2
-.crosshat4ch4ed
-.cr8o8s8s9o8v8e8r.
-.cros1so
-.cros4sov
-.cr8y8p9t8o9g8r8a8m.
-.cry2p1t
-.cryp1to
-.crypto2gr
-.cr8y8p9t8o9g8r8a8m8s.
-.cryptogra4m1s2
-.cu8f8f9l8i8n8k.
-.c4uf
-.cu4f1f
-.cuff4l2
-.cufflin4
-.cuffl4i4nk2
-.cu8f8f9l8i8n8k8s.
-.cufflin4k1s2
-.cu9n8e8i9f8o8r8m.
-.3cun
-.cu2ne
-.cunei2
-.cunei1fo
-.cuneifo2r
-.cuneifor1m
-.cu8s9t8o8m9i8z9a9b8l8e.
-.1c2us
-.cus1to
-.custom2iz
-.customiza1
-.customiz5a2b
-.customizab2l2
-.cu8s9t8o8m9i8z8e.
-.customi2ze
-.cu8s9t8o8m9i8z8e8s.
-.cu8s9t8o8m9i8z8e8d.
-.da8c8h8s9h8u8n8d.
-.1d2a
-.da2ch4
-.dac4h1s2
-.dach4s2h
-.da8m9s8e8l9f8l8y.
-.da2m2
-.da4m1s2
-.dam5se2l2f
-.damself4l2
-.damself2ly5
-.da8m9s8e8l9f8l8i8e8s.
-.damselfl2ie4
-.da8c8t8y8l9o9g8r8a8m.
-.da2c1t
-.dac1ty
-.dac2tyl
-.dacty3lo
-.dactylo1gr
-.da8c8t8y8l9o9g8r8a8p8h.
-.da8t8a9b8a8s8e.
-.3dat
-.da2ta
-.da2tab
-.da8t8a9b8a8s8e8s.
-.databas1e4s
-.da8t8a9p8a8t8h.
-.dat5ap
-.datap5at
-.data1pa
-.datap4ath
-.da8t8a9p8a8t8h8s.
-.datapa2t4h1s2
-.da8t8e9s8t8a8m8p.
-.dat3est
-.dates1ta
-.datesta4m1p
-.da8t8e9s8t8a8m8p8s.
-.datestam2p1s2
-.de9c8l8a8r9a8b8l8e.
-.de4cl2a2r
-.decla2rab
-.declarab2l2
-.de9f8i8n9i9t8i8v8e.
-.de1f
-.de1fi
-.de2fin
-.def2ini
-.defin2it
-.defini1ti
-.defini1t2iv
-.de9l8e8c9t8a9b8l8e.
-.d5elec
-.dele2c1t
-.delec2ta4b
-.delec1ta
-.delectab2l2
-.de8m8i9s8e8m8i9q8u8a9v8e8r.
-.de4m2is
-.dem4ise
-.demisemi3qua
-.demisemiqu2
-.demisemiqua5v4
-.de8m8i9s8e8m8i9q8u8a9v8e8r8s.
-.demisemiquave4r1s2
-.de9m8o8c9r8a9t8i8s8m.
-.de4mocr
-.democrati2s4m
-.de8m8o8s.
-.demos2
-.de9r8i8v9a9t8i8v8e.
-.der2i4v
-.de4ri1va
-.deri3vat
-.der2iva1t2iv
-.de9r8i8v9a9t8i8v8e8s.
-.derivativ4e2s
-.di8a9l8e8c9t8i8c.
-.1d4i3a
-.di2al
-.di2ale
-.diale2c1t
-.di8a9l8e8c9t8i8c8s.
-.dialecti4c3s2
-.di8a9l8e8c9t8i9c8i8a8n.
-.dialect2i1ci
-.d2i1alecti3c2i1a
-.dialectici2a2n
-.di8a9l8e8c9t8i9c8i8a8n8s.
-.dialecticia2n1s2
-.di9c8h8l8o8r8o9m8e8t8h9a8n8e.
-.d4i2ch
-.dic4h1l4
-.dich2lo
-.dichloro2me
-.dichloro4met
-.dichlorometha2n4
-.di8f9f8r8a8c8t.
-.d1if
-.dif4fr
-.di4f1f
-.diffra2c1t
-.di8f9f8r8a8c8t8s.
-.diffrac4t1s2
-.di8f9f8r8a8c9t8i8o8n.
-.diffrac1t2io
-.diffractio2n
-.di8f9f8r8a8c9t8i8o8n8s.
-.diffractio2n3s2
-.di8r8e8r.
-.d4ir2
-.di1re
-.dir1er4
-.di8r8e9n8e8s8s.
-.dire1nes
-.diren2e2ss
-.di8s9p8a8r9a8n8d.
-.dis1
-.dis1p
-.di2s1pa
-.disp2a2r
-.dispara2n
-.dispar4and
-.di8s9p8a8r9a8n8d8s.
-.disparan2d1s2
-.di8s9t8r8a8u8g8h8t9l8y.
-.d4is3t
-.dist4r
-.dis1tra
-.distraugh3
-.distraugh2tl
-.distraught1ly
-.di8s9t8r8i8b9u8t8e.
-.distr4ib
-.di8s9t8r8i8b9u8t8e8s.
-.di8s9t8r8i8b9u8t8e8d.
-.distribu2t1ed
-.do8u9b8l8e9s8p8a8c8e.
-.dou2
-.dou3b2l2
-.dou5ble1sp
-.doubles2
-.double2s1pa
-.doublespa4ce
-.do8u9b8l8e9s8p8a8c9i8n8g.
-.doublesp4a2ci
-.doublespa2c1in
-.doublespac1ing
-.do8l8l9i8s8h.
-.dol1l
-.doll2i
-.dollis2h
-.dr8i8f8t9a8g8e.
-.1dr
-.dr4i2ft
-.drif1ta
-.dr8i8v9e8r8s.
-.dr2iv
-.drive4r1s2
-.dr8o8m9e9d8a8r8y.
-.dro2me
-.dro2med
-.drom2e2d2a
-.drome4dary
-.dromed2a2r
-.dr8o8m9e9d8a8r8i8e8s.
-.dromedar1i
-.dromedar2ie4
-.du9o8p9o9l8i8s8t.
-.duopol2i
-.du9o8p9o9l8i8s8t8s.
-.duopolis4t1s2
-.du9o8p9o8l8y.
-.duopo2ly
-.dy8s9l8e8x8i8a.
-.d2y
-.dys1l2
-.dys2le
-.dyslex3i
-.dyslex2i5a
-.dy8s9l8e8c9t8i8c.
-.dysle2c1t
-.ea8s8t9e8n8d9e8r8s.
-.east3
-.eas3ten
-.eas3tend
-.easten1de
-.eastende4r5s2
-.ec8o9n8o8m9i8c8s.
-.e1co
-.eco2n
-.eco3nomic
-.economi4c3s2
-.ec8o8n9o9m8i8s8t.
-.econom2is
-.ec8o8n9o9m8i8s8t8s.
-.economis4t1s2
-.ei9g8e8n9c8l8a8s8s.
-.ei2
-.e2ig2
-.ei1gen
-.eigen1c4l4
-.eigencla2ss
-.ei9g8e8n9c8l8a8s8s8e8s.
-.eigenclass1e4s
-.ei9g8e8n9v8a8l9u8e.
-.eigen1v2
-.eigen1va
-.eigenval1u
-.ei9g8e8n9v8a8l9u8e8s.
-.el8e8c8t8r8o9m8e8c8h8a8n9i9c8a8l.
-.5elec
-.ele2c1t
-.electro2me
-.electrome2ch
-.electrome5cha4n1ic
-.electromecha2n
-.electromechani1ca
-.el8e8c8t8r8o9m8e8c8h8a8n8o9a8c8o8u8s8t8i8c.
-.electromechano4
-.electromechan4oa
-.electromechanoa1co
-.electromechanoacou2
-.electromechanoaco2us
-.electromechanoacoust2i
-.electromechanoacous1tic
-.el8i8t9i8s8t.
-.el2i
-.el1it
-.eli1ti
-.el4itis
-.el8i8t9i8s8t8s.
-.elitis4t1s2
-.en9t8r8e9p8r8e9n8e8u8r.
-.en1t
-.entrepr2
-.entrepren4eu
-.en9t8r8e9p8r8e9n8e8u8r9i8a8l.
-.entrepreneur2i3a
-.entrepreneuri2al
-.ep9i9n8e8p8h9r8i8n8e.
-.epi2n
-.ep2ine
-.epinep4hr4
-.ep2inephr2in4e
-.eq8u8i9v8a8r8i9a8n8t.
-.equ2iv3
-.equi1va
-.equiv2a2r
-.equivar1i
-.equivar3i2a2n
-.equivar2i3a
-.equivar4ian4t
-.eq8u8i9v8a8r8i9a8n8c8e.
-.equivar4ianc
-.et8h9a8n8e.
-.etha2n4
-.et8h9y8l9e8n8e.
-.ev8e8r9s8i9b8l8e.
-.ev1er
-.eve4r1s2
-.ever1si
-.ever4si4b
-.eversi1b2l2
-.ev8e8r8t.
-.ev8e8r8t8s.
-.ever4t1s2
-.ev8e8r8t9e8d.
-.ever2t1ed
-.ev8e8r8t9i8n8g.
-.ever1ti
-.ever2t1in
-.ex9q8u8i8s9i8t8e.
-.exqu2
-.exq2ui2
-.exquis2ite
-.ex9t8r8a9o8r9d8i9n8a8r8y.
-.ex1t2
-.ex1tra
-.extr4ao
-.extraord2i
-.extraord1in4
-.extraor1di1na
-.extraordin2a2r
-.fa8l8l9i8n8g.
-.1fa
-.fal1l
-.fall2i
-.fal2lin4
-.fe8r8m8i9o8n8s.
-.fer1
-.fer3m4
-.fer4m2io
-.fermio2n
-.fermio2n3s2
-.fi9n8i8t8e9l8y.
-.1fi
-.2fin
-.f2ini
-.fin2it
-.fin2ite
-.finite1ly
-.fl8a9g8e8l9l8u8m.
-.f4l2
-.flag5el1l
-.fl8a9g8e8l9l8a.
-.flag4ella
-.fl8a8m9m8a9b8l8e8s.
-.flam1m
-.flam1ma
-.flam2mab
-.flammab2l2
-.flammables2
-.fl8e8d8g9l8i8n8g.
-.fledgl2
-.fl8o8w9c8h8a8r8t.
-.flow2ch
-.flowch2a2r
-.fl8o8w9c8h8a8r8t8s.
-.flowchar4t1s2
-.fl8u8o8r8o9c8a8r9b8o8n.
-.flu3o
-.fluo3r
-.fluor2oc
-.fluoro1ca
-.fluoroc2a2r
-.fluorocar1b
-.fluorocarb4o
-.fluorocarbo2n
-.fo8r9m8i9d8a9b8l8e.
-.for2mi
-.formi1d4a
-.form2id
-.formi2d3a4b
-.formidab2l2
-.fo8r9m8i9d8a9b8l8y.
-.formidab1ly
-.fo8r9s8y8t8h9i8a.
-.fo4rs2
-.fors4y
-.forsyth2i1a
-.fo8r8t8h9r8i8g8h8t.
-.fort4hr4
-.forthr2ig
-.fr8e8e9l8o8a8d8e8r.
-.freel4oa
-.freeloa2d3
-.fr8e8e9l8o8a8d8e8r8s.
-.freeloade4r5s2
-.fr8i8e8n8d9l8i8e8r.
-.fri2
-.fr2ie4
-.friendl2ie4
-.fr8i9v8o8l9i8t8y.
-.fr2iv
-.frivol2i
-.frivol1it
-.frivoli1ty
-.fr8i9v8o8l9i9t8i8e8s.
-.frivoli1ti
-.frivolit2ie4
-.fr8i8v9o9l8o8u8s.
-.frivolou2
-.frivolo2us
-.ga9l8a8c9t8i8c.
-.gala2c1t
-.ga8l9a8x8y.
-.ga8l9a8x9i8e8s.
-.galax3i
-.galax2ie4
-.ga8s9o8m9e9t8e8r.
-.ga1so
-.ga3som
-.gaso2me
-.gaso4met
-.gasome1te
-.ge9o9d8e8s9i8c.
-.geodes2
-.geode1si
-.geode2sic
-.ge9o9d8e8t9i8c.
-.geode1t
-.geodet1ic
-.ge8o9m8e8t9r8i8c.
-.ge3om
-.geo2me
-.geo4met
-.geom4etr
-.geo5met3ric
-.ge8o9m8e8t9r8i8c8s.
-.geome4tri4c3s2
-.ge9o9s8t8r8o8p8h8i8c.
-.geos4
-.geost4r
-.geostr2oph
-.geostroph1ic
-.ge8o9t8h8e8r9m8a8l.
-.ge4ot
-.ge4oth
-.geoth2e
-.geother3m4
-.geother1ma
-.ge9o8t9r8o9p8i8s8m.
-.geotropi2s1m
-.gn8o9m8o8n.
-.g1no
-.gno4mo
-.gno4mo2n
-.gn8o9m8o8n8s.
-.gnomo2n3s2
-.gr8a8n8d9u8n8c8l8e.
-.1gr
-.gra2n2
-.gr4and
-.gran1du
-.grandu4n
-.grandun1c4l4
-.gr8a8n8d9u8n8c8l8e8s.
-.granduncles2
-.gr8i8e8v9a8n8c8e.
-.gr2ie4
-.grie1va
-.grieva2n
-.gr8i8e8v9a8n8c8e8s.
-.gr8i8e8v9o8u8s.
-.grievou2
-.grievo2us
-.gr8i8e8v9o8u8s9l8y.
-.grievous1l2
-.grievous1ly
-.ha8i8r9s8t8y8l8e.
-.hai2
-.ha4ir
-.hai4rs2
-.hairs2ty
-.hairs2tyl
-.ha8i8r9s8t8y8l8e8s.
-.hairstyles2
-.ha8i8r9s8t8y8l9i8s8t.
-.ha8i8r9s8t8y8l9i8s8t8s.
-.hairstylis4t1s2
-.ha8l8f9s8p8a8c8e.
-.ha2lf
-.hal2f3s
-.half2s1pa
-.halfspa4ce
-.ha8l8f9s8p8a8c8e8s.
-.ha8l8f9w8a8y.
-.ha8r9b8i8n9g8e8r.
-.h2a2r
-.har1b
-.harbi2
-.har2bin
-.harb4inge
-.ha8r9b8i8n9g8e8r8s.
-.harbinge4r1s2
-.ha8r9l8e9q8u8i8n.
-.har4le4
-.har1l
-.harle1q
-.harlequ2
-.harleq2ui2
-.harlequi4n
-.ha8r9l8e9q8u8i8n8s.
-.harlequ2i2n1s2
-.ha8t8c8h9e8r8i8e8s.
-.ha4tc
-.hat4ch
-.hatche2
-.hatcher1i
-.hatcher2ie4
-.he8m8i9d8e8m8i9s8e8m8i9q8u8a9v8e8r.
-.hem2id
-.hemid4em
-.hemide4m2is
-.hemidem4ise
-.hemidemisemi3qua
-.hemidemisemiqu2
-.hemidemisemiqua5v4
-.he8m8i9d8e8m8i9s8e8m8i9q8u8a9v8e8r8s.
-.hemidemisemiquave4r1s2
-.he9m8o9g8l8o9b8i8n.
-.hemo4g
-.he1mo
-.hemo4gl2
-.hemo3glo
-.hemoglo1bi
-.hemoglo2bin
-.he9m8o9p8h8i8l9i8a.
-.hem2oph
-.hemoph4il2
-.hemophil1i
-.hemophil3i1a
-.he9m8o9p8h8i8l9i8a8c.
-.he9m8o9p8h8i8l9i8a8c8s.
-.hemophilia4c3s2
-.he8m8o9r8h8e9o8l9o8g8y.
-.hemo2r
-.hemorh4
-.hemorhe3ol
-.hemorheol1o1gy
-.he9p8a8t9i8c.
-.hep5
-.he2pa
-.hepat1ic
-.he8r9m8a8p8h9r8o9d8i8t8e.
-.her3m4
-.her1ma
-.her4map
-.hermap4hr4
-.hermaphrod2ite
-.he8r9m8a8p8h9r8o9d8i8t9i8c.
-.hermaphrod2i1ti
-.hermaphrod4i2tic
-.he9r8o8e8s.
-.hero4e
-.he8x8a9d8e8c9i9m8a8l.
-.hex1a
-.hexa2d
-.hexade1c2i
-.hexade2c3im
-.hexadeci1ma
-.ho9l8o9n8o9m8y.
-.holo2n
-.holon3o3my
-.ho9m8e8o9m8o8r9p8h8i8c.
-.ho2me3
-.homeo1mo
-.homeomo2r
-.homeomor1p
-.homeomorp4h4
-.homeomorph1ic
-.ho9m8e8o9m8o8r9p8h8i8s8m.
-.homeomorphi2s1m
-.ho9m8o9t8h8e8t8i8c.
-.ho1mo
-.hom4oth3
-.homoth2e
-.homo3the4t
-.homothet1ic
-.ho8r8s8e9r8a8d9i8s8h.
-.hor4se
-.ho4rs2
-.horser1a
-.horsera2d
-.horser2adi
-.horseradis1
-.horseradis2h
-.ho8t9b8e8d.
-.ho2t1b
-.hot4be2d
-.ho8t9b8e8d8s.
-.hotbe2d1s2
-.hy9d8r8o9t8h8e8r9m8a8l.
-.hy1d
-.hy1dr
-.hydro4th2e
-.hydr4oth
-.hydrother3m4
-.hydrother1ma
-.hy9p8o9t8h8a8l9a9m8u8s.
-.hy3po
-.hyp4ot
-.hyp4oth
-.hypotha3la
-.hypothala3m
-.hypothala1mu
-.hypothalam2us
-.id8e8a8l8s.
-.ide3a4l
-.idea2l1s2
-.id8e8o9g8r8a8p8h8s.
-.ideo2g
-.ideo1gr
-.ideogra4p4h1s2
-.id8i8o9s8y8n9c8r8a8s8y.
-.i2di
-.i1d3io
-.idi4os
-.idios4y
-.idiosyn1cr
-.idiosyncr2as
-.idiosyncras4y
-.id8i8o9s8y8n9c8r8a9s8i8e8s.
-.idiosyncras2ie4
-.id8i8o9s8y8n9c8r8a8t8i8c.
-.idiosyn5crat1ic
-.id8i8o9s8y8n9c8r8a8t9i9c8a8l9l8y.
-.idiosyncrati1ca
-.idiosyncratical1l
-.idiosyncratical1ly
-.ig9n8i8t9e8r.
-.2ig
-.ig1ni
-.ign2it
-.ign2ite
-.ig9n8i8t9e8r8s.
-.ignite4r1s2
-.ig9n8i9t8o8r.
-.ign3itor
-.igni1to
-.ig8n8o8r8e9s8p8a8c8e8s.
-.ig1no
-.ignore1sp
-.ignore2s1pa
-.ignorespa4ce
-.im9p8e8d9a8n8c8e.
-.im2p2ed
-.imp2e2d2a
-.impeda2n
-.im9p8e8d9a8n8c8e8s.
-.in9d8u9b8i9t8a9b8l8e.
-.4ind
-.in1du
-.indu1b4i
-.indubi2t
-.indubi1ta
-.indubi2tab
-.indubitab2l2
-.in9f8i8n9i8t8e9l8y.
-.in3f
-.in1fi
-.in2fin
-.inf2ini
-.infin2it
-.infin2ite
-.infinite1ly
-.in9f8i8n9i9t8e8s9i9m8a8l.
-.infinit4es
-.infinite1si
-.infinite2s5im
-.infinitesi1ma
-.in9f8r8a9s8t8r8u8c9t8u8r8e.
-.infr2as
-.infras1t4r
-.infrastru2c1t
-.infrastructu4r
-.infrastruc1tu
-.infrastruc3ture
-.in9f8r8a9s8t8r8u8c9t8u8r8e8s.
-.in9s8t8a8l8l9e8r.
-.ins2ta2l
-.ins1ta
-.instal1l
-.instal2le
-.in9s8t8a8l8l9e8r8s.
-.installe4r1s2
-.in9t8e8r9d8i8s9c8i9p8l8i9n8a8r8y.
-.in1t
-.in5ter3d
-.interd2i
-.interdis1
-.interd2is1c
-.interdis1ci
-.interdisc2ip
-.interdisci1p2l2
-.interdiscipli4n
-.interdiscipl4i1na
-.interdisciplin2a2r
-.in9t8e8r9g8a9l8a8c9t8i8c.
-.interg2
-.inter1ga
-.intergala2c1t
-.in9u8t8i8l8e.
-.in1u
-.in4u1t2i
-.in9u8t8i8l9i9t8y.
-.inutil1i
-.inut2il1it
-.inutili1ty
-.ir9r8e9d8u8c9i8b8l8e.
-.ir2r2ed
-.irre1du
-.irredu2c
-.irreduci4b
-.irredu1ci
-.irreduci1b2l2
-.ir9r8e9d8u8c9i8b8l8y.
-.irreducib1ly
-.ir9r8e8v9o9c8a9b8l8e.
-.irrev2
-.irre5voc
-.irrevo1ca
-.irrevoca1b2l2
-.is8o8t9r8o8p8y.
-.i2so
-.isotropy5
-.is8o9t8r8o8p9i8c.
-.isotrop3ic
-.it8i8n9e8r9a8r8y.
-.i1ti
-.i2t1in
-.it2ine
-.itin4er4a2r
-.itin1er
-.itiner1a
-.it8i8n9e8r9a8r9i8e8s.
-.itinerar1i
-.itinerar2ie4
-.je9r8e9m8i9a8d8s.
-.1je
-.jerem2i3a
-.jeremia2d
-.jeremia2d1s2
-.ke8y9n8o8t8e.
-.ke8y9n8o8t8e8s.
-.keyno4tes
-.ke8y9s8t8r8o8k8e.
-.keys4
-.keys1t
-.keyst4r
-.keystr2ok2
-.ke8y9s8t8r8o8k8e8s.
-.keystrokes4
-.ki8l8n9i8n8g.
-.k1i
-.k4i2l1n2
-.kiln1in
-.kilnin4g
-.la8c9i9e8s8t.
-.l4a2ci4
-.la3c2ie4
-.laci1est
-.la8m9e8n9t8a9b8l8e.
-.la1men
-.la3men1t
-.lamen2ta4b
-.lamen1ta
-.lamentab2l2
-.la8n8d9s8c8a8p9e8r.
-.3l4and
-.la2n
-.lan2d1s2
-.landsca4p
-.lands1ca
-.landsca5per
-.la8n8d9s8c8a8p9e8r8s.
-.landscape4r1s2
-.la8r9c8e9n8y.
-.l2a2r
-.lar1c
-.lar2ce
-.lar1cen4
-.la8r9c8e9n9i8s8t.
-.lar4ceni
-.le8a8f9h8o8p9p8e8r.
-.le2a
-.lea2f
-.lea4fh
-.leafho4p1p
-.leafhop2pe
-.leafhop3per
-.le8a8f9h8o8p9p8e8r8s.
-.leafhoppe4r1s2
-.le8t9t8e8r9s8p8a8c9i8n8g.
-.le4t3t2
-.lette4r1s2
-.letter1sp
-.letter2s1pa
-.lettersp4a2ci
-.letterspa2c1in
-.letterspac1ing
-.li8f8e9s8p8a8n.
-.life1sp
-.life2s1pa
-.lifespa4n
-.li8f8e9s8p8a8n8s.
-.lifespa2n1s2
-.li8f8e9s8t8y8l8e.
-.lifes2ty
-.lifes2tyl
-.li8f8e9s8t8y8l8e8s.
-.lifestyles2
-.li8g8h8t9w8e8i8g8h8t.
-.3ligh
-.lightw4
-.lightwei2
-.l2ightwe2ig2
-.li8m9o8u9s8i8n8e8s.
-.li4mo
-.li3mo2us
-.limou2
-.limou2s1in
-.limous2ine
-.limousi1nes
-.li8n8e9b8a8c8k8e8r.
-.1l4ine
-.lin2e2b
-.lineback1
-.lineback1er
-.li8n8e9s8p8a8c8i8n8g.
-.li1nes
-.li4ne1sp
-.line2s1pa
-.linesp4a2ci
-.linespa2c1in
-.linespac1ing
-.li9o8n9e8s8s.
-.lio2n
-.lio1nes
-.lion2e2ss
-.li8t8h9o9g8r8a8p8h8e8d.
-.l2ith
-.litho4g
-.litho1gr
-.lithograph4ed
-.li8t8h9o9g8r8a8p8h8s.
-.lithogra4p4h1s2
-.lo9b8o8t9o8m8y.
-.lobo4to
-.loboto3my
-.lo9b8o8t9o8m9i8z8e.
-.lobotom2iz
-.lobotomi2ze
-.lo8g8e8s.
-.lo1ge
-.lo8n8g9e8s8t.
-.5long
-.lo2n
-.lo9q8u8a8c9i8t8y.
-.lo1q
-.loqu2
-.loquac4
-.loqu4a2ci
-.loqua2c1it
-.loquaci1ty
-.lo8v8e9s8t8r8u8c8k.
-.4lov
-.lov4e2s
-.lov2est4r
-.lovestruc5
-.lovestruck1
-.ma8c8r8o9e8c8o9n8o8m8i8c8s.
-.macro4e
-.macroe1co
-.macroeco2n
-.macroeco3nomic
-.macroeconomi4c3s2
-.ma8l9a9p8r8o8p9i8s8m.
-.malapr2
-.malapropi2s1m
-.ma8l9a9p8r8o8p9i8s8m8s.
-.malaprop4is4m1s2
-.ma8n9s8l8a8u8g8h9t8e8r.
-.ma2n1s2
-.man2s1l2
-.manslaugh3
-.ma8n9u9s8c8r8i8p8t.
-.man2us
-.manusc2
-.manuscri2
-.manuscr2ip
-.manuscri2p1t
-.ma8r9g8i8n9a8l.
-.marg2
-.margi4n
-.margi1na
-.ma8t8h9e9m8a9t8i9c8i8a8n.
-.m4ath3
-.math5em
-.math2e
-.1mathe1ma
-.mathemat1ic
-.mathemat2i1ci
-.mathemati3c2i1a
-.mathematici2a2n
-.ma8t8h9e9m8a9t8i9c8i8a8n8s.
-.mathematicia2n1s2
-.ma8t8t8e8s.
-.mat5te
-.ma4t3t2
-.mat4tes
-.me8d9i8c9a8i8d.
-.2med
-.m4edi
-.med3i1ca
-.medicai2
-.medica2id
-.me8d8i9o8c8r8e.
-.me1d2io
-.mediocre3
-.me8d8i9o8c9r8i9t8i8e8s.
-.medi5ocrit
-.mediocri2
-.medio5cri1ti
-.mediocrit2ie4
-.me8g8a9l8i8t8h.
-.me2g
-.m4egal
-.me1ga
-.me3gal1i
-.megal1it
-.megal2ith
-.me8g8a9l8i8t8h8s.
-.megali2t4h1s2
-.me8t8a9b8o8l9i8c.
-.me4ta
-.me2ta4b
-.metabol3ic
-.metabol2i
-.me9t8a8b9o9l8i8s8m.
-.metaboli2s1m
-.me9t8a8b9o9l8i8s8m8s.
-.metabol4is4m1s2
-.me9t8a8b9o9l8i8t8e.
-.metabo5l2ite
-.metabol1it
-.me9t8a8b9o9l8i8t8e8s.
-.metabolit4es
-.me8t8a9l8a8n9g8u8a8g8e.
-.met3a2l
-.meta5la
-.metala2n
-.metal2ang
-.metalan1gu
-.metalangu4a
-.me8t8a9l8a8n9g8u8a8g8e8s.
-.me8t8a9p8h8o8r9i8c.
-.metapho4r
-.me8t8h9a8n8e.
-.metha2n4
-.me9t8r8o8p9o9l8i8s.
-.m4etr
-.metropol2i
-.me9t8r8o8p9o9l8i8s8e8s.
-.metropol4ise
-.metropolis1e4s
-.me8t9r8o9p8o8l9i9t8a8n.
-.metropol1it
-.metropoli3ta2n
-.metropoli1ta
-.me8t9r8o9p8o8l9i9t8a8n8s.
-.metropolita2n1s2
-.mi8c8r8o9e8c8o9n8o8m8i8c8s.
-.m4i1cr
-.micro4e
-.microe1co
-.microeco2n
-.microeco3nomic
-.microeconomi4c3s2
-.mi9c8r8o9f8i8c8h8e.
-.micro2fi
-.microf4i2ch
-.microfiche2
-.mi9c8r8o9f8i8c8h8e8s.
-.microfich1es
-.mi8c8r8o9o8r8g8a8n9i8s8m.
-.microo2
-.microorg2
-.microor1ga
-.microorgan5is
-.microorga2n
-.microorgani2s1m
-.mi8c8r8o9o8r8g8a8n9i8s8m8s.
-.microorgan4is4m1s2
-.mi8l8l9a8g8e.
-.m4il1l
-.mi8l9l8i9l8i8t8e8r.
-.mill2i
-.mil4l4i4l
-.millil1i
-.mill2il1it
-.millil2ite
-.mi8m8e8o9g8r8a8p8h8e8d.
-.mimeo2g
-.mimeo1gr
-.mimeograph4ed
-.mi8m8e8o9g8r8a8p8h8s.
-.mimeogra4p4h1s2
-.mi8m9i8c9r8i8e8s.
-.mim1i
-.mim4i1cr
-.mimicri2
-.mimicr2ie4
-.mi8n9i8s.
-.m2ini
-.min1is
-.mi8n8i9s8y8m9p8o9s8i8u8m.
-.minis4y
-.minisy4m1p
-.minisym1pos
-.minisympo5si4u
-.mi8n8i9s8y8m9p8o9s8i8a.
-.minisympos2i1a
-.mi9n8u8t9e8r.
-.m4in1u
-.mi9n8u8t9e8s8t.
-.mi8s9c8h8i8e9v8o8u8s9l8y.
-.m2is1c
-.mis3ch2
-.misch2ie4
-.mischievou2
-.mischievo2us
-.mischievous1l2
-.mischievous1ly
-.mi9s8e8r8s.
-.m4ise
-.mis3er
-.mise4r1s2
-.mi9s8o8g9a9m8y.
-.mi2so
-.miso1ga
-.miso2gam
-.mo8d9e8l9l8i8n8g.
-.mo2d1
-.model1l
-.modell2i
-.model2lin4
-.mo8l9e9c8u8l8e.
-.mole1cu
-.mole4cul
-.molecul4e
-.mo8l9e9c8u8l8e8s.
-.molecules2
-.mo8n9a8r8c8h8s.
-.mo1n1a
-.monar3c
-.mon2a2r
-.monar2ch
-.monarc4h1s2
-.mo8n8e8y9l8e8n9d8e8r.
-.moneylen1de
-.mo8n8e8y9l8e8n9d8e8r8s.
-.moneylende4r5s2
-.mo8n8o9c8h8r8o8m8e.
-.mono2ch4
-.monoc4hr4
-.monochro2me
-.mo8n8o9e8n9e8r9g8e8t8i8c.
-.mo3noe
-.monoen1er
-.monoenerg2
-.monoener3get
-.monoenerget1ic
-.mo8n9o8i8d.
-.monoi2
-.mono2id
-.mo8n8o9p8o8l8e.
-.mo4nop
-.mo8n8o9p8o8l8e8s.
-.monopoles2
-.mo9n8o8p9o8l8y.
-.monopo2ly
-.mo8n8o9s8p8l8i8n8e.
-.monos1p2l2
-.monospli4n
-.monosp1l4ine
-.mo8n8o9s8p8l8i8n8e8s.
-.monospli1nes
-.mo8n8o9s8t8r8o8f8i8c.
-.monos5t
-.monost4r
-.monostro2fi
-.mo9n8o8t9o9n8i8e8s.
-.mono1to
-.mo2noto2n
-.monoton2ie4
-.mo9n8o8t9o9n8o8u8s.
-.mono4tono
-.monoto1nou2
-.monotono2us
-.mo9r8o8n9i8s8m.
-.moro5n4is
-.moro2n
-.moroni2s1m
-.mo8s9q8u8i9t8o.
-.mos2
-.mosqu2
-.mosq2ui2
-.mosqui1to
-.mo8s9q8u8i9t8o8s.
-.mosquitos2
-.mo8s9q8u8i9t8o8e8s.
-.mu8d9r8o8o8m.
-.mu1dr
-.mud1room
-.mudroo2
-.mu8d9r8o8o8m8s.
-.mudroo4m1s2
-.mu8l9t8i9f8a8c9e8t8e8d.
-.5mu4lt
-.mul1ti3
-.multif2
-.multi1fa
-.multifa4ce
-.multifacet4
-.multiface2t1ed
-.mu8l9t8i9p8l8i8c9a8b8l8e.
-.mult2ip
-.multi1p2l2
-.multipli1ca
-.multiplica1b2l2
-.mu8l8t8i9u8s8e8r.
-.multi4u
-.multi2us
-.ne8o9f8i8e8l8d8s.
-.3neo
-.ne5of
-.neo2fi
-.neof2ie4
-.neofie2ld3
-.neofiel2d1s2
-.ne8o9n8a8z8i.
-.neo2n
-.neo1n1a
-.neona2z1i
-.ne8o9n8a8z8i8s.
-.neonaz4is
-.ne8p8h9e8w8s.
-.nephe4
-.ne8p8h9r8i8t8e.
-.nep4hr4
-.nephr2ite
-.ne8p8h9r8i8t8i8c.
-.nephr4i2t3ic
-.nephri1ti
-.ne8w9e8s8t.
-.ne4w
-.newest3
-.ne8w8s9l8e8t9t8e8r.
-.news4l2
-.news2le
-.newsle4t3t2
-.ne8w8s9l8e8t9t8e8r8s.
-.newslette4r1s2
-.ni8t8r8o9m8e8t8h9a8n8e.
-.n2it
-.ni3tr
-.nitro2me
-.nitro4met
-.nitrometha2n4
-.no9n8a8m8e.
-.no4n
-.no1n1a
-.no8n9a8r9i8t8h9m8e8t9i8c.
-.nonar3i
-.non2a2r
-.nonar2ith
-.nonarit4h1m
-.nonarithmet4
-.nonarithmet1ic
-.no8n9e8m8e8r9g8e8n8c8y.
-.none1me
-.nonemerg2
-.nonemer1gen
-.nonemergen1cy
-.no8n9e8q8u8i9v8a8r8i9a8n8c8e.
-.none2q
-.nonequ2
-.noneq2ui2
-.nonequ2iv3
-.nonequi1va
-.nonequiv2a2r
-.nonequivar1i
-.nonequivar3i2a2n
-.nonequivar2i3a
-.nonequivar4ianc
-.no8n8e9t8h8e9l8e8s8s.
-.noneth2e
-.nonethe1les2
-.nonethe3l2e2ss
-.no8n9e8u8c8l8i8d9e8a8n.
-.non4eu
-.noneu1c4l4
-.noneucl2id
-.noneuclidea2n
-.no8n9i8s8o9m8o8r9p8h8i8c.
-.non5i
-.non1is
-.noni2so
-.noni3som
-.noniso1mo
-.nonisomo2r
-.nonisomor1p
-.nonisomorp4h4
-.nonisomorph1ic
-.no8n9p8s8e8u8d8o9c8o8m9p8a8c8t.
-.non1p4
-.non2p1s2
-.nonp2se
-.nonps4eu
-.nonpseu1do
-.nonpseudo1co
-.nonpseudoco4m1p
-.nonpseudocom1pa
-.nonpseudocompa2c4t
-.no8n9s8m8o8o8t8h.
-.no2n3s2
-.non2s3m
-.nons1mo
-.nonsmoo2
-.nonsmo4oth
-.no8n9u8n8i9f8o8r8m.
-.no3nu4n
-.nonu1ni
-.nonuni1fo
-.nonunifo2r
-.nonunifor1m
-.no8n9u8n8i9f8o8r8m9l8y.
-.nonunifor4m1l
-.nonuniform1ly
-.no8r9e8p9i9n8e8p8h9r8i8n8e.
-.nore5pi2n
-.norep2ine
-.norepinep4hr4
-.norep2inephr2in4e
-.no8t9w8i8t8h9s8t8a8n8d9i8n8g.
-.notw4
-.notwi2
-.notw2ith3
-.notwi2t4h1s2
-.notwith5st4and
-.notwiths1ta
-.notwithsta2n
-.notwithstand1in
-.nu9c8l8e8o9t8i8d8e.
-.nucle3
-.nu1c4l4
-.nucle4ot
-.nucleot2id
-.nu9c8l8e8o9t8i8d8e8s.
-.nucleotide4s2
-.nu8t9c8r8a8c8k9e8r.
-.nu4tc
-.nutcrack1
-.nutcrack1er
-.nu8t9c8r8a8c8k9e8r8s.
-.nutcracke4r1s2
-.oe8r9s8t8e8d8s.
-.o3er
-.oe4r1s2
-.oers4t1ed
-.oerste2d1s2
-.of8f9l8i8n8e.
-.o4f1f
-.off4l2
-.offlin4
-.off1l4ine
-.of8f9l8o8a8d.
-.offl4oa
-.offloa2d3
-.of8f9l8o8a8d8s.
-.offloa2d1s2
-.of8f9l8o8a8d8e8d.
-.offloa2d1ed
-.ol8i9g8o8p9o9l8i8s8t.
-.ol2i
-.ol2ig
-.oli2go
-.ol2igopol2i
-.ol8i9g8o8p9o9l8i8s8t8s.
-.oligopolis4t1s2
-.ol8i9g8o8p9o8l8y.
-.oligopo2ly
-.ol8i9g8o8p9o8l9i8e8s.
-.oligopol2ie4
-.op9e8r9a8n8d.
-.op1er
-.3oper1a
-.op4er4and
-.opera2n
-.op9e8r9a8n8d8s.
-.operan2d1s2
-.or8a8n8g9u8t8a8n.
-.ora2n
-.or2ang
-.oran1gu
-.oran4gu4t
-.orangu1ta
-.ora2nguta2n
-.or8a8n8g9u8t8a8n8s.
-.oranguta2n1s2
-.or9t8h8o9d8o8n9t8i8s8t.
-.ortho2do4
-.orthodo2n
-.orthodon3t4i
-.orthodon1t
-.or9t8h8o9d8o8n9t8i8s8t8s.
-.orthodontis4t1s2
-.or9t8h8o9k8e8r9a9t8o8l9o8g8y.
-.orth2ok
-.orthok1er
-.orthoker1a
-.orthokera1to
-.orthokeratol1o1gy
-.or8t8h8o9n8i8t8r8o9t8o8l8u8e8n8e.
-.ortho2n
-.orthon2it
-.orthoni3tr
-.orthonitro1to
-.orthonitrotolu3en
-.orthonitrotolu4ene
-.ov8e8r9v8i8e8w.
-.overv2ie4
-.ov8e8r9v8i8e8w8s.
-.ox9i8d9i8c.
-.ox3i
-.oxi5di
-.ox2id
-.pa8d9d8i8n8g.
-.1pa
-.p4a2d
-.pad4d1in
-.pad1d4
-.pa8i8n9l8e8s8s9l8y.
-.p4ai2
-.pa4i4n4
-.pa4i4n1l
-.painles2
-.pain3l2e2ss
-.painles4s1l2
-.painless1ly
-.pa8l9e8t8t8e.
-.p4al
-.p2ale
-.pale4t3t2
-.pa8l9e8t8t8e8s.
-.palet4tes
-.pa8r9a9b8o8l8a.
-.p2a2r
-.pa2rab
-.parabo1la
-.pa8r9a9b8o8l9i8c.
-.parabol3ic
-.parabol2i
-.pa9r8a8b9o9l8o8i8d.
-.paraboloi2
-.parabolo2id
-.pa8r9a9d8i8g8m.
-.para2d
-.par2adi
-.parad2ig
-.paradig1m
-.pa8r9a9d8i8g8m8s.
-.paradig4m1s2
-.pa8r8a9c8h8u8t8e.
-.para2ch
-.parachu4t
-.pa8r8a9c8h8u8t8e8s.
-.pa8r8a9d8i9m8e8t8h8y8l9b8e8n8z8e8n8e.
-.parad4imet
-.paradimethy2l1b
-.paradimethylb4e4n3z
-.paradimethylben2ze
-.paradimethylbenze4n
-.pa8r8a9f8l8u8o8r8o9t8o8l8u8e8n8e.
-.para2f
-.paraf4l2
-.paraflu3o
-.parafluo3r
-.parafluoro1to
-.parafluorotolu3en
-.parafluorotolu4ene
-.pa8r8a9g8r8a8p8h9e8r.
-.para1gr
-.parag5ra3ph4er
-.pa8r8a9l8e9g8a8l.
-.par3al
-.par2ale
-.paral4egal
-.parale1ga
-.pa8r9a8l9l8e8l9i8s8m.
-.paral1l
-.paral2le
-.paral3lel
-.parallel2i
-.paralle2lis
-.paralleli2s1m
-.pa8r8a9m8a8g9n8e8t9i8s8m.
-.par4a1ma
-.param3ag
-.para5mag1n
-.paramagneti2s4m
-.pa8r8a9m8e8d8i8c.
-.para2med
-.param4edi
-.pa8r8a9m8e8t8h8y8l9a8n8i8s8o8l8e.
-.param3et
-.paramethy3la
-.paramethyla2n
-.paramethylani2so
-.pa9r8a8m9e9t8r8i8z8e.
-.param4etr
-.parametri2ze
-.pa8r8a9m8i8l9i9t8a8r8y.
-.par2ami
-.paramil1i
-.param2il1it
-.paramili1ta
-.paramilit2a2r
-.pa8r8a9m8o8u8n8t.
-.para2mo
-.paramou2
-.paramoun1t
-.pa8t8h9o9g8e8n9i8c.
-.p4ath
-.pat4ho
-.patho4g
-.patho1ge4
-.patho1gen
-.pe8e8v9i8s8h.
-.p4ee
-.pee1vi
-.peevis2h
-.pe8e8v9i8s8h9n8e8s8s.
-.peevis2h1n
-.peevish1nes
-.peevishn2e2ss
-.pe8n9t8a9g8o8n.
-.pen1t
-.pen1ta
-.penta2go
-.pentago2n2
-.pe8n9t8a9g8o8n8s.
-.pentago2n3s2
-.pe9t8r8o9l8e9u8m.
-.petrol4eu
-.ph8e9n8o8m9e9n8o8n.
-.ph4e3no
-.phe2n
-.pheno2me
-.pheno1men
-.phenom4eno
-.phenomeno4n
-.ph8e8n8y8l9a8l8a9n8i8n8e.
-.pheny3la
-.phenylala2n
-.phenylala5n2ine
-.phenylalan1in
-.ph8i9l8a8t9e9l8i8s8t.
-.phi4latel2i4
-.philate2lis
-.ph8i9l8a8t9e9l8i8s8t8s.
-.philatelis4t1s2
-.ph8o9n8e8m8e.
-.3phone
-.pho2n
-.phone1me
-.ph8o9n8e8m8e8s.
-.phone2mes
-.ph8o9n8e9m8i8c.
-.phone5mi
-.ph8o8s9p8h8o8r9i8c.
-.phos1p
-.phospho5
-.phospho4r
-.ph8o9t8o9g8r8a8p8h8s.
-.pho1to
-.photo2gr
-.photogra4p4h1s2
-.ph8o9t8o9o8f8f9s8e8t.
-.photoo2
-.photoo4f1f
-.photoof2f3s
-.pi8c9a9d8o8r.
-.pi1ca
-.pica2d
-.pica1do
-.picad4or
-.pi8c9a9d8o8r8s.
-.picado4rs2
-.pi8p8e9l8i8n8e.
-.p2ip
-.pipe4
-.pipel2i
-.pipe1l4ine
-.pi8p8e9l8i8n8e8s.
-.pipeli1nes
-.pi8p8e9l8i8n9i8n8g.
-.pipel2in3i
-.pipelin1in
-.pipelinin4g
-.pi9r8a9n8h8a8s.
-.p4ir
-.pi1ra
-.pira2n
-.pira4n1h4
-.piranha4
-.pl8a8c8a9b8l8e.
-.1p2l2
-.pla1ca
-.placa1b2l2
-.pl8a8n8t9h8o8p9p8e8r.
-.3pla2n
-.plan1t
-.plantho4p1p
-.planthop2pe
-.planthop3per
-.pl8a8n8t9h8o8p9p8e8r8s.
-.planthoppe4r1s2
-.pl8e8a8s9a8n8c8e.
-.ple2a
-.pleasa2
-.plea3sanc
-.pleasa2n
-.pl8u8g9i8n.
-.plug5in
-.pl8u8g9i8n8s.
-.plu5g4i2n1s2
-.po8l9t8e8r9g8e8i8s8t.
-.po4l2t
-.pol1te
-.polterg2
-.poltergei2
-.po8l8y9e8n8e.
-.po2ly
-.po8l8y9e8t8h9y8l9e8n8e.
-.polye4t
-.po9l8y8g9a9m8i8s8t.
-.poly1ga
-.poly2gam
-.polygam2is
-.po9l8y8g9a9m8i8s8t8s.
-.polygamis4t1s2
-.po8l8y8g9o8n9i9z8a9t8i8o8n.
-.poly1go
-.polygo2n2
-.polygo3ni
-.polygoniza1
-.polygoniza1t2io
-.polygonizatio2n
-.po9l8y8p8h9o9n8o8u8s.
-.polypho2n
-.polypho1nou2
-.polyphono2us
-.po8l8y9s8t8y8r8e8n8e.
-.po2lys4
-.polys1t
-.polys2ty
-.po8m8e9g8r8a8n9a8t8e.
-.po2me
-.pome2g
-.pome1gr
-.pomegra2n2
-.pomegra1na
-.pomegran2at
-.po8r8o9e8l8a8s9t8i8c.
-.1p4or
-.poro4e
-.poro4el
-.poroe1la
-.poroelast2i
-.poroelas1tic
-.po8r9o8u8s.
-.porou2
-.poro2us
-.po8r9t8a9b8l8e.
-.por1ta
-.por2tab
-.portab2l2
-.po8s8t9a8m9b8l8e.
-.1pos
-.pos2ta
-.posta4m1b
-.postamb2l2
-.po8s8t9a8m9b8l8e8s.
-.postambles2
-.po8s8t9h8u9m8o8u8s.
-.posthu1mo
-.posthu3mo2us
-.posthumou2
-.po8s8t9s8c8r8i8p8t.
-.pos4t1s2
-.post4sc
-.postscri2
-.postscr2ip
-.postscri2p1t
-.po8s8t9s8c8r8i8p8t8s.
-.postscrip4t1s2
-.po8s9t8u8r9a8l.
-.pos1tu
-.postu1ra
-.pr8e9a8m9b8l8e.
-.prea4m1b
-.preamb2l2
-.pr8e9a8m9b8l8e8s.
-.preambles2
-.pr8e9l8o8a8d8e8d.
-.prel4oa
-.preloa2d3
-.preloa2d1ed
-.pr8e9p8a8r9i8n8g.
-.pre2pa
-.prep4a4r1i
-.prep2a2r
-.preparin4g
-.pr8e9p8r8i8n8t.
-.pr2epr2
-.preprin4t3
-.pr8e9p8r8i8n8t8s.
-.preprin4t4s2
-.pr8e9p8r8o8c8e8s9s8o8r.
-.pre3pro
-.prepr2oc
-.prepro1ce
-.preproc2e2ss
-.preproces1so
-.pr8e9p8r8o8c8e8s9s8o8r8s.
-.preprocesso4rs2
-.pr8e9s8p8l8i8t9t8i8n8g.
-.pre1sp
-.pres1p2l2
-.prespl1it
-.prespl4i4t3t2
-.presplit2t1in
-.pr8e9w8r8a8p.
-.prewra4
-.pr8e9w8r8a8p8p8e8d.
-.prewra4p1p
-.prewrap2pe
-.prewrap4p2ed
-.pr8i8e8s8t9e8s8s8e8s.
-.5pr2i4e4
-.pri1est
-.pries4t2e2ss
-.priestess1e4s
-.pr8e8t9t8y9p8r8i8n9t8e8r.
-.pre4t3t2
-.pret1ty
-.pr2ettypr2
-.prettyprin4t3
-.pr8e8t9t8y9p8r8i8n9t8i8n8g.
-.prettyprint2i
-.prettyprin4t3ing
-.prettyprin2t1in
-.pr8o9c8e9d8u8r9a8l.
-.pr2oc
-.pro1ce
-.proce1du
-.procedu1ra
-.pr8o8c8e8s8s.
-.proc2e2ss
-.pr8o9c8u8r9a8n8c8e.
-.procu1ra
-.procura2n
-.pr8o8g9e9n8i8e8s.
-.pro1ge
-.pro1gen
-.proge5n2ie4
-.pr8o8g9e9n8y.
-.pro4geny
-.pr8o9g8r8a8m9m8a8b8l8e.
-.pro1gr
-.program1m
-.program1ma
-.program2mab
-.programmab2l2
-.pr8o8m9i9n8e8n8t.
-.prom4i
-.prom1in
-.prom2ine
-.promi1nen
-.prominen1t
-.pr8o9m8i8s9c8u9o8u8s.
-.prom2is
-.prom2is1c
-.promis1cu
-.promiscu1ou2
-.promiscuo2us
-.pr8o8m9i8s9s8o8r8y.
-.prom4i2s1s
-.promis1so
-.promisso1ry
-.pr8o8m9i8s8e.
-.prom4ise
-.pr8o8m9i8s8e8s.
-.promis1e4s
-.pr8o9p8e8l9l8e8r.
-.pro3pel
-.propel1l
-.propel2le
-.pr8o9p8e8l9l8e8r8s.
-.propelle4r1s2
-.pr8o9p8e8l9l8i8n8g.
-.propell2i
-.propel2lin4
-.pr8o9h8i8b9i9t8i8v8e.
-.pro1h2
-.prohibi2t
-.prohibi1ti
-.prohibi1t2iv
-.pr8o9h8i8b9i9t8i8v8e9l8y.
-.prohibitiv4e1ly
-.pr8o9s8c8i8u8t9t8o.
-.pros2c
-.pros1ci
-.prosci1u
-.prosciu4t3t2
-.prosciut5to
-.pr8o9t8e8s8t9e8r.
-.pro1t
-.pro4tes
-.pr8o9t8e8s8t9e8r8s.
-.proteste4r1s2
-.pr8o9t8e8s9t8o8r.
-.prot4es2to
-.pr8o9t8e8s9t8o8r8s.
-.protesto4rs2
-.pr8o9t8o9l8a8n9g8u8a8g8e.
-.pro1to
-.proto1la
-.proto4la2n
-.protol2ang
-.protolan1gu
-.protolangu4a
-.pr8o9t8o9t8y8p9a8l.
-.proto1ty
-.prototy1pa
-.prototyp4al
-.pr8o8v9i8n8c8e.
-.prov1in
-.prov2inc
-.pr8o8v9i8n8c8e8s.
-.pr8o9v8i8n9c8i8a8l.
-.provin1ci
-.provin3c2i1a
-.provinci2al
-.pr8o8w9e8s8s.
-.prow2e2ss
-.ps8e8u9d8o9d8i8f9f8e8r9e8n9t8i8a8l.
-.2p1s2
-.p2se
-.ps4eu
-.pseu1do
-.pseudod1if
-.pseudodi4f1f
-.pseudodiffer1
-.pseudodiffer3en1t
-.pseudodifferent2i
-.pseudodifferen1t2i1a
-.pseudodifferenti2al
-.ps8e8u9d8o9f8i9n8i8t8e.
-.pseu2d5of
-.pseudo2fi
-.pseudo2fin
-.pseudof2ini
-.pseudofin2it
-.pseudofin2ite
-.ps8e8u9d8o9f8i9n8i8t8e9l8y.
-.pseudofinite1ly
-.ps8e8u9d8o9f8o8r8c8e8s.
-.pseudo1fo
-.pseudofo2r
-.pseudofor1c
-.pseudofor2ce
-.ps8e8u9d8o8g9r8a9p8h8e8r.
-.pseud4og
-.pseudo1gr
-.pseudog5ra3ph4er
-.ps8e8u9d8o9g8r8o8u8p.
-.pseudo4g4ro
-.pseudogrou2
-.ps8e8u9d8o9g8r8o8u8p8s.
-.pseudogrou2p1s2
-.ps8e8u9d8o9n8y8m.
-.pseu4do2n
-.pseudonym4
-.ps8e8u9d8o9n8y8m8s.
-.pseudony4m1s2
-.ps8e8u9d8o9w8o8r8d.
-.pseudo4wo2
-.ps8e8u9d8o9w8o8r8d8s.
-.pseudowor2d1s2
-.ps8y9c8h8e9d8e8l9i8c.
-.ps4y
-.p4sy1c
-.psy3ch
-.psych4e2
-.psy4ch4ed
-.psychedel2i
-.ps8y8c8h8s.
-.psyc4h1s2
-.pu9b8e8s9c8e8n8c8e.
-.pub3
-.pub4e
-.pu4bes4
-.pubes2c
-.pubes1cen
-.pubes3cenc
-.qu8a8d9d8i8n8g.
-.qu2
-.qua2d
-.quad4d1in
-.quad1d4
-.qu8a9d8r8a8t9i8c.
-.qua1dr
-.quadrat1ic
-.qu8a9d8r8a8t9i8c8s.
-.quadrati4c3s2
-.qu8a8d9r8a9t8u8r8e.
-.quadra2tu
-.quadra3ture
-.qu8a8d9r8i9p8l8e8g9i8c.
-.quadri2p2l2
-.quadr2ip
-.quadripleg4ic
-.qu8a8i8n8t9e8r.
-.quai2
-.qua4i4n
-.quain1t
-.qu8a8i8n8t9e8s8t.
-.qu8a9s8i9e8q8u8i8v9a9l8e8n8c8e.
-.quas2ie4
-.quasie1q
-.qu2asiequ2
-.quasieq2ui2
-.quasiequ2iv3
-.quasiequi1va
-.quasiequiv2ale
-.quasiequiva3lenc
-.qu8a9s8i9e8q8u8i8v9a9l8e8n8c8e8s.
-.qu8a9s8i9e8q8u8i8v9a9l8e8n8t.
-.quasiequiva1len1t
-.qu8a9s8i9h8y9p8o9n8o8r9m8a8l.
-.quasi3h
-.quasihy3po
-.quasihypo2n
-.quasihyponor1m
-.quasihyponor1ma
-.qu8a9s8i9r8a8d9i9c8a8l.
-.quas4i2r
-.quasi1r5a
-.quasira2d
-.quasir2adi
-.quasirad3i1ca
-.qu8a9s8i9r8e8s8i8d9u8a8l.
-.quasi4res
-.quasire1si
-.quasire2s2id
-.quasiresi2du
-.quasiresid1u1a
-.qu8a9s8i9s8m8o8o8t8h.
-.qua1sis
-.quasi2s1m
-.quasis1mo
-.quasismoo2
-.quasismo4oth
-.qu8a9s8i9s8t8a9t8i8o8n9a8r8y.
-.quasis1ta
-.quasistation5a2r
-.quasista1t2io
-.quasistatio2n
-.quasistatio1n1a
-.qu8a9s8i9t8o8p8o8s.
-.qu5a5si4t
-.quasi1to
-.quasito1pos
-.qu8a9s8i9t8r8i9a8n9g8u9l8a8r.
-.quasi5tr2i3a
-.quasitri2a2n
-.quasitri2ang
-.quasitrian1gu
-.quasitriangu1la
-.quasitriangul2a2r
-.qu8a9s8i9t8r8i8v9i8a8l.
-.quasitr2i4v
-.quasitriv3i
-.quasitriv2i1a
-.quasitrivi2al
-.qu8i8n9t8e8s9s8e8n8c8e.
-.q2ui2
-.qui4n
-.quin1t
-.quin4t2e2ss
-.quintes4senc
-.qu8i8n9t8e8s9s8e8n8c8e8s.
-.qu8i8n9t8e8s9s8e8n9t8i8a8l.
-.quintessen1t
-.quintessent2i
-.quintessen1t2i1a
-.quintessenti2al
-.ra8b9b8i8t9r8y.
-.2rab
-.ra2b1b
-.rabbi2t
-.rabbi3tr
-.rabbit5ry
-.ra9d8i9o8g9r8a9p8h8y.
-.ra2d
-.r2adi
-.ra3d2io
-.radio5g
-.radio2gr
-.radio4g3ra1phy
-.ra8f8f9i8s8h.
-.raf5fi
-.ra2f
-.ra4f1f4
-.raf2f5is
-.raffis2h
-.ra8f8f9i8s8h9l8y.
-.raffis4h1l4
-.raffish1ly
-.ra8m9s8h8a8c8k8l8e.
-.ra4m1s2
-.ram4s2h
-.ramshack1
-.ramshack1l
-.ra8v9e8n9o8u8s.
-.rav4e4no
-.rave1nou2
-.raveno2us
-.re9a8r8r8a8n8g8e9m8e8n8t.
-.re5ar1r4
-.re2a2r
-.rearran4ge
-.rearra2n
-.rearr2ang
-.rearrange1me
-.rearrange1men
-.rearrange3men1t
-.re9a8r8r8a8n8g8e9m8e8n8t8s.
-.rearrangemen4t4s2
-.re8c9i9p8r8o8c9i9t8i8e8s.
-.reciproci1ti
-.reciprocit2ie4
-.re8c9t8a8n9g8l8e.
-.rec4ta2n
-.re2c1t
-.rect5ang
-.rec1ta
-.rectan1gl2
-.rectan1gle
-.re8c9t8a8n9g8l8e8s.
-.rectangles2
-.re8c9t8a8n9g8u9l8a8r.
-.rectan1gu
-.rectangu1la
-.rectangul2a2r
-.re9d8i9r8e8c8t.
-.2r2ed
-.r4edi
-.red4ir2
-.redi1re
-.redire2c1t
-.re9d8i9r8e8c8t9i8o8n.
-.redirec1t2io
-.redirectio2n
-.re9d8u8c9i8b8l8e.
-.re1du
-.redu2c
-.reduci4b
-.redu1ci
-.reduci1b2l2
-.re9e8c8h8o.
-.ree2c
-.ree2ch
-.ree3cho2
-.re9p8h8r8a8s8e.
-.rep4hr4
-.rephr2as
-.re9p8h8r8a8s8e8s.
-.rephras1e4s
-.re9p8h8r8a8s8e8d.
-.rephra4s4ed
-.re9p8o9s8i9t8i8o8n.
-.re4posi
-.re1po
-.re1pos
-.repo3s2i1t2io
-.reposi1ti
-.repositio2n
-.re9p8o9s8i9t8i8o8n8s.
-.repositio2n3s2
-.re9p8r8i8n8t.
-.repr2
-.reprin4t3
-.re9p8r8i8n8t8s.
-.reprin4t4s2
-.re9s8t8o8r9a8b8l8e.
-.r4es2to
-.resto2ra
-.resto2rab
-.restorab2l2
-.re8t8r8o9f8i8t.
-.retro2fi
-.re8t8r8o9f8i8t9t8e8d.
-.retrof4i4t4t2
-.retrofit2t1ed
-.re9u8s9a8b8l8e.
-.r4eu2
-.re2us4
-.reusa2
-.reu2s1ab
-.reusab2l2
-.re9u8s8e.
-.re9w8i8r8e.
-.rewi2
-.rew4ir4
-.re9w8r8a8p.
-.rewra4
-.re9w8r8a8p8p8e8d.
-.rewra4p1p
-.rewrap2pe
-.rewrap4p2ed
-.re9w8r8i8t8e.
-.rewri4
-.rewr2ite
-.rh8i9n8o8c9e8r9o8s.
-.rh4
-.rh2i1no
-.rhi4no4c
-.rhino1ce
-.rhinoc2ero
-.ri8g8h8t9e8o8u8s.
-.righ1teo
-.righteou2
-.righteo2us
-.ri8g8h8t9e8o8u8s9n8e8s8s.
-.righteous1n4
-.righteous1nes
-.righteousn2e2ss
-.ri8n8g9l8e8a8d8e8r.
-.rin4g
-.ringl2
-.rin1gle
-.ringle2a
-.ringlea2d1
-.ri8n8g9l8e8a8d8e8r8s.
-.ringleade4r5s2
-.ro9b8o8t.
-.ro9b8o8t8s.
-.robo4t1s2
-.ro9b8o8t8i8c.
-.ro9b8o8t9i8c8s.
-.roboti4c3s2
-.ro8u8n8d9t8a8b8l8e.
-.rou2
-.roun2d
-.round1ta
-.round2tab
-.roundtab2l2
-.ro8u8n8d9t8a8b8l8e8s.
-.roundta5bles2
-.sa8l8e8s9c8l8e8r8k.
-.sa2
-.s2ale
-.sales2
-.sales2c
-.salescle5
-.sales1c4l4
-.sa8l8e8s9c8l8e8r8k8s.
-.salescler4k1s2
-.sa8l8e8s9w8o8m8a8n.
-.sales4w2
-.sale4s1wo2
-.saleswom1
-.saleswo1ma
-.saleswoma2n
-.sa8l8e8s9w8o8m8e8n.
-.saleswo2me
-.saleswo1men
-.sa8l9m8o9n8e8l9l8a.
-.s4a2l4m
-.salmo2n4
-.sal1mo
-.salmon4ella
-.salmonel1l
-.sa8l9t8a9t8i8o8n.
-.sa4l4t
-.sal1ta
-.salta1t2io
-.saltatio2n
-.sa8r9s8a9p8a8r9i8l9l8a.
-.s2a2r
-.sa2r4sa2
-.sa4rs2
-.sars1ap
-.s2a2rsap2a2r4
-.sarsa1pa
-.sarsap4a4r1i
-.sarsaparil1l
-.sa8u8e8r9k8r8a8u8t.
-.sau4
-.sauerkrau4t
-.sc8a8t9o9l8o8g9i9c8a8l.
-.s1ca
-.sca1to
-.scato3log1ic
-.scatologi1ca
-.sc8h8e8d9u8l9i8n8g.
-.s2ch2
-.sche2
-.s4ch4ed
-.sche4dul
-.sche1du
-.schedul2i
-.schedul3ing
-.sc8h8i8z9o9p8h8r8e8n8i8c.
-.schi2z
-.schi1zo
-.schiz2oph
-.schizop4hr4
-.sc8h8n8a8u9z8e8r.
-.sc2h1n
-.sch1na
-.schn2au
-.schnau2z4e
-.schnauz1er
-.sc8h8o8o8l9c8h8i8l8d.
-.s4cho2
-.schoo2
-.schoo4l1c2
-.s2chool2ch
-.schoolch4il2
-.schoolchi2ld
-.sc8h8o8o8l9c8h8i8l8d9r8e8n.
-.schoolchil3dr
-.schoolchildre4
-.schoolchil5dren
-.sc8h8o8o8l9t8e8a8c8h8e8r.
-.schoo4l2t
-.school1te
-.s2chooltea2ch
-.schoolteache2
-.sc8h8o8o8l9t8e8a8c8h9e8r8s.
-.schoolteach3e4r1s2
-.sc8r8u9t8i9n8y.
-.scru2t1i5n
-.scr4u1t2i
-.scrut4iny
-.sc8y8t8h9i8n8g.
-.s1cy
-.scy3thin
-.se8l8l9e8r.
-.sel2le
-.se8l8l9e8r8s.
-.selle4r1s2
-.se8c9r8e9t8a8r9i8a8t.
-.se1cr
-.se4c3re1ta
-.secret2a2r
-.secretar1i
-.secretar2i3a
-.se8c9r8e9t8a8r9i8a8t8s.
-.secretaria4t1s2
-.se8m9a9p8h8o8r8e.
-.se1ma
-.se4map
-.semapho4r
-.se8m9a9p8h8o8r8e8s.
-.se9m8e8s9t8e8r.
-.4se1me
-.se2mes
-.se8m8i9d8e8f9i9n8i8t8e.
-.sem2id
-.semide1f
-.semidef5i5n2ite
-.semide1fi
-.semide2fin
-.semidef2ini
-.semidefin2it
-.se8m8i9d8i9r8e8c8t.
-.semi2di
-.semid4ir2
-.semidi1re
-.semidire2c1t
-.se8m8i9h8o9m8o9t8h8e8t9i8c.
-.semi3h
-.semiho1mo
-.semihom4oth3
-.semihomoth2e
-.semihomo3the4t
-.semihomothet1ic
-.se8m8i9r8i8n8g.
-.sem4ir
-.semir1i
-.semirin4g
-.se8m8i9r8i8n8g8s.
-.semirings2
-.se8m8i9s8i8m9p8l8e.
-.se4m2is
-.semisi4m1p
-.semisim1p2l2
-.se8m8i9s8k8i8l8l8e8d.
-.sem4is4k2
-.semisk1i
-.semisk4il1l
-.semiskil2le
-.se8r8o9e8p8i9d8e9m8i9o9l8o8g9i9c8a8l.
-.s2er4o
-.sero4e
-.seroep4id
-.seroepi3de
-.seroepid4em
-.seroepidem2io
-.seroepidemi1ol
-.seroepidemio3log1ic
-.seroepidemiologi1ca
-.se8r9v8o9m8e8c8h9a8n8i8s8m.
-.4ser3vo
-.servo2me
-.servome2ch
-.servomech5a5nis
-.servomecha2n
-.servomechani2s1m
-.se8r9v8o9m8e8c8h9a8n8i8s8m8s.
-.servomechan4is4m1s2
-.se8s9q8u8i9p8e9d8a9l8i8a8n.
-.s1e4s
-.sesqu2
-.sesq2ui2
-.sesqu2ip
-.sesquipe4
-.sesqui2p2ed
-.sesquip2e2d2a
-.sesquipedal1i
-.sesquipedal2i1a
-.sesquipedali2a2n
-.se8t9u8p.
-.se1tu
-.se8t9u8p8s.
-.setu2p1s2
-.se9v8e8r8e9l8y.
-.5sev
-.sev1er
-.sev4erel
-.severe1ly
-.sh8a8p8e9a8b8l8e.
-.sha3pe4a
-.shape1a4b
-.shapeab2l2
-.sh8o8e9s8t8r8i8n8g.
-.sho4
-.sho2est4r
-.shoestrin4g
-.sh8o8e9s8t8r8i8n8g8s.
-.shoestrings2
-.si8d8e9s8t8e8p.
-.5side4s2
-.s2id
-.sideste4p
-.si8d8e9s8t8e8p8s.
-.sideste2p1s2
-.si8d8e9s8w8i8p8e.
-.sides4w2
-.sideswi2
-.sidesw2ip
-.sideswipe4
-.sk8y9s8c8r8a8p8e8r.
-.sk2
-.skys4c
-.skyscrap3er
-.sk8y9s8c8r8a8p8e8r8s.
-.skyscrape4r1s2
-.sm8o8k8e9s8t8a8c8k.
-.2s1m
-.s1mo
-.s4m2ok
-.smokes4
-.smokes1ta
-.smokestack1
-.sm8o8k8e9s8t8a8c8k8s.
-.smokestac4k1s2
-.sn8o8r9k8e8l9i8n8g.
-.s1n4
-.snorke5l2i
-.snorke4l3ing
-.so9l8e9n8o8i8d.
-.1so
-.sol4eno
-.solenoi2
-.soleno2id
-.so9l8e9n8o8i8d8s.
-.solenoi2d1s2
-.so8l8u8t8e.
-.so1lut
-.so8l8u8t8e8s.
-.so8v9e8r9e8i8g8n.
-.4sov
-.soverei2
-.sovere2ig2
-.so8v9e8r9e8i8g8n8s.
-.sovereig2n1s2
-.sp8a9c8e8s.
-.2s1pa
-.spa4ce
-.sp8e9c8i8o8u8s.
-.spe2c
-.spe1c2i
-.spec2io
-.speciou2
-.specio2us
-.sp8e8l8l9e8r.
-.spel1l
-.spel2le
-.sp8e8l8l9e8r8s.
-.spelle4r1s2
-.sp8e8l8l9i8n8g.
-.spell2i
-.spel2lin4
-.sp8e9l8u8n8k9e8r.
-.spelu4nk2
-.spelunk1er
-.sp8e8n8d9t8h8r8i8f8t.
-.spen4d
-.spend2th
-.spendt4hr4
-.spendthr4i2ft
-.sp8h8e8r9o8i8d.
-.s2phe
-.3sph4er
-.sph2ero
-.spheroi2
-.sphero2id
-.sp8h8e8r9o8i8d9a8l.
-.spheroi1d2a
-.sp8h8i8n9g8e8s.
-.sph5ing
-.sph4inge
-.sp8i8c9i9l8y.
-.sp2i1ci
-.spici1ly
-.sp8i8n9o8r8s.
-.spi2n
-.sp4i1no
-.spino4rs2
-.sp8o8k8e8s9w8o8m8a8n.
-.sp2ok
-.spokes4
-.spokes4w2
-.spoke4s1wo2
-.spokeswom1
-.spokeswo1ma
-.spokeswoma2n
-.sp8o8k8e8s9w8o8m8e8n.
-.spokeswo2me
-.spokeswo1men
-.sp8o8r8t8s9c8a8s8t.
-.s1p4or4
-.spor4t1s2
-.sport4sc
-.sports1ca
-.sp8o8r8t8s9c8a8s8t9e8r.
-.sportscast5er
-.sp8o8r9t8i8v8e9l8y.
-.spor1ti
-.spor4t2iv
-.sportiv4e1ly
-.sp8o8r8t8s9w8e8a8r.
-.sport4sw2
-.sportswe2a2r
-.sp8o8r8t8s9w8r8i8t8e8r.
-.sportswri4
-.sportswr2ite
-.sp8o8r8t8s9w8r8i8t8e8r8s.
-.sportswrit5e4r1s2
-.sp8r8i8g8h8t9l8i8e8r.
-.spr2
-.spr2ig
-.sprigh2tl
-.sprightl2ie4
-.sq8u8e8a9m8i8s8h.
-.squ2
-.squeam2is
-.squeamis2h
-.st8a8n8d9a8l8o8n8e.
-.5st4and
-.sta2n
-.stan1d2a
-.standalo2n
-.st8a8r9t8l8i8n8g.
-.st2a2r
-.star2tl
-.st8a8r9t8l8i8n8g9l8y.
-.startlingl2
-.startling1ly
-.st8a9t8i8s9t8i8c8s.
-.statis1t2i
-.statis1tic
-.statisti4c3s2
-.st8e8a8l8t8h9i8l8y.
-.stea4l
-.stea4lt
-.stealth3i
-.steal4th4il2
-.stealthi1ly
-.st8e8e8p8l8e9c8h8a8s8e.
-.s1tee
-.stee4p1
-.stee1p2l2
-.steeple2ch
-.st8e8r8e8o9g8r8a8p8h9i8c.
-.stere1o
-.stereo2g
-.stereo1gr
-.stereo5graph1ic
-.stereogr4aphi
-.st8o9c8h8a8s9t8i8c.
-.s1to
-.sto2ch4
-.stochast2i
-.stochas1tic
-.st8r8a8n8g8e9n8e8s8s.
-.st4r
-.s1tra
-.stran4ge
-.stra2n
-.str2ang
-.strange4n4e
-.stran1gen
-.strange1nes
-.strangen2e2ss
-.st8r8a8p9h8a8n8g8e8r.
-.straph2an4g
-.straphang5er
-.strapha2n
-.st8r8a8t9a9g8e8m.
-.stra2ta
-.st8r8a8t9a9g8e8m8s.
-.stratage4m1s2
-.st8r8e8t8c8h9i9e8r.
-.stre4tc
-.stret4ch
-.stretch2ie4
-.st8r8i8p9t8e8a8s8e.
-.str2ip
-.stri2p1t
-.strip2te
-.st8r8o8n8g9h8o8l8d.
-.stro2n
-.strongho2l2d
-.st8r8o8n8g9e8s8t.
-.st8u9p8i8d9e8r.
-.s1tu
-.stup4id
-.stupi3de
-.st8u9p8i8d9e8s8t.
-.stupide4s2
-.su8b9d8i8f9f8e8r9e8n9t8i8a8l.
-.1su
-.su4b3
-.su4b1d
-.subd1if
-.subdi4f1f
-.subdiffer1
-.subdiffer3en1t
-.subdifferent2i
-.subdifferen1t2i1a
-.subdifferenti2al
-.su8b9e8x9p8r8e8s9s8i8o8n.
-.sub4e
-.sub1ex3p
-.subexpr2
-.subex3pr2e2ss
-.subexpres1si
-.subexpres1s2io
-.subexpres5sio2n
-.su8b9e8x9p8r8e8s9s8i8o8n8s.
-.subexpressio2n3s2
-.su8m9m8a9b8l8e.
-.su2m
-.sum1m
-.sum1ma
-.sum2mab
-.summab2l2
-.su8p8e8r9e8g8o.
-.su1pe
-.supere1go
-.su8p8e8r9e8g8o8s.
-.supere4gos
-.su9p8r8e8m9a9c8i8s8t.
-.supr2
-.supre4mac
-.supre1ma
-.suprem4a2ci
-.su9p8r8e8m9a9c8i8s8t8s.
-.supremacis4t1s2
-.su8r9v8e8i8l9l8a8n8c8e.
-.su2r
-.surv4e
-.survei2
-.surveil1l
-.surveilla2n
-.sw8i8m9m8i8n8g9l8y.
-.sw2
-.swi2
-.swim1m
-.swimm4ingl2
-.swimm5ing1ly
-.sy8m8p9t8o9m8a8t8i8c.
-.sy4m1p
-.sym2p1t
-.symp1to
-.sympto2ma
-.symptomat1ic
-.sy8n9c8h8r8o9m8e8s8h.
-.syn3c4hr4
-.syn2ch
-.synchro2me
-.synchro2mes
-.synchrom4es2h
-.sy8n9c8h8r8o9n8o8u8s.
-.synchro2n
-.synchro1nou2
-.synchrono2us
-.sy8n9c8h8r8o9t8r8o8n.
-.synchrotro2n
-.ta8f8f9r8a8i8l.
-.4ta2f4
-.ta4f1f4
-.taffr2ai2
-.ta8l8k9a9t8i8v8e.
-.ta2l
-.4talk
-.talka3
-.talka4t
-.talka1t2iv
-.ta9p8e8s9t8r8y.
-.tap2est4r
-.tape4stry
-.ta9p8e8s9t8r8i8e8s.
-.tapestr2ie4
-.ta8r9p8a8u9l8i8n.
-.t2a2r
-.tar2p
-.tar1pa
-.tarpau4l2
-.tarpaul2i
-.ta8r9p8a8u9l8i8n8s.
-.tarpaul2i2n1s2
-.te9l8e8g9r8a9p8h8e8r.
-.tele1gr
-.teleg5ra3ph4er
-.te9l8e8g9r8a9p8h8e8r8s.
-.telegraphe4r1s2
-.te8l8e9k8i9n8e8t9i8c.
-.teleki4n
-.telek1i
-.telek2ine
-.teleki3net1ic
-.te8l8e9k8i9n8e8t9i8c8s.
-.telekineti4c3s2
-.te8l8e9r8o9b8o8t9i8c8s.
-.te4l1er
-.tel4ero
-.teler5ob
-.teleroboti4c3s2
-.te8l8l9e8r.
-.tel1l
-.tel2le
-.te8l8l9e8r8s.
-.telle4r1s2
-.te8m9p8o9r8a8r9i8l8y.
-.te4m1p
-.tem1p4or
-.tempo1ra
-.tempo4raril
-.tempor2a2r
-.temporar1i
-.temporari1ly
-.te8n9u8r8e.
-.te8s8t9b8e8d.
-.tes2t1b
-.test4be2d
-.te8x8t9w8i8d8t8h.
-.3tex
-.tex1t2
-.textw4
-.textwi2
-.textw2id
-.textwid2th
-.th8a8l9a9m8u8s.
-.tha3la
-.thala3m
-.thala1mu
-.thalam2us
-.th8e8r9m8o9e8l8a8s9t8i8c.
-.th2e
-.ther3m4
-.ther1mo
-.thermo4el
-.thermoe1la
-.thermoelast2i
-.thermoelas1tic
-.ti8m8e9s8t8a8m8p.
-.ti2mes
-.times1ta
-.timesta4m1p
-.ti8m8e9s8t8a8m8p8s.
-.timestam2p1s2
-.to8o8l9k8i8t.
-.too2
-.toolk1i
-.to8o8l9k8i8t8s.
-.toolki4t1s2
-.to8p8o9g8r8a8p8h9i9c8a8l.
-.to5po4g
-.topo1gr
-.topo5graph1ic
-.topogr4aphi
-.topographi1ca
-.to8q8u8e8s.
-.to1q
-.toqu2
-.tr8a8i9t8o8r9o8u8s.
-.1tra
-.tr2ai2
-.trai1to
-.traitorou2
-.traitoro2us
-.tr8a8n8s9c8e8i8v8e8r.
-.tra2n
-.tra2n1s2
-.trans4c
-.tran4s3cei2
-.transce2iv
-.tr8a8n8s9c8e8i8v8e8r8s.
-.transceive4r1s2
-.tr8a8n8s9g8r8e8s8s.
-.tran2s3g
-.trans1gr
-.transgr2e2ss
-.tr8a8n8s9v8e8r9s8a8l.
-.tran4sv
-.transve4r1s2
-.transver1sa2
-.tr8a8n8s9v8e8r9s8a8l8s.
-.transversa2l1s2
-.tr8a8n8s9v8e8s9t8i8t8e.
-.transv4e2s
-.transvest2i
-.transvest2ite
-.tr8a8n8s9v8e8s9t8i8t8e8s.
-.transvestit4es
-.tr8a9v8e8r8s9a9b8l8e.
-.trave4r1s2
-.traver1sa2
-.traver2s1ab
-.traversab2l2
-.tr8a9v8e8r9s8a8l.
-.tr8a9v8e8r9s8a8l8s.
-.traversa2l1s2
-.tr8i9e8t8h8y8l9a8m8i8n8e.
-.tri5et
-.tr2ie4
-.triethy3la
-.triethylam1in
-.triethylam2ine
-.tr8e8a8c8h9e8r8i8e8s.
-.trea2ch
-.treache2
-.treacher1i
-.treacher2ie4
-.tr8o8u9b8a9d8o8u8r.
-.trou2
-.trouba2d
-.trouba1do
-.troubadou2
-.tu8r9k8e8y.
-.1tu
-.tu8r9k8e8y8s.
-.turkeys4
-.tu8r8n9a8r8o8u8n8d.
-.tur4n2a2r
-.tur1na
-.turnarou2
-.turnaroun2d
-.tu8r8n9a8r8o8u8n8d8s.
-.turnaroun2d1s2
-.ty8p9a8l.
-.1ty
-.ty1pa
-.typ4al
-.un9a8t9t8a8c8h8e8d.
-.un2at4
-.una4t3t2
-.unat1ta
-.unatta2ch
-.unattache2
-.unatta4ch4ed
-.un9e8r8r9i8n8g9l8y.
-.un4er
-.uner4r4
-.unerrin4g
-.unerringl2
-.unerring1ly
-.un9f8r8i8e8n8d9l8y.
-.un3f
-.unfri2
-.unfr2ie4
-.unfrien2d1ly
-.un9f8r8i8e8n8d9l8i9e8r.
-.unfriendl2ie4
-.va8g8u8e8r.
-.1va
-.vag4
-.va5guer
-.va2gue
-.va8u8d8e9v8i8l8l8e.
-.vaude1v4
-.vaude2v3i4l
-.vaude1vi
-.vaudevil1l
-.vaudevil2le
-.vi8c9a8r8s.
-.v4ic2a2r
-.vi1ca
-.vica4rs2
-.vi8l9l8a8i8n9e8s8s.
-.2vil
-.vil1l
-.villai2
-.villa4i4n
-.villa2ine
-.villai5n2e2ss
-.villai1nes
-.vi8s9u8a8l.
-.vi3su
-.visu1al
-.vi8s9u8a8l9l8y.
-.visual1l
-.visual1ly
-.vi9v8i8p9a9r8o8u8s.
-.3v2iv
-.viv2i4p
-.vivi1pa
-.vivip2a2r
-.viviparou2
-.viviparo2us
-.vo8i8c8e9p8r8i8n8t.
-.voi4
-.voi3cep
-.voicepr2
-.voiceprin4t3
-.vs8p8a8c8e.
-.v2s1pa
-.vspa4ce
-.wa8d9d8i8n8g.
-.wa2d
-.wad4d1in
-.wad1d4
-.wa8l8l9f8l8o8w8e8r.
-.wal1l
-.wal2lf
-.wallf4l2
-.wallflow1er
-.wa8l8l9f8l8o8w9e8r8s.
-.wallflowe4r1s2
-.wa8r8m9e8s8t.
-.w2a2r
-.war1m
-.war2me
-.war2mes
-.wa8s8t8e9w8a8t8e8r.
-.was4t
-.waste2w
-.waste1w5a
-.wastewa1te
-.wa8v8e9g8u8i8d8e.
-.waveg3
-.waveg2ui2
-.wavegu2id
-.wa8v8e9g8u8i8d8e8s.
-.waveguide4s2
-.wa8v8e9l8e8t.
-.wa8v8e9l8e8t8s.
-.wavele4t1s2
-.we8b9l8i8k8e.
-.w2e1b
-.web2l2
-.web3l4ik
-.we8e8k9n8i8g8h8t.
-.weekn2ig
-.we8e8k9n8i8g8h8t8s.
-.weeknigh4t1s2
-.wh8e8e8l9c8h8a8i8r.
-.whee4l1c2
-.wheel2ch
-.wheelchai2
-.wheelcha4ir
-.wh8e8e8l9c8h8a8i8r8s.
-.wheelchai4rs2
-.wh8i8c8h9e8v8e8r.
-.whi4
-.wh4i2ch
-.whiche2
-.whichev1er
-.wh8i8t8e9s8i8d8e8d.
-.wh2ite
-.whit4es
-.white1si
-.white2s2id
-.whitesi2d1ed
-.wh8i8t8e9s8p8a8c8e.
-.white1sp
-.white2s1pa
-.whitespa4ce
-.wh8i8t8e9s8p8a8c8e8s.
-.wi8d8e9s8p8r8e8a8d.
-.w2id
-.wide4s2
-.wide1sp
-.wides4pre
-.widespr2
-.widesprea2d1
-.wi8n8g9s8p8a8n.
-.win4g
-.wings2
-.wing2s1pa
-.wingspa4n
-.wi8n8g9s8p8a8n8s.
-.wingspa2n1s2
-.wi8n8g9s8p8r8e8a8d.
-.wingspr2
-.wingsprea2d1
-.wi8t8c8h9c8r8a8f8t.
-.wi4tc
-.wit4ch
-.witchcra2f4t
-.witchcra2f
-.wo8r8d9s8p8a8c9i8n8g.
-.1wo2
-.wor2d1s2
-.words4p
-.word2s1pa
-.wordsp4a2ci
-.wordspa2c1in
-.wordspac1ing
-.wo8r8k9a8r8o8u8n8d.
-.work2a2r
-.workarou2
-.workaroun2d
-.wo8r8k9a8r8o8u8n8d8s.
-.workaroun2d1s2
-.wo8r8k9h8o8r8s8e.
-.workh4
-.workhor4se
-.workho4rs2
-.wo8r8k9h8o8r8s8e8s.
-.workhors3e4s
-.wr8a8p9a8r8o8u8n8d.
-.wra4
-.wrap2a2r4
-.wra1pa
-.wraparou2
-.wraparoun2d
-.wr8e8t8c8h9e8d.
-.wre4tc
-.wret4ch
-.wretche2
-.wret4ch4ed
-.wr8e8t8c8h9e8d9l8y.
-.wretche2d1ly
-.ye8s9t8e8r9y8e8a8r.
-.yes4
-.yesterye2a2r
-.al9g8e9b8r8a8i9s8c8h8e.
-.algebra2is1c
-.algebrais3ch2
-.algebraische2
-.al9l8e9g8h8e9n8y.
-.al1l
-.al2le
-.al3leg
-.alleghe2n
-.ar9k8a8n9s8a8s.
-.arka2n
-.arkan2sa2
-.arka2n1s2
-.at8p9a8s8e.
-.a4t1p
-.at1pa
-.at8p9a8s8e8s.
-.atpas1e4s
-.au8s9t8r8a8l9a8s8i8a8n.
-.a2us
-.aus1t4r
-.aus1tra
-.australas2i1a
-.australasi2a2n
-.au8t8o9m8a8t8i9s8i8e8r9t8e8r.
-.automa3tis
-.automatis2ie4
-.automatisiert3er
-.be9d8i8e9n8u8n8g.
-.4be2d
-.b4e3di
-.be5di3en
-.bed2ie4
-.bedie3nu4n
-.be8m8b8o.
-.4be5m
-.be4m5b
-.bi8b9l8i9o9g8r8a9p8h8i9s8c8h8e.
-.bibliogr4aphi
-.bibliograph2is1c
-.bibliographis3ch2
-.bibliographische2
-.bo8s9t8o8n.
-.5bos4
-.bos1to
-.bosto2n
-.br8o8w8n9i8a8n.
-.brown5i
-.brow3n4i1a
-.browni3a2n
-.br8u8n8s9w8i8c8k.
-.bru2n
-.bru2n3s4
-.brun4sw2
-.brunswi2
-.brunswick1
-.bu9d8a9p8e8s8t.
-.bu1d2a
-.ca8r9i8b9b8e8a8n.
-.car1i
-.car4ib
-.cari2b1b
-.carib2be
-.caribbea2n
-.ch8a8r8l8e8s9t8o8n.
-.char4le4
-.char1l
-.charles2
-.charl4es2to
-.charle3sto2n
-.ch8a8r9l8o8t8t8e8s9v8i8l8l8e.
-.char3lo4
-.charlo4t3t2
-.charlot4tes
-.charlotte4sv
-.charlottes2vil
-.charlottesvil1l
-.charlottesvil2le
-.co9l8u8m9b8i8a.
-.colum4bi
-.colu4m1b
-.columb2i1a
-.cz8e8c8h8o9s8l8o9v8a9k8i8a.
-.c2ze4
-.cze2ch
-.cze3cho2
-.czechos4l2
-.czechos4lov
-.czechoslo1va
-.czechoslovak1i
-.czechoslovak2i1a
-.de8l9a9w8a8r8e.
-.de1la
-.de4law
-.delaw2a2r
-.di8j8k9s8t8r8a.
-.di3j
-.dij4k1s2
-.dijkst4r
-.dijks1tra
-.du8a8n8e.
-.d1u1a
-.dua2n
-.dy9n8a9m8i9s8c8h8e.
-.5dyn
-.dy1na
-.dynam2is
-.dynam2is1c
-.dynamis3ch2
-.dynamische2
-.en8g9l8i8s8h.
-.engl2
-.englis2h
-.eu8l8e8r9i8a8n.
-.eul4e
-.eu3l4er1i
-.eule1r2i3a4
-.euleri2a2n
-.ev8a8n9s8t8o8n.
-.e1va
-.eva2n
-.evan4st
-.eva2n1s2
-.evans1to
-.evansto2n
-.fe8b9r8u9a8r8y.
-.f2e4b
-.fe3br
-.febru3a
-.febru2a2r
-.fe8s8t9s8c8h8r8i8f8t.
-.fes4t1s2
-.fest4sc
-.fests2ch2
-.festsc4hr4
-.festschr4i2ft
-.fl8o8r9i9d8a.
-.flor2id
-.flori1d2a
-.fl8o8r9i9d9i8a8n.
-.flori2di
-.florid5i2a2n
-.flori1d4i3a
-.fo8r9s8c8h8u8n8g8s9i8n9s8t8i9t8u8t.
-.fors4c
-.fors2ch2
-.forschungs2
-.forschung2s1in
-.forschungs2i2n1s2
-.forschungsinst2i
-.forschungsinsti1tu
-.fr8e8e9b8s8d.
-.fre2e1b
-.free2b5s2
-.freeb4s5d
-.fu8n8k9t8s8i8o8n8a8l.
-.3fu
-.fu4nk2
-.funk5t
-.funk4t1s2
-.funkt1s2io
-.funkt5sio2n
-.funktsio1n5a
-.ga8u8s8s9i8a8n.
-.ga2us
-.gau2ss
-.gaus1si
-.gauss2i1a
-.gaussi2a2n
-.gh8o8s8t9s8c8r8i8p8t.
-.ghos4t1s2
-.ghost4sc
-.ghostscri2
-.ghostscr2ip
-.ghostscri2p1t
-.gh8o8s8t9v8i8e8w.
-.ghos4tv
-.ghostv2ie4
-.gr8a8s8s9m8a8n8n9i8a8n.
-.gr2as
-.gra2ss
-.gras2s1m
-.grass3ma
-.grassma2n3
-.grassma4n1n2
-.grassman3n4i1a
-.grassma2nni3a2n
-.gr8e8i8f8s9w8a8l8d.
-.grei2
-.grei2f3s
-.greifsw2
-.greifswa2ld
-.gr8o8t8h8e8n9d8i8e8c8k.
-.g4ro
-.gro4th2e
-.gr4oth
-.grothe2n
-.grothend2ie4
-.grothendieck1
-.gr8u8n8d9l8e8h9r8e8n.
-.gru2n
-.grundle1h4
-.grundle4hr4
-.ha9d8a9m8a8r8d.
-.ha2d
-.ha1d2a
-.hada2m2
-.had4a1ma
-.hadam2a2r
-.ha8i9f8a.
-.hai1fa
-.ha8m8i8l9t8o8n9i8a8n.
-.ha4m
-.hami4lt
-.hamil1to
-.hamilto2n
-.hamilto3n4i1a
-.hamiltoni3a2n
-.he8l9s8i8n8k8i.
-.he2l1s2
-.hel2s1in
-.hels4i4nk2
-.helsink1i
-.he8r9m8i8t9i8a8n.
-.her3mit
-.hermi1ti
-.herm4i1t2i1a
-.hermiti2a2n
-.hi8b8b8s.
-.hi2b1b
-.hib2b5s2
-.ho8k9k8a8i9d8o.
-.h2ok
-.hokk4
-.hokkai2
-.hokka2id
-.hokkai1do
-.ja8c9k8o8w9s8k8i.
-.5ja
-.jack1
-.jackowsk2
-.jackowsk1i
-.ja8n9u9a8r8y.
-.ja2n
-.jan3u1a
-.janu2a2r
-.ja9p8a9n8e8s8e.
-.ja4p
-.ja1pa
-.japa2n
-.japa1nes
-.japane1s2e
-.ka8d9o8m9t8s8e8v.
-.ka2d
-.ka1do
-.kado4mt
-.kadom4t1s2
-.kadomt5sev
-.ka8n9s8a8s.
-.ka2n
-.kan2sa2
-.ka2n1s2
-.ka8r8l8s9r8u8h8e.
-.k2a2r
-.kar1l
-.kar2l1s2
-.karls1r
-.ko8r9t8e9w8e8g.
-.ko5r
-.kr8i8s8h8n8a.
-.kr2is
-.kr3is2h
-.kris2h1n
-.krish1na
-.kr8i8s8h9n8a9i8s8m.
-.krishnai2
-.krishnai2s1m
-.kr8i8s8h9n8a8n.
-.krishn2a2n
-.la8n9c8a8s9t8e8r.
-.lan1ca
-.lancast5er
-.le9g8e8n8d8r8e.
-.le1gen
-.legen1dr
-.legendre4
-.le8i8c8e8s9t8e8r.
-.lei2
-.le5ic
-.leices5t
-.li8p9s8c8h8i8t8z.
-.l2ip
-.li2p1s2
-.lips2ch2
-.lips3chit
-.lipschi4tz
-.li8p9s8c8h8i8t8z9i8a8n.
-.lipschit2z1i
-.lipschitz2i1a
-.lipschitzi2a2n
-.lo8j9b8a8n.
-.lo5j
-.lojba2n
-.lo8u9i9s8i9a8n8a.
-.lou2
-.lo2ui2
-.louis2i1a
-.louisi2a2n
-.louisia1na
-.ma8c9o8s.
-.ma1co
-.ma8n9c8h8e8s9t8e8r.
-.man2ch
-.manche2
-.manch1es
-.ma8r9k8o8v9i8a8n.
-.marko5vi2a2n
-.markov2i1a
-.ma8r8k8t9o8b8e8r9d8o8r8f.
-.mark5t
-.mark1to
-.markto3b
-.marktober1do
-.marktoberd4or
-.marktoberdor1f
-.ma8s8s9a9c8h8u9s8e8t8t8s.
-.ma2ss
-.mas1sa2
-.massa2ch
-.massach2us
-.massachuse4t3t2
-.massachuset4t1s2
-.ma8x9w8e8l8l.
-.maxwel4l
-.mi9c8r8o9s8o8f8t.
-.micro2so
-.microso2ft3
-.mi8n9n8e9a8p9o9l8i8s.
-.m2i4n1n2
-.minne4
-.minneapol2i
-.mi8n9n8e9s8o8t8a.
-.min1nes
-.minne1so
-.minneso1ta
-.mo8s9c8o8w.
-.mos2c
-.mos1co
-.na8c8h9r8i8c8h8t8e8n.
-.1na
-.na2ch
-.nac4hr4
-.na2chr4i2ch
-.nachricht1en
-.na8s8h9v8i8l8l8e.
-.n4as
-.nas2h
-.nash2vil
-.nashvil1l
-.nashvil2le
-.ne8t9b8s8d.
-.ne2t1b
-.net2b5s2
-.netb4s5d
-.ne8t9s8c8a8p8e.
-.ne4t1s2
-.net4sc
-.netsca4p
-.nets1ca
-.ni8j9m8e9g8e8n.
-.ni3j
-.nijme2g
-.nijme1gen
-.no8e9t8h8e8r9i8a8n.
-.3noe
-.noeth2e
-.noether1i
-.noethe1r2i3a4
-.noetheri2a2n
-.no8o8r8d9w8i8j8k8e8r9h8o8u8t.
-.noo2
-.no3ord
-.noord1w
-.noordwi2
-.noordwi3j
-.noordwijk1er
-.noordwijker1h4
-.noordwijkerhou2
-.no9v8e8m9b8e8r.
-.nove4m5b
-.op8e8n9b8s8d.
-.ope4n1b4
-.open2b5s2
-.openb4s5d
-.op8e8n9o8f8f8i8c8e.
-.op4eno
-.openo4f1f
-.openof1fi
-.pa8l8a9t8i8n8o.
-.pala2t1in
-.palat2i1no
-.pa9l8e8r9m8o.
-.paler3m4
-.paler1mo
-.pe9t8r8o8v9s8k8i.
-.petro3v
-.petrovsk2
-.petrovsk1i
-.pf8a8f8f9i8a8n.
-.4pf
-.p1fa
-.pfa2f
-.pfa4f1f4
-.pfaf1fi
-.pfaff2i3a
-.pfaffi2a2n
-.ph8i8l9a9d8e8l9p8h8i8a.
-.phi4l4ade
-.phila2d
-.philade2lp
-.philadel5phi
-.philadelph2i1a
-.ph8i8l9o9s8o8p8h9i9s8c8h8e.
-.philo2so
-.philos4op
-.philos2oph
-.philosoph2is1c
-.philosophis3ch2
-.philosophische2
-.po8i8n9c8a8r8e.
-.poin2
-.poi2
-.poinc2a2r5
-.poin1ca
-.po9t8e8n9t8i8a8l9g8l8e8i9c8h8u8n8g.
-.p4ot
-.po1ten1t
-.potent2i
-.poten1t2i1a
-.potenti2al
-.potentia4l1g4
-.potentialgl2
-.potential1gle
-.potentialglei2
-.potentialgle5ic
-.potentialgle4i2ch
-.ra9d8h8a9k8r8i8s8h9n8a8n.
-.rad1h2
-.radhakr2is
-.radhakr3is2h
-.radhakris2h1n
-.radhakrish1na
-.radhakrishn2a2n
-.ra8t8h8s9k8e8l9l8e8r.
-.r4ath
-.ra2t4h1s2
-.rathsk2
-.rath4ske
-.rathskel1l
-.rathskel2le
-.ri8e9m8a8n8n9i8a8n.
-.r2ie4
-.rie5ma2n
-.rie1ma
-.riema4n1n2
-.rieman3n4i1a
-.riema2nni3a2n
-.ry8d9b8e8r8g.
-.ry1d
-.ryd1b
-.rydberg2
-.sc8h8o8t9t8i8s8c8h8e.
-.scho4t3t2
-.schott2is1c
-.s2ch2ottis3ch2
-.schottische2
-.sc8h8r8o9d8i8n8g9e8r.
-.sc4hr4
-.schrod1in
-.schrod4inge
-.sc8h8w8a9b8a9c8h8e8r.
-.sch1w
-.schwaba2ch
-.schwabache2
-.sc8h8w8a8r8z9s8c8h8i8l8d.
-.schw2a2r
-.s2chwarzs2ch2
-.schwarzsch4il2
-.schwarzschi2ld
-.se8p9t8e8m9b8e8r.
-.se2p1t
-.sep2te
-.septe4m5b
-.st8o8k8e8s9s8c8h8e.
-.st2ok
-.stokes4
-.stok2e2ss
-.stokes2s5c
-.stokess2ch2
-.stokessche2
-.st8u8t8t9g8a8r8t.
-.stu4t3t2
-.stut4t1g
-.stutt1ga
-.stuttg2a2r
-.su8s9q8u8e9h8a8n9n8a.
-.s2us
-.susqu2
-.susque1h4
-.susqueha2n
-.susqueha4n1n2
-.susquehan1na
-.ta8u9b8e8r9i8a8n.
-.tau4b
-.taub4e
-.tau3ber
-.tauber1i
-.taube1r2i3a4
-.tauberi2a2n
-.te8c8h9n8i9s8c8h8e.
-.te2ch
-.tec2h1n
-.techn2is1c
-.te2chnis3ch2
-.technische2
-.te8n9n8e8s9s8e8e.
-.t4e4n1n2
-.tenne4
-.ten1nes
-.tenn2e2ss
-.to9m8a9s8z8e8w9s8k8i.
-.to2ma
-.tomas2ze
-.tomaszewsk2
-.tomaszewsk1i
-.ty9p8o9g8r8a8p8h8i8q8u8e.
-.ty3po
-.ty5po4g
-.typo1gr
-.typogr4aphi
-.typographiqu2
-.uk8r8a8i8n9i8a8n.
-.4uk
-.ukr2ai2
-.ukra4i4n
-.ukra2ini
-.ukrai4n4i1a
-.ukraini3a2n
-.ve8r9a8l8l9g8e9m8e8i8n9e8r8t8e.
-.veral1l
-.veral4l1g4
-.verallge1me
-.verallgemei2
-.verallgeme2ine
-.verallgemein1er
-.ve8r9e8i8n9i9g8u8n8g.
-.vere3in
-.verei2
-.vere2ini
-.verein2ig
-.vereini3gun
-.ve8r9t8e8i9l8u8n9g8e8n.
-.vertei2
-.verteilun1gen
-.vi8i8i8t8h.
-.v4i5i4
-.vi4i5i4
-.vii2ith
-.vi8i8t8h.
-.vi2ith
-.wa8h8r9s8c8h8e8i8n9l8i8c8h9k8e8i8t8s9t8h8e8o9r8i8e.
-.wa4hr4
-.wah4rs2
-.wahrs4c
-.wahrs2ch2
-.wahrsche2
-.wahrschei2
-.wahrsche4i4n1l
-.wahrs2cheinl4i2ch
-.wahrscheinlic4hk
-.wahrscheinlichkei2
-.wahrscheinlichkei4t1s2
-.wahrscheinlichkeits3th2e
-.wahrscheinlichkeitsthe1o5r
-.wahrscheinlichkeitstheor2ie4
-.we8r9n8e8r.
-.w1er
-.wer4n1er
-.we8r9t8h8e8r9i8a8n.
-.werth2e
-.werther1i
-.werthe1r2i3a4
-.wertheri2a2n
-.wi8n9c8h8e8s9t8e8r.
-.win2ch
-.winche2
-.winch1es
-.wi8r8t9s8c8h8a8f8t.
-.w4ir4
-.wir4t1s2
-.wirt4sc
-.wirts2ch2
-.wirtscha2f
-.wirtscha2ft
-.wi8s9s8e8n9s8c8h8a8f8t9l8i8c8h.
-.w4i2s1s
-.wissen4
-.wisse2n1s2
-.wissens4c
-.wissens2ch2
-.wissenscha2f
-.wissenscha2ft
-.wissenschaf2tl
-.wissens2chaftl4i2ch
-.xv8i8i8i8t8h.
-.xv4i5i4
-.xvi4i5i4
-.xvii2ith
-.xv8i8i8t8h.
-.xvi2ith
-.xx8i8i8i8r8d.
-.xx4
-.xx3i
-.xx4i5i4
-.xxi4i5i4
-.xxii4ir
-.xx8i8i8n8d.
-.xxi4ind
-.yi8n8g9y8o8n8g.
-.y1i
-.yin2gy
-.yingy1o4
-.yingyo2n
-.sh8u9x8u8e.
-.shux1u3
-.ji9s8u8a8n.
-.ji2su
-.jisua2n
-.ze8a9l8a8n8d.
-.2ze
-.zea4l
-.zea3l4and
-.zeala2n
-.ze8i8t9s8c8h8r8i8f8t.
-.zei2
-.zei4t1s2
-.zeit4sc
-.zeits2ch2
-.zeitsc4hr4
-.zeitschr4i2ft
diff --git a/core/res/assets/webkit/incognito_mode_start_page.html b/core/res/assets/webkit/incognito_mode_start_page.html
deleted file mode 100644
index 5d7a3fb..0000000
--- a/core/res/assets/webkit/incognito_mode_start_page.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<html>
-  <head>
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
-    <title>New incognito window</title>
-  </head>
-  <body>
-    <p><strong>You've gone incognito</strong>. Pages you view in this window
-      won't appear in your browser history or search history, and they won't
-      leave other traces, like cookies, on your device after you close the
-      incognito window. Any files you download or bookmarks you create will be
-      preserved, however.</p>
-
-    <p><strong>Going incognito doesn't affect the behavior of other people,
-      servers, or software. Be wary of:</strong></p>
-
-    <ul>
-      <li>Websites that collect or share information about you</li>
-      <li>Internet service providers or employers that track the pages you visit</li>
-      <li>Malicious software that tracks your keystrokes in exchange for free smileys</li>
-      <li>Surveillance by secret agents</li>
-      <li>People standing behind you</li>
-    </ul>
-  </body>
-</html>
diff --git a/core/res/assets/webkit/missingImage.png b/core/res/assets/webkit/missingImage.png
deleted file mode 100644
index f49a98d..0000000
--- a/core/res/assets/webkit/missingImage.png
+++ /dev/null
Binary files differ
diff --git a/core/res/assets/webkit/nullPlugin.png b/core/res/assets/webkit/nullPlugin.png
deleted file mode 100644
index 96a52e3..0000000
--- a/core/res/assets/webkit/nullPlugin.png
+++ /dev/null
Binary files differ
diff --git a/core/res/assets/webkit/play.png b/core/res/assets/webkit/play.png
deleted file mode 100644
index 26fe286..0000000
--- a/core/res/assets/webkit/play.png
+++ /dev/null
Binary files differ
diff --git a/core/res/assets/webkit/textAreaResizeCorner.png b/core/res/assets/webkit/textAreaResizeCorner.png
deleted file mode 100644
index 777eff0..0000000
--- a/core/res/assets/webkit/textAreaResizeCorner.png
+++ /dev/null
Binary files differ
diff --git a/core/res/assets/webkit/togglePlugin.png b/core/res/assets/webkit/togglePlugin.png
deleted file mode 100644
index 008333c..0000000
--- a/core/res/assets/webkit/togglePlugin.png
+++ /dev/null
Binary files differ
diff --git a/core/res/assets/webkit/youtube.html b/core/res/assets/webkit/youtube.html
deleted file mode 100644
index 8e103c1..0000000
--- a/core/res/assets/webkit/youtube.html
+++ /dev/null
@@ -1,71 +0,0 @@
-<html>
-  <head>
-    <style type="text/css">
-      body      { background-color: black; }
-      a:hover   { text-decoration: none; }
-      a:link    { color: black; }
-      a:visited { color: black; }
-      #main {
-        position: absolute;
-        left: 0%;
-        top: 0%;
-        width: 100%;
-        height: 100%;
-        padding: 0%;
-        z-index: 10;
-        background-size: 100%;
-        background: no-repeat;
-        background-position: center;
-      }
-      #play {
-        position: absolute;
-        left: 50%;
-        top: 50%;
-      }
-      #logo {
-        position: absolute;
-        bottom: 0;
-        right: 0;
-      }
-    </style>
-  </head>
-  <body id="body">
-  <script type="text/javascript">
-    function setup() {
-        var width = document.body.clientWidth;
-        var height = document.body.clientHeight;
-        var mainElement = document.getElementById("main");
-        var playElement = document.getElementById("play");
-        var loadcount = 0;
-        var POSTER = "http://img.youtube.com/vi/VIDEO_ID/0.jpg";
-
-        function doload() {
-            if (++loadcount == 2) {
-                // Resize the element to the right size
-                mainElement.width = width;
-                mainElement.height = height;
-                mainElement.style.backgroundImage = "url('" + POSTER + "')";
-                // Center the play button
-                playElement.style.marginTop = "-" + play.height/2 + "px";
-                playElement.style.marginLeft = "-" + play.width/2 + "px";
-                playElement.addEventListener("click", function(e) {
-                    top.location.href = "vnd.youtube:VIDEO_ID";
-                }, false);
-            }
-        }
-        var background = new Image();
-        background.onload = doload;
-        background.src = POSTER;
-        play = new Image();
-        play.onload = doload;
-        play.src = "play.png";
-    }
-
-    window.onload = setup;
-  </script>
-    <div id="main">
-        <img src="play.png" id="play"></img>
-        <img src="youtube.png" id="logo"></img>
-    </div>
-  </body>
-</html>
diff --git a/core/res/assets/webkit/youtube.png b/core/res/assets/webkit/youtube.png
deleted file mode 100644
index 87779b1..0000000
--- a/core/res/assets/webkit/youtube.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 34d42d0..b374095 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -598,7 +598,7 @@
     <string name="phoneTypeCallback" msgid="2712175203065678206">"Devolver chamada"</string>
     <string name="phoneTypeCar" msgid="8738360689616716982">"Coche"</string>
     <string name="phoneTypeCompanyMain" msgid="540434356461478916">"Empresa (ppal.)"</string>
-    <string name="phoneTypeIsdn" msgid="8022453193171370337">"ISDN"</string>
+    <string name="phoneTypeIsdn" msgid="8022453193171370337">"RDSI"</string>
     <string name="phoneTypeMain" msgid="6766137010628326916">"Principal"</string>
     <string name="phoneTypeOtherFax" msgid="8587657145072446565">"Outro fax"</string>
     <string name="phoneTypeRadio" msgid="4093738079908667513">"Radio"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 3242752..101c6ecc 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1362,7 +1362,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"אפשרויות נוספות"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"‏%1$s‏, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"‏%1$s‏, %2$s‏, %3$s"</string>
-    <string name="storage_internal" msgid="3570990907910199483">"אחסון משותף פנימי"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"אחסון שיתוף פנימי"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"‏כרטיס SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"‏כרטיס SD של <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"‏כונן USB"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index fe3ebe4..8810bf9 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1310,7 +1310,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"옵션 더보기"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="3570990907910199483">"내부 공유 저장공간"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"내부 공유 저장용량"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD 카드"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD 카드"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB 드라이브"</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index bccb5fa..53ada58 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -1197,8 +1197,7 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Колдонмого орнотуу сеанстарын окуу мүмкүнчүлүгүн берет. Ушуну менен, ал жигердүү топтом орнотууларынын чоо-жайын көрө алат."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"орнотуу топтомдорун суроо"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Колдонмо топтомдорду орнотууга уруксат сурай алат."</string>
-    <!-- no translation found for tutorial_double_tap_to_zoom_message_short (1311810005957319690) -->
-    <skip />
+    <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Масштабдын параметрлерин өзгөртүү үчүн бул жерди эки жолу басыңыз."</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Виджетти кошуу мүмкүн болбоду."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Өтүү"</string>
     <string name="ime_action_search" msgid="658110271822807811">"Издөө"</string>
@@ -1229,10 +1228,8 @@
     <string name="notification_ranker_binding_label" msgid="774540592299064747">"Эскертмелердин маанилүүлүгүн баалоо кызматы"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN иштетилди"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN <xliff:g id="APP">%s</xliff:g> аркылуу жандырылды"</string>
-    <!-- no translation found for vpn_text (1610714069627824309) -->
-    <skip />
-    <!-- no translation found for vpn_text_long (4907843483284977618) -->
-    <skip />
+    <string name="vpn_text" msgid="1610714069627824309">"Тармактын параметрлерин өзгөртүү үчүн бул жерди басыңыз."</string>
+    <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> сеансына туташуу ишке ашты. Желенин параметрлерин өзгөртүү үчүн бул жерди басыңыз."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Дайым иштеген VPN туташууда…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Дайым иштеген VPN туташтырылды"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Дайым иштеген VPN\'де ката кетти"</string>
diff --git a/core/res/res/values-mcc222-mnc10/config.xml b/core/res/res/values-mcc222-mnc10/config.xml
index cd6e8c6..c819de2 100644
--- a/core/res/res/values-mcc222-mnc10/config.xml
+++ b/core/res/res/values-mcc222-mnc10/config.xml
@@ -28,29 +28,4 @@
     <string-array translatable="false" name="config_tether_apndata">
       <item>Tethering Internet,web.omnitel.it,,,,,,,,,222,10,,DUN</item>
     </string-array>
-
-    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
-        <item>21401</item>
-        <item>21402</item>
-        <item>21403</item>
-        <item>21404</item>
-        <item>21405</item>
-        <item>21406</item>
-        <item>21407</item>
-        <item>21408</item>
-        <item>21409</item>
-        <item>21410</item>
-        <item>21411</item>
-        <item>21412</item>
-        <item>21413</item>
-        <item>21414</item>
-        <item>21415</item>
-        <item>21416</item>
-        <item>21417</item>
-        <item>21418</item>
-        <item>21419</item>
-        <item>21420</item>
-        <item>21421</item>
-    </string-array>
-
 </resources>
diff --git a/core/res/res/values-mcc232-mnc10/config.xml b/core/res/res/values-mcc232-mnc10/config.xml
new file mode 100644
index 0000000..bdf83016
--- /dev/null
+++ b/core/res/res/values-mcc232-mnc10/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ ** Copyright 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>23203</item>
+        <item>23205</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc232-mnc13/config.xml b/core/res/res/values-mcc232-mnc13/config.xml
new file mode 100644
index 0000000..2c14f87
--- /dev/null
+++ b/core/res/res/values-mcc232-mnc13/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ ** Copyright 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>23203</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc500/config.xml b/core/res/res/values-mcc302-mnc500/config.xml
new file mode 100644
index 0000000..77f6419
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc500/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ ** Copyright 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>302</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc510/config.xml b/core/res/res/values-mcc302-mnc510/config.xml
new file mode 100644
index 0000000..77f6419
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc510/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ ** Copyright 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>302</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 4c6f29f..21daba9 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1310,7 +1310,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Mais opções"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="3570990907910199483">"Armazenamento interno partilhado"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"Armazen. interno partilhado"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Cartão SD"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"Cartão SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"Unidade USB"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6161494..ec93e47 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1135,6 +1135,40 @@
     <integer-array name="config_autoBrightnessKeyboardBacklightValues">
     </integer-array>
 
+    <!-- Array of hysteresis constraint values for brightening, represented as tenths of a
+         percent. The length of this array is assumed to be one greater than
+         config_dynamicHysteresisLuxLevels. The brightening threshold is calculated as
+         lux * (1.0f + CONSTRAINT_VALUE). When the current lux is higher than this threshold,
+         the screen brightness is recalculated. See the config_dynamicHysteresisLuxLevels
+         description for how the constraint value is chosen. -->
+    <integer-array name="config_dynamicHysteresisBrightLevels">
+        <item>100</item>
+    </integer-array>
+
+    <!-- Array of hysteresis constraint values for darkening, represented as tenths of a
+         percent. The length of this array is assumed to be one greater than
+         config_dynamicHysteresisLuxLevels. The darkening threshold is calculated as
+         lux * (1.0f - CONSTRAINT_VALUE). When the current lux is lower than this threshold,
+         the screen brightness is recalculated. See the config_dynamicHysteresisLuxLevels
+         description for how the constraint value is chosen. -->
+    <integer-array name="config_dynamicHysteresisDarkLevels">
+        <item>200</item>
+    </integer-array>
+
+    <!-- Array of ambient lux threshold values. This is used for determining hysteresis constraint
+         values by calculating the index to use for lookup and then setting the constraint value
+         to the corresponding value of the array. The new brightening hysteresis constraint value
+         is the n-th element of config_dynamicHysteresisBrightLevels, and the new darkening
+         hysteresis constraint value is the n-th element of config_dynamicHysteresisDarkLevels.
+
+         The (zero-based) index is calculated as follows: (MAX is the largest index of the array)
+         condition                      calculated index
+         value < lux[0]                 0
+         lux[n] <= value < lux[n+1]     n+1
+         lux[MAX] <= value              MAX+1 -->
+    <integer-array name="config_dynamicHysteresisLuxLevels">
+    </integer-array>
+
     <!-- Amount of time it takes for the light sensor to warm up in milliseconds.
          For this time after the screen turns on, the Power Manager
          will not debounce light sensor readings -->
@@ -1764,6 +1798,10 @@
     <!-- Amount of time in ms the user needs to press the relevant key to bring up the global actions dialog -->
     <integer name="config_globalActionsKeyTimeout">500</integer>
 
+    <!-- Distance that should be scrolled in response to a {@link MotionEvent#ACTION_SCROLL event}
+         with an axis value of 1. -->
+    <dimen name="config_scrollFactor">64dp</dimen>
+
     <!-- Maximum number of grid columns permitted in the ResolverActivity
          used for picking activities to handle an intent. -->
     <integer name="config_maxResolverActivityColumns">3</integer>
@@ -2554,4 +2592,12 @@
          UI is handled by ActivityManagerService -->
     <bool name="config_customUserSwitchUi">false</bool>
 
+    <!-- A array of regex to treat a SMS as VVM SMS if the message body matches.
+         Each item represents an entry, which consists of two parts:
+         a comma (,) separated list of MCCMNC the regex applies to, followed by a semicolon (;), and
+         then the regex itself. -->
+    <string-array translatable="false" name="config_vvmSmsFilterRegexes">
+        <!-- Verizon requires any SMS that starts with //VZWVVM to be treated as a VVM SMS-->
+        <item>310004,310010,310012,310013,310590,310890,310910,311110,311270,311271,311272,311273,311274,311275,311276,311277,311278,311279,311280,311281,311282,311283,311284,311285,311286,311287,311288,311289,311390,311480,311481,311482,311483,311484,311485,311486,311487,311488,311489;^//VZWVVM.*</item>
+    </string-array>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index c4594e5..4f36e46 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2937,6 +2937,18 @@
     <!-- A notification is shown when the user connects to a Wi-Fi network and the system detects that that network has no Internet access. This is the notification's message. -->
     <string name="wifi_no_internet_detailed">Tap for options</string>
 
+    <!-- Network type names used in the network_switch_metered and network_switch_metered_detail strings. These must be kept in the sync with the values NetworkCapabilities.TRANSPORT_xxx values, and in the same order. -->
+    <string-array name="network_switch_type_name">
+        <item>cellular data</item>
+        <item>Wi-Fi</item>
+        <item>Bluetooth</item>
+        <item>Ethernet</item>
+        <item>VPN</item>
+    </string-array>
+
+    <!-- Network type name displayed if one of the types is not found in network_switch_type_name. -->
+    <string name="network_switch_type_name_unknown">an unknown network type</string>
+
      <!-- A notification is shown when a user's selected SSID is later disabled due to connectivity problems.  This is the notification's title / ticker. -->
      <string name="wifi_watchdog_network_disabled">Couldn\'t connect to Wi-Fi</string>
      <!-- A notification is shown when a user's selected SSID is later disabled due to connectivity problems.  The complete alert msg is: <hotspot name> + this string, i.e. "Linksys has a poor internet connection" -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3c2b55b..166862f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -418,6 +418,7 @@
   <java-symbol type="dimen" name="config_viewConfigurationTouchSlop" />
   <java-symbol type="dimen" name="config_viewMinFlingVelocity" />
   <java-symbol type="dimen" name="config_viewMaxFlingVelocity" />
+  <java-symbol type="dimen" name="config_scrollFactor" />
   <java-symbol type="dimen" name="default_app_widget_padding_bottom" />
   <java-symbol type="dimen" name="default_app_widget_padding_left" />
   <java-symbol type="dimen" name="default_app_widget_padding_right" />
@@ -950,6 +951,8 @@
   <java-symbol type="string" name="wifi_available_sign_in" />
   <java-symbol type="string" name="network_available_sign_in" />
   <java-symbol type="string" name="network_available_sign_in_detailed" />
+  <java-symbol type="array" name="network_switch_type_name" />
+  <java-symbol type="string" name="network_switch_type_name_unknown" />
   <java-symbol type="string" name="wifi_no_internet" />
   <java-symbol type="string" name="wifi_no_internet_detailed" />
   <java-symbol type="string" name="wifi_connect_alert_title" />
@@ -1642,6 +1645,9 @@
   <java-symbol type="array" name="config_autoBrightnessKeyboardBacklightValues" />
   <java-symbol type="array" name="config_autoBrightnessLcdBacklightValues" />
   <java-symbol type="array" name="config_autoBrightnessLevels" />
+  <java-symbol type="array" name="config_dynamicHysteresisBrightLevels" />
+  <java-symbol type="array" name="config_dynamicHysteresisDarkLevels" />
+  <java-symbol type="array" name="config_dynamicHysteresisLuxLevels" />
   <java-symbol type="array" name="config_protectedNetworks" />
   <java-symbol type="array" name="config_statusBarIcons" />
   <java-symbol type="array" name="config_tether_bluetooth_regexs" />
@@ -2271,6 +2277,8 @@
   <java-symbol type="string" name="prohibit_manual_network_selection_in_gobal_mode" />
   <java-symbol type="id" name="profile_button" />
 
+  <java-symbol type="array" name="config_vvmSmsFilterRegexes" />
+
   <!-- Cascading submenus -->
   <java-symbol type="dimen" name="cascading_menus_min_smallest_width" />
 
diff --git a/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java b/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java
index fc9c9d3..f520b0e 100644
--- a/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java
+++ b/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java
@@ -17,18 +17,31 @@
 
 import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS;
 import static android.net.NetworkPolicyManager.MASK_METERED_NETWORKS;
+import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
+import static android.net.NetworkPolicyManager.POLICY_NONE;
+import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
 import static android.net.NetworkPolicyManager.RULE_NONE;
 import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
 import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
+import static android.net.NetworkPolicyManager.uidPoliciesToString;
 import static android.net.NetworkPolicyManager.uidRulesToString;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 
-public class NetworkPolicyManagerTest extends TestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
+import java.util.Arrays;
+
+@RunWith(JUnit4.class)
+public class NetworkPolicyManagerTest {
+
+    @Test
     public void testUidRulesToString() {
         uidRulesToStringTest(RULE_NONE, "0 (NONE)");
         uidRulesToStringTest(RULE_ALLOW_METERED, "1 (ALLOW_METERED)");
@@ -38,24 +51,43 @@
         uidRulesToStringTest(RULE_REJECT_ALL, "64 (REJECT_ALL)");
 
         uidRulesToStringTest(RULE_ALLOW_METERED | RULE_ALLOW_ALL,
-                "33 (ALLOW_METERED|ALLOW_ALL)");
+                "33 (ALLOW_METERED|ALLOW_ALL)",
+                "33 (ALLOW_ALL|ALLOW_METERED)");
         uidRulesToStringTest(RULE_ALLOW_METERED | RULE_REJECT_ALL,
-                "65 (ALLOW_METERED|REJECT_ALL)");
+                "65 (ALLOW_METERED|REJECT_ALL)",
+                "65 (REJECT_ALL|ALLOW_METERED)");
         uidRulesToStringTest(RULE_TEMPORARY_ALLOW_METERED | RULE_ALLOW_ALL,
-                "34 (TEMPORARY_ALLOW_METERED|ALLOW_ALL)");
+                "34 (TEMPORARY_ALLOW_METERED|ALLOW_ALL)",
+                "34 (ALLOW_ALL|TEMPORARY_ALLOW_METERED)");
         uidRulesToStringTest(RULE_TEMPORARY_ALLOW_METERED | RULE_REJECT_ALL,
-                "66 (TEMPORARY_ALLOW_METERED|REJECT_ALL)");
+                "66 (TEMPORARY_ALLOW_METERED|REJECT_ALL)",
+                "66 (REJECT_ALL|TEMPORARY_ALLOW_METERED)");
         uidRulesToStringTest(RULE_REJECT_METERED | RULE_ALLOW_ALL,
-                "36 (REJECT_METERED|ALLOW_ALL)");
+                "36 (REJECT_METERED|ALLOW_ALL)",
+                "36 (ALLOW_ALL|REJECT_METERED)");
         uidRulesToStringTest(RULE_REJECT_METERED | RULE_REJECT_ALL,
-                "68 (REJECT_METERED|REJECT_ALL)");
+                "68 (REJECT_METERED|REJECT_ALL)",
+                "68 (REJECT_ALL|REJECT_METERED)");
     }
 
-    private void uidRulesToStringTest(int uidRules, String expected) {
-        final String actual = uidRulesToString(uidRules);
-        assertEquals("Wrong string for uidRules " + uidRules, expected, actual);
+    private void uidRulesToStringTest(int uidRules, String... expectedOptions) {
+        assertContains(uidRulesToString(uidRules), expectedOptions);
     }
 
+    @Test
+    public void testUidPoliciesToString() {
+        uidPoliciesToStringTest(POLICY_NONE, "0 (NONE)");
+        uidPoliciesToStringTest(POLICY_REJECT_METERED_BACKGROUND,
+                "1 (REJECT_METERED_BACKGROUND)");
+        uidPoliciesToStringTest(POLICY_ALLOW_METERED_BACKGROUND,
+                "4 (ALLOW_BACKGROUND_BATTERY_SAVE)");
+    }
+
+    private void uidPoliciesToStringTest(int policyRules, String... expectedOptions) {
+        assertContains(uidPoliciesToString(policyRules), expectedOptions);
+    }
+
+    @Test
     public void testMeteredNetworksMask() {
         assertEquals(RULE_NONE, MASK_METERED_NETWORKS
                 & RULE_NONE);
@@ -82,6 +114,7 @@
                 & (RULE_REJECT_METERED | RULE_REJECT_ALL));
     }
 
+    @Test
     public void testAllNetworksMask() {
         assertEquals(RULE_NONE, MASK_ALL_NETWORKS
                 & RULE_NONE);
@@ -104,4 +137,12 @@
         assertEquals(RULE_REJECT_ALL, MASK_ALL_NETWORKS
                 & (RULE_REJECT_ALL | RULE_REJECT_METERED));
     }
+
+    // TODO: use Truth or Hamcrest
+    private void assertContains(String actual, String...expectedOptions) {
+        for (String expected : expectedOptions) {
+            if (expected.equals(actual)) return;
+        }
+        fail(actual + " not in " + Arrays.toString(expectedOptions));
+    }
 }
diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java
index 9074f8a..d48a67a 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java
@@ -454,7 +454,7 @@
             .addValues(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
 
         assertTrue(delta.migrateTun(tunUid, tunIface, underlyingIface));
-        assertEquals(21, delta.size());
+        assertEquals(20, delta.size());
 
         // tunIface and TEST_IFACE entries are not changed.
         assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
@@ -478,38 +478,89 @@
 
         // Existing underlying Iface entries are updated
         assertValues(delta, 9, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
-                44783L, 54L, 13829L, 60L, 0L);
+                44783L, 54L, 14178L, 62L, 0L);
         assertValues(delta, 10, underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
                 0L, 0L, 0L, 0L, 0L);
 
         // VPN underlying Iface entries are updated
         assertValues(delta, 11, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO,
-                28304L, 27L, 1719L, 12L, 0L);
+                28304L, 27L, 1L, 2L, 0L);
         assertValues(delta, 12, underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
                 0L, 0L, 0L, 0L, 0L);
 
         // New entries are added for new application's underlying Iface traffic
         assertContains(delta, underlyingIface, 10120, SET_DEFAULT, TAG_NONE, ROAMING_NO,
-                72667L, 197L, 41872L, 219L, 0L);
+                72667L, 197L, 43123L, 227L, 0L);
         assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, TAG_NONE, ROAMING_NO,
-                9297L, 17L, 3936, 19L, 0L);
+                9297L, 17L, 4054, 19L, 0L);
         assertContains(delta, underlyingIface, 10120, SET_DEFAULT, testTag1, ROAMING_NO,
-                21691L, 41L, 13179L, 46L, 0L);
+                21691L, 41L, 13572L, 48L, 0L);
         assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, testTag1, ROAMING_NO,
-                1281L, 2L, 634L, 1L, 0L);
+                1281L, 2L, 653L, 1L, 0L);
 
         // New entries are added for debug purpose
         assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
-                39605L, 46L, 11690, 49, 0);
+                39605L, 46L, 12039, 51, 0);
         assertContains(delta, underlyingIface, 10120, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
-                81964, 214, 45808, 238, 0);
-        assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
-                4983, 10, 1717, 10, 0);
+                81964, 214, 47177, 246, 0);
         assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, ROAMING_ALL,
-                126552, 270, 59215, 297, 0);
+                121569, 260, 59216, 297, 0);
 
     }
 
+    // Tests a case where all of the data received by the tun0 interface is echo back into the tun0
+    // interface by the vpn app before it's sent out of the underlying interface. The VPN app should
+    // not be charged for the echoed data but it should still be charged for any extra data it sends
+    // via the underlying interface.
+    public void testMigrateTun_VpnAsLoopback() {
+        final int tunUid = 10030;
+        final String tunIface = "tun0";
+        final String underlyingIface = "wlan0";
+        NetworkStats delta = new NetworkStats(TEST_START, 9)
+            // 2 different apps sent/receive data via tun0.
+            .addValues(tunIface, 10100, SET_DEFAULT, TAG_NONE, 50000L, 25L, 100000L, 50L, 0L)
+            .addValues(tunIface, 20100, SET_DEFAULT, TAG_NONE, 500L, 2L, 200L, 5L, 0L)
+            // VPN package resends data through the tunnel (with exaggerated overhead)
+            .addValues(tunIface, tunUid, SET_DEFAULT, TAG_NONE, 240000, 100L, 120000L, 60L, 0L)
+            // 1 app already has some traffic on the underlying interface, the other doesn't yet
+            .addValues(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, 1000L, 10L, 2000L, 20L, 0L)
+            // Traffic through the underlying interface via the vpn app.
+            // This test should redistribute this data correctly.
+            .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE,
+                    75500L, 37L, 130000L, 70L, 0L);
+
+        assertTrue(delta.migrateTun(tunUid, tunIface, underlyingIface));
+        assertEquals(9, delta.size());
+
+        // tunIface entries should not be changed.
+        assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+                50000L, 25L, 100000L, 50L, 0L);
+        assertValues(delta, 1, tunIface, 20100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+                500L, 2L, 200L, 5L, 0L);
+        assertValues(delta, 2, tunIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+                240000L, 100L, 120000L, 60L, 0L);
+
+        // Existing underlying Iface entries are updated
+        assertValues(delta, 3, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+                51000L, 35L, 102000L, 70L, 0L);
+
+        // VPN underlying Iface entries are updated
+        assertValues(delta, 4, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+                25000L, 10L, 29800L, 15L, 0L);
+
+        // New entries are added for new application's underlying Iface traffic
+        assertContains(delta, underlyingIface, 20100, SET_DEFAULT, TAG_NONE, ROAMING_NO,
+                500L, 2L, 200L, 5L, 0L);
+
+        // New entries are added for debug purpose
+        assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
+                50000L, 25L, 100000L, 50L, 0L);
+        assertContains(delta, underlyingIface, 20100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_NO,
+                500, 2L, 200L, 5L, 0L);
+        assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, ROAMING_ALL,
+                50500L, 27L, 100200L, 55, 0);
+    }
+
     private static void assertContains(NetworkStats stats,  String iface, int uid, int set,
             int tag, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets,
             long operations) {
diff --git a/docs/html-intl/intl/es/about/versions/nougat/android-7.0-testing.jd b/docs/html-intl/intl/es/about/versions/nougat/android-7.0-testing.jd
deleted file mode 100644
index 20d2d6e..0000000
--- a/docs/html-intl/intl/es/about/versions/nougat/android-7.0-testing.jd
+++ /dev/null
@@ -1,190 +0,0 @@
-page.title=Guía de prueba
-page.image=images/cards/card-n-guide_2x.png
-meta.tags="preview", "testing"
-page.tags="preview", "developer preview"
-
-@jd:body
-
-<div id="tb-wrapper">
-  <div id="tb">
-    <h2>En este documento</h2>
-      <ol>
-        <li><a href="#runtime-permissions">Prueba de los permisos</a></li>
-        <li><a href="#doze-standby">Prueba de los modos Descanso y App Standby</a></li>
-        <li><a href="#ids">Copia de seguridad automática e identificadores de dispositivos</a></li>
-      </ol>
-  </div>
-</div>
-
-<p>
-  Android N te brinda la oportunidad de garantizar que tus aplicaciones funcionen con la próxima versión de la plataforma.
- Esta versión preliminar incluye diversas API y cambios en los comportamientos que pueden
-tener impactos en tu aplicación, como se describe en las secciones <a href="{@docRoot}preview/api-overview.html">Información general de la API</a> y <a href="{@docRoot}preview/behavior-changes.html">Cambios en los comportamientos</a>.
- Al probar tu aplicación con la versión preliminar, te debes centrar en algunos cambios específicos del sistema para garantizar que los usuarios disfruten de una buena experiencia.
-
-
-</p>
-
-<p>
-  En esta guía, se describen qué y cómo probar las características preliminares con tu aplicación. Debes priorizar la prueba de estas características específicas preliminares, puesto que podrían tener un alto impacto en el comportamiento de tu aplicación:
-
-
-</p>
-
-<ul>
-  <li><a href="#runtime-permissions">Permisos</a>
-  </li>
-  <li><a href="#doze-standby">Modos Descanso y App Standby</a>
-  </li>
-  <li><a href="#ids">Copia de seguridad automática e identificadores de dispositivos</a></li>
-</ul>
-
-<p>
-  Para obtener más información sobre cómo configurar dispositivos o dispositivos virtuales con una imagen
- del sistema de la versión preliminar para realizar pruebas, consulta la sección <a href="{@docRoot}preview/setup-sdk.html">Configurar el SDK de Android N</a>.
-
-</p>
-
-
-<h2 id="runtime-permissions">Prueba de los permisos</h2>
-
-<p>
-  El nuevo modelo de <a href="{@docRoot}preview/features/runtime-permissions.html">permisos</a> cambia el modo en que el usuario asigna permisos a tu aplicación.
- En lugar de conceder todos los permisos durante el procedimiento de instalación, tu aplicación debe solicitar al usuario los permisos individuales en el tiempo de ejecución.
-
- Para los usuarios, este comportamiento ofrece más control granular sobre las actividades de cada aplicación, así como un mejor contexto para comprender por qué la aplicación está solicitando un permiso específico.
- Los usuarios pueden conceder o revocar los permisos concedidos a una aplicación de forma individual en cualquier momento.
- Es muy probable que esta característica de la versión preliminar tenga un impacto en el comportamiento de tu aplicación y puede hacer que algunas características de tu aplicación no funcionen o funcionen en un estado degradado.
-
-
-</p>
-
-<p class="caution">
-  Este cambio afecta a todas las aplicaciones que se ejecutan en la nueva plataforma, incluso a aquellas que no tienen como destino la nueva versión de la plataforma.
- La plataforma ofrece un comportamiento de compatibilidad limitada para las aplicaciones heredadas, pero debes comenzar a planificar ahora la migración de tu aplicación al nuevo modelo de permisos, con el objetivo de publicar una versión actualizada de tu aplicación cuando se lance la plataforma oficial.
-
-
-</p>
-
-
-<h3 id="permission-test-tips">Tips para pruebas</h3>
-
-<p>
-  Usa los siguientes tips para pruebas como ayuda para planificar y ejecutar las pruebas de tu aplicación con el nuevo comportamiento de permisos.
-
-</p>
-
-<ul>
-  <li>Identifica los permisos actuales de tu aplicación y las rutas de códigos relacionadas.</li>
-  <li>Prueba los flujos del usuario en los datos y servicios protegidos por permisos.</li>
-  <li>Realiza pruebas con varias combinaciones de permisos concedidos/revocados.</li>
-  <li>Usa la herramienta {@code adb} para administrar permisos desde la línea de comando:
-    <ul>
-      <li>Enumera los permisos y estados por grupo:
-        <pre>adb shell pm list permissions -d -g</pre>
-      </li>
-      <li>Concede o revoca un permiso o más permisos utilizando la siguiente sintaxis:<br>
-        <pre>adb shell pm [grant|revoke] &lt;permission.name&gt; ...</pre>
-      </li>
-    </ul>
-  </li>
-  <li>Analiza tu aplicación para detectar servicios que utilizan permisos.</li>
-</ul>
-
-<h3 id="permission-test-strategy">Estrategia de prueba</h3>
-
-<p>
-  El cambio en los permisos afecta la estructura y el diseño de tu aplicación, además de la experiencia del usuario y los flujos que proporcionas a los usuarios.
- Debes evaluar el uso de los permisos actuales de tu aplicación y comenzar a planificar los nuevos flujos que deseas ofrecer.
- La versión oficial de la plataforma proporciona un comportamiento de compatibilidad, pero debes prever la actualización de tu aplicación y no depender de estos comportamientos.
-
-
-</p>
-
-<p>
-  Identifica los permisos que tu aplicación verdaderamente necesita y utiliza, y luego busca las diversas rutas de códigos que utilizan los servicios protegidos por permisos.
- Puedes realizar esto mediante una combinación de pruebas en la plataforma nueva y análisis de códigos.
- Al realizar las pruebas, debes centrarte en
- incluir permisos de tiempo de ejecución cambiando {@code targetSdkVersion} de la aplicación a la versión preliminar. Para
- obtener más información, consulta la sección <a href="{@docRoot}preview/setup-sdk.html#">Configurar el SDK de Android N</a>.
-
-</p>
-
-<p>
-  Realiza pruebas con diversas combinaciones de permisos revocados y agregados, a fin de destacar los flujos del usuario que dependen de permisos.
- Cuando una dependencia no sea obvia ni lógica, debes considerar la opción de refactorizar o compartimentar ese flujo para eliminar la dependencia o aclarar por qué se necesita el permiso.
-
-
-</p>
-
-<p>
-  Para obtener más información sobre el comportamiento de los permisos de tiempo de ejecución, las pruebas y las mejores prácticas, consulta la página <a href="{@docRoot}preview/features/runtime-permissions.html">Permisos</a> de la versión preliminar para desarrolladores.
-
-
-</p>
-
-
-<h2 id="doze-standby">Prueba de los modos Descanso y App Standby</h2>
-
-<p>
-  Las características de ahorro de energía de los modos Descanso y App Standby limitan la cantidad de procesamiento en segundo plano que puede realizar tu aplicación cuando un dispositivo se encuentra en estado inactivo o mientras tu aplicación no está en foco.
- Entre las restricciones que el sistema puede imponer en las aplicaciones se incluyen el acceso limitado a la red o denegación de acceso, suspensión de las tareas en segundo plano, suspensión de notificaciones, y alarmas y solicitudes de reactivación ignoradas.
-
- Para garantizar que tu aplicación tenga un comportamiento correcto con estas optimizaciones de ahorro de energía, debes probar tu aplicación simulando estos estados de bajo consumo.
-
-
-</p>
-
-<h4 id="doze">Cómo probar la aplicación en modo Descanso</h4>
-
-<p>Para probar el modo Descanso con tu aplicación, realiza lo siguiente:</p>
-
-<ol>
-<li>Configura un dispositivo de hardware o un dispositivo virtual con una imagen del sistema Android N.</li>
-<li>Conecta el dispositivo a tu equipo de desarrollo e instala tu aplicación.</li>
-<li>Ejecuta tu aplicación y déjala activa.</li>
-<li>Simula la activación del modo Descanso en el dispositivo ejecutando los siguientes comandos:
-
-<pre>
-$ adb shell dumpsys battery unplug
-$ adb shell dumpsys deviceidle step
-$ adb shell dumpsys deviceidle -h
-</pre>
-
-  </li>
-  <li>Observa el comportamiento de tu aplicación cuando se reactive el dispositivo. Asegúrate de que se recupere correctamente cuando el dispositivo salga del modo Descanso.
-</li>
-</ol>
-
-
-<h4 id="standby">Cómo probar aplicaciones en modo App Standby</h4>
-
-<p>Para probar el modo App Standby con tu aplicación, realiza lo siguiente:</p>
-
-<ol>
-  <li>Configura un dispositivo de hardware o un dispositivo virtual con una imagen del sistema Android N.</li>
-  <li>Conecta el dispositivo a tu equipo de desarrollo e instala tu aplicación.</li>
-  <li>Ejecuta tu aplicación y déjala activa.</li>
-  <li>Simula la activación del modo App Standby en la aplicación ejecutando los siguientes comandos:
-
-<pre>
-$ adb shell am broadcast -a android.os.action.DISCHARGING
-$ adb shell am set-idle &lt;packageName&gt; true
-</pre>
-
-  </li>
-  <li>Simula la activación de tu aplicación con el siguiente comando:
-    <pre>$ adb shell am set-idle &lt;packageName&gt; false</pre>
-  </li>
-  <li>Observa el comportamiento de tu aplicación al reactivarse. Asegúrate de que se recupere correctamente del modo App Standby.
- En particular, debes comprobar si los trabajos en segundo plano y las notificaciones de tu aplicación continúan funcionando de la manera esperada.
-</li>
-</ol>
-
-<h2 id="ids">Copia de seguridad automática para aplicaciones e identificadores específicos del dispositivo</h2>
-
-<p>Si tu aplicación continúa teniendo algún identificador específico del dispositivo, como la Id. de registro de Google Cloud Messaging, en el almacenamiento interno, asegúrate de seguir las mejores prácticas para excluir la ubicación de almacenamiento de la copia de seguridad automática, como se describe en la sección <a href="{@docRoot}preview/backup/index.html">Copia de seguridad automática para aplicaciones</a>.
-
-
-
- </p>
diff --git a/docs/html-intl/intl/es/about/versions/nougat/index.jd b/docs/html-intl/intl/es/about/versions/nougat/index.jd
index c931270..b30cc88 100644
--- a/docs/html-intl/intl/es/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/es/about/versions/nougat/index.jd
@@ -1,6 +1,6 @@
-page.title=Android N Developer Preview
-page.tags="preview","developer"
-meta.tags="preview", "android"
+page.title=Android 7.0 Nougat
+page.tags="androidn","versions"
+meta.tags="android n", "nougat", "android 7.0"
 fullpage=true
 forcelocalnav=true
 header.hide=1
@@ -17,62 +17,56 @@
   })
 </script>
 
-<section class="dac-expand dac-hero dac-light" style="background-color:#B2DFDB">
+<section class="dac-expand dac-hero dac-light">
   <div class="wrap" style="max-width:1100px;margin-top:0">
+  <a href="{@docRoot}about/versions/nougat/android-7.0.html">
     <div class="cols dac-hero-content" style="padding-bottom:1em;">
 
-      <div class="col-7of16 col-push-9of16" style="padding-left:2em">
-        <h1 class="dac-hero-title">Android N Developer Preview</h1>
+      <div class="col-7of16 col-push-8of16" style="padding-left:2em">
+        <h1 class="dac-hero-title">Android 7.0 Nougat</h1>
         <p class="dac-hero-description">
-          ¡Prepárate para Android N!
+          ¡Prepárate para Android Nougat!
           <strong>Prueba tus aplicaciones</strong> en Nexus y en otros dispositivos. Admite comportamientos del sistema
  nuevo para <strong>ahorrar energía y memoria</strong>.
           Amplía la funcionalidad de tus aplicaciones gracias a una <strong>IU con ventanas múltiples</strong>,
  <strong>notificaciones de respuestas directas</strong> y más.
         </p>
 
-        <a class="dac-hero-cta" href="{@docRoot}preview/overview.html">
+        <a class="dac-hero-cta" href="{@docRoot}about/versions/nougat/android-7.0.html">
           <span class="dac-sprite dac-auto-chevron"></span>
           Comencemos
-        </a><!--<br>
-        <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Update to Android N (final SDK)
-        </a><br>-->
+        </a>
       </div>
-      <div class="col-9of16 col-pull-7of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
-        <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png" srcset="{@docRoot}images/home/n-preview-hero.png 1x,
-             {@docRoot}images/home/n-preview-hero_2x.png 2x">
+      <div class="col-7of16 col-pull-6of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
+        <a  href="{@docRoot}about/versions/nougat/android-7.0.html">
+        <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png"
+             srcset="{@docRoot}images/home/n-preview-hero.png 1x,
+             {@docRoot}images/home/n-preview-hero_2x.png 2x" />
+           </a>
       </div>
-    </div>
+    </div></a>
     <div class="dac-section dac-small">
       <div class="resource-widget resource-flow-layout col-16"
-           data-query="collection:preview/landing/resources"
+           data-query="collection:nougat/landing/resources"
            data-cardSizes="6x2"
-           data-maxResults="6"></div>
-    </div>
+           data-maxResults="3"></div>
+         </div>
   </div>
 </section>
 
 <div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
+    <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
       <i class="dac-sprite dac-arrow-down-gray"></i>
     </a>
     <ul class="dac-actions">
       <li class="dac-action">
-        <a class="dac-action-link" href="https://developer.android.com/preview/bug">
+        <a class="dac-action-link" href="https://source.android.com/source/report-bugs.html">
           <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
           Informa un problema
         </a>
       </li>
       <li class="dac-action">
-        <a class="dac-action-link" href="{@docRoot}preview/support.html">
-          <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
-          Consulta las notas de la versión
-        </a>
-      </li>
-      <li class="dac-action">
         <a class="dac-action-link" href="{@docRoot}preview/dev-community">
           <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
           Únete a la comunidad de desarrolladores
@@ -113,19 +107,33 @@
     data-initial-results="3"></div>
 </div></section>
 
-<section class="dac-section dac-gray"><div class="wrap">
-  <h1 class="dac-section-title">Recursos</h1>
+<section class="dac-section dac-gray" id="videos"><div class="wrap">
+  <h1 class="dac-section-title">Videos</h1>
   <div class="dac-section-subtitle">
-    Información esencial para ayudarte a preparar tus aplicaciones para Android N.
+    New Android capabilities and the right way to use them in your apps.
   </div>
 
   <div class="resource-widget resource-flow-layout col-16"
-       data-query="collection:preview/landing/more"
+    data-query="collection:nougat/landing/videos/first,type:youtube+tag:androidn"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x6"
+    data-items-per-page="6"
+    data-maxResults="15"
+    data-initial-results="3">
+  </div>
+</div></section>
+
+<section class="dac-section dac-light" id="resources"><div class="wrap">
+  <h1 class="dac-section-title">Recursos</h1>
+  <div class="dac-section-subtitle">
+    Información esencial para ayudarte a preparar tus aplicaciones para Android Nougat.
+  </div>
+
+  <div class="resource-widget resource-flow-layout col-16"
+       data-query="collection:nougat/landing/more"
        data-cardSizes="6x6"
        data-items-per-page="6"
        data-maxResults="15"
        data-initial-results="6"></div>
-
   </div>
-</section>
-
+</section>
\ No newline at end of file
diff --git a/docs/html-intl/intl/es/index.jd b/docs/html-intl/intl/es/index.jd
index 66f9bf0..e0d80c1 100644
--- a/docs/html-intl/intl/es/index.jd
+++ b/docs/html-intl/intl/es/index.jd
@@ -15,33 +15,30 @@
   })
 </script>
 
-<section class="dac-expand dac-hero dac-invert" style="background-color:#455A64">
-  <div class="wrap" style="max-width:1100px;margin-top:0">
-    <div class="col-7of16 col-push-9of16" style="padding-left:2em;">
-      <a href="{@docRoot}preview/index.html">
-        <h1 class="dac-hero-title">Android N Developer Preview</h1>
-        <p class="dac-hero-description">
-          Get ready for the next version of Android!
-          <strong>Test your apps</strong> on Nexus and other devices. Support new system
-          behaviors to <strong>save power and memory</strong>.
+<section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
+  <div class="wrap" style="max-width:1000px;margin-top:0">
+    <div class="col-7of16 col-push-8of16">
+      <a href="{@docRoot}about/versions/nougat/index.html">
+        <h1 class="dac-hero-title" style="color:#004d40">Android 7.0 Nougat!</h1>
+        <p class="dac-hero-description" style="color:#004d40">
+          <strong>Android 7.0 Nougat is here!</strong>
+          Get your apps ready for the latest version of Android, with new system
+          behaviors to <strong>save battery and memory</strong>.
           Extend your apps with <strong>multi-window UI</strong>,
           <strong>direct reply notifications</strong> and more.
         </p>
-        <a class="dac-hero-cta" href="/preview/index.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
+        <a class="dac-hero-cta" href="{@docRoot}about/versions/nougat/index.html" style="color:#004d40">
+          <span class="dac-sprite dac-auto-chevron" style="background-color:#b2dfdb"></span>
           Learn more
-        </a><!--<br>
-        <a class="dac-hero-cta" href="/preview/support.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Update to Developer Preview (final SDK)
-        </a><br>-->
+        </a>
+        </a>
       </a>
     </div>
-    <div class="col-9of16 col-pull-7of16 dac-hero-figure" style="margin-top:0em;padding-right:1.5em;">
-      <a href="{@docRoot}preview/index.html">
-        <img style="" class="dac-hero-image" src="/images/home/n-preview-hero.png"
-             srcset="/images/home/n-preview-hero.png 1x,
-             /images/home/n-preview-hero_2x.png 2x">
+    <div class="col-6of16 col-pull-6of16 dac-hero-figure" style="padding-left:1em;padding-top:1em;">
+      <a href="{@docRoot}about/versions/nougat/index.html">
+        <img class="dac-hero-image" src="{@docRoot}images/home/nougat_bg.jpg"
+             srcset="{@docRoot}images/home/nougat_bg.jpg 1x,
+             {@docRoot}images/home/nougat_bg_2x.jpg 2x">
         </a>
     </div>
   </div>
diff --git a/docs/html-intl/intl/in/about/versions/nougat/android-7.0-testing.jd b/docs/html-intl/intl/in/about/versions/nougat/android-7.0-testing.jd
deleted file mode 100644
index 94bc74c..0000000
--- a/docs/html-intl/intl/in/about/versions/nougat/android-7.0-testing.jd
+++ /dev/null
@@ -1,190 +0,0 @@
-page.title=Panduan Pengujian
-page.image=images/cards/card-n-guide_2x.png
-meta.tags="preview", "testing"
-page.tags="preview", "developer preview"
-
-@jd:body
-
-<div id="tb-wrapper">
-  <div id="tb">
-    <h2>Dalam dokumen ini</h2>
-      <ol>
-        <li><a href="#runtime-permissions">Izin Pengujian</a></li>
-        <li><a href="#doze-standby">Menguji Istirahatkan dan Aplikasi Siaga</a></li>
-        <li><a href="#ids">Pencadangan Otomatis dan Identifier Perangkat</a></li>
-      </ol>
-  </div>
-</div>
-
-<p>
-  Android N memberi Anda kesempatan untuk memastikan aplikasi bekerja pada
-  platform versi berikutnya. Pratinjau ini berisi beberapa API dan perubahan perilaku yang bisa
-  memengaruhi aplikasi Anda, sebagaimana dijelaskan dalam <a href="{@docRoot}preview/api-overview.html">Ringkasan
-  API</a> dan <a href="{@docRoot}preview/behavior-changes.html">Perubahan Perilaku</a>. Dalam menguji
-  aplikasi dengan pratinjau, ada beberapa perubahan sistem spesifik yang harus Anda fokuskan untuk
-  memastikan pengguna mendapatkan pengalaman yang bagus.
-</p>
-
-<p>
-  Panduan ini menjelaskan apa dan bagaimana menguji fitur pratinjau dengan aplikasi Anda. Anda harus
-  mengutamakan pengujian fitur pratinjau spesifik ini, dikarenakan pengaruhnya yang besar pada
-  perilaku aplikasi Anda:
-</p>
-
-<ul>
-  <li><a href="#runtime-permissions">Izin</a>
-  </li>
-  <li><a href="#doze-standby">Istirahatkan dan Aplikasi Siaga</a>
-  </li>
-  <li><a href="#ids">Pencadangan Otomatis dan Identifier Perangkat</a></li>
-</ul>
-
-<p>
-  Untuk informasi selengkapnya tentang cara menyiapkan perangkat atau perangkat maya dengan citra sistem pratinjau
-  untuk pengujian, lihat <a href="{@docRoot}preview/setup-sdk.html">Menyiapkan
-Android N SDK</a>.
-</p>
-
-
-<h2 id="runtime-permissions">Izin Pengujian</h2>
-
-<p>
-  Model <a href="{@docRoot}preview/features/runtime-permissions.html">Izin</a> yang baru
-  mengubah cara alokasi izin untuk aplikasi Anda oleh pengguna. Sebagai ganti memberi semua
-  izin selama prosedur pemasangan, aplikasi Anda harus meminta izin kepada pengguna secara individual
- pada waktu proses. Bagi pengguna, perilaku ini memberi kontrol yang lebih detail atas setiap aktivitas aplikasi, dan
-  juga konteks yang lebih untuk memahami sebab aplikasi meminta izin tertentu. Pengguna
-  bisa memberi atau mencabut izin yang diberikan pada suatu aplikasi secara individual kapan saja. Fitur
-  pratinjau ini kemungkinan besar memengaruhi perilaku aplikasi Anda dan mungkin menghambat fungsi beberapa
-  fitur aplikasi Anda, atau mengurangi kualitas kerjanya.
-</p>
-
-<p class="caution">
-  Perubahan ini memengaruhi semua aplikasi yang berjalan di platform baru, bahkan aplikasi yang tidak menargetkan versi
-  platform baru. Platform ini memberikan perilaku kompatibilitas terbatas untuk aplikasi lawas, namun Anda
-  harus mulai merencanakan migrasi aplikasi ke model izin baru sekarang juga, dengan tujuan
-  mempublikasikan versi terbaru aplikasi Anda saat peluncuran platform secara resmi.
-</p>
-
-
-<h3 id="permission-test-tips">Tip pengujian</h3>
-
-<p>
-  Gunakan tip berikut untuk membantu Anda merencanakan dan menjalankan pengujian aplikasi dengan
-  perilaku izin yang baru.
-</p>
-
-<ul>
-  <li>Identifikasi izin aplikasi Anda saat ini dan jalur kode terkait.</li>
-  <li>Uji alur pengguna pada semua layanan dan data yang dilindungi izin.</li>
-  <li>Uji dengan berbagai kombinasi izin yang diberikan/dicabut.</li>
-  <li>Gunakan alat bantu {@code adb} untuk mengelola izin dari baris perintah:
-    <ul>
-      <li>Cantumkan daftar izin dan status berdasarkan kelompok:
-        <pre>adb shell pm list permissions -d -g</pre>
-      </li>
-      <li>Beri atau cabut satu atau beberapa izin menggunakan sintaks berikut:<br>
-        <pre>adb shell pm [grant|revoke] &lt;permission.name&gt; ...</pre>
-      </li>
-    </ul>
-  </li>
-  <li>Analisis aplikasi Anda untuk layanan yang menggunakan izin.</li>
-</ul>
-
-<h3 id="permission-test-strategy">Strategi pengujian</h3>
-
-<p>
-  Perubahan izin memengaruhi struktur dan desain aplikasi Anda, begitu juga
-  pengalaman pengguna dan alur yang Anda sediakan untuk pengguna. Anda harus menilai penggunaan izin
-  aplikasi saat ini dan mulai merencanakan alur baru yang ingin ditawarkan. Rilis platform
-  resmi menyediakan perilaku kompatibilitas, namun Anda harus merencanakan pembaruan aplikasi dan tidak
-  bergantung pada perilaku ini.
-</p>
-
-<p>
-  Identifikasi izin yang sebenarnya diperlukan dan digunakan aplikasi Anda, kemudian temukan berbagai
-  jalur kode yang menggunakan layanan yang dilindungi izin. Anda bisa melakukan ini melalui kombinasi
-  pengujian pada platform baru dan analisis kode. Dalam pengujian, Anda harus fokus pada pemilihan
- izin waktu proses dengan mengubah {@code targetSdkVersion} aplikasi ke versi pratinjau. Untuk
-  informasi selengkapnya, lihat <a href="{@docRoot}preview/setup-sdk.html#">Menyiapkan
-Android N SDK</a>.
-</p>
-
-<p>
-  Uji dengan berbagai kombinasi izin yang dicabut dan ditambahkan, untuk menyoroti alur pengguna yang
-  bergantung pada izin. Jika dependensi tidak jelas atau logis, Anda harus mempertimbangkan
-optimalisasi atau kompartementalisasi alur tersebut untuk mengeliminasi dependensi atau menjelaskan alasan
-  diperlukannya izin.
-</p>
-
-<p>
-  Untuk informasi selengkapnya tentang perilaku izin waktu proses, pengujian, dan praktik terbaik, lihat
-  halaman pratinjau <a href="{@docRoot}preview/features/runtime-permissions.html">Izin</a>
-  pengembang.
-</p>
-
-
-<h2 id="doze-standby">Menguji Istirahatkan dan Aplikasi Siaga</h2>
-
-<p>
-  Fitur penghematan daya Istirahatkan dan Aplikasi Siaga membatasi jumlah pemrosesan latar belakang yang
-  bisa dikerjakan aplikasi Anda saat perangkat dalam keadaan diam atau saat aplikasi Anda sedang tidak fokus. Pembatasan
-  yang dapat diberlakukan oleh sistem pada aplikasi termasuk akses jaringan terbatas atau tidak ada,
-  tugas latar belakang yang ditangguhkan, Pemberitahuan yang ditangguhkan, permintaan membangunkan yang diabaikan, serta alarm. Untuk memastikan
-  aplikasi Anda berperilaku dengan benar pada optimalisasi penghematan daya ini, Anda harus menguji aplikasi dengan
- menyimulasikan keadaan baterai yang sedang tinggal sedikit ini.
-</p>
-
-<h4 id="doze">Menguji aplikasi Anda dengan Istirahatkan</h4>
-
-<p>Untuk menguji Istirahatkan dengan aplikasi Anda:</p>
-
-<ol>
-<li>Konfigurasikan perangkat keras atau perangkat maya dengan citra sistem Android N.</li>
-<li>Hubungkan perangkat dengan mesin pengembangan dan pasang aplikasi Anda.</li>
-<li>Jalankan aplikasi Anda dan biarkan aktif.</li>
-<li>Simulasikan perangkat yang sedang masuk ke dalam mode Istirahatkan dengan menjalankan perintah berikut:
-
-<pre>
-$ adb shell dumpsys battery unplug
-$ adb shell dumpsys deviceidle step
-$ adb shell dumpsys deviceidle -h
-</pre>
-
-  </li>
-  <li>Amati perilaku aplikasi Anda saat perangkat diaktifkan kembali. Pastikan aplikasi
-    pulih dengan baik saat perangkat keluar dari Istirahatkan.</li>
-</ol>
-
-
-<h4 id="standby">Menguji aplikasi dengan Aplikasi Siaga</h4>
-
-<p>Untuk menguji mode Aplikasi Siaga dengan aplikasi Anda:</p>
-
-<ol>
-  <li>Konfigurasikan perangkat keras atau perangkat maya dengan citra sistem Android N.</li>
-  <li>Hubungkan perangkat dengan mesin pengembangan dan pasang aplikasi Anda.</li>
-  <li>Jalankan aplikasi Anda dan biarkan aktif.</li>
-  <li>Simulasikan aplikasi yang sedang masuk ke dalam mode siaga dengan menjalankan perintah berikut:
-
-<pre>
-$ adb shell am broadcast -a android.os.action.DISCHARGING
-$ adb shell am set-idle &lt;packageName&gt; true
-</pre>
-
-  </li>
-  <li>Simulasikan membangunkan aplikasi Anda menggunakan perintah berikut:
-    <pre>$ adb shell am set-idle &lt;packageName&gt; false</pre>
-  </li>
-  <li>Amati perilaku aplikasi Anda saat dibangunkan. Pastikan aplikasi pulih dengan baik
-   dari mode siaga. Secara khusus, Anda harus memeriksa apakah Pemberitahuan aplikasi dan pekerjaan latar belakang
-   tetap berjalan sebagaimana yang diharapkan.</li>
-</ol>
-
-<h2 id="ids">Auto Backup for Apps dan Identifier Perangkat Spesifik</h2>
-
-<p>Jika aplikasi Anda mempertahankan identifier perangkat spesifik, seperti ID pendaftaran Google
-Cloud Messaging, dalam penyimpanan internal,
-pastikan Anda mengikuti praktik terbaik untuk mengecualikan lokasi
-penyimpanan dari pencadangan otomatis, seperti dijelaskan dalam <a href="{@docRoot}preview/backup/index.html">Auto
-Backup for Apps</a>. </p>
diff --git a/docs/html-intl/intl/in/about/versions/nougat/index.jd b/docs/html-intl/intl/in/about/versions/nougat/index.jd
index a8f61eb..5234f91 100644
--- a/docs/html-intl/intl/in/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/in/about/versions/nougat/index.jd
@@ -1,6 +1,6 @@
-page.title=Android N Developer Preview
-page.tags="preview","developer"
-meta.tags="preview", "android"
+page.title=Android 7.0 Nougat
+page.tags="androidn","versions"
+meta.tags="android n", "nougat", "android 7.0"
 fullpage=true
 forcelocalnav=true
 header.hide=1
@@ -17,66 +17,61 @@
   })
 </script>
 
-<section class="dac-expand dac-hero dac-light" style="background-color:#B2DFDB">
+<section class="dac-expand dac-hero dac-light">
   <div class="wrap" style="max-width:1100px;margin-top:0">
+  <a href="{@docRoot}about/versions/nougat/android-7.0.html">
     <div class="cols dac-hero-content" style="padding-bottom:1em;">
 
-      <div class="col-7of16 col-push-9of16" style="padding-left:2em">
-        <h1 class="dac-hero-title">Android N Developer Preview</h1>
+      <div class="col-7of16 col-push-8of16" style="padding-left:2em">
+        <h1 class="dac-hero-title">Android 7.0 Nougat</h1>
         <p class="dac-hero-description">
-          Bersiaplah menyambut Android N!
+          Bersiaplah menyambut Android Nougat!
           <strong>Uji aplikasi Anda</strong> pada perangkat Nexus dan perangkat lainnya. Dukung perilaku sistem
           baru untuk <strong>menghemat daya dan memori</strong>.
           Tambah aplikasi Anda dengan <strong>UI multi-jendela</strong>,
           <strong>pemberitahuan balasan langsung</strong> dan lainnya.
         </p>
 
-        <a class="dac-hero-cta" href="{@docRoot}preview/overview.html">
+        <a class="dac-hero-cta" href="{@docRoot}about/versions/nougat/android-7.0.html">
           <span class="dac-sprite dac-auto-chevron"></span>
           Mulai
-        </a><!--<br>
-        <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Update to Android N (final SDK)
-        </a><br>-->
+        </a>
       </div>
-      <div class="col-9of16 col-pull-7of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
-        <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png" srcset="{@docRoot}images/home/n-preview-hero.png 1x,
-             {@docRoot}images/home/n-preview-hero_2x.png 2x">
+      <div class="col-7of16 col-pull-6of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
+        <a  href="{@docRoot}about/versions/nougat/android-7.0.html">
+        <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png"
+             srcset="{@docRoot}images/home/n-preview-hero.png 1x,
+             {@docRoot}images/home/n-preview-hero_2x.png 2x" />
+           </a>
       </div>
-    </div>
+    </div></a>
     <div class="dac-section dac-small">
       <div class="resource-widget resource-flow-layout col-16"
-           data-query="collection:preview/landing/resources"
+           data-query="collection:nougat/landing/resources"
            data-cardSizes="6x2"
-           data-maxResults="6"></div>
-    </div>
+           data-maxResults="3"></div>
+         </div>
   </div>
 </section>
 
+
 <div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
+    <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
       <i class="dac-sprite dac-arrow-down-gray"></i>
     </a>
     <ul class="dac-actions">
       <li class="dac-action">
-        <a class="dac-action-link" href="https://developer.android.com/preview/bug">
+        <a class="dac-action-link" href="https://source.android.com/source/report-bugs.html">
           <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
           Laporkan masalah
-          </a>
-      </li>
-      <li class="dac-action">
-        <a class="dac-action-link" href="{@docRoot}preview/support.html">
-          <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
-          Lihat catatan rilis
-          </a>
+        </a>
       </li>
       <li class="dac-action">
         <a class="dac-action-link" href="{@docRoot}preview/dev-community">
           <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
           Bergabunglah dengan komunitas pengembang
-          </a>
+        </a>
       </li>
     </ul>
   </div><!-- end .wrap -->
@@ -113,19 +108,33 @@
     data-initial-results="3"></div>
 </div></section>
 
-<section class="dac-section dac-gray"><div class="wrap">
-  <h1 class="dac-section-title">Sumber Daya</h1>
+<section class="dac-section dac-gray" id="videos"><div class="wrap">
+  <h1 class="dac-section-title">Videos</h1>
   <div class="dac-section-subtitle">
-    Informasi penting guna membantu mempersiapkan aplikasi untuk Android N.
+    New Android capabilities and the right way to use them in your apps.
   </div>
 
   <div class="resource-widget resource-flow-layout col-16"
-       data-query="collection:preview/landing/more"
+    data-query="collection:nougat/landing/videos/first,type:youtube+tag:androidn"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x6"
+    data-items-per-page="6"
+    data-maxResults="15"
+    data-initial-results="3">
+  </div>
+</div></section>
+
+<section class="dac-section dac-light" id="resources"><div class="wrap">
+  <h1 class="dac-section-title">Sumber Daya</h1>
+  <div class="dac-section-subtitle">
+    Informasi penting guna membantu mempersiapkan aplikasi untuk Android Nougat.
+  </div>
+
+  <div class="resource-widget resource-flow-layout col-16"
+       data-query="collection:nougat/landing/more"
        data-cardSizes="6x6"
        data-items-per-page="6"
        data-maxResults="15"
        data-initial-results="6"></div>
-
   </div>
-</section>
-
+</section>
\ No newline at end of file
diff --git a/docs/html-intl/intl/ja/about/versions/nougat/android-7.0-testing.jd b/docs/html-intl/intl/ja/about/versions/nougat/android-7.0-testing.jd
deleted file mode 100644
index 9f03412..0000000
--- a/docs/html-intl/intl/ja/about/versions/nougat/android-7.0-testing.jd
+++ /dev/null
@@ -1,190 +0,0 @@
-page.title=テストガイド
-page.image=images/cards/card-n-guide_2x.png
-meta.tags="preview", "testing"
-page.tags="preview", "developer preview"
-
-@jd:body
-
-<div id="tb-wrapper">
-  <div id="tb">
-    <h2>このドキュメントの内容</h2>
-      <ol>
-        <li><a href="#runtime-permissions">パーミッションをテストする</a></li>
-        <li><a href="#doze-standby">Doze とアプリ スタンバイをテストする</a></li>
-        <li><a href="#ids">自動バックアップと端末識別子</a></li>
-      </ol>
-  </div>
-</div>
-
-<p>
-  Android N を利用すると、次期バージョンのプラットフォームでアプリが動作するか確認できます。
-このプレビューには、<a href="{@docRoot}preview/api-overview.html">API の概要</a>と<a href="{@docRoot}preview/behavior-changes.html">動作の変更点</a>に記載されているように、アプリに影響を与える可能性のある多くの API と動作の変更が含まれています。
-
-このプレビューでアプリをテストするときには、アプリの良好な使用感を確保するために、システムのいくつかの変更点に特に注意する必要があります。
-
-
-</p>
-
-<p>
-  このガイドでは、アプリでプレビューの機能の何をどのようにテストすればよいか説明します。以下のプレビュー機能は、アプリの動作に大きな影響を与える可能性があるので、優先してテストする必要があります。
-
-
-</p>
-
-<ul>
-  <li><a href="#runtime-permissions">パーミッション</a>
-  </li>
-  <li><a href="#doze-standby">Doze とアプリ スタンバイ</a>
-  </li>
-  <li><a href="#ids">自動バックアップと端末識別子</a></li>
-</ul>
-
-<p>
-  テスト用のプレビュー システム イメージを使用した端末または仮想端末のセットアップ方法の詳細については、<a href="{@docRoot}preview/setup-sdk.html">Android N SDK のセットアップ</a>をご覧ください。
-
-
-</p>
-
-
-<h2 id="runtime-permissions">パーミッションをテストする</h2>
-
-<p>
-  <a href="{@docRoot}preview/features/runtime-permissions.html">パーミッション</a> モデルの変更により、ユーザーがアプリにパーミッションを付与する方法が変わりました。
-アプリでは、インストール時にすべてのパーミッションを要求するのではなく、実行時に個々のパーミッションをユーザーに要求する必要があります。
-
-これにより、ユーザーは、各アプリのアクティビティをより細かくコントロールできるようになるだけではなく、アプリが各パーミッションを要求する理由をこれまでよりもよく理解できるようになります。
-ユーザーは、いつでもアプリに個別にパーミッションを付与したり、付与したパーミッションを個別に取り消したりできます。
-プレビューのこの機能は、アプリの動作に大きな影響を与える可能性があり、アプリの一部の機能が動作しなくなったり、限定された機能しか使えなくなったりする可能性もあります。
-
-
-</p>
-
-<p class="caution">
-  この変更は、アプリがこの新しいバージョンを対象にしているかどうかにかかわらず、この新しいプラットフォーム上で実行されるすべてのアプリに影響します。
-このプラットフォームは以前のアプリに限定的な互換動作を提供しますが、公式版のプラットフォームのリリースに合わせてアップデート版のアプリを公開できるように、新しいパーミッション モデルに対応させるためのアプリの移行を今から計画することを強くお勧めします。
-
-
-</p>
-
-
-<h3 id="permission-test-tips">テストのヒント</h3>
-
-<p>
-  以下のテストのヒントを活用して、アプリでの新しいパーミッション動作のテストを計画し、実行してください。
-
-</p>
-
-<ul>
-  <li>アプリの現在のパーミッションと関連するコードパスを確認します。</li>
-  <li>パーミッションで保護されているサービスとデータ間のユーザーフローをテストします。</li>
-  <li>付与されたパーミッションと取り消されたパーミッションのさまざまな組み合わせをテストします。</li>
-  <li>{@code adb} ツールを使用して、コマンドラインからパーミッションを管理します。
-    <ul>
-      <li>パーミッションとステータスをグループ化して表示します。
-        <pre>adb shell pm list permissions -d -g</pre>
-      </li>
-      <li>以下の構文を使用して 1 つまたは複数のパーミッションを付与または取り消します。<br>
-        <pre>adb shell pm [grant|revoke] &lt;permission.name&gt; ...</pre>
-      </li>
-    </ul>
-  </li>
-  <li>アプリでパーミッションを使用しているサービスを分析します。</li>
-</ul>
-
-<h3 id="permission-test-strategy">テスト方針</h3>
-
-<p>
-  このパーミッションの変化は、アプリの構造と設計、ユーザー エクスペリエンスとフローに影響を与えます。
-アプリの現在のパーミッション利用の状況を調査し、新しいフローの検討を開始する必要があります。
-このプラットフォームの公式リリースは互換動作を提供しますが、互換動作に頼ることなくアプリのアップデートを計画することを強くお勧めします。
-
-
-</p>
-
-<p>
-  まずアプリが実際に必要とし使用しているパーミッションを特定してから、パーミッションで保護されたサービスを使用している各コードパスを探してください。
-これには、新しいプラットフォーム上でのテストと、コードの解析が必要です。
-テストでは、アプリの {@code targetSdkVersion} をこのプレビュー版に変えて、ランタイム パーミッションのオプトインに重点的にテストする必要があります。
-詳細については、<a href="{@docRoot}preview/setup-sdk.html#">Android N SDK のセットアップ</a>をご覧ください。
-
-
-</p>
-
-<p>
-  パーミッションの取り消しと追加のさまざまな組み合わせをテストし、パーミッションに依存するユーザーフローを確認します。
-パーミッションへの依存性が明白または論理的ではない箇所では、依存性を取り除くため、またはパーミッションが必要な理由を明白にするために、フローのリファクタリングまたはコンパートメント化を検討する必要があります。
-
-
-</p>
-
-<p>
-  ランタイム パーミッションの動作、テスト、ベスト プラクティスについては、Developer Preview ページの<a href="{@docRoot}preview/features/runtime-permissions.html">パーミッション</a>をご覧ください。
-
-
-</p>
-
-
-<h2 id="doze-standby">Doze とアプリ スタンバイをテストする</h2>
-
-<p>
-  省電力機能である Doze とアプリ スタンバイにより、端末がアイドル状態のときやそのアプリにフォーカスがないときに、アプリが実行できるバックグラウンド処理の量が制限されます。
-システムによってアプリに加えられる可能性のある制限には、ネットワーク アクセスの制限や停止、バックグラウンド タスクの停止、通知の停止、ウェイク リクエストの無視、アラームなどがあります。
-
-これらの省電力のための最適化が行われた状態で確実にアプリが適切に動作するように、これらの省電力状態をシミュレートしてアプリをテストする必要があります。
-
-
-</p>
-
-<h4 id="doze">アプリで Doze をテストする</h4>
-
-<p>アプリで Doze をテストするには: </p>
-
-<ol>
-<li>Android N のシステム イメージを使用して、ハードウェア端末または仮想端末を設定します。</li>
-<li>端末を開発マシンに接続し、アプリをインストールします。</li>
-<li>アプリを実行し、アクティブ状態のままにします。</li>
-<li>以下のコマンドを実行して、端末の Doze モードへの移行をシミュレートします。
-
-<pre>
-$ adb shell dumpsys battery unplug
-$ adb shell dumpsys deviceidle step
-$ adb shell dumpsys deviceidle -h
-</pre>
-
-  </li>
-  <li>端末がアクティブ状態に戻ったときのアプリの動作を観察します。端末が Doze モードから抜けるときに、アプリがスムーズに復帰することを確認します。
-</li>
-</ol>
-
-
-<h4 id="standby">アプリでアプリ スタンバイをテストする</h4>
-
-<p>アプリでアプリ スタンバイ モードをテストするには: </p>
-
-<ol>
-  <li>Android N のシステム イメージを使用して、ハードウェア端末または仮想端末を設定します。</li>
-  <li>端末を開発マシンに接続し、アプリをインストールします。</li>
-  <li>アプリを実行し、アクティブ状態のままにします。</li>
-  <li>以下のコマンドを実行して、アプリのスタンバイ モードへの移行をシミュレートします。
-
-<pre>
-$ adb shell am broadcast -a android.os.action.DISCHARGING
-$ adb shell am set-idle &lt;packageName&gt; true
-</pre>
-
-  </li>
-  <li>以下のコマンドを使用して、アプリのウェイクをシミュレートします。
-    <pre>$ adb shell am set-idle &lt;packageName&gt; false</pre>
-  </li>
-  <li>アプリがウェイク状態に戻ったときのアプリの動作を観察します。アプリがスタンバイ モードからスムーズに復帰することを確認します。
-特に、アプリの通知とバックグラウンド ジョブが想定通りの動作を続けているかを確認する必要があります。
-</li>
-</ol>
-
-<h2 id="ids">アプリの自動バックアップと端末固有識別子</h2>
-
-<p>アプリが、Google Cloud Messaging の登録 ID などのなんらかの端末固有の識別子を内部ストレージに保持している場合、<a href="{@docRoot}preview/backup/index.html">アプリの自動バックアップ</a>の説明に従って、そのストレージのロケーションを自動バックアップの対象から除外してください。
-
-
-
- </p>
diff --git a/docs/html-intl/intl/ja/about/versions/nougat/index.jd b/docs/html-intl/intl/ja/about/versions/nougat/index.jd
index 774e065..5881cf6 100644
--- a/docs/html-intl/intl/ja/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/ja/about/versions/nougat/index.jd
@@ -1,6 +1,6 @@
-page.title=Android N Developer Preview
-page.tags="preview","developer"
-meta.tags="preview", "android"
+page.title=Android 7.0 Nougat
+page.tags="androidn","versions"
+meta.tags="android n", "nougat", "android 7.0"
 fullpage=true
 forcelocalnav=true
 header.hide=1
@@ -17,66 +17,61 @@
   })
 </script>
 
-<section class="dac-expand dac-hero dac-light" style="background-color:#B2DFDB">
+<section class="dac-expand dac-hero dac-light">
   <div class="wrap" style="max-width:1100px;margin-top:0">
+  <a href="{@docRoot}about/versions/nougat/android-7.0.html">
     <div class="cols dac-hero-content" style="padding-bottom:1em;">
 
-      <div class="col-7of16 col-push-9of16" style="padding-left:2em">
-        <h1 class="dac-hero-title">Android N Developer Preview</h1>
+      <div class="col-7of16 col-push-8of16" style="padding-left:2em">
+        <h1 class="dac-hero-title">Android 7.0 Nougat</h1>
         <p class="dac-hero-description">
-          Android N が正式リリースされる前に、
+          Android Nougat が正式リリースされる前に、
           Nexus や他の端末で事前に<strong>アプリの動作をご確認いただけます</strong>。新しいシステム動作をサポートして、<strong>電力やメモリの使用量を削減しましょう</strong>。
 
           <strong>マルチ ウィンドウ UI</strong> や<strong>ダイレクト リプライ通知</strong>などの機能も利用して、アプリを拡張してみてください。
 
         </p>
 
-        <a class="dac-hero-cta" href="{@docRoot}preview/overview.html">
+        <a class="dac-hero-cta" href="{@docRoot}about/versions/nougat/android-7.0.html">
           <span class="dac-sprite dac-auto-chevron"></span>
-          スタートガイド</a>
-<!--<br>
-        <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Update to Android N (final SDK)
-        </a><br>-->
+          スタートガイド
+        </a>
       </div>
-      <div class="col-9of16 col-pull-7of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
-        <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png" srcset="{@docRoot}images/home/n-preview-hero.png 1x,
-             {@docRoot}images/home/n-preview-hero_2x.png 2x">
+      <div class="col-7of16 col-pull-6of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
+        <a  href="{@docRoot}about/versions/nougat/android-7.0.html">
+        <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png"
+             srcset="{@docRoot}images/home/n-preview-hero.png 1x,
+             {@docRoot}images/home/n-preview-hero_2x.png 2x" />
+           </a>
       </div>
-    </div>
+    </div></a>
     <div class="dac-section dac-small">
       <div class="resource-widget resource-flow-layout col-16"
-           data-query="collection:preview/landing/resources"
+           data-query="collection:nougat/landing/resources"
            data-cardSizes="6x2"
-           data-maxResults="6"></div>
-    </div>
+           data-maxResults="3"></div>
+         </div>
   </div>
 </section>
 
+
 <div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
+    <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
       <i class="dac-sprite dac-arrow-down-gray"></i>
     </a>
     <ul class="dac-actions">
       <li class="dac-action">
-        <a class="dac-action-link" href="https://developer.android.com/preview/bug">
+        <a class="dac-action-link" href="https://source.android.com/source/report-bugs.html">
           <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
-          問題の報告</a>
-
-      </li>
-      <li class="dac-action">
-        <a class="dac-action-link" href="{@docRoot}preview/support.html">
-          <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
-          リリースノートの確認</a>
-
+          問題の報告
+        </a>
       </li>
       <li class="dac-action">
         <a class="dac-action-link" href="{@docRoot}preview/dev-community">
           <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
-          開発者コミュニティに参加</a>
-
+          開発者コミュニティに参加
+        </a>
       </li>
     </ul>
   </div><!-- end .wrap -->
@@ -113,19 +108,33 @@
     data-initial-results="3"></div>
 </div></section>
 
-<section class="dac-section dac-gray"><div class="wrap">
-  <h1 class="dac-section-title">リソース</h1>
+<section class="dac-section dac-gray" id="videos"><div class="wrap">
+  <h1 class="dac-section-title">Videos</h1>
   <div class="dac-section-subtitle">
-    Android N 向けにアプリを開発する上で役立つ必須情報をご提供します。
+    New Android capabilities and the right way to use them in your apps.
   </div>
 
   <div class="resource-widget resource-flow-layout col-16"
-       data-query="collection:preview/landing/more"
+    data-query="collection:nougat/landing/videos/first,type:youtube+tag:androidn"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x6"
+    data-items-per-page="6"
+    data-maxResults="15"
+    data-initial-results="3">
+  </div>
+</div></section>
+
+<section class="dac-section dac-light" id="resources"><div class="wrap">
+  <h1 class="dac-section-title">リソース</h1>
+  <div class="dac-section-subtitle">
+    Android Nougat 向けにアプリを開発する上で役立つ必須情報をご提供します。
+  </div>
+
+  <div class="resource-widget resource-flow-layout col-16"
+       data-query="collection:nougat/landing/more"
        data-cardSizes="6x6"
        data-items-per-page="6"
        data-maxResults="15"
        data-initial-results="6"></div>
-
   </div>
-</section>
-
+</section>
\ No newline at end of file
diff --git a/docs/html-intl/intl/ja/index.jd b/docs/html-intl/intl/ja/index.jd
index 755ec62..ba73c41 100644
--- a/docs/html-intl/intl/ja/index.jd
+++ b/docs/html-intl/intl/ja/index.jd
@@ -15,33 +15,30 @@
   })
 </script>
 
-<section class="dac-expand dac-hero dac-invert" style="background-color:#455A64">
-  <div class="wrap" style="max-width:1100px;margin-top:0">
-    <div class="col-7of16 col-push-9of16" style="padding-left:2em;">
-      <a href="{@docRoot}preview/index.html">
-        <h1 class="dac-hero-title">Android N Developer Preview</h1>
-        <p class="dac-hero-description">
-          Get ready for the next version of Android!
-          <strong>Test your apps</strong> on Nexus and other devices. Support new system
-          behaviors to <strong>save power and memory</strong>.
+<section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
+  <div class="wrap" style="max-width:1000px;margin-top:0">
+    <div class="col-7of16 col-push-8of16">
+      <a href="{@docRoot}about/versions/nougat/index.html">
+        <h1 class="dac-hero-title" style="color:#004d40">Android 7.0 Nougat!</h1>
+        <p class="dac-hero-description" style="color:#004d40">
+          <strong>Android 7.0 Nougat is here!</strong>
+          Get your apps ready for the latest version of Android, with new system
+          behaviors to <strong>save battery and memory</strong>.
           Extend your apps with <strong>multi-window UI</strong>,
           <strong>direct reply notifications</strong> and more.
         </p>
-        <a class="dac-hero-cta" href="/preview/index.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
+        <a class="dac-hero-cta" href="{@docRoot}about/versions/nougat/index.html" style="color:#004d40">
+          <span class="dac-sprite dac-auto-chevron" style="background-color:#b2dfdb"></span>
           Learn more
-        </a><!--<br>
-        <a class="dac-hero-cta" href="/preview/support.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Update to Developer Preview (final SDK)
-        </a><br>-->
+        </a>
+        </a>
       </a>
     </div>
-    <div class="col-9of16 col-pull-7of16 dac-hero-figure" style="margin-top:0em;padding-right:1.5em;">
-      <a href="{@docRoot}preview/index.html">
-        <img style="" class="dac-hero-image" src="/images/home/n-preview-hero.png"
-             srcset="/images/home/n-preview-hero.png 1x,
-             /images/home/n-preview-hero_2x.png 2x">
+    <div class="col-6of16 col-pull-6of16 dac-hero-figure" style="padding-left:1em;padding-top:1em;">
+      <a href="{@docRoot}about/versions/nougat/index.html">
+        <img class="dac-hero-image" src="{@docRoot}images/home/nougat_bg.jpg"
+             srcset="{@docRoot}images/home/nougat_bg.jpg 1x,
+             {@docRoot}images/home/nougat_bg_2x.jpg 2x">
         </a>
     </div>
   </div>
diff --git a/docs/html-intl/intl/ko/about/versions/nougat/android-7.0-testing.jd b/docs/html-intl/intl/ko/about/versions/nougat/android-7.0-testing.jd
deleted file mode 100644
index 1222227..0000000
--- a/docs/html-intl/intl/ko/about/versions/nougat/android-7.0-testing.jd
+++ /dev/null
@@ -1,190 +0,0 @@
-page.title=테스트 가이드
-page.image=images/cards/card-n-guide_2x.png
-meta.tags="preview", "testing"
-page.tags="preview", "developer preview"
-
-@jd:body
-
-<div id="tb-wrapper">
-  <div id="tb">
-    <h2>이 문서의 내용</h2>
-      <ol>
-        <li><a href="#runtime-permissions">권한 테스트</a></li>
-        <li><a href="#doze-standby">잠자기 및 앱 대기 모드 테스트</a></li>
-        <li><a href="#ids">자동 백업 및 기기 식별자</a></li>
-      </ol>
-  </div>
-</div>
-
-<p>
-  Android N에서는 앱이 차기 버전의 플랫폼에서 제대로 작동하는지 확인해볼 수 있습니다.
- 이 프리뷰에는 앱에 영향을 미칠 수 있는 수많은 API와 동작 변경 사항이 포함되어 있습니다. 이에 대해서는 <a href="{@docRoot}preview/api-overview.html">API 개요</a>와 <a href="{@docRoot}preview/behavior-changes.html">동작 변경 사항</a>에 설명되어 있습니다.
-
- 프리뷰로 앱을 테스트할 때에는 사용자에게 좋은 환경을 제공하기 위해 개발자 여러분이 꼭 초점을 맞춰야 하는 몇 가지 특정한 시스템 변경사항이 있습니다.
-
-
-</p>
-
-<p>
-  이 가이드에서는 앱에서 테스트할 프리뷰 기능은 어떤 것이고, 테스트 방법은 어떤지에 대해 설명합니다. 이와 같은 특정 프리뷰 기능을 먼저 테스트하는 것이 좋습니다. 왜냐하면 이들 기능은 앱의 동작에 큰 영향을 미칠 가능성이 높기 때문입니다.
-
-
-</p>
-
-<ul>
-  <li><a href="#runtime-permissions">권한</a>
-  </li>
-  <li><a href="#doze-standby">잠자기 및 앱 대기 모드</a>
-  </li>
-  <li><a href="#ids">자동 백업 및 기기 식별자</a></li>
-</ul>
-
-<p>
-  테스트용 프리뷰 시스템 이미지로 기기 또는 가상 기기를 설정하는 방법에 대한 자세한 정보는 <a href="{@docRoot}preview/setup-sdk.html">Android N SDK 설정</a>을 참조하세요.
-
-
-</p>
-
-
-<h2 id="runtime-permissions">권한 테스트</h2>
-
-<p>
-  새로운 <a href="{@docRoot}preview/features/runtime-permissions.html">권한</a> 모델은 사용자가 여러분의 앱에 권한을 할당하는 방법을 바꿔 놓습니다.
- 설치 절차 중에 모든 권한을 허용하는 것이 아니라, 앱이 런타임에 사용자에게 각각의 권한을 요청해야 합니다.
-
- 사용자 입장에서는 이러한 동작으로 각 앱의 액티비티에 대해 더 세분화된 제어권을 행사할 수 있을 뿐만 아니라 이 앱이 어째서 특정한 권한을 요청하고 있는 것인지 맥락을 더 잘 이해할 수 있게 되기도 합니다.
- 사용자는 언제든 앱에 개별적으로 권한을 허용할 수 있고, 이를 취소할 수도 있습니다.
- 미리 보기의 이러한 기능은 앱의 동작에 영향을 미칠 가능성이 가장 높고, 앱의 몇 가지 기능이 작동하지 않도록 막거나 저하된 상태로 작동하게 할 수도 있습니다.
-
-
-</p>
-
-<p class="caution">
-  이 변경 내용은 새 플랫폼에서 실행되는 모든 앱에 영향을 비치며, 새 플랫폼 버전을 대상으로 하지 않는 앱도 예외가 아닙니다.
- 레거시 앱에 대해 플랫폼이 제한된 호환성 동작을 제공하기는 하지만, 지금 바로 새 권한 모델로 앱의 마이그레이션 계획을 시작하는 편이 좋습니다. 플랫폼이 공식적으로 출시될 때에 맞춰 앱의 업데이트된 버전을 게시하는 것을 목표로 하십시오.
-
-
-</p>
-
-
-<h3 id="permission-test-tips">테스트 팁</h3>
-
-<p>
-  다음은 새 권한 동작에 대해 앱 테스트를 계획하고 실행하는 데 유용한 몇 가지 테스트 팁입니다.
-
-</p>
-
-<ul>
-  <li>앱의 현재 권한과 관련된 코드 경로를 확인합니다.</li>
-  <li>권한 보호된 서비스 및 데이터 전반에 걸친 사용자 흐름을 테스트합니다.</li>
-  <li>허용된/취소된 권한을 여러 가지로 조합하여 테스트합니다.</li>
-  <li>명령줄에서 권한을 관리할 때 {@code adb} 도구를 사용합니다.
-    <ul>
-      <li>권한과 상태를 그룹별로 목록으로 나열합니다.
-        <pre>adb shell pm list permissions -d -g</pre>
-      </li>
-      <li>하나 이상의 권한을 다음과 같은 구문을 사용하여 허용하거나 취소합니다.<br>
-        <pre>adb shell pm [grant|revoke] &lt;permission.name&gt; ...</pre>
-      </li>
-    </ul>
-  </li>
-  <li>권한을 사용하는 서비스에 대해 앱을 분석해봅니다.</li>
-</ul>
-
-<h3 id="permission-test-strategy">테스트 전략</h3>
-
-<p>
-  권한을 변경하면 앱의 구조와 디자인은 물론 사용자 환경과, 개발자가 사용자에게 제공하는 흐름에도 영향을 미칩니다.
- 앱의 현재 권한 사용 내용을 평가한 다음 제공하고자 하는 새로운 흐름을 계획하기 시작해야 합니다.
- 플랫폼의 공식 릴리스에서 호환성 동작을 제공할 예정이지만, 이와 같은 동작에만 의존하지 말고 앱 업데이트를 계획하는 것이 좋습니다.
-
-
-</p>
-
-<p>
-  앱이 실제로 필요로 하고 사용하는 권한을 확인한 다음, 권한 보호된 서비스를 사용하는 여러 가지 코드 경로를 찾습니다.
- 이렇게 하려면 새 플랫폼에서 여러 가지로 조합한 테스트를 거치고 코드 분석을 통해야 합니다.
- 테스트에서는 런타임 권한에 옵트인하는 것에 초점을 맞춰야 합니다. 이를 위해 앱의 {@code targetSdkVersion}을 프리뷰 버전으로 변경하세요.
- 자세한 정보는 <a href="{@docRoot}preview/setup-sdk.html#">Android N SDK 설정</a>을 참조하세요.
-
-
-</p>
-
-<p>
-  다양한 조합의 권한을 해지하고 추가하는 방식으로 테스트를 수행하여 권한에 종속되는 사용자 흐름을 파악합니다.
- 종속성이 분명하지 않거나 논리적인 경우, 리팩터링을 고려해 보거나 해당 흐름을 구분하여 종속성을 제거, 또는 해당 권한이 왜 필요한지 분명히 하는 방안을 고려해야 합니다.
-
-
-</p>
-
-<p>
-  런타임 권한의 동작, 테스트 및 모범 사례에 대한 자세한 정보는 <a href="{@docRoot}preview/features/runtime-permissions.html">권한</a> 개발자 미리 보기 페이지를 참조하십시오.
-
-
-</p>
-
-
-<h2 id="doze-standby">잠자기 및 앱 대기 모드 테스트</h2>
-
-<p>
-  잠자기 및 앱 대기 모드의 절전 기능은 기기가 유휴 상태에 있을 때 또는 사용자가 앱에 초점을 맞추고 있지 않을 때 앱이 수행할 수 있는 배경 처리의 양을 제한합니다.
- 시스템이 앱에 부과할 수 있는 제한 사항에는 네트워크 액세스를 제한하거나 없애기, 배경 작업을 일시 중지시키기, 알림 일시 중지, 절전 모드 해제 및 알람 요청 무시 등이 포함됩니다.
-
- 이러한 절전 기능에 앱이 적절히 동작하도록 확실히 해 두려면 이와 같은 저전력 상태를 시뮬레이트하여 앱을 테스트해보아야 합니다.
-
-
-</p>
-
-<h4 id="doze">앱에서 잠자기 모드 테스트하기</h4>
-
-<p>앱에서 잠자기 모드를 테스트하려면:</p>
-
-<ol>
-<li>Android N 시스템 이미지로 하드웨어 기기 또는 가상 기기를 구성합니다.</li>
-<li>기기를 개발 머신에 연결하고 앱을 설치합니다.</li>
-<li>앱을 실행시킨 다음 활성 상태로 그냥 둡니다.</li>
-<li>다음 명령을 실행하여 기기가 잠자기 모드에 들어가는 것을 시뮬레이션합니다.
-
-<pre>
-$ adb shell dumpsys battery unplug
-$ adb shell dumpsys deviceidle step
-$ adb shell dumpsys deviceidle -h
-</pre>
-
-  </li>
-  <li>기기가 다시 활성화되면 앱이 어떻게 동작하는지 살펴봅니다. 기기가 잠자기 모드를 종료할 때 정상적으로 복구되는지 확인해야 합니다.
-</li>
-</ol>
-
-
-<h4 id="standby">앱에서 앱 대기 모드 테스트하기</h4>
-
-<p>앱에서 앱 대기 모드를 테스트하려면:</p>
-
-<ol>
-  <li>Android N 시스템 이미지로 하드웨어 기기 또는 가상 기기를 구성합니다.</li>
-  <li>기기를 개발 머신에 연결하고 앱을 설치합니다.</li>
-  <li>앱을 실행시킨 다음 활성 상태로 그냥 둡니다.</li>
-  <li>다음 명령을 실행하여 앱이 대기 모드에 들어가는 것을 시뮬레이션합니다.
-
-<pre>
-$ adb shell am broadcast -a android.os.action.DISCHARGING
-$ adb shell am set-idle &lt;packageName&gt; true
-</pre>
-
-  </li>
-  <li>다음 명령을 사용하여 앱이 대기 모드에서 해제되는 것을 시뮬레이션합니다.
-    <pre>$ adb shell am set-idle &lt;packageName&gt; false</pre>
-  </li>
-  <li>앱이 대기 모드에서 해제된 상태에서 어떻게 동작하는지 살펴봅니다. 대기 모드에서 정상적으로 복구되는지 확인해야 합니다.
- 특히, 앱의 알림과 배경 작업이 계속 예상했던 대로 기능하는지 확인해야 합니다.
-</li>
-</ol>
-
-<h2 id="ids">앱용 자동 백업 및 기기별 식별자</h2>
-
-<p>앱이 내부 저장소에서 각 기기에 따라 다른 식별자(예: Google Cloud Messaging 등록 ID)를 유지하는 경우, 모범 사례를 따라 저장소 위치를 자동 백업에서 배제해야 합니다. 이 내용은 <a href="{@docRoot}preview/backup/index.html">앱용 자동 백업</a>에 설명되어 있습니다.
-
-
-
- </p>
diff --git a/docs/html-intl/intl/ko/about/versions/nougat/index.jd b/docs/html-intl/intl/ko/about/versions/nougat/index.jd
index 4b0ccc5..6ed065b 100644
--- a/docs/html-intl/intl/ko/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/ko/about/versions/nougat/index.jd
@@ -1,6 +1,6 @@
-page.title=Android N Developer Preview
-page.tags="preview","developer"
-meta.tags="preview", "android"
+page.title=Android 7.0 Nougat
+page.tags="androidn","versions"
+meta.tags="android n", "nougat", "android 7.0"
 fullpage=true
 forcelocalnav=true
 header.hide=1
@@ -17,62 +17,56 @@
   })
 </script>
 
-<section class="dac-expand dac-hero dac-light" style="background-color:#B2DFDB">
+<section class="dac-expand dac-hero dac-light">
   <div class="wrap" style="max-width:1100px;margin-top:0">
+  <a href="{@docRoot}about/versions/nougat/android-7.0.html">
     <div class="cols dac-hero-content" style="padding-bottom:1em;">
 
-      <div class="col-7of16 col-push-9of16" style="padding-left:2em">
-        <h1 class="dac-hero-title">Android N Developer Preview</h1>
+      <div class="col-7of16 col-push-8of16" style="padding-left:2em">
+        <h1 class="dac-hero-title">Android 7.0 Nougat</h1>
         <p class="dac-hero-description">
-          Android N을 맞이할 준비를 하세요!
+          Android Nougat을 맞이할 준비를 하세요!
           Nexus와 다른 기기에서 <strong>앱을 테스트하세요</strong>. <strong>전력과 메모리를 절약</strong>하는 새로운 시스템
 동작을 지원하세요.
           <strong>다중 창 UI</strong>,
 <strong>직접 회신 알림</strong> 등으로 앱을 확장하세요.
         </p>
 
-        <a class="dac-hero-cta" href="{@docRoot}preview/overview.html">
+        <a class="dac-hero-cta" href="{@docRoot}about/versions/nougat/android-7.0.html">
           <span class="dac-sprite dac-auto-chevron"></span>
           시작하기
-        </a><!--<br>
-        <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Update to Android N (final SDK)
-        </a><br>-->
+        </a>
       </div>
-      <div class="col-9of16 col-pull-7of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
-        <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png" srcset="{@docRoot}images/home/n-preview-hero.png 1x,
-             {@docRoot}images/home/n-preview-hero_2x.png 2x">
+      <div class="col-7of16 col-pull-6of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
+        <a  href="{@docRoot}about/versions/nougat/android-7.0.html">
+        <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png"
+             srcset="{@docRoot}images/home/n-preview-hero.png 1x,
+             {@docRoot}images/home/n-preview-hero_2x.png 2x" />
+           </a>
       </div>
-    </div>
+    </div></a>
     <div class="dac-section dac-small">
       <div class="resource-widget resource-flow-layout col-16"
-           data-query="collection:preview/landing/resources"
+           data-query="collection:nougat/landing/resources"
            data-cardSizes="6x2"
-           data-maxResults="6"></div>
-    </div>
+           data-maxResults="3"></div>
+         </div>
   </div>
 </section>
 
 <div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
+    <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
       <i class="dac-sprite dac-arrow-down-gray"></i>
     </a>
     <ul class="dac-actions">
       <li class="dac-action">
-        <a class="dac-action-link" href="https://developer.android.com/preview/bug">
+        <a class="dac-action-link" href="https://source.android.com/source/report-bugs.html">
           <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
           문제 보고
         </a>
       </li>
       <li class="dac-action">
-        <a class="dac-action-link" href="{@docRoot}preview/support.html">
-          <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
-          릴리스 노트 보기
-        </a>
-      </li>
-      <li class="dac-action">
         <a class="dac-action-link" href="{@docRoot}preview/dev-community">
           <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
           개발자 커뮤니티 가입
@@ -113,19 +107,34 @@
     data-initial-results="3"></div>
 </div></section>
 
-<section class="dac-section dac-gray"><div class="wrap">
-  <h1 class="dac-section-title">리소스</h1>
+<section class="dac-section dac-gray" id="videos"><div class="wrap">
+  <h1 class="dac-section-title">Videos</h1>
   <div class="dac-section-subtitle">
-    앱을 Android N에서 사용할 수 있도록 준비하는 데 유용한 중요 정보입니다.
+    New Android capabilities and the right way to use them in your apps.
   </div>
 
   <div class="resource-widget resource-flow-layout col-16"
-       data-query="collection:preview/landing/more"
+    data-query="collection:nougat/landing/videos/first,type:youtube+tag:androidn"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x6"
+    data-items-per-page="6"
+    data-maxResults="15"
+    data-initial-results="3">
+  </div>
+</div></section>
+
+<section class="dac-section dac-light" id="resources"><div class="wrap">
+  <h1 class="dac-section-title">리소스</h1>
+  <div class="dac-section-subtitle">
+    앱을 Android Nougat에서 사용할 수 있도록 준비하는 데 유용한 중요 정보입니다.
+  </div>
+
+  <div class="resource-widget resource-flow-layout col-16"
+       data-query="collection:nougat/landing/more"
        data-cardSizes="6x6"
        data-items-per-page="6"
        data-maxResults="15"
        data-initial-results="6"></div>
 
   </div>
-</section>
-
+</section>
\ No newline at end of file
diff --git a/docs/html-intl/intl/ko/index.jd b/docs/html-intl/intl/ko/index.jd
index 01c8587..e102411 100644
--- a/docs/html-intl/intl/ko/index.jd
+++ b/docs/html-intl/intl/ko/index.jd
@@ -15,33 +15,30 @@
   })
 </script>
 
-<section class="dac-expand dac-hero dac-invert" style="background-color:#455A64">
-  <div class="wrap" style="max-width:1100px;margin-top:0">
-    <div class="col-7of16 col-push-9of16" style="padding-left:2em;">
-      <a href="{@docRoot}preview/index.html">
-        <h1 class="dac-hero-title">Android N Developer Preview</h1>
-        <p class="dac-hero-description">
-          Get ready for the next version of Android!
-          <strong>Test your apps</strong> on Nexus and other devices. Support new system
-          behaviors to <strong>save power and memory</strong>.
+<section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
+  <div class="wrap" style="max-width:1000px;margin-top:0">
+    <div class="col-7of16 col-push-8of16">
+      <a href="{@docRoot}about/versions/nougat/index.html">
+        <h1 class="dac-hero-title" style="color:#004d40">Android 7.0 Nougat!</h1>
+        <p class="dac-hero-description" style="color:#004d40">
+          <strong>Android 7.0 Nougat is here!</strong>
+          Get your apps ready for the latest version of Android, with new system
+          behaviors to <strong>save battery and memory</strong>.
           Extend your apps with <strong>multi-window UI</strong>,
           <strong>direct reply notifications</strong> and more.
         </p>
-        <a class="dac-hero-cta" href="/preview/index.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
+        <a class="dac-hero-cta" href="{@docRoot}about/versions/nougat/index.html" style="color:#004d40">
+          <span class="dac-sprite dac-auto-chevron" style="background-color:#b2dfdb"></span>
           Learn more
-        </a><!--<br>
-        <a class="dac-hero-cta" href="/preview/support.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Update to Developer Preview (final SDK)
-        </a><br>-->
+        </a>
+        </a>
       </a>
     </div>
-    <div class="col-9of16 col-pull-7of16 dac-hero-figure" style="margin-top:0em;padding-right:1.5em;">
-      <a href="{@docRoot}preview/index.html">
-        <img style="" class="dac-hero-image" src="/images/home/n-preview-hero.png"
-             srcset="/images/home/n-preview-hero.png 1x,
-             /images/home/n-preview-hero_2x.png 2x">
+    <div class="col-6of16 col-pull-6of16 dac-hero-figure" style="padding-left:1em;padding-top:1em;">
+      <a href="{@docRoot}about/versions/nougat/index.html">
+        <img class="dac-hero-image" src="{@docRoot}images/home/nougat_bg.jpg"
+             srcset="{@docRoot}images/home/nougat_bg.jpg 1x,
+             {@docRoot}images/home/nougat_bg_2x.jpg 2x">
         </a>
     </div>
   </div>
diff --git a/docs/html-intl/intl/pt-br/about/versions/nougat/android-7.0-testing.jd b/docs/html-intl/intl/pt-br/about/versions/nougat/android-7.0-testing.jd
deleted file mode 100644
index c00fd21..0000000
--- a/docs/html-intl/intl/pt-br/about/versions/nougat/android-7.0-testing.jd
+++ /dev/null
@@ -1,190 +0,0 @@
-page.title=Guia de teste
-page.image=images/cards/card-n-guide_2x.png
-meta.tags="preview", "testing"
-page.tags="preview", "developer preview"
-
-@jd:body
-
-<div id="tb-wrapper">
-  <div id="tb">
-    <h2>Neste documento</h2>
-      <ol>
-        <li><a href="#runtime-permissions">Teste de permissões</a></li>
-        <li><a href="#doze-standby">Teste de soneca e App em espera</a></li>
-        <li><a href="#ids">Identificadores de dispositivo e backup automático</a></li>
-      </ol>
-  </div>
-</div>
-
-<p>
-  O Android N fornece uma oportunidade de garantir que os aplicativos funcionem
- na próxima versão da plataforma. Esta prévia inclui uma série de mudanças de comportamento e APIs que podem
- ter impacto no aplicativo, como descrito em <a href="{@docRoot}preview/api-overview.html">Visão geral da API
-</a> e <a href="{@docRoot}preview/behavior-changes.html">Mudanças de comportamento</a>. No teste
- do aplicativo com a prévia, há algumas alterações de sistema específicas em que você deve se concentrar
- para garantir que os usuários tenham uma boa experiência.
-</p>
-
-<p>
-  Este guia descreve quais recursos de prévia testar e como testá-los com o aplicativo. Você deve
- priorizar o teste destes recursos de prévia específicos devido ao grande impacto potencial no
- comportamento do aplicativo:
-</p>
-
-<ul>
-  <li><a href="#runtime-permissions">Permissões</a>
-  </li>
-  <li><a href="#doze-standby">Soneca e App em espera</a>
-  </li>
-  <li><a href="#ids">Identificadores de dispositivo e backup automático</a></li>
-</ul>
-
-<p>
-  Para obter mais informações sobre como configurar dispositivos físicos ou virtuais com uma imagem do sistema de prévia
- para teste, consulte <a href="{@docRoot}preview/setup-sdk.html">Configuração
-do Android N SDK</a>.
-</p>
-
-
-<h2 id="runtime-permissions">Teste de permissões</h2>
-
-<p>
-  O novo modelo de <a href="{@docRoot}preview/features/runtime-permissions.html">permissões</a>
- altera a maneira que as permissões são alocadas ao aplicativo pelo usuário. Em vez de conceder todas as permissões
- durante o procedimento de instalação, o aplicativo deve pedir ao usuário permissões individuais
- em tempo de execução. Para os usuários, este comportamento fornece um controle mais granular sobre as atividades de cada aplicativo, bem
- como um melhor contexto para entender o porquê do aplicativo estar solicitando uma permissão específica. Os usuários
- podem conceder ou revogar as permissões concedidas a um aplicativo individualmente a qualquer momento. É provável que este recurso
- da prévia tenha um impacto no comportamento do aplicativo e pode impedir que alguns
- dos recursos do aplicativo funcionem, ou funcionem em um estado degradado.
-</p>
-
-<p class="caution">
-  Esta alteração afeta todos os aplicativos em execução na nova plataforma, mesmo aqueles que não são destinados
- para a versão nova da plataforma. A plataforma fornece um comportamento de compatibilidade limitado para aplicativos legados. No entanto,
- você deve começar a planejar a migração do aplicativo para o novo modelo de permissões agora, com o objetivo
- de publicar uma versão atualizada do aplicativo no lançamento oficial da plataforma.
-</p>
-
-
-<h3 id="permission-test-tips">Dicas de teste</h3>
-
-<p>
-  Use as seguintes dicas de teste para ajudar você a planejar e executar os testes do aplicativo com o novo
- comportamento de permissões.
-</p>
-
-<ul>
-  <li>Identifique as permissões atuais do aplicativo e os caminhos de código relacionados.</li>
-  <li>Teste o fluxo de usuário entre serviços protegidos por permissão e dados.</li>
-  <li>Teste com várias combinações de permissões revogadas/concedidas.</li>
-  <li>Use a ferramenta {@code adb} para gerenciar as permissões da linha de comando:
-    <ul>
-      <li>Liste as permissões e o status por grupos:
-        <pre>adb shell pm list permissions -d -g</pre>
-      </li>
-      <li>Conceda ou revogue uma ou mais permissões usando a seguinte sintaxe:<br>
-        <pre>adb shell pm [grant|revoke] &lt;permission.name&gt; ...</pre>
-      </li>
-    </ul>
-  </li>
-  <li>Analise o aplicativo para encontrar os serviços que usam permissões.</li>
-</ul>
-
-<h3 id="permission-test-strategy">Estratégia de teste</h3>
-
-<p>
-  A mudança de permissões afeta a estrutura e o projeto do aplicativo, bem como
- a experiência do usuário e os fluxos fornecidos a eles. Você deve avaliar o uso das permissões atuais
- do aplicativo e começar a planejar novos fluxos que deseja oferecer. O lançamento oficial
- da plataforma fornece comportamento de compatibilidade, mas deve-se planejar a atualização do aplicativo e
- não confiar nestes comportamentos.
-</p>
-
-<p>
-  Identifique as permissões que o aplicativo realmente precisa e usa e, em seguida, encontre os vários caminhos
- de código que usam os serviços protegidos por permissões. É possível fazer isto por meio de uma combinação de
- testes na nova plataforma e análise de códigos. Nos testes, você deve se concentrar em usar
- as permissões em tempo de execução alterando {@code targetSdkVersion} do aplicativo para a versão da prévia. Para
- obter mais informações, consulte <a href="{@docRoot}preview/setup-sdk.html#">Configuração
-do Android N SDK</a>.
-</p>
-
-<p>
-  Teste com várias combinações de permissões revogadas e concedidas para destacar os fluxos de usuário
-que dependem de permissões. Onde uma dependência não for óbvia ou lógica, considere
-refatorar ou compartimentalizar este fluxo para eliminar a dependência ou para esclarecer por que
-a permissão é necessária.
-</p>
-
-<p>
-  Para obter mais informações sobre o comportamento das permissões em tempo de execução, de testes e de melhores práticas, consulte a página
- <a href="{@docRoot}preview/features/runtime-permissions.html">Permissões</a> do Developer
- Preview.
-</p>
-
-
-<h2 id="doze-standby">Teste de soneca e App em espera</h2>
-
-<p>
-  Os recursos de economia de energia de App em espera e soneca limitam a quantidade de processamento de segundo plano que o aplicativo
- pode realizar quando um dispositivo está no estado ocioso ou enquanto não está em foco. As
- restrições que o sistema pode impor nos aplicativos inclui acesso a rede limitado ou restrito,
- tarefas de segundo plano suspensas, notificações suspensas, solicitações de soneca ignoradas e despertadores. Para garantir
- que o aplicativo se comportará adequadamente com essas otimizações de economia de energia, deve-se testá-lo
- simulando estes estados de baixa energia.
-</p>
-
-<h4 id="doze">Testar o aplicativo com Soneca</h4>
-
-<p>Para testar a Soneca com o aplicativo:</p>
-
-<ol>
-<li>Configure um dispositivo de hardware ou virtual com uma imagem do sistema Android N.</li>
-<li>Conecte o dispositivo à máquina de desenvolvimento e instale o aplicativo.</li>
-<li>Execute o aplicativo e deixe-o ativo.</li>
-<li>Simule o dispositivo acessando o modo Soneca executando os seguintes comandos:
-
-<pre>
-$ adb shell dumpsys battery unplug
-$ adb shell dumpsys deviceidle step
-$ adb shell dumpsys deviceidle -h
-</pre>
-
-  </li>
-  <li>Observe o comportamento do aplicativo quando o dispositivo é reativado. Certifique-se de que
- ele se recupere corretamente quando o dispositivo sai do modo Soneca.</li>
-</ol>
-
-
-<h4 id="standby">Testar aplicativos com App em espera</h4>
-
-<p>Para testar o modo de espera do aplicativo:</p>
-
-<ol>
-  <li>Configure um dispositivo de hardware ou virtual com uma imagem do sistema Android N.</li>
-  <li>Conecte o dispositivo à máquina de desenvolvimento e instale o aplicativo.</li>
-  <li>Execute o aplicativo e deixe-o ativo.</li>
-  <li>Simule o aplicativo acessando o modo de espera executando os seguintes comandos:
-
-<pre>
-$ adb shell am broadcast -a android.os.action.DISCHARGING
-$ adb shell am set-idle &lt;packageName&gt; true
-</pre>
-
-  </li>
-  <li>Simule o despertar do aplicativo usando o seguinte comando:
-    <pre>$ adb shell am set-idle &lt;packageName&gt; false</pre>
-  </li>
-  <li>Observe o comportamento do aplicativo quando ele é despertado. Certifique-se de que ele se recupere corretamente
- do modo de espera. Particularmente, deve-se verificar se as notificações e os trabalho de segundo plano
- do aplicativo continuam a funcionar como o esperado.</li>
-</ol>
-
-<h2 id="ids">Backup automático para aplicativos e identificadores específicos do dispositivo</h2>
-
-<p>Caso o aplicativo esteja persistindo qualquer identificador específico do dispositivo, como o ID de registro do Google
-Cloud Messaging, no armazenamento interno,
-certifique-se de seguir as práticas recomendadas para excluir o local de armazenamento
-do backup automático, como descrito em <a href="{@docRoot}preview/backup/index.html">Backup automático
-para aplicativos</a>. </p>
diff --git a/docs/html-intl/intl/pt-br/about/versions/nougat/index.jd b/docs/html-intl/intl/pt-br/about/versions/nougat/index.jd
index 58b2408..c7aee2a 100644
--- a/docs/html-intl/intl/pt-br/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/pt-br/about/versions/nougat/index.jd
@@ -1,6 +1,6 @@
-page.title=Android N Developer Preview
-page.tags="preview","developer"
-meta.tags="preview", "android"
+page.title=Android 7.0 Nougat
+page.tags="androidn","versions"
+meta.tags="android n", "nougat", "android 7.0"
 fullpage=true
 forcelocalnav=true
 header.hide=1
@@ -17,62 +17,56 @@
   })
 </script>
 
-<section class="dac-expand dac-hero dac-light" style="background-color:#B2DFDB">
+<section class="dac-expand dac-hero dac-light">
   <div class="wrap" style="max-width:1100px;margin-top:0">
+  <a href="{@docRoot}about/versions/nougat/android-7.0.html">
     <div class="cols dac-hero-content" style="padding-bottom:1em;">
 
-      <div class="col-7of16 col-push-9of16" style="padding-left:2em">
-        <h1 class="dac-hero-title">Android N Developer Preview</h1>
+      <div class="col-7of16 col-push-8of16" style="padding-left:2em">
+        <h1 class="dac-hero-title">Android 7.0 Nougat</h1>
         <p class="dac-hero-description">
-          Prepare-se para o Android N!
+          Prepare-se para o Android Nougat!
           <strong>Teste os aplicativos</strong> no Nexus e outros dispositivos. Ofereça suporte aos novos
  comportamentos do sistema para <strong>economizar energia e memória</strong>.
           Estenda seus aplicativos com a <strong>IU de várias janelas</strong>,
  <strong>direcione notificações de resposta</strong> e muito mais.
         </p>
 
-        <a class="dac-hero-cta" href="{@docRoot}preview/overview.html">
+        <a class="dac-hero-cta" href="{@docRoot}about/versions/nougat/android-7.0.html">
           <span class="dac-sprite dac-auto-chevron"></span>
           Primeiros passos
-        </a><!--<br>
-        <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Update to Android N (final SDK)
-        </a><br>-->
+        </a>
       </div>
-      <div class="col-9of16 col-pull-7of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
-        <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png" srcset="{@docRoot}images/home/n-preview-hero.png 1x,
-             {@docRoot}images/home/n-preview-hero_2x.png 2x">
+      <div class="col-7of16 col-pull-6of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
+        <a  href="{@docRoot}about/versions/nougat/android-7.0.html">
+        <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png"
+             srcset="{@docRoot}images/home/n-preview-hero.png 1x,
+             {@docRoot}images/home/n-preview-hero_2x.png 2x" />
+           </a>
       </div>
-    </div>
+    </div></a>
     <div class="dac-section dac-small">
       <div class="resource-widget resource-flow-layout col-16"
-           data-query="collection:preview/landing/resources"
+           data-query="collection:nougat/landing/resources"
            data-cardSizes="6x2"
-           data-maxResults="6"></div>
-    </div>
+           data-maxResults="3"></div>
+         </div>
   </div>
 </section>
 
 <div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
+    <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
       <i class="dac-sprite dac-arrow-down-gray"></i>
     </a>
     <ul class="dac-actions">
       <li class="dac-action">
-        <a class="dac-action-link" href="https://developer.android.com/preview/bug">
+        <a class="dac-action-link" href="https://source.android.com/source/report-bugs.html">
           <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
           Informe um problema
         </a>
       </li>
       <li class="dac-action">
-        <a class="dac-action-link" href="{@docRoot}preview/support.html">
-          <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
-          Veja as notas de versão
-        </a>
-      </li>
-      <li class="dac-action">
         <a class="dac-action-link" href="{@docRoot}preview/dev-community">
           <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
           Participe da comunidade de desenvolvedores
@@ -82,26 +76,6 @@
   </div><!-- end .wrap -->
 </div><!-- end .dac-actions -->
 
-<div id="useOldTemplates" style="display:none;color:black" class="actions-bar dac-expand dac-invert">
-  <div class="wrap dac-offset-parent">
-
-    <div class="actions">
-      <div><a href="https://developer.android.com/preview/bug">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Informe um problema
-      </a></div>
-      <div><a href="{@docRoot}preview/support.html">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Veja as notas de versão
-      </a></div>
-      <div><a href="{@docRoot}preview/dev-community">
-        <span class="dac-sprite dac-auto-chevron-large"></span>
-        Participe da comunidade de desenvolvedores
-      </a></div>
-    </div><!-- end .actions -->
-  </div><!-- end .wrap -->
-</div>
-
 <section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
   <h2 class="norule">Mais recente</h2>
   <div class="resource-widget resource-flow-layout col-16"
@@ -113,19 +87,33 @@
     data-initial-results="3"></div>
 </div></section>
 
-<section class="dac-section dac-gray"><div class="wrap">
-  <h1 class="dac-section-title">Recursos</h1>
+<section class="dac-section dac-gray" id="videos"><div class="wrap">
+  <h1 class="dac-section-title">Videos</h1>
   <div class="dac-section-subtitle">
-    Informações essenciais para ajudar você a preparar seus aplicativos para o Android N.
+    New Android capabilities and the right way to use them in your apps.
   </div>
 
   <div class="resource-widget resource-flow-layout col-16"
-       data-query="collection:preview/landing/more"
+    data-query="collection:nougat/landing/videos/first,type:youtube+tag:androidn"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x6"
+    data-items-per-page="6"
+    data-maxResults="15"
+    data-initial-results="3">
+  </div>
+</div></section>
+
+<section class="dac-section dac-light" id="resources"><div class="wrap">
+  <h1 class="dac-section-title">Recursos</h1>
+  <div class="dac-section-subtitle">
+    Informações essenciais para ajudar você a preparar seus aplicativos para o Android Nougat.
+  </div>
+
+  <div class="resource-widget resource-flow-layout col-16"
+       data-query="collection:nougat/landing/more"
        data-cardSizes="6x6"
        data-items-per-page="6"
        data-maxResults="15"
        data-initial-results="6"></div>
-
   </div>
-</section>
-
+</section>
\ No newline at end of file
diff --git a/docs/html-intl/intl/pt-br/index.jd b/docs/html-intl/intl/pt-br/index.jd
index f5e1569..3c8f75d 100644
--- a/docs/html-intl/intl/pt-br/index.jd
+++ b/docs/html-intl/intl/pt-br/index.jd
@@ -15,33 +15,30 @@
   })
 </script>
 
-<section class="dac-expand dac-hero dac-invert" style="background-color:#455A64">
-  <div class="wrap" style="max-width:1100px;margin-top:0">
-    <div class="col-7of16 col-push-9of16" style="padding-left:2em;">
-      <a href="{@docRoot}preview/index.html">
-        <h1 class="dac-hero-title">Android N Developer Preview</h1>
-        <p class="dac-hero-description">
-          Get ready for the next version of Android!
-          <strong>Test your apps</strong> on Nexus and other devices. Support new system
-          behaviors to <strong>save power and memory</strong>.
+<section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
+  <div class="wrap" style="max-width:1000px;margin-top:0">
+    <div class="col-7of16 col-push-8of16">
+      <a href="{@docRoot}about/versions/nougat/index.html">
+        <h1 class="dac-hero-title" style="color:#004d40">Android 7.0 Nougat!</h1>
+        <p class="dac-hero-description" style="color:#004d40">
+          <strong>Android 7.0 Nougat is here!</strong>
+          Get your apps ready for the latest version of Android, with new system
+          behaviors to <strong>save battery and memory</strong>.
           Extend your apps with <strong>multi-window UI</strong>,
           <strong>direct reply notifications</strong> and more.
         </p>
-        <a class="dac-hero-cta" href="/preview/index.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
+        <a class="dac-hero-cta" href="{@docRoot}about/versions/nougat/index.html" style="color:#004d40">
+          <span class="dac-sprite dac-auto-chevron" style="background-color:#b2dfdb"></span>
           Learn more
-        </a><!--<br>
-        <a class="dac-hero-cta" href="/preview/support.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Update to Developer Preview (final SDK)
-        </a><br>-->
+        </a>
+        </a>
       </a>
     </div>
-    <div class="col-9of16 col-pull-7of16 dac-hero-figure" style="margin-top:0em;padding-right:1.5em;">
-      <a href="{@docRoot}preview/index.html">
-        <img style="" class="dac-hero-image" src="/images/home/n-preview-hero.png"
-             srcset="/images/home/n-preview-hero.png 1x,
-             /images/home/n-preview-hero_2x.png 2x">
+    <div class="col-6of16 col-pull-6of16 dac-hero-figure" style="padding-left:1em;padding-top:1em;">
+      <a href="{@docRoot}about/versions/nougat/index.html">
+        <img class="dac-hero-image" src="{@docRoot}images/home/nougat_bg.jpg"
+             srcset="{@docRoot}images/home/nougat_bg.jpg 1x,
+             {@docRoot}images/home/nougat_bg_2x.jpg 2x">
         </a>
     </div>
   </div>
diff --git a/docs/html-intl/intl/ru/about/versions/nougat/index.jd b/docs/html-intl/intl/ru/about/versions/nougat/index.jd
index 9bb56ba..1103166 100644
--- a/docs/html-intl/intl/ru/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/ru/about/versions/nougat/index.jd
@@ -1,6 +1,6 @@
-page.title=Android N Developer Preview
-page.tags="preview","developer"
-meta.tags="предварительная версия", "android"
+page.title=Android 7.0 Nougat
+page.tags="androidn","versions"
+meta.tags="android n", "nougat", "android 7.0"
 fullpage=true
 forcelocalnav=true
 header.hide=1
@@ -17,62 +17,56 @@
   })
 </script>
 
-<section class="dac-expand dac-hero dac-light" style="background-color:#B2DFDB">
+<section class="dac-expand dac-hero dac-light">
   <div class="wrap" style="max-width:1100px;margin-top:0">
+  <a href="{@docRoot}about/versions/nougat/android-7.0.html">
     <div class="cols dac-hero-content" style="padding-bottom:1em;">
 
-      <div class="col-7of16 col-push-9of16" style="padding-left:2em">
-        <h1 class="dac-hero-title">Android N Developer Preview</h1>
+      <div class="col-7of16 col-push-8of16" style="padding-left:2em">
+        <h1 class="dac-hero-title">Android 7.0 Nougat</h1>
         <p class="dac-hero-description">
-          Подготовьтесь к выходу Android N!
+          Подготовьтесь к выходу Android Nougat!
 <strong>Протестируйте свои приложения</strong> на Nexus и других устройствах. Поддержите нововведения
 системы, позволяющие <strong>снизить потребление энергии и памяти</strong>.
 Добавьте в свои приложения <strong>многооконный режим</strong>,
 <strong>возможность прямой отправки ответов из уведомлений</strong> и другие функции.
         </p>
 
-        <a class="dac-hero-cta" href="{@docRoot}preview/overview.html">
+        <a class="dac-hero-cta" href="{@docRoot}about/versions/nougat/android-7.0.html">
           <span class="dac-sprite dac-auto-chevron"></span>
           Начало работы
-        </a><!--<br>
-        <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Update to Android N (final SDK)
-        </a><br>-->
+        </a>
       </div>
-      <div class="col-9of16 col-pull-7of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
-        <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png" srcset="{@docRoot}images/home/n-preview-hero.png 1x,
-             {@docRoot}images/home/n-preview-hero_2x.png 2x">
+      <div class="col-7of16 col-pull-6of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
+        <a  href="{@docRoot}about/versions/nougat/android-7.0.html">
+        <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png"
+             srcset="{@docRoot}images/home/n-preview-hero.png 1x,
+             {@docRoot}images/home/n-preview-hero_2x.png 2x" />
+           </a>
       </div>
-    </div>
+    </div></a>
     <div class="dac-section dac-small">
       <div class="resource-widget resource-flow-layout col-16"
-           data-query="collection:preview/landing/resources"
+           data-query="collection:nougat/landing/resources"
            data-cardSizes="6x2"
-           data-maxResults="6"></div>
-    </div>
+           data-maxResults="3"></div>
+         </div>
   </div>
 </section>
 
 <div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
+    <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
       <i class="dac-sprite dac-arrow-down-gray"></i>
     </a>
     <ul class="dac-actions">
       <li class="dac-action">
-        <a class="dac-action-link" href="https://developer.android.com/preview/bug">
+        <a class="dac-action-link" href="https://source.android.com/source/report-bugs.html">
           <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
           Сообщить о проблеме
         </a>
       </li>
       <li class="dac-action">
-        <a class="dac-action-link" href="{@docRoot}preview/support.html">
-          <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
-          См. примечания к выпуску
-        </a>
-      </li>
-      <li class="dac-action">
         <a class="dac-action-link" href="{@docRoot}preview/dev-community">
           <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
           Вступить в сообщество разработчиков
@@ -102,19 +96,45 @@
   </div><!-- end .wrap -->
 </div>
 
-<section class="dac-section dac-light"><div class="wrap">
-  <h1 class="dac-section-title">Ресурсы</h1>
+<section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
+  <h2 class="norule">Latest</h2>
+  <div class="resource-widget resource-flow-layout col-16"
+    data-query="type:blog+tag:androidn+tag:featured, type:youtube+tag:androidn+tag:featured"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x6"
+    data-items-per-page="6"
+    data-maxResults="15"
+    data-initial-results="3"></div>
+</div></section>
+
+<section class="dac-section dac-gray" id="videos"><div class="wrap">
+  <h1 class="dac-section-title">Videos</h1>
   <div class="dac-section-subtitle">
-    Важная информация, которая поможет вам подготовить ваши приложения для работы в Android N.
+    New Android capabilities and the right way to use them in your apps.
   </div>
 
   <div class="resource-widget resource-flow-layout col-16"
-       data-query="collection:preview/landing/more"
+    data-query="collection:nougat/landing/videos/first,type:youtube+tag:androidn"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x6"
+    data-items-per-page="6"
+    data-maxResults="15"
+    data-initial-results="3">
+  </div>
+</div></section>
+
+<section class="dac-section dac-light" id="resources"><div class="wrap">
+  <h1 class="dac-section-title">Ресурсы</h1>
+  <div class="dac-section-subtitle">
+    Важная информация, которая поможет вам подготовить ваши приложения для работы в Android Nougat.
+  </div>
+
+  <div class="resource-widget resource-flow-layout col-16"
+       data-query="collection:nougat/landing/more"
        data-cardSizes="6x6"
        data-items-per-page="6"
        data-maxResults="15"
        data-initial-results="6"></div>
 
   </div>
-</section>
-
+</section>
\ No newline at end of file
diff --git a/docs/html-intl/intl/ru/index.jd b/docs/html-intl/intl/ru/index.jd
index e917a8d..b3f3cc2 100644
--- a/docs/html-intl/intl/ru/index.jd
+++ b/docs/html-intl/intl/ru/index.jd
@@ -15,33 +15,30 @@
   })
 </script>
 
-<section class="dac-expand dac-hero dac-invert" style="background-color:#455A64">
-  <div class="wrap" style="max-width:1100px;margin-top:0">
-    <div class="col-7of16 col-push-9of16" style="padding-left:2em;">
-      <a href="{@docRoot}preview/index.html">
-        <h1 class="dac-hero-title">Android N Developer Preview</h1>
-        <p class="dac-hero-description">
-          Get ready for the next version of Android!
-          <strong>Test your apps</strong> on Nexus and other devices. Support new system
-          behaviors to <strong>save power and memory</strong>.
+<section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
+  <div class="wrap" style="max-width:1000px;margin-top:0">
+    <div class="col-7of16 col-push-8of16">
+      <a href="{@docRoot}about/versions/nougat/index.html">
+        <h1 class="dac-hero-title" style="color:#004d40">Android 7.0 Nougat!</h1>
+        <p class="dac-hero-description" style="color:#004d40">
+          <strong>Android 7.0 Nougat is here!</strong>
+          Get your apps ready for the latest version of Android, with new system
+          behaviors to <strong>save battery and memory</strong>.
           Extend your apps with <strong>multi-window UI</strong>,
           <strong>direct reply notifications</strong> and more.
         </p>
-        <a class="dac-hero-cta" href="/preview/index.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
+        <a class="dac-hero-cta" href="{@docRoot}about/versions/nougat/index.html" style="color:#004d40">
+          <span class="dac-sprite dac-auto-chevron" style="background-color:#b2dfdb"></span>
           Learn more
-        </a><!--<br>
-        <a class="dac-hero-cta" href="/preview/support.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Update to Developer Preview (final SDK)
-        </a><br>-->
+        </a>
+        </a>
       </a>
     </div>
-    <div class="col-9of16 col-pull-7of16 dac-hero-figure" style="margin-top:0em;padding-right:1.5em;">
-      <a href="{@docRoot}preview/index.html">
-        <img style="" class="dac-hero-image" src="/images/home/n-preview-hero.png"
-             srcset="/images/home/n-preview-hero.png 1x,
-             /images/home/n-preview-hero_2x.png 2x">
+    <div class="col-6of16 col-pull-6of16 dac-hero-figure" style="padding-left:1em;padding-top:1em;">
+      <a href="{@docRoot}about/versions/nougat/index.html">
+        <img class="dac-hero-image" src="{@docRoot}images/home/nougat_bg.jpg"
+             srcset="{@docRoot}images/home/nougat_bg.jpg 1x,
+             {@docRoot}images/home/nougat_bg_2x.jpg 2x">
         </a>
     </div>
   </div>
diff --git a/docs/html-intl/intl/vi/about/versions/nougat/index.jd b/docs/html-intl/intl/vi/about/versions/nougat/index.jd
index bd64b25..58b4b5f 100644
--- a/docs/html-intl/intl/vi/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/vi/about/versions/nougat/index.jd
@@ -1,6 +1,6 @@
-page.title=Android N Developer Preview
-page.tags="preview","developer"
-meta.tags="preview", "android"
+page.title=Android 7.0 Nougat
+page.tags="androidn","versions"
+meta.tags="android n", "nougat", "android 7.0"
 fullpage=true
 forcelocalnav=true
 header.hide=1
@@ -17,62 +17,57 @@
   })
 </script>
 
-<section class="dac-expand dac-hero dac-light" style="background-color:#B2DFDB">
+<section class="dac-expand dac-hero dac-light">
   <div class="wrap" style="max-width:1100px;margin-top:0">
+  <a href="{@docRoot}about/versions/nougat/android-7.0.html">
     <div class="cols dac-hero-content" style="padding-bottom:1em;">
 
-      <div class="col-7of16 col-push-9of16" style="padding-left:2em">
-        <h1 class="dac-hero-title">Android N Developer Preview</h1>
+      <div class="col-7of16 col-push-8of16" style="padding-left:2em">
+        <h1 class="dac-hero-title">Android 7.0 Nougat</h1>
         <p class="dac-hero-description">
-          Hãy chuẩn bị sẵn sàng cho Android N!
+          Hãy chuẩn bị sẵn sàng cho Android Nougat!
           <strong>Kiểm thử ứng dụng của bạn</strong> trên Nexus và các thiết bị khác. Hỗ trợ các hành vi
           hệ thống mới nhằm <strong>tiết kiệm năng lượng và bộ nhớ</strong>.
           Mở rộng ứng dụng của bạn bằng <strong>UI đa cửa sổ</strong>,
           <strong>thông báo trả lời trực tiếp</strong> và nhiều tính năng khác.
         </p>
 
-        <a class="dac-hero-cta" href="{@docRoot}preview/overview.html">
+        <a class="dac-hero-cta" href="{@docRoot}about/versions/nougat/android-7.0.html">
           <span class="dac-sprite dac-auto-chevron"></span>
           Bắt đầu
-        </a><!--<br>
-        <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Update to Android N (final SDK)
-        </a><br>-->
+        </a>
       </div>
-      <div class="col-9of16 col-pull-7of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
-        <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png" srcset="{@docRoot}images/home/n-preview-hero.png 1x,
-             {@docRoot}images/home/n-preview-hero_2x.png 2x">
+      <div class="col-7of16 col-pull-6of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
+        <a  href="{@docRoot}about/versions/nougat/android-7.0.html">
+        <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png"
+             srcset="{@docRoot}images/home/n-preview-hero.png 1x,
+             {@docRoot}images/home/n-preview-hero_2x.png 2x" />
+           </a>
       </div>
-    </div>
+    </div></a>
     <div class="dac-section dac-small">
       <div class="resource-widget resource-flow-layout col-16"
-           data-query="collection:preview/landing/resources"
+           data-query="collection:nougat/landing/resources"
            data-cardSizes="6x2"
-           data-maxResults="6"></div>
-    </div>
+           data-maxResults="3"></div>
+         </div>
   </div>
 </section>
 
+
 <div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#build-apps">
+    <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
       <i class="dac-sprite dac-arrow-down-gray"></i>
     </a>
     <ul class="dac-actions">
       <li class="dac-action">
-        <a class="dac-action-link" href="https://developer.android.com/preview/bug">
+        <a class="dac-action-link" href="https://source.android.com/source/report-bugs.html">
           <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
           Báo cáo vấn đề
         </a>
       </li>
       <li class="dac-action">
-        <a class="dac-action-link" href="{@docRoot}preview/support.html">
-          <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
-          Xem ghi chú phát hành
-        </a>
-      </li>
-      <li class="dac-action">
         <a class="dac-action-link" href="{@docRoot}preview/dev-community">
           <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
           Tham gia cộng đồng nhà phát triển
@@ -102,19 +97,44 @@
   </div><!-- end .wrap -->
 </div>
 
-<section class="dac-section dac-light"><div class="wrap">
-  <h1 class="dac-section-title">Tài nguyên</h1>
+<section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
+  <h2 class="norule">Latest</h2>
+  <div class="resource-widget resource-flow-layout col-16"
+    data-query="type:blog+tag:androidn+tag:featured, type:youtube+tag:androidn+tag:featured"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x6"
+    data-items-per-page="6"
+    data-maxResults="15"
+    data-initial-results="3"></div>
+</div></section>
+
+<section class="dac-section dac-gray" id="videos"><div class="wrap">
+  <h1 class="dac-section-title">Videos</h1>
   <div class="dac-section-subtitle">
-    Các thông tin cần thiết để trợ giúp bạn chuẩn bị cho ứng dụng sẵn sàng chạy trên Android N.
+    New Android capabilities and the right way to use them in your apps.
   </div>
 
   <div class="resource-widget resource-flow-layout col-16"
-       data-query="collection:preview/landing/more"
+    data-query="collection:nougat/landing/videos/first,type:youtube+tag:androidn"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x6"
+    data-items-per-page="6"
+    data-maxResults="15"
+    data-initial-results="3">
+  </div>
+</div></section>
+
+<section class="dac-section dac-light" id="resources"><div class="wrap">
+  <h1 class="dac-section-title">Tài nguyên</h1>
+  <div class="dac-section-subtitle">
+    Các thông tin cần thiết để trợ giúp bạn chuẩn bị cho ứng dụng sẵn sàng chạy trên Android Nougat.
+  </div>
+
+  <div class="resource-widget resource-flow-layout col-16"
+       data-query="collection:nougat/landing/more"
        data-cardSizes="6x6"
        data-items-per-page="6"
        data-maxResults="15"
        data-initial-results="6"></div>
-
   </div>
-</section>
-
+</section>
\ No newline at end of file
diff --git a/docs/html-intl/intl/zh-cn/about/versions/nougat/android-7.0-testing.jd b/docs/html-intl/intl/zh-cn/about/versions/nougat/android-7.0-testing.jd
deleted file mode 100644
index d1e1187..0000000
--- a/docs/html-intl/intl/zh-cn/about/versions/nougat/android-7.0-testing.jd
+++ /dev/null
@@ -1,190 +0,0 @@
-page.title=测试指南
-page.image=images/cards/card-n-guide_2x.png
-meta.tags="preview", "testing"
-page.tags="preview", "developer preview"
-
-@jd:body
-
-<div id="tb-wrapper">
-  <div id="tb">
-    <h2>本文内容</h2>
-      <ol>
-        <li><a href="#runtime-permissions">测试权限</a></li>
-        <li><a href="#doze-standby">测试低电耗模式和应用待机模式</a></li>
-        <li><a href="#ids">自动备份和设备标识符</a></li>
-      </ol>
-  </div>
-</div>
-
-<p>
-  利用 Android N,您有机会确保应用可使用下一平台版本。
-如 <a href="{@docRoot}preview/api-overview.html">API 概览</a>和<a href="{@docRoot}preview/behavior-changes.html">行为变更</a>中所述,该 Preview 包括大量 API 和可能影响应用的行为变更。
-
-使用 Preview 测试应用时,您应重点关注一些特定的系统变更,确保用户拥有愉悦的体验。
-
-
-</p>
-
-<p>
-  本指南介绍可使用您的应用测试 Preview 的哪些功能以及如何测试。您应确定优先测试以下特定 Preview 功能,因为它们可能会对应用行为产生较大影响。
-
-
-</p>
-
-<ul>
-  <li><a href="#runtime-permissions">权限</a>
-  </li>
-  <li><a href="#doze-standby">低电耗模式和应用待机模式</a>
-  </li>
-  <li><a href="#ids">自动备份和设备标识符</a></li>
-</ul>
-
-<p>
-  如需了解有关如何使用 Preview 系统映像设置设备或虚拟设备以进行测试的详细信息,请参阅<a href="{@docRoot}preview/setup-sdk.html">设置 Android N SDK</a>。
-
-
-</p>
-
-
-<h2 id="runtime-permissions">测试权限</h2>
-
-<p>
-  新<a href="{@docRoot}preview/features/runtime-permissions.html">权限</a>模型改变了用户向您的应用分配权限的方式。
-您的应用必须在运行时要求用户提供各项权限,而不是在安装过程中要求授予所有权限。
-
-对于用户而言,此行为有助于他们更精细地控制每个应用的 Activity,并更深入地了解应用为何请求提供特定权限的上下文信息。
-用户可以随时向应用授予某项权限或撤销其某项权限。
-预览版的这种功能最有可能会对应用行为产生影响,而且可能会阻止某些应用功能运行或只能在降级状态中运行。
-
-
-</p>
-
-<p class="caution">
-  这一变更会影响在新平台上运行的所有应用,即便这些应用并非面向新平台版本开发亦是如此。
-该平台为旧版应用提供有限的兼容性行为,但您现在应当开始计划将应用迁移到新权限模型,以便在官方平台启动时发布更新的应用版本。
-
-
-</p>
-
-
-<h3 id="permission-test-tips">测试提示</h3>
-
-<p>
-  使用以下测试提示有助于您计划并通过新权限行为执行应用测试。
-
-</p>
-
-<ul>
-  <li>识别应用的当前权限和相关的代码路径</li>
-  <li>跨受权限保护的服务和数据测试用户流程</li>
-  <li>使用授予/撤销权限的各种组合进行测试</li>
-  <li>使用 {@code adb} 工具从命令行管理权限:
-    <ul>
-      <li>按组列出权限和状态:
-        <pre>adb shell pm list permissions -d -g</pre>
-      </li>
-      <li>使用以下语法授予或撤销一项或多项权限:<br>
-        <pre>adb shell pm [grant|revoke] &lt;permission.name&gt; ...</pre>
-      </li>
-    </ul>
-  </li>
-  <li>针对使用权限的服务对应用进行分析</li>
-</ul>
-
-<h3 id="permission-test-strategy">测试策略</h3>
-
-<p>
-  权限更改会影响应用的结构和设计,以及您为用户提供的用户体验和流程。
-您应评估应用的当前权限使用情况并开始计划要提供的新流程。
-平台的正式版本提供兼容性行为,但您应计划更新应用,而不是依赖于这些行为。
-
-
-</p>
-
-<p>
-  确定应用实际需要和使用的权限,然后找出各种使用受权限保护的服务的代码路径。
-您可通过结合使用新平台测试和代码分析完成此操作。
-在测试中,您应通过将应用的 {@code targetSdkVersion} 更改为预览版,重点关注选择运行时权限。
-如需了解详细信息,请参阅<a href="{@docRoot}preview/setup-sdk.html#">设置 Android N SDK</a>。
-
-
-</p>
-
-<p>
-  使用已撤销和已添加权限的各种组合进行测试,突出显示依赖于权限的用户流程。
-如果依赖关系不明显或不符合逻辑,则您应考虑重构或划分该流程,以消除依赖关系或阐明需要权限的原因。
-
-
-</p>
-
-<p>
-  如需了解有关运行时权限行为、测试和最佳做法的详细信息,请参阅<a href="{@docRoot}preview/features/runtime-permissions.html">权限</a>开发者预览版页面。
-
-
-</p>
-
-
-<h2 id="doze-standby">测试低电耗模式和应用待机模式</h2>
-
-<p>
-  当设备处于空闲状态或应用未聚焦时,低电耗模式和应用待机模式的节能功能将限制应用可执行的后台处理工作量。
-系统可对应用实施的限制包括:限制或禁止访问网络、暂停后台任务、暂停通知、忽略唤醒请求和闹铃。
-
-要确保应用在完成这些节能优化后正常运行,您应通过模拟这些低功耗状态对应用进行测试。
-
-
-</p>
-
-<h4 id="doze">在低电耗模式下测试您的应用</h4>
-
-<p>要在低电耗模式下测试您的应用,请执行以下操作:</p>
-
-<ol>
-<li>使用 Android N 系统映像配置硬件设备或虚拟设备</li>
-<li>将设备连接到开发计算机并安装应用</li>
-<li>运行应用并使其保持活动状态</li>
-<li>通过运行以下命令,模拟进入低电耗模式的设备:
-
-<pre>
-$ adb shell dumpsys battery unplug
-$ adb shell dumpsys deviceidle step
-$ adb shell dumpsys deviceidle -h
-</pre>
-
-  </li>
-  <li>观察重新激活设备时的应用行为。确保应用在设备退出低电耗模式时正常恢复
-</li>
-</ol>
-
-
-<h4 id="standby">在应用待机模式下测试您的应用</h4>
-
-<p>要在应用待机模式下测试您的应用,请执行以下操作:</p>
-
-<ol>
-  <li>使用 Android N 系统映像配置硬件设备或虚拟设备</li>
-  <li>将设备连接到开发计算机并安装应用</li>
-  <li>运行应用并使其保持活动状态</li>
-  <li>通过运行以下命令,模拟进入待机模式的应用:
-
-<pre>
-$ adb shell am broadcast -a android.os.action.DISCHARGING
-$ adb shell am set-idle &lt;packageName&gt; true
-</pre>
-
-  </li>
-  <li>使用以下命令模拟如何唤醒应用:
-    <pre>$ adb shell am set-idle &lt;packageName&gt; false</pre>
-  </li>
-  <li>观察唤醒后的应用行为。确保应用从待机模式中正常恢复。
-特别地,您应检查应用的通知和后台作业是否按预期继续运行
-</li>
-</ol>
-
-<h2 id="ids">自动备份应用和设备特定的标识符</h2>
-
-<p>如果应用坚持在内部存储中使用任何设备特定的标识符,如 Google 云消息传递注册 ID,请确保遵循最佳做法将存储位置从自动备份中排除,如<a href="{@docRoot}preview/backup/index.html">自动备份应用</a>中所述。
-
-
-
- </p>
diff --git a/docs/html-intl/intl/zh-cn/about/versions/nougat/index.jd b/docs/html-intl/intl/zh-cn/about/versions/nougat/index.jd
index 74cd039..c1eb423 100644
--- a/docs/html-intl/intl/zh-cn/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/zh-cn/about/versions/nougat/index.jd
@@ -1,6 +1,6 @@
-page.title=Android N Developer Preview
-page.tags="preview","developer"
-meta.tags="preview", "android"
+page.title=Android 7.0 Nougat
+page.tags="androidn","versions"
+meta.tags="android n", "nougat", "android 7.0"
 fullpage=true
 forcelocalnav=true
 header.hide=1
@@ -17,62 +17,57 @@
   })
 </script>
 
-<section class="dac-expand dac-hero dac-light" style="background-color:#B2DFDB">
+<section class="dac-expand dac-hero dac-light">
   <div class="wrap" style="max-width:1100px;margin-top:0">
+  <a href="{@docRoot}about/versions/nougat/android-7.0.html">
     <div class="cols dac-hero-content" style="padding-bottom:1em;">
 
-      <div class="col-7of16 col-push-9of16" style="padding-left:2em">
-        <h1 class="dac-hero-title">Android N Developer Preview</h1>
+      <div class="col-7of16 col-push-8of16" style="padding-left:2em">
+        <h1 class="dac-hero-title">Android 7.0 Nougat</h1>
         <p class="dac-hero-description">
-          为 Android N 进行准备!
+          为 Android Nougat 进行准备!
           在 Nexus 和其他设备上<strong>测试您的应用</strong>。支持新系统行为以<strong>节省电量和内存</strong>。
 
           使用<strong>多窗口 UI</strong> 扩展您的应用,以便能够<strong>直接答复通知</strong>及执行其他操作。
 
         </p>
 
-        <a class="dac-hero-cta" href="{@docRoot}preview/overview.html">
+        <a class="dac-hero-cta" href="{@docRoot}about/versions/nougat/android-7.0.html">
           <span class="dac-sprite dac-auto-chevron"></span>
           入门指南
-        </a><!--<br>
-        <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Update to Android N (final SDK)
-        </a><br>-->
+        </a>
       </div>
-      <div class="col-9of16 col-pull-7of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
-        <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png" srcset="{@docRoot}images/home/n-preview-hero.png 1x,
-             {@docRoot}images/home/n-preview-hero_2x.png 2x">
+      <div class="col-7of16 col-pull-6of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
+        <a  href="{@docRoot}about/versions/nougat/android-7.0.html">
+        <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png"
+             srcset="{@docRoot}images/home/n-preview-hero.png 1x,
+             {@docRoot}images/home/n-preview-hero_2x.png 2x" />
+           </a>
       </div>
-    </div>
+    </div></a>
     <div class="dac-section dac-small">
       <div class="resource-widget resource-flow-layout col-16"
-           data-query="collection:preview/landing/resources"
+           data-query="collection:nougat/landing/resources"
            data-cardSizes="6x2"
-           data-maxResults="6"></div>
-    </div>
+           data-maxResults="3"></div>
+         </div>
   </div>
 </section>
 
+
 <div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
+    <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
       <i class="dac-sprite dac-arrow-down-gray"></i>
     </a>
     <ul class="dac-actions">
       <li class="dac-action">
-        <a class="dac-action-link" href="https://developer.android.com/preview/bug">
+        <a class="dac-action-link" href="https://source.android.com/source/report-bugs.html">
           <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
           报告问题
         </a>
       </li>
       <li class="dac-action">
-        <a class="dac-action-link" href="{@docRoot}preview/support.html">
-          <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
-          查阅版本说明
-        </a>
-      </li>
-      <li class="dac-action">
         <a class="dac-action-link" href="{@docRoot}preview/dev-community">
           <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
           加入开发者社区
@@ -113,19 +108,33 @@
     data-initial-results="3"></div>
 </div></section>
 
-<section class="dac-section dac-gray"><div class="wrap">
-  <h1 class="dac-section-title">资源</h1>
+<section class="dac-section dac-gray" id="videos"><div class="wrap">
+  <h1 class="dac-section-title">Videos</h1>
   <div class="dac-section-subtitle">
-    这些必备信息可帮助您的应用为Android N做好准备。
+    New Android capabilities and the right way to use them in your apps.
   </div>
 
   <div class="resource-widget resource-flow-layout col-16"
-       data-query="collection:preview/landing/more"
+    data-query="collection:nougat/landing/videos/first,type:youtube+tag:androidn"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x6"
+    data-items-per-page="6"
+    data-maxResults="15"
+    data-initial-results="3">
+  </div>
+</div></section>
+
+<section class="dac-section dac-light" id="resources"><div class="wrap">
+  <h1 class="dac-section-title">资源</h1>
+  <div class="dac-section-subtitle">
+    这些必备信息可帮助您的应用为Android Nougat做好准备。
+  </div>
+
+  <div class="resource-widget resource-flow-layout col-16"
+       data-query="collection:nougat/landing/more"
        data-cardSizes="6x6"
        data-items-per-page="6"
        data-maxResults="15"
        data-initial-results="6"></div>
-
   </div>
-</section>
-
+</section>
\ No newline at end of file
diff --git a/docs/html-intl/intl/zh-cn/index.jd b/docs/html-intl/intl/zh-cn/index.jd
index ca3a84b..8872d16 100644
--- a/docs/html-intl/intl/zh-cn/index.jd
+++ b/docs/html-intl/intl/zh-cn/index.jd
@@ -15,33 +15,30 @@
   })
 </script>
 
-<section class="dac-expand dac-hero dac-invert" style="background-color:#455A64">
-  <div class="wrap" style="max-width:1100px;margin-top:0">
-    <div class="col-7of16 col-push-9of16" style="padding-left:2em;">
-      <a href="{@docRoot}preview/index.html">
-        <h1 class="dac-hero-title">Android N Developer Preview</h1>
-        <p class="dac-hero-description">
-          Get ready for the next version of Android!
-          <strong>Test your apps</strong> on Nexus and other devices. Support new system
-          behaviors to <strong>save power and memory</strong>.
+<section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
+  <div class="wrap" style="max-width:1000px;margin-top:0">
+    <div class="col-7of16 col-push-8of16">
+      <a href="{@docRoot}about/versions/nougat/index.html">
+        <h1 class="dac-hero-title" style="color:#004d40">Android 7.0 Nougat!</h1>
+        <p class="dac-hero-description" style="color:#004d40">
+          <strong>Android 7.0 Nougat is here!</strong>
+          Get your apps ready for the latest version of Android, with new system
+          behaviors to <strong>save battery and memory</strong>.
           Extend your apps with <strong>multi-window UI</strong>,
           <strong>direct reply notifications</strong> and more.
         </p>
-        <a class="dac-hero-cta" href="/preview/index.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
+        <a class="dac-hero-cta" href="{@docRoot}about/versions/nougat/index.html" style="color:#004d40">
+          <span class="dac-sprite dac-auto-chevron" style="background-color:#b2dfdb"></span>
           Learn more
-        </a><!--<br>
-        <a class="dac-hero-cta" href="/preview/support.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Update to Developer Preview (final SDK)
-        </a><br>-->
+        </a>
+        </a>
       </a>
     </div>
-    <div class="col-9of16 col-pull-7of16 dac-hero-figure" style="margin-top:0em;padding-right:1.5em;">
-      <a href="{@docRoot}preview/index.html">
-        <img style="" class="dac-hero-image" src="/images/home/n-preview-hero.png"
-             srcset="/images/home/n-preview-hero.png 1x,
-             /images/home/n-preview-hero_2x.png 2x">
+    <div class="col-6of16 col-pull-6of16 dac-hero-figure" style="padding-left:1em;padding-top:1em;">
+      <a href="{@docRoot}about/versions/nougat/index.html">
+        <img class="dac-hero-image" src="{@docRoot}images/home/nougat_bg.jpg"
+             srcset="{@docRoot}images/home/nougat_bg.jpg 1x,
+             {@docRoot}images/home/nougat_bg_2x.jpg 2x">
         </a>
     </div>
   </div>
diff --git a/docs/html-intl/intl/zh-tw/about/versions/nougat/index.jd b/docs/html-intl/intl/zh-tw/about/versions/nougat/index.jd
index e899bc0..d4db467 100644
--- a/docs/html-intl/intl/zh-tw/about/versions/nougat/index.jd
+++ b/docs/html-intl/intl/zh-tw/about/versions/nougat/index.jd
@@ -1,6 +1,6 @@
-page.title=Android N Developer Preview
-page.tags="preview","developer"
-meta.tags="preview", "android"
+page.title=Android 7.0 Nougat
+page.tags="androidn","versions"
+meta.tags="android n", "nougat", "android 7.0"
 fullpage=true
 forcelocalnav=true
 header.hide=1
@@ -17,66 +17,61 @@
   })
 </script>
 
-<section class="dac-expand dac-hero dac-light" style="background-color:#B2DFDB">
+<section class="dac-expand dac-hero dac-light">
   <div class="wrap" style="max-width:1100px;margin-top:0">
+  <a href="{@docRoot}about/versions/nougat/android-7.0.html">
     <div class="cols dac-hero-content" style="padding-bottom:1em;">
 
-      <div class="col-7of16 col-push-9of16" style="padding-left:2em">
-        <h1 class="dac-hero-title">Android N Developer Preview</h1>
+      <div class="col-7of16 col-push-8of16" style="padding-left:2em">
+        <h1 class="dac-hero-title">Android 7.0 Nougat</h1>
         <p class="dac-hero-description">
-          為 Android N 做好準備!
+        為 Android Nougat 做好準備!
           在 Nexus 與其他裝置上<strong>測試您的應用程式</strong>。支援新系統行為以<strong>節省電力與記憶體</strong>。使用<strong>多視窗 UI</strong>、<strong>直接回覆通知</strong>等延伸您的應用程式。
 
 
 
         </p>
 
-        <a class="dac-hero-cta" href="{@docRoot}preview/overview.html">
+        <a class="dac-hero-cta" href="{@docRoot}about/versions/nougat/android-7.0.html">
           <span class="dac-sprite dac-auto-chevron"></span>
-          開始使用</a>
-<!--<br>
-        <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Update to Android N (final SDK)
-        </a><br>-->
+          開始使用
+        </a>
       </div>
-      <div class="col-9of16 col-pull-7of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
-        <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png" srcset="{@docRoot}images/home/n-preview-hero.png 1x,
-             {@docRoot}images/home/n-preview-hero_2x.png 2x">
+      <div class="col-7of16 col-pull-6of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
+        <a  href="{@docRoot}about/versions/nougat/android-7.0.html">
+        <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png"
+             srcset="{@docRoot}images/home/n-preview-hero.png 1x,
+             {@docRoot}images/home/n-preview-hero_2x.png 2x" />
+           </a>
       </div>
-    </div>
+    </div></a>
     <div class="dac-section dac-small">
       <div class="resource-widget resource-flow-layout col-16"
-           data-query="collection:preview/landing/resources"
+           data-query="collection:nougat/landing/resources"
            data-cardSizes="6x2"
-           data-maxResults="6"></div>
-    </div>
+           data-maxResults="3"></div>
+         </div>
   </div>
 </section>
 
+
 <div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
-    <a class="dac-fab dac-scroll-button" data-scroll-button href="#build-apps">
+    <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
       <i class="dac-sprite dac-arrow-down-gray"></i>
     </a>
     <ul class="dac-actions">
       <li class="dac-action">
-        <a class="dac-action-link" href="https://developer.android.com/preview/bug">
+        <a class="dac-action-link" href="https://source.android.com/source/report-bugs.html">
           <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
           回報問題
-</a>
-      </li>
-      <li class="dac-action">
-        <a class="dac-action-link" href="{@docRoot}preview/support.html">
-          <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
-          查看版本資訊</a>
-
+        </a>
       </li>
       <li class="dac-action">
         <a class="dac-action-link" href="{@docRoot}preview/dev-community">
           <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
-          加入開發人員社群</a>
-
+          加入開發人員社群
+        </a>
       </li>
     </ul>
   </div><!-- end .wrap -->
@@ -102,19 +97,44 @@
   </div><!-- end .wrap -->
 </div>
 
-<section class="dac-section dac-light"><div class="wrap">
-  <h1 class="dac-section-title">資源</h1>
+<section class="dac-section dac-light dac-small" id="latest"><div class="wrap">
+  <h2 class="norule">Latest</h2>
+  <div class="resource-widget resource-flow-layout col-16"
+    data-query="type:blog+tag:androidn+tag:featured, type:youtube+tag:androidn+tag:featured"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x6"
+    data-items-per-page="6"
+    data-maxResults="15"
+    data-initial-results="3"></div>
+</div></section>
+
+<section class="dac-section dac-gray" id="videos"><div class="wrap">
+  <h1 class="dac-section-title">Videos</h1>
   <div class="dac-section-subtitle">
-    以下重要資訊可幫助您的應用程式準備好使用 Android N。
+    New Android capabilities and the right way to use them in your apps.
   </div>
 
   <div class="resource-widget resource-flow-layout col-16"
-       data-query="collection:preview/landing/more"
+    data-query="collection:nougat/landing/videos/first,type:youtube+tag:androidn"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x6"
+    data-items-per-page="6"
+    data-maxResults="15"
+    data-initial-results="3">
+  </div>
+</div></section>
+
+<section class="dac-section dac-light" id="resources"><div class="wrap">
+  <h1 class="dac-section-title">資源</h1>
+  <div class="dac-section-subtitle">
+    以下重要資訊可幫助您的應用程式準備好使用 Android Nougat。
+  </div>
+
+  <div class="resource-widget resource-flow-layout col-16"
+       data-query="collection:nougat/landing/more"
        data-cardSizes="6x6"
        data-items-per-page="6"
        data-maxResults="15"
        data-initial-results="6"></div>
-
   </div>
-</section>
-
+</section>
\ No newline at end of file
diff --git a/docs/html-intl/intl/zh-tw/index.jd b/docs/html-intl/intl/zh-tw/index.jd
index a5772ef..540801a 100644
--- a/docs/html-intl/intl/zh-tw/index.jd
+++ b/docs/html-intl/intl/zh-tw/index.jd
@@ -15,33 +15,30 @@
   })
 </script>
 
-<section class="dac-expand dac-hero dac-invert" style="background-color:#455A64">
-  <div class="wrap" style="max-width:1100px;margin-top:0">
-    <div class="col-7of16 col-push-9of16" style="padding-left:2em;">
-      <a href="{@docRoot}preview/index.html">
-        <h1 class="dac-hero-title">Android N Developer Preview</h1>
-        <p class="dac-hero-description">
-          Get ready for the next version of Android!
-          <strong>Test your apps</strong> on Nexus and other devices. Support new system
-          behaviors to <strong>save power and memory</strong>.
+<section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
+  <div class="wrap" style="max-width:1000px;margin-top:0">
+    <div class="col-7of16 col-push-8of16">
+      <a href="{@docRoot}about/versions/nougat/index.html">
+        <h1 class="dac-hero-title" style="color:#004d40">Android 7.0 Nougat!</h1>
+        <p class="dac-hero-description" style="color:#004d40">
+          <strong>Android 7.0 Nougat is here!</strong>
+          Get your apps ready for the latest version of Android, with new system
+          behaviors to <strong>save battery and memory</strong>.
           Extend your apps with <strong>multi-window UI</strong>,
           <strong>direct reply notifications</strong> and more.
         </p>
-        <a class="dac-hero-cta" href="/preview/index.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
+        <a class="dac-hero-cta" href="{@docRoot}about/versions/nougat/index.html" style="color:#004d40">
+          <span class="dac-sprite dac-auto-chevron" style="background-color:#b2dfdb"></span>
           Learn more
-        </a><!--<br>
-        <a class="dac-hero-cta" href="/preview/support.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Update to Developer Preview (final SDK)
-        </a><br>-->
+        </a>
+        </a>
       </a>
     </div>
-    <div class="col-9of16 col-pull-7of16 dac-hero-figure" style="margin-top:0em;padding-right:1.5em;">
-      <a href="{@docRoot}preview/index.html">
-        <img style="" class="dac-hero-image" src="/images/home/n-preview-hero.png"
-             srcset="/images/home/n-preview-hero.png 1x,
-             /images/home/n-preview-hero_2x.png 2x">
+    <div class="col-6of16 col-pull-6of16 dac-hero-figure" style="padding-left:1em;padding-top:1em;">
+      <a href="{@docRoot}about/versions/nougat/index.html">
+        <img class="dac-hero-image" src="{@docRoot}images/home/nougat_bg.jpg"
+             srcset="{@docRoot}images/home/nougat_bg.jpg 1x,
+             {@docRoot}images/home/nougat_bg_2x.jpg 2x">
         </a>
     </div>
   </div>
diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml
index fd54b7d..aefe1c1 100644
--- a/docs/html/_redirects.yaml
+++ b/docs/html/_redirects.yaml
@@ -25,6 +25,8 @@
   to: /topic/libraries/support-library/index.html
 - from: /billions
   to: /topic/billions/index.html
+- from: /performance
+  to: /topic/performance/index.html
 - from: /tools/extras/support-library.html
   to: /topic/libraries/support-library/index.html
 - from: /training/basics/fragments/support-lib.html
@@ -153,6 +155,8 @@
   to: /google/play/billing/index.html
 - from: /guide/developing/tools/proguard.html
   to: /studio/build/shrink-code.html
+- from: /guide/developing/tools/aidl.html
+  to: /guide/components/aidl.html
 - from: /guide/developing/tools/...
   to: /studio/command-line/
 - from: /guide/developing/...
@@ -798,13 +802,13 @@
 - from: /preview/dev-community
   to: https://plus.google.com/communities/103655397235276743411
 - from: /preview/bug
-  to: https://code.google.com/p/android/issues/entry?template=Developer%20preview%20report
+  to: https://source.android.com/source/report-bugs.html
 - from: /preview/bug/
-  to: https://code.google.com/p/android/issues/entry?template=Developer%20preview%20report
+  to: https://source.android.com/source/report-bugs.html
 - from: /preview/bugreport
-  to: https://code.google.com/p/android/issues/entry?template=Developer%20preview%20report
+  to: https://source.android.com/source/report-bugs.html
 - from: /preview/bugreport/
-  to: https://code.google.com/p/android/issues/entry?template=Developer%20preview%20report
+  to: https://source.android.com/source/report-bugs.html
 - from: /preview/bugs
   to: https://code.google.com/p/android/issues/list?can=2&q=label%3ADevPreview-N
 - from: /preview/bugs/
@@ -1248,7 +1252,7 @@
 - from: /preview/samples.html
   to: /about/versions/nougat/android-7.0-samples.html
 - from: /preview/guide.html
-  to: /about/versions/nougat/android-7.0-testing.html
+  to: /about/versions/nougat/index.html
 - from: /preview/api-overview.html
   to: /about/versions/nougat/android-7.0.html
 - from: /preview/index.html
diff --git a/docs/html/about/_book.yaml b/docs/html/about/_book.yaml
index 958435d..642113b 100644
--- a/docs/html/about/_book.yaml
+++ b/docs/html/about/_book.yaml
@@ -2,14 +2,67 @@
 - title: Nougat
   path: /about/versions/nougat/index.html
   section:
-  - title: Android 7.0 APIs
+  - title: Android 7.0 for Developers
     path: /about/versions/nougat/android-7.0.html
-  - title: Android 7.0 Changes
+    path_attributes:
+    - name: es-lang
+      value: Información general de la API
+    - name: in-lang
+      value: Android N untuk Pengembang
+    - name: ja-lang
+      value: API の概要
+    - name: ko-lang
+      value: API 개요
+    - name: pt-br-lang
+      value: Visão geral da API
+    - name: ru-lang
+      value: Обзор API-интерфейсов
+    - name: vi-lang
+      value: Android N cho Nhà phát triển
+    - name: zh-cn-lang
+      value: API 概览
+    - name: zh-tw-lang
+      value: API 總覽
+  - title: Android 7.0 Behavior Changes
     path: /about/versions/nougat/android-7.0-changes.html
+    path_attributes:
+    - name: es-lang
+      value: Cambios en los comportamientos
+    - name: in-lang
+      value: Perubahan Perilaku
+    - name: ja-lang
+      value: 動作の変更点
+    - name: ko-lang
+      value: 동작 변경
+    - name: pt-br-lang
+      value: Mudanças de comportamento
+    - name: ru-lang
+      value: Изменения в работе
+    - name: vi-lang
+      value: Các thay đổi Hành vi
+    - name: zh-cn-lang
+      value: 行为变更
+    - name: zh-tw-lang
+      value: 行為變更
   - title: Android 7.0 Samples
     path: /about/versions/nougat/android-7.0-samples.html
-  - title: Android 7.0 Testing
-    path: /about/versions/nougat/android-7.0-testing.html
+    path_attributes:
+    - name: es-lang
+      value: Ejemplos
+    - name: in-lang
+      value: Contoh
+    - name: ja-lang
+      value: サンプル
+    - name: ko-lang
+      value: 샘플
+    - name: pt-br-lang
+      value: Exemplos
+    - name: ru-lang
+      value: Примеры
+    - name: zh-cn-lang
+      value: 示例
+    - name: zh-tw-lang
+      value: 範例
 
 - title: Marshmallow
   path: /about/versions/marshmallow/index.html
diff --git a/docs/html/about/about_toc.cs b/docs/html/about/about_toc.cs
index a456012..de39620 100644
--- a/docs/html/about/about_toc.cs
+++ b/docs/html/about/about_toc.cs
@@ -1,5 +1,17 @@
 <ul id="nav">
   <li class="nav-section">
+    <div class="nav-section-header"><a href="<?cs var:toroot ?>about/versions/nougat/index.html">
+      <span class="en">Nougat</span></a></div>
+      <ul>
+        <li><a href="<?cs var:toroot ?>about/versions/nougat/android-7.0.html">
+        Android 7.0 for Developers</a></li>
+        <li><a href="<?cs var:toroot ?>about/versions/nougat/android-7.0-changes.html">
+        Android 7.0 Changes</a></li>
+        <li><a href="<?cs var:toroot ?>about/versions/nougat/android-7.0-samples.html">
+        Android 7.0 Samples</a></li>
+      </ul>
+  </li>
+  <li class="nav-section">
     <div class="nav-section-header"><a href="<?cs var:toroot ?>about/versions/marshmallow/index.html">
       <span class="en">Marshmallow</span></a></div>
       <ul>
diff --git a/docs/html/about/versions/marshmallow/index.jd b/docs/html/about/versions/marshmallow/index.jd
index 35edd72..93d0fec 100644
--- a/docs/html/about/versions/marshmallow/index.jd
+++ b/docs/html/about/versions/marshmallow/index.jd
@@ -2,7 +2,6 @@
 page.tags="marshmallow"
 meta.tags="marshamallow","android60"
 fullpage=true
-nonavpage=true
 forcelocalnav=true
 header.hide=1
 footer.hide=1
diff --git a/docs/html/about/versions/nougat/android-7.0-changes.jd b/docs/html/about/versions/nougat/android-7.0-changes.jd
index 4f9054c..84a56d0 100644
--- a/docs/html/about/versions/nougat/android-7.0-changes.jd
+++ b/docs/html/about/versions/nougat/android-7.0-changes.jd
@@ -1,7 +1,7 @@
-page.title=Android 7.0 Changes
+page.title=Android 7.0 Behavior Changes
 page.keywords=preview,sdk,compatibility
-meta.tags="Android 7.0", "Nougat", "android n", "compatibility"
-page.tags="Android 7.0", "Nougat", "android n", "developer preview"
+meta.tags="Nougat", "android n", "compatibility"
+page.tags="Android 7.0", "Nougat", "android n"
 page.image=images/cards/card-n-changes_2x.png
 @jd:body
 
@@ -35,16 +35,14 @@
 
 <h2>API Differences</h2>
 <ol>
-  <li><a href="{@docRoot}sdk/api_diff/n-preview-4-incr/changes.html">
-    Preview 3 to API 24</a></li>
   <li><a href="{@docRoot}sdk/api_diff/24/changes.html">
     API 23 to API 24</a></li>
 </ol>
 
 <h2>See Also</h2>
 <ol>
-  <li><a href="{@docRoot}preview/api-overview.html">
-    Android 7.0 APIs</a></li>
+  <li><a href="{@docRoot}about/versions/nougat/android-7.0.html">
+    Android 7.0 for Developers</a></li>
 </ol>
 
 </div>
diff --git a/docs/html/about/versions/nougat/android-7.0-samples.jd b/docs/html/about/versions/nougat/android-7.0-samples.jd
index 98f7090..e283a7a 100644
--- a/docs/html/about/versions/nougat/android-7.0-samples.jd
+++ b/docs/html/about/versions/nougat/android-7.0-samples.jd
@@ -1,10 +1,11 @@
 page.title=Android 7.0 Samples
 page.tags="Android 7.0", "nougat", "samples", "android"
+meta.tags="android n", "Nougat", "android 7.0"
 page.image=images/cards/card-n-samples_2x.png
 @jd:body
 
 <p>
-  The following code samples are provided for Android 7.0. To
+  Use the code samples below to learn about Android 7.0 capabilities and APIs. To
   download the samples in Android Studio, select the <b>File &gt; Import
   Samples</b> menu option.
 </p>
diff --git a/docs/html/about/versions/nougat/android-7.0-testing.jd b/docs/html/about/versions/nougat/android-7.0-testing.jd
deleted file mode 100644
index f30382e..0000000
--- a/docs/html/about/versions/nougat/android-7.0-testing.jd
+++ /dev/null
@@ -1,190 +0,0 @@
-page.title=Android 7.0 Testing Guide
-page.image=images/cards/card-n-guide_2x.png
-meta.tags="preview", "testing"
-page.tags="preview", "developer preview"
-
-@jd:body
-
-<div id="qv-wrapper">
-  <div id="qv">
-    <h2>In this document</h2>
-      <ol>
-        <li><a href="#runtime-permissions">Testing Permissions</a></li>
-        <li><a href="#doze-standby">Testing Doze and App Standby</a></li>
-        <li><a href="#ids">Auto Backup and Device Identifiers</a></li>
-      </ol>
-  </div>
-</div>
-
-<p>
-  Android 7.0 gives you an opportunity to ensure your apps work with the next
-  version of the platform. This preview includes a number of APIs and behavior changes that can
-  impact your app, as described in the <a href="{@docRoot}preview/api-overview.html">API
-  Overview</a> and <a href="{@docRoot}preview/behavior-changes.html">Behavior Changes</a>. In testing
-  your app with the preview, there are some specific system changes that you should focus on to
-  ensure that users have a good experience.
-</p>
-
-<p>
-  This guide describes the what and how to test preview features with your app. You should
-  prioritize testing of these specific preview features, due to their high potential impact on your
-  app's behavior:
-</p>
-
-<ul>
-  <li><a href="#runtime-permissions">Permissions</a>
-  </li>
-  <li><a href="#doze-standby">Doze and App Standby</a>
-  </li>
-  <li><a href="#ids">Auto Backup and Device Identifiers</a></li>
-</ul>
-
-<p>
-  For more information about how to set up devices or virtual devices with a preview system image
-  for testing, see <a href="{@docRoot}preview/setup-sdk.html">Set up
-the Android N SDK</a>.
-</p>
-
-
-<h2 id="runtime-permissions">Testing Permissions</h2>
-
-<p>
-  The new <a href="{@docRoot}preview/features/runtime-permissions.html">Permissions</a> model
-  changes the way that permissions are allocated to your app by the user. Instead of granting all
-  permissions during the install procedure, your app must ask the user for individual permissions
-  at runtime. For users this behavior provides more granular control over each app’s activities, as
-  well as better context for understanding why the app is requesting a specific permission. Users
-  can grant or revoke the permissions granted to an app individually at any time. This feature of
-  the preview is most likely to have an impact on your app's behavior and may prevent some of your
-  app features from working, or they may work in a degraded state.
-</p>
-
-<p class="caution">
-  This change affects all apps running on the new platform, even those not targeting the new
-  platform version. The platform provides a limited compatibility behavior for legacy apps, but you
-  should begin planning your app’s migration to the new permissions model now, with a goal of
-  publishing an updated version of your app at the official platform launch.
-</p>
-
-
-<h3 id="permission-test-tips">Test tips</h3>
-
-<p>
-  Use the following test tips to help you plan and execute testing of your app with the new
-  permissions behavior.
-</p>
-
-<ul>
-  <li>Identify your app’s current permissions and the related code paths.</li>
-  <li>Test user flows across permission-protected services and data.</li>
-  <li>Test with various combinations of granted/revoked permission.</li>
-  <li>Use the {@code adb} tool to manage permssions from the command line:
-    <ul>
-      <li>List permissions and status by group:
-        <pre>adb shell pm list permissions -d -g</pre>
-      </li>
-      <li>Grant or revoke one or more permissions using the following syntax:<br>
-        <pre>adb shell pm [grant|revoke] &lt;permission.name&gt; ...</pre>
-      </li>
-    </ul>
-  </li>
-  <li>Analyze your app for services that use permissions.</li>
-</ul>
-
-<h3 id="permission-test-strategy">Test strategy</h3>
-
-<p>
-  The permissions change affects the structure and design of your app, as well as
-  the user experience and flows you provide to users. You should assess your app’s current
-  permissions use and start planning for the new flows you want to offer. The official release of
-  the platform provides compatibility behavior, but you should plan on updating your app and not
-  rely on these behaviors.
-</p>
-
-<p>
-  Identify the permissions that your app actually needs and uses, and then find the various code
-  paths that use the permission-protected services. You can do this through a combination of
-  testing on the new platform and code analysis. In testing, you should focus on opting in to
-  runtime permissions by changing the app’s {@code targetSdkVersion} to the preview version. For
-  more information, see <a href="{@docRoot}preview/setup-sdk.html#">Set up
-the Android N SDK</a>.
-</p>
-
-<p>
-  Test with various combinations of permissions revoked and added, to highlight the user flows that
-  depend on permissions. Where a dependency is not obvious or logical you should consider
-  refactoring or compartmentalizing that flow to eliminate the dependency or make it clear why the
-  permission is needed.
-</p>
-
-<p>
-  For more information on the behavior of runtime permissions, testing, and best practices, see the
-  <a href="{@docRoot}preview/features/runtime-permissions.html">Permissions</a> developer
-  preview page.
-</p>
-
-
-<h2 id="doze-standby">Testing Doze and App Standby</h2>
-
-<p>
-  The power saving features of Doze and App Standby limit the amount of background processing that
-  your app can perform when a device is in an idle state or while your app is not in focus. The
-  restrictions the system may impose on apps include limited or no network access,
-  suspended background tasks, suspended Notifications, ignored wake requests, and alarms. To ensure
-  that your app behaves properly with these power saving optimizations, you should test your app by
-  simulating these low power states.
-</p>
-
-<h4 id="doze">Testing your app with Doze</h4>
-
-<p>To test Doze with your app:</p>
-
-<ol>
-<li>Configure a hardware device or virtual device with an Android N system image.</li>
-<li>Connect the device to your development machine and install your app.</li>
-<li>Run your app and leave it active.</li>
-<li>Simulate the device going into Doze mode by running the following commands:
-
-<pre>
-$ adb shell dumpsys battery unplug
-$ adb shell dumpsys deviceidle step
-$ adb shell dumpsys deviceidle -h
-</pre>
-
-  </li>
-  <li>Observe the behavior of your app when the device is re-activated. Make sure it
-    recovers gracefully when the device exits Doze.</li>
-</ol>
-
-
-<h4 id="standby">Testing apps with App Standby</h4>
-
-<p>To test the App Standby mode with your app:</p>
-
-<ol>
-  <li>Configure a hardware device or virtual device with an Android N system image.</li>
-  <li>Connect the device to your development machine and install your app.</li>
-  <li>Run your app and leave it active.</li>
-  <li>Simulate the app going into standby mode by running the following commands:
-
-<pre>
-$ adb shell am broadcast -a android.os.action.DISCHARGING
-$ adb shell am set-idle &lt;packageName&gt; true
-</pre>
-
-  </li>
-  <li>Simulate waking your app using the following command:
-    <pre>$ adb shell am set-idle &lt;packageName&gt; false</pre>
-  </li>
-  <li>Observe the behavior of your app when it is woken. Make sure it recovers gracefully
-    from standby mode. In particular, you should check if your app's Notifications and background
-    jobs continue to function as expected.</li>
-</ol>
-
-<h2 id="ids">Auto Backup for Apps and Device-Specific Identifiers</h2>
-
-<p>If your app is persisting any device-specific identifiers, such as Google
-Cloud Messaging registration ID, in internal storage,
-make sure to follow best practices to exclude the storage
-location from auto-backup, as described in <a href="{@docRoot}preview/backup/index.html">Auto
-Backup for Apps</a>. </p>
diff --git a/docs/html/about/versions/nougat/android-7.0.jd b/docs/html/about/versions/nougat/android-7.0.jd
index 87c8d93..1ca540c 100644
--- a/docs/html/about/versions/nougat/android-7.0.jd
+++ b/docs/html/about/versions/nougat/android-7.0.jd
@@ -1,6 +1,6 @@
-page.title=Android 7.0 APIs
-meta.tags="Android 7.0", "android n", "Nougat"
-page.tags="Android 7.0", "Nougat", "android n", "developer preview"
+page.title=Android 7.0 for Developers
+meta.tags="Nougat", "android n"
+page.tags="Android 7.0", "Nougat", "android n"
 page.image=images/cards/card-n-apis_2x.png
 @jd:body
 
@@ -52,16 +52,20 @@
 
 
 <p>
-Android 7.0
-(<a href="{@docRoot}reference/android/os/Build.VERSION_CODES.html#N">N</a>) 
-offers new features for users and app developers. This document provides
-an introduction to the most notable APIs. Make sure, also,
-to check out the <href="{@docRoot}about/versions/nougat/behavior.changes.html">
-Behavior Changes</a> to learn about areas where platform changes
-may affect your apps. In addition, the various developer guides
-can provide more information about key features.
+Android 7.0 Nougat introduces a variety of
+new features and capabilities for users and developers.
+This document highlights what's new for developers. </p>
+
+<p>Make sure check out the
+<href="{@docRoot}about/versions/nougat/android-7.0-changes.html">
+Android 7.0 behavior changes</a> to learn about areas where platform changes
+may affect your apps.
 </p>
 
+<p>To learn more about
+the consumer features of Android 7.0, visit <a
+href="http://www.android.com">www.android.com</a>.</p>
+
 <h2 id="multi-window_support">Multi-window Support</h2>
 
 
diff --git a/docs/html/about/versions/nougat/index.jd b/docs/html/about/versions/nougat/index.jd
index aaf7e92..30a3576 100644
--- a/docs/html/about/versions/nougat/index.jd
+++ b/docs/html/about/versions/nougat/index.jd
@@ -1,6 +1,6 @@
-page.title=Android N Developer Preview
-page.tags="preview","developer"
-meta.tags="preview", "android"
+page.title=Android 7.0 Nougat
+page.tags="androidn","versions"
+meta.tags="android n", "nougat", "android 7.0"
 fullpage=true
 forcelocalnav=true
 header.hide=1
@@ -17,44 +17,44 @@
   })
 </script>
 
-<section class="dac-expand dac-hero dac-light" style="background-color:#B2DFDB">
+<section class="dac-expand dac-hero dac-light">
   <div class="wrap" style="max-width:1100px;margin-top:0">
+  <a href="{@docRoot}about/versions/nougat/android-7.0.html">
     <div class="cols dac-hero-content" style="padding-bottom:1em;">
 
-      <div class="col-7of16 col-push-9of16" style="padding-left:2em">
+      <div class="col-7of16 col-push-8of16" style="padding-left:2em">
         <h1 class="dac-hero-title">Android 7.0 Nougat</h1>
         <p class="dac-hero-description">
-          <strong>Android 7.0 Nougat brings a new crop of sweet features to your Android device.</strong>
-          <strong>Test your apps</strong> on Nexus and other devices. Support new system
+          Android 7.0 brings new features for performance, productivity,
+          and security. <strong>Test your apps</strong> with new system
           behaviors to <strong>save power and memory</strong>.
-          Extend your apps with <strong>multi-window UI</strong>,
+          Take advantage of <strong>multi-window UI</strong>,
           <strong>direct reply notifications</strong> and more.
         </p>
 
-        <a class="dac-hero-cta" href="{@docRoot}preview/overview.html">
+        <a class="dac-hero-cta" href="{@docRoot}about/versions/nougat/android-7.0.html">
           <span class="dac-sprite dac-auto-chevron"></span>
           Get started
-        </a><!--<br>
-        <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Update to Android N (final SDK)
-        </a><br>-->
+        </a>
       </div>
-      <div class="col-9of16 col-pull-7of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
+      <div class="col-7of16 col-pull-6of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
+        <a  href="{@docRoot}about/versions/nougat/android-7.0.html">
         <img class="dac-hero-image" src="{@docRoot}images/home/n-preview-hero.png"
              srcset="{@docRoot}images/home/n-preview-hero.png 1x,
-             {@docRoot}images/home/n-preview-hero_2x.png 2x">
+             {@docRoot}images/home/n-preview-hero_2x.png 2x" />
+           </a>
       </div>
-    </div>
+    </div></a>
     <div class="dac-section dac-small">
       <div class="resource-widget resource-flow-layout col-16"
            data-query="collection:nougat/landing/resources"
            data-cardSizes="6x2"
            data-maxResults="3"></div>
-    </div>
+         </div>
   </div>
 </section>
 
+
 <div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand">
   <div class="wrap dac-offset-parent">
     <a class="dac-fab dac-scroll-button" data-scroll-button href="#latest">
@@ -62,18 +62,12 @@
     </a>
     <ul class="dac-actions">
       <li class="dac-action">
-        <a class="dac-action-link" href="https://developer.android.com/preview/bug">
+        <a class="dac-action-link" href="https://source.android.com/source/report-bugs.html">
           <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
           Report an issue
         </a>
       </li>
       <li class="dac-action">
-        <a class="dac-action-link" href="{@docRoot}preview/support.html">
-          <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
-          See release notes
-        </a>
-      </li>
-      <li class="dac-action">
         <a class="dac-action-link" href="{@docRoot}preview/dev-community">
           <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i>
           Join dev community
@@ -114,7 +108,6 @@
     data-initial-results="3"></div>
 </div></section>
 
-
 <section class="dac-section dac-gray" id="videos"><div class="wrap">
   <h1 class="dac-section-title">Videos</h1>
   <div class="dac-section-subtitle">
@@ -122,7 +115,7 @@
   </div>
 
   <div class="resource-widget resource-flow-layout col-16"
-    data-query="collection:preview/landing/videos/first,type:youtube+tag:androidn"
+    data-query="collection:nougat/landing/videos/first,type:youtube+tag:androidn"
     data-sortOrder="-timestamp"
     data-cardSizes="6x6"
     data-items-per-page="6"
@@ -131,20 +124,17 @@
   </div>
 </div></section>
 
-
 <section class="dac-section dac-light" id="resources"><div class="wrap">
   <h1 class="dac-section-title">Resources</h1>
   <div class="dac-section-subtitle">
-    Essential information to help you get your apps ready for Android N.
+    Essential information to help you get your apps ready for Android Nougat.
   </div>
 
   <div class="resource-widget resource-flow-layout col-16"
-       data-query="collection:preview/landing/more"
+       data-query="collection:nougat/landing/more"
        data-cardSizes="6x6"
        data-items-per-page="6"
        data-maxResults="15"
        data-initial-results="6"></div>
-
   </div>
-</section>
-
+</section>
\ No newline at end of file
diff --git a/docs/html/distribute/essentials/quality/billions.jd b/docs/html/distribute/essentials/quality/billions.jd
index 2e14b37..355b272 100644
--- a/docs/html/distribute/essentials/quality/billions.jd
+++ b/docs/html/distribute/essentials/quality/billions.jd
@@ -220,6 +220,13 @@
    Android training on <a
    href="{@docRoot}training/basics/network-ops/managing.html">Managing Network
    Usage</a>.</li>
+  <li>On devices powered by Android 7.0 (API level 24) and higher,
+  users can turn on the
+  <strong>Data Saver</strong> setting, which helps minimize data usage. Android 7.0
+  extends {@link android.net.ConnectivityManager} to detect <strong>Data Saver</strong>
+  settings. For more information about this feature, see
+  <a href="/training/basics/network-ops/data-saver.html">Data Saver.</a>
+  </li>
  </ul>
 <h4 id="network-behavior">Detect network changes, then change app behavior</h4>
  <ul>
@@ -257,9 +264,11 @@
    <code>registerReceiver</code></a> to receive this broadcast. After receiving
    the broadcast, you should reevaluate the current network state and adjust
    your UI and network usage appropriately. You should not declare this receiver
-   in your manifest, as it will no longer function beginning with Android N.
-   For more details see <a href="{@docRoot}preview/behavior-changes.html">
-   Android N behavior changes</a>.</li>
+   in your manifest, as that feature is unavailable in Android 7.0 (API level 24)
+   and higher.
+   For more information about this and other changes in Android 7.0,
+   see <a href="/about/versions/nougat/android-7.0-changes.html">
+   Android 7.0 Changes</a>.</li>
  </ul>
 
 <h3 class="rel-resources clearfloat">Related resources</h3>
@@ -490,14 +499,18 @@
    smaller file sizes than its PNG and JPG counterparts, with at least the
    same image quality. Even at lossy settings, WebP can produce a nearly
    identical image. Android has had lossy WebP support since Android 4.0 (API
-   level 14: Ice Cream Sandwich) and support for lossless / transparent WebP since Android 4.2 (API level 17: Jelly Bean).</li>
+   level 14: Ice Cream Sandwich) and support for lossless / transparent WebP
+   since Android 4.2 (API level 17: Jelly Bean).</li>
   <li>If you have many large images across multiple densities, consider
    using <a href="{@docRoot}google/play/publishing/multiple-apks.html">Multiple
    APK support</a> to split your APK by density. This results in builds
    targeted for specific densities, meaning users with low-density devices
    won’t have to incur the penalty of unused high-density assets.</li>
-  <li>A detailed guide on reducing your APK size can be found in <a
-   class="external-link" href="https://medium.com/@wkalicinski/smallerapk-part-4-multi-apk-through-abi-and-density-splits-477083989006">
+  <li>For more information about reducing APK size, see
+  <a href="/topic/performance/reduce-apk-size.html">Reduce APK Size</a> and
+  <a href="/studio/build/shrink-code.html">Shrink Your Code and Resources</a>. In addition, you can
+  find a detailed guide on reducing APK size in this <a class="external-link"
+  href="https://medium.com/@wkalicinski/smallerapk-part-4-multi-apk-through-abi-and-density-splits-477083989006">
    series of Medium posts</a>.</li>
  </ul>
 <h4 id="appsize-code">Reduce code size</h4>
@@ -607,6 +620,19 @@
  <ul>
   <li>Your app should do minimal activity when in the background and when the
    device is running on battery power.</li>
+   <li>Sensors, like GPS, can also significantly drain your battery. For this
+   reason, we recommend that you use the <a
+   href="https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderApi">
+   <code>FusedLocationProvider</code></a> API. The
+   <code>FusedLocationProvider</code> API manages the
+   underlying location technology and provides a simple API so that you can
+   specify requirements&mdash;like high accuracy or low power&mdash;at a high
+   level. It also optimizes the device's use of battery power by caching
+   locations and batching requests across apps. For more information about the
+   ideal ways to request location, see the <a
+   href="{@docRoot}training/location/retrieve-current.html">Getting the Last
+   Known Location</a> training guide.
+  </li>
   <li><a href="{@docRoot}reference/android/os/PowerManager.WakeLock.html">Wake
    locks</a> are mechanisms to keep devices on so that they can perform
    background activities. Avoid using wake locks because they prevent the
@@ -623,18 +649,9 @@
    network connectivity, device charging state, retries, and backoff. Use
    <code>GcmNetworkManager</code> to perform non-essential background activity
    when the device is charging and is connected to an unmetered network.</li>
-  <li>Sensors, like GPS, can also have a significant drain on the battery. The
-   recommended way to request location is to use the FusedLocationProvider API.
-   The <a
-   href="https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderApi">FusedLocationProvider</a> API manages the
-   underlying location technology and provides a simple API so that you can
-   specify requirements&mdash;like high accuracy or low power&mdash;at a high
-   level. It also optimizes the device's use of battery power by caching
-   locations and batching requests across apps. For  more information on the
-   ideal ways to request location, see the <a
-   href="{@docRoot}training/location/retrieve-current.html">Getting the Last
-   Known Location</a> training guide.
-  </li>
+  <li>For more information on how network activity can drain the battery, and
+  how to tackle this issue, see <a
+  href="/topic/performance/power/network/index.html">Reducing Network Battery Drain</a>.
  </ul>
 <h3 id="consumption-benchmark">Benchmark battery usage</h3>
  <ul>
@@ -735,9 +752,12 @@
    the device’s CPU and GPU.  For more information, see the Android training on
    <a href="{@docRoot}training/improving-layouts/index.html">Improving Layout
    Performance</a>. </li>
+  <li>An efficient view hierarchy can speed up your app without increasing the
+      app's memory footprint. For more information, see
+  <a href="/topic/performance/optimizing-view-hierarchies.html">Performance
+  and View Hierarchies.</a>
  </ul>
-<h4 id="content-firstload">If anticipated start speed is low, use launch screen
-on first load</h4>
+<h4 id="content-firstload">If anticipated start speed is low, use launch screen on first load</h4>
  <ul>
   <li>The launch screen is a user’s first experience of your application.
    Launching your app while displaying a blank canvas increases its perceived
@@ -753,6 +773,9 @@
   <li>For more information on implementing splash screens, see the <a
    href="https://www.google.com/design/spec/patterns/launch-screens.html">
    Launch screens</a> section of the Material Design spec.</li>
+  <li>The best way to deal with slow start speeds is not to have them. <a
+  href="/topic/performance/launch-time.html">Launch-Time Performance</a> provides
+  information that may help you speed up your app's launch time.</li>
  </ul>
 <h3 id="ui">UI best practices</h3>
  <ul>
@@ -778,6 +801,12 @@
   <li>To learn more, visit the Android training on <a
  href="{@docRoot}training/basics/supporting-devices/languages.html">
  Supporting Different Languages</a>.</li>
+  <li>Starting from Android 7.0 (API level 24), the Android framework
+  makes available a subset of the <a class="external-link"
+  href="http://userguide.icu-project.org/">ICU4J APIs</a>, which can
+  help you localize your app into multiple languages. For more
+  information, see <a href="/guide/topics/resources/icu4j-framework.html"> 
+  ICU4J Android Framework APIs.</a>
  </ul>
 
 <h3 class="rel-resources clearfloat">Related resources</h3>
diff --git a/docs/html/guide/components/intents-common.jd b/docs/html/guide/components/intents-common.jd
index 9488f6e..e6c9fc6 100644
--- a/docs/html/guide/components/intents-common.jd
+++ b/docs/html/guide/components/intents-common.jd
@@ -99,7 +99,6 @@
     </ol>
   </li>
   <li><a href="#AdbIntents">Verify Intents with the Android Debug Bridge</a></li>
-  <li><a href="#Now">Intents Fired by Google Now</a></li>
 </ol>
 
   <h2>See also</h2>
@@ -110,9 +109,9 @@
 </div>
 </div>
 
-<!-- Google Now box styles -->
+<!-- Google Voice Actions box styles -->
 <style type="text/css">
-.now-box {
+.voice-box {
   border-color: rgb(204,204,204);
   border-style: solid;
   border-width: 1px;
@@ -121,99 +120,120 @@
   padding: 17px;
   width: 200px;
 }
-.now-box li {
+.voice-box li {
   font-size: 13px;
   font-style: italic;
   margin-top: 0px;
 }
-.now-box ul {
+.voice-box ul {
   margin-bottom: 0px;
 }
-.now-img {
+.voice-img {
   width: 30px;
   margin-bottom: 0px !important;
 }
-.now-img-cont {
+.voice-img-cont {
   float: left;
   margin-right: 10px;
 }
-.now-title {
+.voice-title {
   font-weight: bold;
   margin-top: 7px;
 }
-.now-list {
+.voice-list {
   font-size: 13px;
   margin-bottom: 10px !important;
   list-style-type: none;
 }
-.now-list li {
+.voice-list li {
   font-style: italic;
 }
 </style>
 
-<p>An intent allows you to start an activity in another app by describing a simple
-action you'd like to perform (such as "view a map" or "take a picture")
-in an {@link android.content.Intent} object. This type of intent is
-called an <em>implicit</em> intent because it does not specify the app component
-to start, but instead specifies an <em>action</em> and provides some
-<em>data</em> with which to perform the action.</p>
+<p>
+  An intent allows you to start an activity in another app by describing a
+  simple action you'd like to perform (such as "view a map" or "take a
+  picture") in an {@link android.content.Intent} object. This type of intent
+  is called an <em>implicit</em> intent because it does not specify the app
+  component to start, but instead specifies an <em>action</em> and provides
+  some <em>data</em> with which to perform the action.
+</p>
 
-<p>When you call
-{@link android.content.Context#startActivity startActivity()} or
-{@link android.app.Activity#startActivityForResult startActivityForResult()} and pass it an
-implicit intent, the system <a href="{@docRoot}guide/components/intents-filters.html#Resolution"
->resolves the intent</a> to an app that can handle the intent
-and starts its corresponding {@link android.app.Activity}. If there's more than one app
-that can handle the intent, the system presents the user with a dialog to pick which app
-to use.</p>
+<p>
+  When you call {@link android.content.Context#startActivity startActivity()}
+  or {@link android.app.Activity#startActivityForResult
+  startActivityForResult()} and pass it an implicit intent, the system
+  <a href="{@docRoot}guide/components/intents-filters.html#Resolution">resolves
+  the intent</a> to an app that can handle the intent and starts its
+  corresponding {@link android.app.Activity}. If there's more than one app
+  that can handle the intent, the system presents the user with a dialog to
+  pick which app to use.
+</p>
 
-<p>This page describes several implicit intents that you can use to perform common actions,
-organized by the type of app that handles the intent. Each section also shows how you can
-create an <a href="{@docRoot}guide/components/intents-filters.html#Receiving">intent filter</a> to
-advertise your app's ability to perform the same action.</p>
+<p>
+  This page describes several implicit intents that you can use to perform
+  common actions, organized by the type of app that handles the intent. Each
+  section also shows how you can create an <a href=
+  "{@docRoot}guide/components/intents-filters.html#Receiving">intent
+  filter</a> to advertise your app's ability to perform the same action.
+</p>
 
-<p class="caution"><strong>Caution:</strong> If there are no apps on the device that can receive
-the implicit intent, your app will crash when it calls {@link android.content.Context#startActivity
-startActivity()}. To first verify that an app exists to receive the intent, call {@link
-android.content.Intent#resolveActivity resolveActivity()} on your {@link android.content.Intent}
-object. If the result is non-null, there is at least one app that can handle the intent and
-it's safe to call {@link android.content.Context#startActivity startActivity()}. If the result is
-null, you should not use the intent and, if possible, you should disable the feature that invokes
-the intent.</p>
+<p class="caution">
+  <strong>Caution:</strong> If there are no apps on the device that can
+  receive the implicit intent, your app will crash when it calls {@link
+  android.content.Context#startActivity startActivity()}. To first verify that
+  an app exists to receive the intent, call {@link
+  android.content.Intent#resolveActivity resolveActivity()} on your {@link
+  android.content.Intent} object. If the result is non-null, there is at least
+  one app that can handle the intent and it's safe to call {@link
+  android.content.Context#startActivity startActivity()}. If the result is
+  null, you should not use the intent and, if possible, you should disable the
+  feature that invokes the intent.
+</p>
 
-<p>If you're not familiar with how to create intents or intent filters, you should first read
-<a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a>.</p>
+<p>
+  If you're not familiar with how to create intents or intent filters, you
+  should first read <a href=
+  "{@docRoot}guide/components/intents-filters.html">Intents and Intent
+  Filters</a>.
+</p>
 
-<p>To learn how to fire the intents listed on this page from your development host, see
-<a href="#AdbIntents">Verify Intents with the Android Debug Bridge</a>.</p>
+<p>
+  To learn how to fire the intents listed on this page from your development
+  host, see <a href="#AdbIntents">Verify Intents with the Android Debug
+  Bridge</a>.
+</p>
 
-<h4>Google Now</h4>
+<h4>Google Voice Actions</h4>
 
-<p><a href="http://www.google.com/landing/now/">Google Now</a> fires some of the intents listed
-on this page in response to voice commands. For more information, see
-<a href="#Now">Intents Fired by Google Now</a>.</p>
-
-
-
-
-
+<p>
+  <a href="https://developers.google.com/voice-actions/">Google Voice
+  Actions</a> fires some of the intents listed on this page in response to
+  voice commands. For more information, see <a href=
+  "https://developers.google.com/voice-actions/system/#system_actions_reference">
+  Intents fired by Google Voice Actions</a>.
+</p>
 
 <h2 id="Clock">Alarm Clock</h2>
 
-
 <h3 id="CreateAlarm">Create an alarm</h3>
 
-<!-- Google Now box -->
-<div class="now-box">
-  <div class="now-img-cont">
-    <a href="#Now">
-      <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" width="30"
-           height="30" alt=""/>
-    </a>
+<!-- Google Voice Actions box -->
+<div class="voice-box">
+  <div class="voice-img-cont">
+    <a href=
+    "https://developers.google.com/voice-actions/system/#system_actions_reference">
+    <img src="{@docRoot}guide/components/images/voice-icon.png" class=
+    "voice-img" width="30" height="30" alt=""></a>
   </div>
-  <p class="now-title">Google Now</p>
+
+  <p class="voice-title">
+    Google Voice Actions
+  </p>
+
   <ul>
-    <li>"set an alarm for 7 am"</li>
+    <li>"set an alarm for 7 am"
+    </li>
   </ul>
 </div>
 
@@ -301,22 +321,30 @@
 
 <h3 id="CreateTimer">Create a timer</h3>
 
-<!-- Google Now box -->
-<div class="now-box">
-  <div class="now-img-cont">
-    <a href="#Now">
-      <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img"
-           width="30" height="30" alt=""/>
-    </a>
+<!-- Google Voice Actions box -->
+<div class="voice-box">
+  <div class="voice-img-cont">
+    <a href=
+    "https://developers.google.com/voice-actions/system/#system_actions_reference">
+    <img src="{@docRoot}guide/components/images/voice-icon.png" class=
+    "voice-img" width="30" height="30" alt=""></a>
   </div>
-  <p class="now-title">Google Now</p>
+
+  <p class="voice-title">
+    Google Voice Actions
+  </p>
+
   <ul>
-    <li>"set timer for 5 minutes"</li>
+    <li>"set timer for 5 minutes"
+    </li>
   </ul>
 </div>
 
-<p>To create a countdown timer, use the {@link android.provider.AlarmClock#ACTION_SET_TIMER}
-action and specify timer details such as the duration using extras defined below.</p>
+<p>
+  To create a countdown timer, use the {@link
+  android.provider.AlarmClock#ACTION_SET_TIMER} action and specify timer
+  details such as the duration using extras defined below.
+</p>
 
 <p class="note"><strong>Note:</strong> This intent was added
 in Android 4.4 (API level 19).</p>
@@ -594,28 +622,36 @@
 &lt;/activity>
 </pre>
 
-<p>When handling this intent, your activity should check for the {@link
-android.provider.MediaStore#EXTRA_OUTPUT} extra in the incoming {@link android.content.Intent},
-then save the captured image or video at the location specified by that extra and call {@link
-android.app.Activity#setResult(int,Intent) setResult()} with an
-{@link android.content.Intent} that includes a compressed thumbnail
-in an extra named <code>"data"</code>.</p>
+<p>
+  When handling this intent, your activity should check for the {@link
+  android.provider.MediaStore#EXTRA_OUTPUT} extra in the incoming {@link
+  android.content.Intent}, then save the captured image or video at the
+  location specified by that extra and call {@link
+  android.app.Activity#setResult(int,Intent) setResult()} with an {@link
+  android.content.Intent} that includes a compressed thumbnail in an extra
+  named <code>"data"</code>.
+</p>
 
 
 
 <h3 id="CameraStill">Start a camera app in still image mode</h3>
 
-<!-- Google Now box -->
-<div class="now-box">
-  <div class="now-img-cont">
-    <a href="#Now">
-      <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img"
-           width="30" height="30" alt=""/>
-    </a>
+<!-- Google Voice Actions box -->
+<div class="voice-box">
+  <div class="voice-img-cont">
+    <a href=
+    "https://developers.google.com/voice-actions/system/#system_actions_reference">
+    <img src="{@docRoot}guide/components/images/voice-icon.png" class=
+    "voice-img" width="30" height="30" alt=""></a>
   </div>
-  <p class="now-title">Google Now</p>
+
+  <p class="voice-title">
+    Google Voice Actions
+  </p>
+
   <ul>
-    <li>"take a picture"</li>
+    <li>"take a picture"
+    </li>
   </ul>
 </div>
 
@@ -661,17 +697,22 @@
 
 <h3 id="CameraVideo">Start a camera app in video mode</h3>
 
-<!-- Google Now box -->
-<div class="now-box">
-  <div class="now-img-cont">
-    <a href="#Now">
-      <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img"
-           width="30" height="30" alt=""/>
-    </a>
+<!-- Google Voice Actions box -->
+<div class="voice-box">
+  <div class="voice-img-cont">
+    <a href=
+    "https://developers.google.com/voice-actions/system/#system_actions_reference">
+    <img src="{@docRoot}guide/components/images/voice-icon.png" class=
+    "voice-img" width="30" height="30" alt=""></a>
   </div>
-  <p class="now-title">Google Now</p>
+
+  <p class="voice-title">
+    Google Voice Actions
+  </p>
+
   <ul>
-    <li>"record a video"</li>
+    <li>"record a video"
+    </li>
   </ul>
 </div>
 
@@ -1348,20 +1389,30 @@
 
 <h3 id="CallCar">Call a car</h3>
 
-<!-- Google Now box -->
-<div class="now-box">
-  <div class="now-img-cont">
-    <a href="#Now">
-      <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img"
-           width="30" height="30" alt=""/>
-    </a>
+<!-- Google Voice Actions box -->
+<div class="voice-box">
+  <div class="voice-img-cont">
+    <a href=
+    "https://developers.google.com/voice-actions/system/#system_actions_reference">
+    <img src="{@docRoot}guide/components/images/voice-icon.png" class=
+    "voice-img" width="30" height="30" alt=""></a>
   </div>
-  <p class="now-title">Google Now</p>
+
+  <p class="voice-title">
+    Google Voice Actions
+  </p>
+
   <ul>
-    <li>"get me a taxi"</li>
-    <li>"call me a car"</li>
+    <li>"get me a taxi"
+    </li>
+
+    <li>"call me a car"
+    </li>
   </ul>
-  <p style="font-size:13px;margin-bottom:0px;margin-top:10px">(Android Wear only)</p>
+
+  <p style="font-size:13px;margin-bottom:0px;margin-top:10px">
+    (Android Wear only)
+  </p>
 </div>
 
 <p>To call a taxi, use the
@@ -1548,17 +1599,22 @@
 
 <h3 id="PlaySearch">Play music based on a search query</h3>
 
-<!-- Google Now box -->
-<div class="now-box">
-  <div class="now-img-cont">
-    <a href="#Now">
-      <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img"
-           width="30" height="30" alt=""/>
-    </a>
+<!-- Google Voice Actions box -->
+<div class="voice-box">
+  <div class="voice-img-cont">
+    <a href=
+    "https://developers.google.com/voice-actions/system/#system_actions_reference">
+    <img src="{@docRoot}guide/components/images/voice-icon.png" class=
+    "voice-img" width="30" height="30" alt=""></a>
   </div>
-  <p class="now-title">Google Now</p>
+
+  <p class="voice-title">
+    Google Voice Actions
+  </p>
+
   <ul>
-    <li>"play michael jackson billie jean"</li>
+    <li>"play michael jackson billie jean"
+    </li>
   </ul>
 </div>
 
@@ -1861,19 +1917,28 @@
 the URI scheme defined below. When the phone app opens, it displays the phone number
 but the user must press the <em>Call</em> button to begin the phone call.</p>
 
-<!-- Google Now box -->
-<div class="now-box">
-  <div class="now-img-cont">
-    <a href="#Now">
-      <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img"
-           width="30" height="30" alt=""/>
-    </a>
+<!-- Google Voice Actions box -->
+<div class="voice-box">
+  <div class="voice-img-cont">
+    <a href=
+    "https://developers.google.com/voice-actions/system/#system_actions_reference">
+    <img src="{@docRoot}guide/components/images/voice-icon.png" class=
+    "voice-img" width="30" height="30" alt=""></a>
   </div>
-  <p class="now-title">Google Now</p>
+
+  <p class="voice-title">
+    Google Voice Actions
+  </p>
+
   <ul>
-    <li>"call 555-5555"</li>
-    <li>"call bob"</li>
-    <li>"call voicemail"</li>
+    <li>"call 555-5555"
+    </li>
+
+    <li>"call bob"
+    </li>
+
+    <li>"call voicemail"
+    </li>
   </ul>
 </div>
 
@@ -1947,16 +2012,22 @@
 
 <h3 id="SearchOnApp">Search using a specific app</h3>
 
-<!-- Google Now box -->
-<div class="now-box">
-  <div class="now-img-cont">
-    <a href="#Now">
-      <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img"
-           width="30" height="30"/></a>
+<!-- Google Voice Actions box -->
+<div class="voice-box">
+  <div class="voice-img-cont">
+    <a href=
+    "https://developers.google.com/voice-actions/system/#system_actions_reference">
+    <img src="{@docRoot}guide/components/images/voice-icon.png" class=
+    "voice-img" width="30" height="30" alt=""></a>
   </div>
-  <p class="now-title">Google Now</p>
+
+  <p class="voice-title">
+    Google Voice Actions
+  </p>
+
   <ul>
-    <li>"search for cat videos on myvideoapp"</li>
+    <li>"search for cat videos on myvideoapp"
+    </li>
   </ul>
 </div>
 <!-- Video box -->
@@ -1976,7 +2047,7 @@
 <dd>
   <dl>
     <dt><code>"com.google.android.gms.actions.SEARCH_ACTION"</code></dt>
-    <dd>Support search queries from Google Now.</dd>
+    <dd>Support search queries from Google Voice Actions.</dd>
   </dl>
 </dd>
 
@@ -2207,17 +2278,22 @@
 
 <h3 id="ViewUrl">Load a web URL</h3>
 
-<!-- Google Now box -->
-<div class="now-box">
-  <div class="now-img-cont">
-    <a href="#Now">
-      <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img"
-           width="30" height="30" alt=""/>
-    </a>
+<!-- Google Voice Actions box -->
+<div class="voice-box">
+  <div class="voice-img-cont">
+    <a href=
+    "https://developers.google.com/voice-actions/system/#system_actions_reference">
+    <img src="{@docRoot}guide/components/images/voice-icon.png" class=
+    "voice-img" width="30" height="30" alt=""></a>
   </div>
-  <p class="now-title">Google Now</p>
+
+  <p class="voice-title">
+    Google Voice Actions
+  </p>
+
   <ul>
-    <li>"open example.com"</li>
+    <li>"open example.com"
+    </li>
   </ul>
 </div>
 
@@ -2307,128 +2383,4 @@
 
 
 <p>For more information, see
-<a href="{@docRoot}tools/help/shell.html#am">ADB Shell Commands</a>.</p>
-
-
-
-
-
-
-<h2 id="Now">Intents Fired by Google Now</h2>
-
-<p><a href="http://www.google.com/landing/now/">Google Now</a> recognizes many voice commands
-and fires intents for them. As such, users may launch your app with a Google Now voice command
-if your app declares the corresponding intent filter. For example, if your app can
-<a href="#CreateAlarm">set an alarm</a> and you add the corresponding intent filter to your
-manifest file, Google Now lets users choose your app when they request to set an alarm, as
-shown in figure 1.</p>
-
-<img src="{@docRoot}guide/components/images/google-action.png"
-     srcset="{@docRoot}guide/components/images/google-action_2x.png 2x"
-     width="700" height="241" alt=""/>
-<p class="img-caption"><strong>Figure 1.</strong> Google Now lets users choose from installed
-apps that support a given action.</p>
-
-<p>Google Now recognizes voice commands for the actions listed in table 1. For more information
-about declaring each intent filter, click on the action description.</p>
-
-<p class="table-caption"><strong>Table 1.</strong> Voice commands recognized by Google Now
-(Google Search app v3.6).</p>
-<table>
-<tr>
-  <th>Category</th>
-  <th>Details and Examples</th>
-  <th>Action Name</th>
-</tr>
-<tr>
-  <td rowspan="2" style="vertical-align:middle">Alarm</td>
-  <td>
-    <p><a href="#CreateAlarm">Set alarm</a></p>
-    <ul class="now-list">
-      <li>"set an alarm for 7 am"</li>
-    </ul>
-  </td>
-  <td>{@link android.provider.AlarmClock#ACTION_SET_ALARM AlarmClock.ACTION_SET_ALARM}</td>
-</tr>
-<tr>
-  <td>
-    <p><a href="#CreateTimer">Set timer</a></p>
-    <ul class="now-list">
-      <li>"set a timer for 5 minutes"</li>
-    </ul>
-  </td>
-  <td>{@link android.provider.AlarmClock#ACTION_SET_TIMER AlarmClock.ACTION_SET_TIMER}</td>
-</tr>
-<tr>
-  <td style="vertical-align:middle">Communication</td>
-  <td>
-    <p><a href="#DialPhone">Call a number</a></p>
-    <ul class="now-list">
-      <li>"call 555-5555"</li>
-      <li>"call bob"</li>
-      <li>"call voicemail"</li>
-    </ul>
-  </td>
-  <td>{@link android.content.Intent#ACTION_CALL Intent.ACTION_CALL}</td>
-</tr>
-<tr>
-  <td style="vertical-align:middle">Local</td>
-  <td>
-    <p><a href="#CallCar">Book a car</a></p>
-    <ul class="now-list">
-      <li>"call me a car"</li>
-      <li>"book me a taxi"</li>
-    </ul>
-  </td>
-  <td><a href="{@docRoot}reference/com/google/android/gms/actions/ReserveIntents.html#ACTION_RESERVE_TAXI_RESERVATION">
-      <code>ReserveIntents<br/>.ACTION_RESERVE_TAXI_RESERVATION</code></a></td>
-</tr>
-<tr>
-  <td rowspan="3" style="vertical-align:middle">Media</td>
-  <td>
-    <p><a href="#PlaySearch">Play music from search</a></p>
-    <ul class="now-list">
-      <li>"play michael jackson billie jean"</li>
-    </ul>
-  </td>
-  <td>{@link android.provider.MediaStore#INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH MediaStore<br/>.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH}</td>
-</tr>
-<tr>
-  <td>
-    <p><a href="#CameraStill">Take a picture</a></p>
-    <ul class="now-list">
-      <li>"take a picture"</li>
-    </ul>
-  </td>
-  <td>{@link android.provider.MediaStore#INTENT_ACTION_STILL_IMAGE_CAMERA MediaStore<br/>.INTENT_ACTION_STILL_IMAGE_CAMERA}</td>
-</tr>
-<tr>
-  <td>
-    <p><a href="#CameraVideo">Record a video</a></p>
-    <ul class="now-list">
-      <li>"record a video"</li>
-    </ul>
-  </td>
-  <td>{@link android.provider.MediaStore#INTENT_ACTION_VIDEO_CAMERA MediaStore<br/>.INTENT_ACTION_VIDEO_CAMERA}</td>
-</tr>
-<tr>
-  <td style="vertical-align:middle">Search</td>
-  <td>
-    <p><a href="#SearchOnApp">Search using a specific app</a></p>
-    <ul class="now-list">
-      <li>"search for cat videos <br/>on myvideoapp"</li>
-    </ul>
-  </td>
-  <td><code>"com.google.android.gms.actions<br/>.SEARCH_ACTION"</code></td>
-</tr>
-<tr>
-  <td style="vertical-align:middle">Web browser</td>
-  <td>
-    <p><a href="#ViewUrl">Open URL</a></p>
-    <ul class="now-list">
-      <li>"open example.com"</li>
-    </ul>
-  </td>
-  <td>{@link android.content.Intent#ACTION_VIEW Intent.ACTION_VIEW}</td>
-</tr>
-</table>
+<a href="{@docRoot}tools/help/shell.html#am">ADB Shell Commands</a>.</p>
\ No newline at end of file
diff --git a/docs/html/guide/topics/renderscript/compute.jd b/docs/html/guide/topics/renderscript/compute.jd
index 13880ec..89cfff9 100755
--- a/docs/html/guide/topics/renderscript/compute.jd
+++ b/docs/html/guide/topics/renderscript/compute.jd
@@ -10,12 +10,13 @@
 
     <ol>
       <li><a href="#writing-an-rs-kernel">Writing a RenderScript Kernel</a></li>
-      <li><a href="#access-rs-apis">Accessing RenderScript APIs</a>
+      <li><a href="#access-rs-apis">Accessing RenderScript APIs from Java</a>
         <ol>
           <li><a href="#ide-setup">Setting Up Your Development Environment</a></li>
         </ol>
       </li>
       <li><a href="#using-rs-from-java">Using RenderScript from Java Code</a></li>
+      <li><a href="#single-source-rs">Single-Source RenderScript</a></li>
       <li><a href="#reduction-in-depth">Reduction Kernels in Depth</a>
         <ol>
           <li><a href="#writing-reduction-kernel">Writing a reduction kernel</a></li>
@@ -45,12 +46,16 @@
 <p>To begin with RenderScript, there are two main concepts you should understand:</p>
 <ul>
 
-<li>High-performance compute kernels are written in a C99-derived language. A <i>compute
-    kernel</i> is a function or collection of functions that you can direct the RenderScript runtime
-    to execute in parallel across a collection of data.</li>
+<li>The <em>language</em> itself is a C99-derived language for writing high-performance compute
+code. <a href="#writing-an-rs-kernel">Writing a RenderScript Kernel</a> describes
+how to use it to write compute kernels.</li>
 
-<li>A Java API is used for managing the lifetime of RenderScript resources and controlling kernel
-execution.</li>
+<li>The <em>control API</em> is used for managing the lifetime of RenderScript resources and
+controlling kernel execution. It is available in three different languages: Java, C++ in Android
+NDK, and the C99-derived kernel language itself.
+<a href="#using-rs-from-java">Using RenderScript from Java Code</a> and
+<a href=#single-source-rs>Single-Source RenderScript</a> describe the first and the third
+options, respectively.</li>
 </ul>
 
 <h2 id="writing-an-rs-kernel">Writing a RenderScript Kernel</h2>
@@ -77,7 +82,9 @@
 access script globals from Java code, and these are often used for parameter passing to RenderScript
 kernels.</p></li>
 
-<li><p>Zero or more <strong><i>compute kernels</i></strong>. There are two kinds of compute
+<li><p>Zero or more <strong><i>compute kernels</i></strong>. A compute kernel is a function
+or collection of functions that you can direct the RenderScript runtime to execute in parallel
+across a collection of data. There are two kinds of compute
 kernels: <i>mapping</i> kernels (also called <i>foreach</i> kernels)
 and <i>reduction</i> kernels.</p>
 
@@ -243,9 +250,9 @@
 precision (such as SIMD CPU instructions).</p>
 
 
-<h2 id="access-rs-apis">Accessing RenderScript APIs</h2>
+<h2 id="access-rs-apis">Accessing RenderScript APIs from Java</h2>
 
-<p>When developing an Android application that uses RenderScript, you can access its API in
+<p>When developing an Android application that uses RenderScript, you can access its API from Java in
   one of two ways:</p>
 
 <ul>
@@ -377,7 +384,7 @@
 <ul>
 
 <li><strong>ScriptC</strong>: These are the user-defined scripts as described in <a
-href="#writing-an-rs-kernel">Writing a RenderScript Kernel</a> above. Every script has a Java class
+href="#writing-an-rs-kernel"><i>Writing a RenderScript Kernel</i></a> above. Every script has a Java class
 reflected by the RenderScript compiler in order to make it easy to access the script from Java code;
 this class has the name <code>ScriptC_<i>filename</i></code>. For example, if the mapping kernel
 above were located in <code>invert.rs</code> and a RenderScript context were already located in
@@ -448,6 +455,116 @@
   a <code>get()</code> method to obtain the result of a reduction. <code>get()</code> is
   synchronous, and is serialized with respect to the reduction (which is asynchronous).</p>
 
+<h2 id="single-source-rs">Single-Source RenderScript</h2>
+
+<p>Android 7.0 (API level 24) introduces a new programming feature called <em>Single-Source
+RenderScript</em>, in which kernels are launched from the script where they are defined, rather than
+from Java. This approach is currently limited to mapping kernels, which are simply referred to as "kernels"
+in this section for conciseness. This new feature also supports creating allocations of type
+<a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_allocation>
+<code>rs_allocation</code></a> from inside the script. It is now possible to
+implement a whole algorithm solely within a script, even if multiple kernel launches are required.
+The benefit is twofold: more readable code, because it keeps the implementation of an algorithm in
+one language; and potentially faster code, because of fewer transitions between Java and
+RenderScript across multiple kernel launches.</p>
+
+<p>In Single-Source RenderScript, you write kernels as described in <a href="#writing-an-rs-kernel">
+Writing a RenderScript Kernel</a>. You then write an invokable function that calls
+<a href="{@docRoot}guide/topics/renderscript/reference/rs_for_each.html#android_rs:rsForEach">
+<code>rsForEach()</code></a> to launch them. That API takes a kernel function as the first
+parameter, followed by input and output allocations. A similar API
+<a href="{@docRoot}guide/topics/renderscript/reference/rs_for_each.html#android_rs:rsForEachWithOptions">
+<code>rsForEachWithOptions()</code></a> takes an extra argument of type
+<a href="{@docRoot}guide/topics/renderscript/reference/rs_for_each.html#android_rs:rs_script_call_t">
+<code>rs_script_call_t</code></a>, which specifies a subset of the elements from the input and
+output allocations for the kernel function to process.</p>
+
+<p>To start RenderScript computation, you call the invokable function from Java.
+Follow the steps in <a href="#using-rs-from-java">Using RenderScript from Java Code</a>.
+In the step <a href="#launching_kernels">launch the appropriate kernels</a>, call
+the invokable function using <code>invoke_<i>function_name</i>()</code>, which will start the
+whole computation, including launching kernels.</p>
+
+<p>Allocations are often needed to save and pass
+intermediate results from one kernel launch to another. You can create them using
+<a href="{@docRoot}guide/topics/renderscript/reference/rs_allocation_create.html#android_rs:rsCreateAllocation">
+rsCreateAllocation()</a>. One easy-to-use form of that API is <code>
+rsCreateAllocation_&ltT&gt&ltW&gt(&hellip;)</code>, where <i>T</i> is the data type for an
+element, and <i>W</i> is the vector width for the element. The API takes the sizes in
+dimensions X, Y, and Z as arguments. For 1D or 2D allocations, the size for dimension Y or Z can
+be omitted. For example, <code>rsCreateAllocation_uchar4(16384)</code> creates a 1D allocation of
+16384 elements, each of which is of type <code>uchar4</code>.</p>
+
+<p>Allocations are managed by the system automatically. You
+do not have to explicitly release or free them. However, you can call
+<a href="{@docRoot}guide/topics/renderscript/reference/rs_object_info.html#android_rs:rsClearObject">
+<code>rsClearObject(rs_allocation* alloc)</code></a> to indicate you no longer need the handle
+<code>alloc</code> to the underlying allocation,
+so that the system can free up resources as early as possible.</p>
+
+<p>The <a href="#writing-an-rs-kernel">Writing a RenderScript Kernel</a> section contains an example
+kernel that inverts an image. The example below expands that to apply more than one effect to an image,
+using Single-Source RenderScript. It includes another kernel, <code>greyscale</code>, which turns a
+color image into black-and-white. An invokable function <code>process()</code> then applies those two kernels
+consecutively to an input image, and produces an output image. Allocations for both the input and
+the output are passed in as arguments of type
+<a href={@docRoot}guide/topics/renderscript/reference/rs_object_types.html#android_rs:rs_allocation>
+<code>rs_allocation</code></a>.</p>
+
+<pre>
+// File: singlesource.rs
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rssample)
+
+static const float4 weight = {0.299f, 0.587f, 0.114f, 0.0f};
+
+uchar4 RS_KERNEL invert(uchar4 in, uint32_t x, uint32_t y) {
+  uchar4 out = in;
+  out.r = 255 - in.r;
+  out.g = 255 - in.g;
+  out.b = 255 - in.b;
+  return out;
+}
+
+uchar4 RS_KERNEL greyscale(uchar4 in) {
+  const float4 inF = rsUnpackColor8888(in);
+  const float4 outF = (float4){ dot(inF, weight) };
+  return rsPackColorTo8888(outF);
+}
+
+void process(rs_allocation inputImage, rs_allocation outputImage) {
+  const uint32_t imageWidth = rsAllocationGetDimX(inputImage);
+  const uint32_t imageHeight = rsAllocationGetDimY(inputImage);
+  rs_allocation tmp = rsCreateAllocation_uchar4(imageWidth, imageHeight);
+  rsForEach(invert, inputImage, tmp);
+  rsForEach(greyscale, tmp, outputImage);
+}
+</pre>
+
+<p>You can call the <code>process()</code> function from Java as follows:</p>
+
+<pre>
+// File SingleSource.java
+
+RenderScript RS = RenderScript.create(context);
+ScriptC_singlesource script = new ScriptC_singlesource(RS);
+Allocation inputAllocation = Allocation.createFromBitmapResource(
+    RS, getResources(), R.drawable.image);
+Allocation outputAllocation = Allocation.createTyped(
+    RS, inputAllocation.getType(),
+    Allocation.USAGE_SCRIPT | Allocation.USAGE_IO_OUTPUT);
+script.invoke_process(inputAllocation, outputAllocation);
+</pre>
+
+<p>This example shows how an algorithm that involves two kernel launches can be implemented completely
+in the RenderScript language itself. Without Single-Source
+RenderScript, you would have to launch both kernels from the Java code, separating kernel launches
+from kernel definitions and making it harder to understand the whole algorithm. Not only is the
+Single-Source RenderScript code easier to read, it also eliminates the transitioning
+between Java and the script across kernel launches. Some iterative algorithms may launch kernels
+hundreds of times, making the overhead of such transitioning considerable.</p>
+
 <h2 id="reduction-in-depth">Reduction Kernels in Depth</h2>
 
 <p><i>Reduction</i> is the process of combining a collection of data into a single
diff --git a/docs/html/guide/topics/ui/notifiers/notifications.jd b/docs/html/guide/topics/ui/notifiers/notifications.jd
index 09dd5f4..373d0a1 100644
--- a/docs/html/guide/topics/ui/notifiers/notifications.jd
+++ b/docs/html/guide/topics/ui/notifiers/notifications.jd
@@ -1,4 +1,6 @@
 page.title=Notifications
+page.image=images/android-7.0/notifications-card.png
+page.tags="notifications", "alerts"
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/images/home/nougat_bg.jpg b/docs/html/images/home/nougat_bg.jpg
new file mode 100644
index 0000000..f2a239d
--- /dev/null
+++ b/docs/html/images/home/nougat_bg.jpg
Binary files differ
diff --git a/docs/html/images/home/nougat_bg_2x.jpg b/docs/html/images/home/nougat_bg_2x.jpg
new file mode 100644
index 0000000..5c7295e
--- /dev/null
+++ b/docs/html/images/home/nougat_bg_2x.jpg
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index b1248af..dc59b71 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -16,34 +16,30 @@
   })
 </script>
 
-<section class="dac-expand dac-hero dac-invert" style="background-color:#455A64">
-  <div class="wrap" style="max-width:1100px;margin-top:0">
-    <div class="col-7of16 col-push-9of16" style="padding-left:2em;">
-      <a href="{@docRoot}preview/index.html">
-        <h1 class="dac-hero-title">Android N Developer Preview</h1>
-        <p class="dac-hero-description">
-          <strong>Android N final SDK is now available!</strong>
-          Get ready for the next version of Android!
-          <strong>Test your apps</strong> on Nexus and other devices. Support new system
-          behaviors to <strong>save power and memory</strong>.
+<section class="dac-expand dac-hero" style="background-color:#b2dfdb;">
+  <div class="wrap" style="max-width:1000px;margin-top:0">
+    <div class="col-7of16 col-push-8of16">
+      <a href="{@docRoot}about/versions/nougat/index.html">
+        <h1 class="dac-hero-title" style="color:#004d40">Android 7.0 Nougat!</h1>
+        <p class="dac-hero-description" style="color:#004d40">
+          <strong>Android 7.0 Nougat is here!</strong>
+          Get your apps ready for the latest version of Android, with new system
+          behaviors to <strong>save battery and memory</strong>.
           Extend your apps with <strong>multi-window UI</strong>,
           <strong>direct reply notifications</strong> and more.
         </p>
-        <a class="dac-hero-cta" href="/preview/index.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
+        <a class="dac-hero-cta" href="{@docRoot}about/versions/nougat/index.html" style="color:#004d40">
+          <span class="dac-sprite dac-auto-chevron" style="background-color:#b2dfdb"></span>
           Learn more
-        </a><!--<br>
-        <a class="dac-hero-cta" href="/preview/support.html">
-          <span class="dac-sprite dac-auto-chevron"></span>
-          Update to Developer Preview (final SDK)
-        </a><br>-->
+        </a>
+        </a>
       </a>
     </div>
-    <div class="col-9of16 col-pull-7of16 dac-hero-figure" style="margin-top:1.5em;padding-right:1.5em;">
-      <a href="{@docRoot}preview/index.html">
-        <img style="" class="dac-hero-image" src="/images/home/n-preview-hero.png"
-             srcset="/images/home/n-preview-hero.png 1x,
-             /images/home/n-preview-hero_2x.png 2x">
+    <div class="col-6of16 col-pull-6of16 dac-hero-figure" style="padding-left:1em;padding-top:1em;">
+      <a href="{@docRoot}about/versions/nougat/index.html">
+        <img class="dac-hero-image" src="{@docRoot}images/home/nougat_bg.jpg"
+             srcset="{@docRoot}images/home/nougat_bg.jpg 1x,
+             {@docRoot}images/home/nougat_bg_2x.jpg 2x">
         </a>
     </div>
   </div>
diff --git a/docs/html/jd_extras_en.js b/docs/html/jd_extras_en.js
index c79ad88..dfc30c3 100644
--- a/docs/html/jd_extras_en.js
+++ b/docs/html/jd_extras_en.js
@@ -5559,13 +5559,13 @@
   "nougat/landing/resources": {
     "title": "",
     "resources": [
-      "about/versions/nougat/api-overview.html",
-      "about/versions/nougat/behavior-changes.html",
-      "about/versions/nougat/samples.html",
+      "about/versions/nougat/android-7.0.html",
+      "about/versions/nougat/android-7.0-changes.html",
+      "about/versions/nougat/android-7.0-samples.html",
     ]
   },
 
-  "preview/landing/videos/first": {
+  "nougat/landing/videos/first": {
     "title": "",
     "resources": [
     "https://www.youtube.com/watch?v=CsulIu3UaUM"
@@ -5583,21 +5583,20 @@
       "training/articles/memory.html",
     ]
   },
-
-  "preview/landing/more": {
+  "nougat/landing/more": {
     "title": "",
     "resources": [
-      "preview/features/multi-window.html",
-      "preview/features/notification-updates.html",
-      "preview/features/background-optimization.html",
-      "preview/features/data-saver.html",
-      "preview/features/direct-boot.html",
-      "preview/features/icu4j-framework.html",
-      "preview/features/multilingual-support.html",
-      "preview/features/scoped-folder-access.html",
-      "preview/features/security-config.html",
-      "preview/features/picture-in-picture.html",
-      "preview/features/tv-recording-api.html"
+      "guide/topics/ui/multi-window.html",
+      "guide/topics/ui/notifiers/notifications.html",
+      "topic/performance/background-optimization.html",
+      "training/basics/network-ops/data-saver.html",
+      "training/articles/direct-boot.html",
+      "guide/topics/resources/icu4j-framework.html",
+      "guide/topics/resources/multilingual-support.html",
+      "training/articles/scoped-directory-access.html",
+      "training/articles/security-config.html",
+      "training/tv/playback/picture-in-picture.html",
+      "training/tv/tif/content-recording.html"
     ]
   },
   "work/landing/primary": {
diff --git a/docs/html/topic/libraries/support-library/features.jd b/docs/html/topic/libraries/support-library/features.jd
index 0f63bf6..614392e 100755
--- a/docs/html/topic/libraries/support-library/features.jd
+++ b/docs/html/topic/libraries/support-library/features.jd
@@ -7,7 +7,15 @@
 
     <h2>In this document</h2>
     <ol>
-      <li><a href="#v4">v4 Support Library</a></li>
+      <li><a href="#v4">v4 Support Libraries</a>
+        <ol>
+          <li><a href="#v4-compat">v4 compat library</a></li>
+          <li><a href="#v4-core-utils">v4 core-utils library</a></li>
+          <li><a href="#v4-core-ui">v4 core-ui library</a></li>
+          <li><a href="#v4-media-compat">v4 media-compat library</a></li>
+          <li><a href="#v4-fragment">v4 fragment library</a></li>
+        </ol>
+      </li>
       <li><a href="#multidex">Multidex Support Library</a></li>
       <li><a href="#v7">v7 Support Libraries</a>
         <ol>
@@ -63,94 +71,115 @@
   include the library in your application.</p>
 
 
-<h2 id="v4">v4 Support Library</h2>
-
-<p>This library is designed to be used with Android 1.6 (API level 4) and higher. It includes the
-  largest set of APIs compared to the other libraries, including support for application components,
-  user interface features, accessibility, data handling, network connectivity, and programming
-  utilities. Here are a few of the key classes included in the v4 library:</p>
-
-<ul>
-  <li>App Components
-    <ul>
-      <li>{@link android.support.v4.app.Fragment}
-        - Adds support for encapsulation of user interface and functionality
-        with Fragments, enabling
-        applications to provide layouts that adjust between small and
-        large-screen devices.
-       </li>
-
-      <li>{@link android.support.v4.app.NotificationCompat} - Adds support for rich notification
-        features.</li>
-      <li>{@link android.support.v4.content.LocalBroadcastManager} - Allows applications to easily
-        register for and receive intents within a single application without broadcasting them
-        globally.</li>
-    </ul>
-  </li>
-  <li>User Interface
-    <ul>
-      <li>{@link android.support.v4.view.ViewPager} - Adds a
-      {@link android.view.ViewGroup} that manages the layout for the
-      child views, which the user can swipe between.</li>
-      <li>{@link android.support.v4.view.PagerTitleStrip}
-        - Adds a non-interactive title strip, that can be added as a child of
-        {@link android.support.v4.view.ViewPager}.</li>
-      <li>{@link android.support.v4.view.PagerTabStrip} - Adds a
-        navigation widget for switching between paged views, that can also be used with
-        {@link android.support.v4.view.ViewPager}.</li>
-      <li>{@link android.support.v4.widget.DrawerLayout} - Adds
-      support for creating a <a href="{@docRoot}training/implementing-navigation/nav-drawer.html"
-      >Navigation Drawer</a> that can be pulled in from the edge of a window.</li>
-      <li>{@link android.support.v4.widget.SlidingPaneLayout}
-        - Adds widget for creating linked summary and detail views that
-        appropriately adapt to various screen sizes.</li>
-    </ul>
-  </li>
-  <li>Accessibility
-    <ul>
-      <li>{@link android.support.v4.widget.ExploreByTouchHelper}
-        - Adds a helper class for implementing accessibility support for custom views.</li>
-      <li>{@link android.support.v4.view.accessibility.AccessibilityEventCompat} - Adds support for
-      {@link android.view.accessibility.AccessibilityEvent}. For more information about implementing
-      accessibility, see <a href="{@docRoot}guide/topics/ui/accessibility/index.html"
-      >Accessibility</a>.</li>
-
-      <li>{@link android.support.v4.view.accessibility.AccessibilityNodeInfoCompat} - Adds support
-      for {@link android.view.accessibility.AccessibilityNodeInfo}.</li>
-      <li>{@link android.support.v4.view.accessibility.AccessibilityNodeProviderCompat} - Adds
-      support for {@link android.view.accessibility.AccessibilityNodeProvider}.</li>
-      <li>{@link android.support.v4.view.AccessibilityDelegateCompat} - Adds support for
-      {@link android.view.View.AccessibilityDelegate}.</li>
-    </ul>
-  </li>
-  <li>Content
-    <ul>
-      <li>{@link android.support.v4.content.Loader} - Adds support for asynchronous loading of data.
-        The library also provides concrete implementations of this class, including
-        {@link android.support.v4.content.CursorLoader} and
-        {@link android.support.v4.content.AsyncTaskLoader}.</li>
-      <li>{@link android.support.v4.content.FileProvider} - Adds support for sharing of private
-        files between applications.</li>
-    </ul>
-  </li>
-</ul>
+<h2 id="v4">v4 Support Libraries</h2>
 
 <p>
-  There are many other APIs included in this library. For complete, detailed information about the
-  v4 Support Library APIs, see the {@link android.support.v4.app android.support.v4} package in the
-  API reference.
+  These libraries are designed to be used with Android 2.3 (API level 9) and
+  higher. They include the largest set of APIs compared to the other libraries,
+  including support for application components, user interface features,
+  accessibility, data handling, network connectivity, and programming
+  utilities.
 </p>
 
-<p class="caution"><strong>Caution:</strong> Using dynamic dependencies, especially for higher version
-numbers, can cause unexpected version updates and regression incompatibilities.</p>
+<p>
+  For complete, detailed information about the classes and methods provided by
+  the v4 support libraries, see the {@link android.support.v4.app
+  android.support.v4} package in the API reference.
+</p>
+
+
+<p class="note">
+  <strong>Note:</strong> Prior to Support Library revision 24.2.0, there was a
+  single v4 support library. That library was divided into multiple modules to
+  improve efficiency. For backwards compatibility, if you list
+  <code>support-v4</code> in your Gradle script, your APK will include all of
+  the v4 modules. However, to reduce APK size, we recommend that you just list
+  the specific modules your app needs.
+</p>
+
+<h3 id="v4-compat">v4 compat library</h3>
+
+<p>
+  Provides compatibility wrappers for a number of framework APIs, such as
+  <code>Context.obtainDrawable()</code> and
+  <code>View.performAccessibilityAction()</code>.
+</p>
 
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:support-v4:24.1.1
+com.android.support:support-compat:24.2.0
 </pre>
 
+<h3 id="v4-core-utils">v4 core-utils library</h3>
 
+<p>
+  Provides a number of utility classes, such as {@link
+  android.support.v4.content.AsyncTaskLoader} and {@link
+  android.support.v4.content.PermissionChecker}.
+</p>
+
+<p>
+  The Gradle build script dependency identifier for this library is as follows:
+</p>
+
+<pre>
+com.android.support:support-core-utils:24.2.0
+</pre>
+
+<h3 id="v4-core-ui">v4 core-ui library</h3>
+
+<p>
+  Implements a variety of UI-related components, such as {@link
+  android.support.v4.view.ViewPager}, {@link
+  android.support.v4.widget.NestedScrollView}, and {@link
+  android.support.v4.widget.ExploreByTouchHelper}.
+</p>
+
+<p>
+  The Gradle build script dependency identifier for this library is as follows:
+</p>
+
+<pre>
+com.android.support:support-core-ui:24.2.0
+</pre>
+
+<h3 id="v4-media-compat">v4 media-compat library</h3>
+
+<p>
+  Backports portions of the <a href=
+  "/reference/android/media/package-summary.html">media</a> framework,
+  including {@link android.media.browse.MediaBrowser} and {@link
+  android.media.session.MediaSession}.
+</p>
+
+<p>
+  The Gradle build script dependency identifier for this library is as follows:
+</p>
+
+<pre>
+com.android.support:support-media-compat:24.2.0
+</pre>
+
+<h3 id="v4-fragment">v4 fragment library</h3>
+
+<p>
+  Adds support for encapsulation of user interface and functionality with
+  <a href=
+  "/guide/components/fragments.html">fragments</a>,
+  enabling applications to provide layouts that adjust between small and
+  large-screen devices. This module has dependencies on <a href=
+  "#v4-compat">compat</a>, <a href="#v4-core-utils">core-utils</a>, <a href=
+  "#v4-core-ui">core-ui</a>, and <a href="#v4-media-compat">media-compat</a>.
+</p>
+
+<p>
+  The Gradle build script dependency identifier for this library is as follows:
+</p>
+
+<pre>
+com.android.support:support-fragment:24.2.0
+</pre>
 
 <h2 id="multidex">Multidex Support Library</h2>
 
@@ -173,7 +202,7 @@
 
 <h2 id="v7">v7 Support Libraries</h2>
 
-<p>There are several libraries designed to be used with Android 2.1 (API level 7) and higher.
+<p>There are several libraries designed to be used with Android 2.3 (API level 9) and higher.
   These libraries provide specific feature sets and can be included in your application
   independently from each other.</p>
 
@@ -216,7 +245,7 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:appcompat-v7:24.1.1
+com.android.support:appcompat-v7:24.2.0
 </pre>
 
 
@@ -231,7 +260,7 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:cardview-v7:24.1.1
+com.android.support:cardview-v7:24.2.0
 </pre>
 
 
@@ -247,7 +276,7 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:gridlayout-v7:24.1.1
+com.android.support:gridlayout-v7:24.2.0
 </pre>
 
 
@@ -270,7 +299,7 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:mediarouter-v7:24.1.1
+com.android.support:mediarouter-v7:24.2.0
 </pre>
 
 <p class="caution">The v7 mediarouter library APIs introduced in Support Library
@@ -290,7 +319,7 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:palette-v7:24.1.1
+com.android.support:palette-v7:24.2.0
 </pre>
 
 
@@ -306,7 +335,7 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:recyclerview-v7:24.1.1
+com.android.support:recyclerview-v7:24.2.0
 </pre>
 
 
@@ -329,18 +358,18 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:preference-v7:24.1.1
+com.android.support:preference-v7:24.2.0
 </pre>
 
 <h2 id="v8">v8 Support Library</h2>
 
-<p>This library is designed to be used with Android 2.2 (API level 8) and higher.
+<p>This library is designed to be used with Android 2.3 (API level 9) and higher.
   This library provides specific feature sets and can be included in your application
   independently from other libraries.</p>
 
 <h3 id="v8-renderscript">v8 renderscript library</h3>
 
-<p>This library is designed to be used with Android (API level 8) and higher. It adds support for
+<p>This library is designed to be used with Android 2.3 (API level 9) and higher. It adds support for
   the <a href="{@docRoot}guide/topics/renderscript/compute.html">RenderScript</a> computation
   framework. These APIs are included in the {@link android.support.v8.renderscript} package. You
   should be aware that the steps for including these APIs in your application is <em>very
@@ -380,7 +409,7 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:support-v13:24.1.1
+com.android.support:support-v13:24.2.0
 </pre>
 
 
@@ -406,7 +435,7 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:preference-v14:24.1.1
+com.android.support:preference-v14:24.2.0
 </pre>
 
 
@@ -429,7 +458,7 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:preference-leanback-v17:24.1.1
+com.android.support:preference-leanback-v17:24.2.0
 </pre>
 
 
@@ -465,7 +494,7 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:leanback-v17:24.1.1
+com.android.support:leanback-v17:24.2.0
 </pre>
 
 
@@ -480,7 +509,7 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:support-annotations:24.1.1
+com.android.support:support-annotations:24.2.0
 </pre>
 
 
@@ -498,7 +527,7 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:design:24.1.1
+com.android.support:design:24.2.0
 </pre>
 
 
@@ -519,7 +548,7 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:customtabs:24.1.1
+com.android.support:customtabs:24.2.0
 </pre>
 
 
@@ -543,7 +572,7 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:percent:24.1.1
+com.android.support:percent:24.2.0
 </pre>
 
 
@@ -566,5 +595,5 @@
 <p>The Gradle build script dependency identifier for this library is as follows:</p>
 
 <pre>
-com.android.support:recommendation:24.1.1
+com.android.support:recommendation:24.2.0
 </pre>
diff --git a/docs/html/topic/libraries/support-library/revisions.jd b/docs/html/topic/libraries/support-library/revisions.jd
index 3b25fb0..4e14c70 100644
--- a/docs/html/topic/libraries/support-library/revisions.jd
+++ b/docs/html/topic/libraries/support-library/revisions.jd
@@ -6,9 +6,324 @@
 <p>This page provides details about the Support Library package releases.</p>
 
 <div class="toggle-content opened">
-  <p id="rev24-1-1">
+  <p id="rev24-2-0">
     <a href="#" onclick="return toggleContent(this)"><img src=
     "{@docRoot}assets/images/styles/disclosure_up.png" class=
+    "toggle-content-img" alt="">Android Support Library, revision 24.2.0</a>
+    <em>(August 2016)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+<p>Release 24.2.0 contains the following changes:</p>
+
+<ul>
+  <li><a href="#24-2-0-v4-refactor">v4 Support Library split</a></li>
+  <li><a href="#24-2-0-api-updates">API updates</a></li>
+  <li><a href="#24-2-0-behavior">Behavior changes</a></li>
+  <li><a href="#24-2-0-deprecations">Deprecations</a></li>
+  <li><a href="#24-2-0-bugfixes">Bug fixes</a></li>
+</ul>
+
+<p class="note"><strong>Note:</strong> Release 24.2.0 removes support for
+  Android 2.2 (API level 8) and lower. Classes and methods that exist only to
+  serve those system versions are now marked as deprecated and should no longer
+  be used. These deprecated classes and methods may be removed in a future
+  release.
+</p>
+
+<h3 id="24-2-0-v4-refactor">v4 Support Library split</h3>
+
+<p>With this release, the <a href="features.html#v4">v4 Support Library</a> has
+  been split into several smaller modules:</p>
+
+<dl>
+  <dt>
+    <code>support-compat</code>
+  </dt>
+
+  <dd>
+    Provides compatibility wrappers for new framework APIs, such as
+    <code>Context.getDrawable()</code> and
+    <code>View.performAccessibilityAction()</code>.
+  </dd>
+
+  <dt>
+    <code>support-core-utils</code>
+  </dt>
+
+  <dd>
+    Provides a number of utility classes, such as {@link
+    android.support.v4.content.AsyncTaskLoader} and {@link
+    android.support.v4.content.PermissionChecker}.
+  </dd>
+
+  <dt>
+    <code>support-core-ui</code>
+  </dt>
+
+  <dd>
+    Implements a variety of UI-related components, such as {@link
+    android.support.v4.view.ViewPager}, {@link
+    android.support.v4.widget.NestedScrollView}, and {@link
+    android.support.v4.widget.ExploreByTouchHelper}.
+  </dd>
+
+  <dt>
+    <code>support-media-compat</code>
+  </dt>
+
+  <dd>
+    Backports portions of the <a href=
+    "/reference/android/media/package-summary.html">media</a> framework,
+    including {@link android.media.browse.MediaBrowser} and {@link
+    android.media.session.MediaSession}.
+  </dd>
+
+  <dt>
+    <code>support-fragment</code>
+  </dt>
+
+  <dd>
+    Backports the <a href=
+    "/guide/components/fragments.html">fragment</a>
+    framework. This module has dependencies on <code>support-compat</code>,
+    <code>support-core-utils</code>, <code>support-core-ui</code>, and
+    <code>support-media-compat</code>.
+  </dd>
+</dl>
+
+<p>For backwards compatibility, if you list <code>support-v4</code> in your
+Gradle script, your APK will include all of these modules. However, to reduce
+APK size, we recommend that you just list the specific modules your app needs.
+</p>
+
+<h3 id="24-2-0-api-updates">API updates</h3>
+
+<ul>
+  <li>Clients using <a href="features.html#custom-tabs">Custom Tabs</a> can
+  control whether Instant Apps should open. (Note that Instant Apps are not yet
+  generally available.) To enable or disable Instant Apps, call <a href=
+  "/reference/android/support/customtabs/CustomTabsIntent.Builder.html#setInstantAppsEnabled(boolean)">
+  <code>CustomTabsIntent.Builder.setInstantAppsEnabled()</code></a> or
+  specify <a href=
+  "/reference/android/support/customtabs/CustomTabsIntent.html#EXTRA_ENABLE_INSTANT_APPS">
+  <code>EXTRA_ENABLE_INSTANT_APPS</code></a>. By default, Custom Tabs will
+  default to enabling Instant Apps, when that feature becomes available.
+  </li>
+
+  <li>{@link android.support.design.widget.TextInputLayout} adds support for
+  the <a href=
+  "https://material.google.com/components/text-fields.html#text-fields-password-input">
+    password visibility toggle</a> from the material design specification.
+  </li>
+
+  <li>The new <a href=
+  "/reference/android/support/transition/package-summary.html"
+  ><code>android.support.transition</code></a>
+  package backports the <a href=
+  "/training/transitions/index.html">Transitions</a> framework to API levels 14
+  and higher. For more information, see the <a href=
+  "/reference/android/support/transition/package-summary.html"
+  ><code>android.support.transition</code></a> reference.
+  </li>
+
+  <li>The <a href="features.html#custom-tabs">Custom Tabs support library</a>
+  adds support for using {@link android.widget.RemoteViews} in the secondary
+  toolbar. The existing {@link
+  android.support.customtabs.CustomTabsSession#setToolbarItem setToolbarItem()}
+  method is now deprecated.
+  </li>
+
+  <li>{@link android.support.v7.content.res.AppCompatResources} adds the
+  ability to load a <code>&lt;vector&gt;</code> (on API level 9 and higher) or
+  <code>&lt;animated-vector&gt;</code> (on API level 11 and higher) from a
+  resource ID, by using the new <a href=
+  "/reference/android/support/v7/content/res/AppCompatResources.html#getDrawable(android.content.Context,%20int)"
+  ><code>getDrawable()</code></a> method.
+  </li>
+
+  <li>{@link android.support.design.widget.CoordinatorLayout} now supports
+  defining inset views, and specifying that other views should dodge the inset
+  views. This allows apps to replicate behavior patterns similar to the way
+  {@link android.support.design.widget.FloatingActionButton} moves out of the
+  way of a {@link android.support.design.widget.Snackbar}, but for any
+  arbitrary view children. For more information, see the <a href=
+  "/reference/android/support/design/widget/CoordinatorLayout.LayoutParams.html#insetEdge">
+  <code>LayoutParams.insetEdge</code></a> and <a href=
+  "/reference/android/support/design/widget/CoordinatorLayout.LayoutParams.html#dodgeInsetEdges">
+  <code>LayoutParams.dodgeInsetEdges</code></a> reference documentation.
+  </li>
+
+  <li>The new <a href="/reference/android/support/v7/util/DiffUtil.html"><code>
+    DiffUtil</code></a> class can calculate the difference between two
+    collections, and can dispatch a list of update operations that are suitable
+    to be consumed by a {@link android.support.v7.widget.RecyclerView.Adapter}.
+  </li>
+
+  <li>
+    <a href=
+    "/reference/android/support/v7/widget/RecyclerView.OnFlingListener.html"><code>
+    RecyclerView.OnFlingListener</code></a> has been added to support custom
+    behavior in response to flings. The <a href=
+    "/reference/android/support/v7/widget/SnapHelper.html"><code>SnapHelper</code></a>
+    class provides an implementation specifically for snapping child views, and
+    the <a href=
+    "/reference/android/support/v7/widget/LinearSnapHelper.html"><code>LinearSnapHelper</code></a>
+    class extends this implementation to provide center-aligned snapping
+    behavior similar to {@link android.support.v4.view.ViewPager}.
+  </li>
+
+</ul>
+
+<h3 id="24-2-0-behavior">Behavior changes</h3>
+
+<ul>
+  <li>If you use the appcompat library's day/night functionality, the system
+  now automatically recreates your activity whenever the day/night mode changes
+  (either because of the time of day, or because of a call to {@link
+  android.support.v7.app.AppCompatDelegate#setLocalNightMode
+  AppCompatDelegate.setLocalNightMode()}).
+  </li>
+
+  <li>{@link android.support.design.widget.Snackbar} now draws behind the
+  navigation bar if the status bar is translucent.
+  </li>
+</ul>
+
+<h3 id="24-2-0-deprecations">Deprecations</h3>
+
+<p>Deprecated classes and methods are subject to removal in a future release. You should migrate away from these APIs as soon as possible.</p>
+
+<ul>
+  <li>Several methods on the following classes were only required for API 8 and
+  lower, and should no longer be used. Instead, use the framework
+  implementations.
+    <ul>
+      <li>{@link android.support.v4.view.KeyEventCompat}: Replace with {@link
+      android.view.KeyEvent}
+      </li>
+
+      <li>{@link android.support.v4.view.MotionEventCompat}: Use {@link
+      android.view.MotionEvent}
+      </li>
+
+      <li>{@link android.support.v4.view.ViewCompat}: Use {@link
+      android.view.View}
+      </li>
+
+      <li>{@link android.support.v4.view.ViewConfigurationCompat}: Use {@link
+      android.view.ViewConfiguration}
+      </li>
+    </ul>
+  </li>
+
+  <li>
+    {@link android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat#getDescription
+    AccessibilityServiceInfoCompat.getDescription()}
+    has been deprecated in favor of
+    <a href="/reference/android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat.html#loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager)"><code>loadDescription()</code></a>
+    which returns a correctly localized description.
+  </li>
+
+  <li>You should not instantiate the <code>ActivityCompat</code> class
+  directly. The non-static <code>getReferrer(Activity)</code> method will be
+  made static in an upcoming release.
+  </li>
+
+  <li>{@link android.support.design.widget.CoordinatorLayout.Behavior#isDirty
+  CoordinatorLayout.Behavior.isDirty()} has been deprecated and is no longer
+  called by {@link android.support.design.widget.CoordinatorLayout}. Any
+  implementations, as well as any calls to this method, should be removed.
+  </li>
+
+  <li>{@link android.support.v4.media.session.MediaSessionCompat#obtain
+  MediaSessionCompat.obtain()} has been deprecated and replaced with the more
+  appropriately-named method
+  <a href="/reference/android/support/v4/media/session/MediaSessionCompat.html#fromMediaSession"><code>fromMediaSession()</code></a>.
+  </li>
+
+  <li>{@link
+  android.support.v4.media.session.MediaSessionCompat.QueueItem#obtain
+  MediaSessionCompat.QueueItem.obtain()} has been deprecated and replaced with
+  the more appropriately-named method
+  <a href="/reference/android/support/v4/media/session/MediaSessionCompat.QueueItem.html#fromQueueItem"><code>fromQueueItem()</code></a>.
+  </li>
+
+  <li>Several abstract classes have been deprecated and replaced with
+  interfaces that more closely reflect their framework equivalents.
+    <ul>
+      <li>{@link
+      android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat}
+      has been replaced by the <a href=
+      "/reference/android/support/v4/view/accessibility/AccessibilityManagerCompat.AccessibilityStateChangeListener.html">
+        <code>AccessibilityManagerCompat.AccessibilityStateChangeListener</code></a>
+        interface.
+      </li>
+
+      <li>{@link
+      android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat} has
+      been replaced by the <a
+      href="/reference/android/support/v4/widget/SearchViewCompat.OnCloseListener.html"
+      ><code>SearchViewCompat.OnCloseListener</code></a> interface.
+      </li>
+
+      <li>{@link
+      android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat }
+      has been replaced by the <a
+      href="/reference/android/support/v4/widget/SearchViewCompat.OnQueryTextListener.html"
+      ><code>SearchViewCompat.OnQueryTextListener</code></a>
+      interface.
+      </li>
+    </ul>
+  </li>
+
+  <li>{@link android.support.customtabs.CustomTabsSession#setToolbarItem
+  CustomTabsSession.setToolbarItem()} has been deprecated and replaced by the
+  RemoteViews-based <a href=
+  "/reference/android/support/customtabs/CustomTabsSession.html#setSecondaryToolbarViews">
+    <code>setSecondaryToolbarViews()</code></a>.
+  </li>
+</ul>
+
+<h3 id="24-2-0-bugfixes">Bug fixes</h3>
+
+<p>The following known issues have been fixed with release 24.2.0:</p>
+
+<ul>
+  <li>Ensure <code>SwipeRefreshLayout</code> indicator is shown when
+  <code>setRefreshing(true)</code> is called before the first measurement pass
+  (<a href="https://code.google.com/p/android/issues/detail?id=77712">AOSP
+  issue 77712</a>)
+  </li>
+
+  <li>Prevent <code>TabLayout</code> from flickering when changing pages
+  (<a href="https://code.google.com/p/android/issues/detail?id=180454">AOSP
+  issue 180454</a>)
+  </li>
+
+  <li>Avoid <code>ClassNotFoundException</code> when unmarshalling
+  <code>SavedState</code> on API level 11 and lower (<a href=
+  "https://code.google.com/p/android/issues/detail?id=196430">AOSP issue
+  196430</a>)
+  </li>
+</ul>
+
+<p>
+  A complete list of public bug fixes is available on the <a href=
+  "https://code.google.com/p/android/issues/list?can=1&q=Component%3DSupport-Libraries+Target%3DSupport-24.2.0">
+  AOSP Issue Tracker</a>.
+</p>
+
+  </div>
+</div>
+
+<!-- end of collapsible section: 24.2.0 -->
+
+<div class="toggle-content closed">
+  <p id="rev24-1-1">
+    <a href="#" onclick="return toggleContent(this)"><img src=
+    "{@docRoot}assets/images/styles/disclosure_down.png" class=
     "toggle-content-img" alt="">Android Support Library, revision 24.1.1</a>
     <em>(July 2016)</em>
   </p>
@@ -76,7 +391,7 @@
     <ul>
       <li>TabLayout.setCustomView(null) results in NullPointerException
         (<a href="https://code.google.com/p/android/issues/detail?id=214753">AOSP
-        issue</a>)
+        issue 214753</a>)
       </li>
 
       <li>TabLayout incorrectly highlights custom tabs (<a href=
diff --git a/docs/html/topic/libraries/support-library/setup.jd b/docs/html/topic/libraries/support-library/setup.jd
index 0cb9389..adb263c 100755
--- a/docs/html/topic/libraries/support-library/setup.jd
+++ b/docs/html/topic/libraries/support-library/setup.jd
@@ -85,17 +85,24 @@
       <li>Make sure you have downloaded the <strong>Android Support Repository</strong>
         using the <a href="#download">SDK Manager</a>.</li>
       <li>Open the {@code build.gradle} file for your application.</li>
-      <li>Add the support library to the {@code dependencies} section. For example, to add the v4
-        support library, add the following lines:
+      <li>Add the support library to the {@code dependencies} section. For
+        example, to add the v4 core-utils library, add the following lines:
 <pre>
 dependencies {
     ...
-    <b>compile "com.android.support:support-v4:24.1.1"</b>
+    <b>compile "com.android.support:support-core-utils:24.2.0"</b>
 }
 </pre>
       </li>
     </ol>
 
+<p class="caution">
+  <strong>Caution:</strong> Using dynamic dependencies (for example,
+  <code>palette-v7:23.0.+</code>) can cause unexpected version updates and
+  regression incompatibilities. We recommend that you explicitly specify a
+  library version (for example, <code>palette-v7:24.2.0</code>).
+</p>
+
 <h2 id="using-apis">Using Support Library APIs</h2>
 
 <p>Support Library classes that provide support for existing framework APIs typically have the
@@ -141,12 +148,12 @@
 
 <pre>
   &lt;uses-sdk
-      android:minSdkVersion="<b>7</b>"
-      android:targetSdkVersion="17" /&gt;
+      android:minSdkVersion="<b>14</b>"
+      android:targetSdkVersion="23" /&gt;
 </pre>
 
 <p>The manifest setting tells Google Play that your application can be installed on devices with Android
-  2.1 (API level 7) and higher.  </p>
+  4.0 (API level 14) and higher.  </p>
 
 <p>If you are using Gradle build files, the <code>minSdkVersion</code> setting in the build file
   overrides the manifest settings.  </p>
@@ -158,7 +165,7 @@
     ...
 
     defaultConfig {
-        minSdkVersion 8
+        minSdkVersion 16
         ...
     }
     ...
@@ -166,13 +173,15 @@
 </pre>
 
 <p>In this case, the build file setting tells Google Play that the default build variant of your
-  application can be installed on devices with Android 2.2 (API level 8) and higher. For more
+  application can be installed on devices with Android 4.1 (API level 16) and higher. For more
   information about build variants, see
   <a href="{@docRoot}studio/build/index.html">Build System Overview</a>. </p>
 
 <p class="note">
-  <strong>Note:</strong> If you are including the v4 support and v7 appcompat libraries in your
-  application, you should specify a minimum SDK version of <code>"7"</code> (and not
-  <code>"4"</code>). The highest support library level you include in your application determines
-  the lowest API version in which it can operate.
+  <strong>Note:</strong> If you are including several support libraries, the
+  minimum SDK version must be the <em>highest</em> version required by any of
+  the specified libraries. For example, if your app includes both the <a href=
+  "features.html#v14-preference">v14 Preference Support library</a> and the
+  <a href="features.html#v17-leanback">v17 Leanback library</a>, your minimum
+  SDK version must be 17 or higher.
 </p>
diff --git a/docs/html/training/notify-user/navigation.jd b/docs/html/training/notify-user/navigation.jd
index 65f8d48b..d0ec1cd 100644
--- a/docs/html/training/notify-user/navigation.jd
+++ b/docs/html/training/notify-user/navigation.jd
@@ -205,7 +205,7 @@
 notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
         Intent.FLAG_ACTIVITY_CLEAR_TASK);
 // Creates the PendingIntent
-PendingIntent notifyIntent =
+PendingIntent pendingIntent =
         PendingIntent.getActivity(
         this,
         0,
@@ -214,7 +214,7 @@
 );
 
 // Puts the PendingIntent into the notification builder
-builder.setContentIntent(notifyIntent);
+builder.setContentIntent(pendingIntent);
 // Notifications are issued by sending them to the
 // NotificationManager system service.
 NotificationManager mNotificationManager =
diff --git a/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd b/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd
index 00622ee..8fc4dca 100644
--- a/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd
+++ b/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd
@@ -95,6 +95,19 @@
 }
 </pre>
 
+<div class="caution">
+<p><strong>Caution:</strong> If your build configuration includes a
+<code>compile</code> dependency for the <code>support-annotations</code>
+library <b>and</b> an <code>androidTestCompile</code> dependency for the
+<code>espresso-core</code> library, your build might fail due to a dependency
+conflict. To resolve, update your dependency for <code>espresso-core</code>
+as follows:</p>
+<pre>
+androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
+    exclude group: 'com.android.support', module: 'support-annotations'
+})
+</pre>
+</div>
 
 <p>
   To use JUnit 4 test classes, make sure to specify <a href=
diff --git a/docs/html/training/transitions/index.jd b/docs/html/training/transitions/index.jd
index 53faa01..b8f99c8 100644
--- a/docs/html/training/transitions/index.jd
+++ b/docs/html/training/transitions/index.jd
@@ -48,11 +48,9 @@
 animations.</p>
 
 <p class="note"><strong>Note:</strong> For Android versions earlier than 4.4.2 (API level 19)
-but greater than or equal to Android 4.0 (API level 14), use the <code>animateLayoutChanges</code>
-attribute to animate layouts. To learn more, see
-<a href="{@docRoot}guide/topics/graphics/prop-animation.html">Property Animation</a> and
-<a href="{@docRoot}training/animation/layout.html">Animating Layout Changes</a>.</p>
-
+but greater than or equal to Android 4.0 (API level 14), use the Android Support
+Library's <a href="/reference/android/support/transitions/package-summary.html"
+><code>android.support.transition</code></a> package.</p>
 
 <h2>Lessons</h2>
 
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index e10445a..0f305f3 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -293,10 +293,7 @@
             // to UI thread animation for AVD.
             if (!mAnimatorSet.isRunning() &&
                     ((VectorDrawableAnimatorRT) mAnimatorSet).mPendingAnimationActions.size() > 0) {
-                VectorDrawableAnimatorRT oldAnim = (VectorDrawableAnimatorRT) mAnimatorSet;
-                mAnimatorSet = new VectorDrawableAnimatorUI(this);
-                mAnimatorSet.init(mAnimatorSetFromXml);
-                oldAnim.transferPendingActions(mAnimatorSet);
+                fallbackOntoUI();
             }
         }
         mAnimatorSet.onDraw(canvas);
@@ -539,10 +536,22 @@
                 throw new UnsupportedOperationException("Cannot force Animated Vector Drawable to" +
                         " run on UI thread when the animation has started on RenderThread.");
             }
+            fallbackOntoUI();
+        }
+    }
+
+    private void fallbackOntoUI() {
+        if (mAnimatorSet instanceof VectorDrawableAnimatorRT) {
+            VectorDrawableAnimatorRT oldAnim = (VectorDrawableAnimatorRT) mAnimatorSet;
             mAnimatorSet = new VectorDrawableAnimatorUI(this);
             if (mAnimatorSetFromXml != null) {
                 mAnimatorSet.init(mAnimatorSetFromXml);
             }
+            // Transfer the listener from RT animator to UI animator
+            if (oldAnim.mListener != null) {
+                mAnimatorSet.setListener(oldAnim.mListener);
+            }
+            oldAnim.transferPendingActions(mAnimatorSet);
         }
     }
 
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index adfdfba..4fc7892 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -20,6 +20,7 @@
 import android.annotation.WorkerThread;
 import android.app.Activity;
 import android.app.PendingIntent;
+import android.app.Service;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -397,6 +398,9 @@
      *
      * <p> This method may block while waiting for a connection to another process, and must never
      * be called from the main thread.
+     * <p> As {@link Activity} and {@link Service} contexts are short-lived and can be destroyed
+     * at any time from the main thread, it is safer to rely on a long-lived context such as one
+     * returned from {@link Context#getApplicationContext()}.
      *
      * @param alias The alias of the desired private key, typically returned via
      *              {@link KeyChainAliasCallback#alias}.
@@ -443,6 +447,9 @@
      *
      * <p> This method may block while waiting for a connection to another process, and must never
      * be called from the main thread.
+     * <p> As {@link Activity} and {@link Service} contexts are short-lived and can be destroyed
+     * at any time from the main thread, it is safer to rely on a long-lived context such as one
+     * returned from {@link Context#getApplicationContext()}.
      *
      * @param alias The alias of the desired certificate chain, typically
      * returned via {@link KeyChainAliasCallback#alias}.
diff --git a/libs/common_time/common_clock_service.h b/libs/common_time/common_clock_service.h
index bd663f0..aea507e 100644
--- a/libs/common_time/common_clock_service.h
+++ b/libs/common_time/common_clock_service.h
@@ -53,7 +53,7 @@
     void notifyOnTimelineChanged(uint64_t timelineID);
 
   private:
-    CommonClockService(CommonTimeServer& timeServer)
+    explicit CommonClockService(CommonTimeServer& timeServer)
         : mTimeServer(timeServer) { };
 
     virtual void binderDied(const wp<IBinder>& who);
diff --git a/libs/common_time/common_time_config_service.h b/libs/common_time/common_time_config_service.h
index 89806dd..23abb1a 100644
--- a/libs/common_time/common_time_config_service.h
+++ b/libs/common_time/common_time_config_service.h
@@ -49,7 +49,7 @@
     virtual status_t forceNetworklessMasterMode();
 
   private:
-    CommonTimeConfigService(CommonTimeServer& timeServer)
+    explicit CommonTimeConfigService(CommonTimeServer& timeServer)
         : mTimeServer(timeServer) { }
     CommonTimeServer& mTimeServer;
 
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index 1c298b1..eb606cb 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -182,7 +182,8 @@
 PathCache::PathCache()
         : mCache(LruCache<PathDescription, PathTexture*>::kUnlimitedCapacity)
         , mSize(0)
-        , mMaxSize(Properties::pathCacheSize) {
+        , mMaxSize(Properties::pathCacheSize)
+        , mTexNum(0) {
     mCache.setOnEntryRemovedListener(this);
 
     GLint maxTextureSize;
@@ -238,6 +239,7 @@
                         "the cache in an inconsistent state", size);
             }
             mSize -= size;
+            mTexNum--;
         }
 
         PATH_LOGD("PathCache::delete name, size, mSize = %d, %d, %d",
@@ -262,7 +264,7 @@
 }
 
 void PathCache::trim() {
-    while (mSize > mMaxSize) {
+    while (mSize > mMaxSize || mTexNum > DEFAULT_PATH_TEXTURE_CAP) {
         mCache.removeOldest();
     }
 }
@@ -310,6 +312,7 @@
     ATRACE_NAME("Upload Path Texture");
     texture->upload(bitmap);
     texture->setFilter(GL_LINEAR);
+    mTexNum++;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index 18bcc56..b45a2c5 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -281,6 +281,12 @@
 
     bool mDebugEnabled;
 
+    /**
+     * Driver allocated 4k/8k/16k memory for small path cache,
+     * limit the number of PathTexture in case occupy too much memory in hardware.
+     */
+    uint32_t mTexNum;
+
     sp<PathProcessor> mProcessor;
 
     std::vector<uint32_t> mGarbage;
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 133ae80..44d7010 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -224,6 +224,9 @@
 
 #define DEFAULT_TEXT_GAMMA 1.4f
 
+// cap to 256 to limite paths in the path cache
+#define DEFAULT_PATH_TEXTURE_CAP 256
+
 ///////////////////////////////////////////////////////////////////////////////
 // Misc
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/debug/gles_redefine.h b/libs/hwui/debug/gles_redefine.h
new file mode 100644
index 0000000..201f0a9
--- /dev/null
+++ b/libs/hwui/debug/gles_redefine.h
@@ -0,0 +1,913 @@
+/*
+ * 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.
+ */
+
+#define glActiveShaderProgram wrap_glActiveShaderProgram
+#define glActiveShaderProgramEXT wrap_glActiveShaderProgramEXT
+#define glActiveTexture wrap_glActiveTexture
+#define glAlphaFunc wrap_glAlphaFunc
+#define glAlphaFuncQCOM wrap_glAlphaFuncQCOM
+#define glAlphaFuncx wrap_glAlphaFuncx
+#define glAlphaFuncxOES wrap_glAlphaFuncxOES
+#define glApplyFramebufferAttachmentCMAAINTEL wrap_glApplyFramebufferAttachmentCMAAINTEL
+#define glAttachShader wrap_glAttachShader
+#define glBeginConditionalRenderNV wrap_glBeginConditionalRenderNV
+#define glBeginPerfMonitorAMD wrap_glBeginPerfMonitorAMD
+#define glBeginPerfQueryINTEL wrap_glBeginPerfQueryINTEL
+#define glBeginQuery wrap_glBeginQuery
+#define glBeginQueryEXT wrap_glBeginQueryEXT
+#define glBeginTransformFeedback wrap_glBeginTransformFeedback
+#define glBindAttribLocation wrap_glBindAttribLocation
+#define glBindBuffer wrap_glBindBuffer
+#define glBindBufferBase wrap_glBindBufferBase
+#define glBindBufferRange wrap_glBindBufferRange
+#define glBindFragDataLocationEXT wrap_glBindFragDataLocationEXT
+#define glBindFragDataLocationIndexedEXT wrap_glBindFragDataLocationIndexedEXT
+#define glBindFramebuffer wrap_glBindFramebuffer
+#define glBindFramebufferOES wrap_glBindFramebufferOES
+#define glBindImageTexture wrap_glBindImageTexture
+#define glBindProgramPipeline wrap_glBindProgramPipeline
+#define glBindProgramPipelineEXT wrap_glBindProgramPipelineEXT
+#define glBindRenderbuffer wrap_glBindRenderbuffer
+#define glBindRenderbufferOES wrap_glBindRenderbufferOES
+#define glBindSampler wrap_glBindSampler
+#define glBindTexture wrap_glBindTexture
+#define glBindTransformFeedback wrap_glBindTransformFeedback
+#define glBindVertexArray wrap_glBindVertexArray
+#define glBindVertexArrayOES wrap_glBindVertexArrayOES
+#define glBindVertexBuffer wrap_glBindVertexBuffer
+#define glBlendBarrier wrap_glBlendBarrier
+#define glBlendBarrierKHR wrap_glBlendBarrierKHR
+#define glBlendBarrierNV wrap_glBlendBarrierNV
+#define glBlendColor wrap_glBlendColor
+#define glBlendEquation wrap_glBlendEquation
+#define glBlendEquationOES wrap_glBlendEquationOES
+#define glBlendEquationSeparate wrap_glBlendEquationSeparate
+#define glBlendEquationSeparateOES wrap_glBlendEquationSeparateOES
+#define glBlendEquationSeparatei wrap_glBlendEquationSeparatei
+#define glBlendEquationSeparateiEXT wrap_glBlendEquationSeparateiEXT
+#define glBlendEquationSeparateiOES wrap_glBlendEquationSeparateiOES
+#define glBlendEquationi wrap_glBlendEquationi
+#define glBlendEquationiEXT wrap_glBlendEquationiEXT
+#define glBlendEquationiOES wrap_glBlendEquationiOES
+#define glBlendFunc wrap_glBlendFunc
+#define glBlendFuncSeparate wrap_glBlendFuncSeparate
+#define glBlendFuncSeparateOES wrap_glBlendFuncSeparateOES
+#define glBlendFuncSeparatei wrap_glBlendFuncSeparatei
+#define glBlendFuncSeparateiEXT wrap_glBlendFuncSeparateiEXT
+#define glBlendFuncSeparateiOES wrap_glBlendFuncSeparateiOES
+#define glBlendFunci wrap_glBlendFunci
+#define glBlendFunciEXT wrap_glBlendFunciEXT
+#define glBlendFunciOES wrap_glBlendFunciOES
+#define glBlendParameteriNV wrap_glBlendParameteriNV
+#define glBlitFramebuffer wrap_glBlitFramebuffer
+#define glBlitFramebufferANGLE wrap_glBlitFramebufferANGLE
+#define glBlitFramebufferNV wrap_glBlitFramebufferNV
+#define glBufferData wrap_glBufferData
+#define glBufferStorageEXT wrap_glBufferStorageEXT
+#define glBufferSubData wrap_glBufferSubData
+#define glCheckFramebufferStatus wrap_glCheckFramebufferStatus
+#define glCheckFramebufferStatusOES wrap_glCheckFramebufferStatusOES
+#define glClear wrap_glClear
+#define glClearBufferfi wrap_glClearBufferfi
+#define glClearBufferfv wrap_glClearBufferfv
+#define glClearBufferiv wrap_glClearBufferiv
+#define glClearBufferuiv wrap_glClearBufferuiv
+#define glClearColor wrap_glClearColor
+#define glClearColorx wrap_glClearColorx
+#define glClearColorxOES wrap_glClearColorxOES
+#define glClearDepthf wrap_glClearDepthf
+#define glClearDepthfOES wrap_glClearDepthfOES
+#define glClearDepthx wrap_glClearDepthx
+#define glClearDepthxOES wrap_glClearDepthxOES
+#define glClearStencil wrap_glClearStencil
+#define glClientActiveTexture wrap_glClientActiveTexture
+#define glClientWaitSync wrap_glClientWaitSync
+#define glClientWaitSyncAPPLE wrap_glClientWaitSyncAPPLE
+#define glClipPlanef wrap_glClipPlanef
+#define glClipPlanefIMG wrap_glClipPlanefIMG
+#define glClipPlanefOES wrap_glClipPlanefOES
+#define glClipPlanex wrap_glClipPlanex
+#define glClipPlanexIMG wrap_glClipPlanexIMG
+#define glClipPlanexOES wrap_glClipPlanexOES
+#define glColor4f wrap_glColor4f
+#define glColor4ub wrap_glColor4ub
+#define glColor4x wrap_glColor4x
+#define glColor4xOES wrap_glColor4xOES
+#define glColorMask wrap_glColorMask
+#define glColorMaski wrap_glColorMaski
+#define glColorMaskiEXT wrap_glColorMaskiEXT
+#define glColorMaskiOES wrap_glColorMaskiOES
+#define glColorPointer wrap_glColorPointer
+#define glCompileShader wrap_glCompileShader
+#define glCompressedTexImage2D wrap_glCompressedTexImage2D
+#define glCompressedTexImage3D wrap_glCompressedTexImage3D
+#define glCompressedTexImage3DOES wrap_glCompressedTexImage3DOES
+#define glCompressedTexSubImage2D wrap_glCompressedTexSubImage2D
+#define glCompressedTexSubImage3D wrap_glCompressedTexSubImage3D
+#define glCompressedTexSubImage3DOES wrap_glCompressedTexSubImage3DOES
+#define glCopyBufferSubData wrap_glCopyBufferSubData
+#define glCopyBufferSubDataNV wrap_glCopyBufferSubDataNV
+#define glCopyImageSubData wrap_glCopyImageSubData
+#define glCopyImageSubDataEXT wrap_glCopyImageSubDataEXT
+#define glCopyImageSubDataOES wrap_glCopyImageSubDataOES
+#define glCopyPathNV wrap_glCopyPathNV
+#define glCopyTexImage2D wrap_glCopyTexImage2D
+#define glCopyTexSubImage2D wrap_glCopyTexSubImage2D
+#define glCopyTexSubImage3D wrap_glCopyTexSubImage3D
+#define glCopyTexSubImage3DOES wrap_glCopyTexSubImage3DOES
+#define glCopyTextureLevelsAPPLE wrap_glCopyTextureLevelsAPPLE
+#define glCoverFillPathInstancedNV wrap_glCoverFillPathInstancedNV
+#define glCoverFillPathNV wrap_glCoverFillPathNV
+#define glCoverStrokePathInstancedNV wrap_glCoverStrokePathInstancedNV
+#define glCoverStrokePathNV wrap_glCoverStrokePathNV
+#define glCoverageMaskNV wrap_glCoverageMaskNV
+#define glCoverageModulationNV wrap_glCoverageModulationNV
+#define glCoverageModulationTableNV wrap_glCoverageModulationTableNV
+#define glCoverageOperationNV wrap_glCoverageOperationNV
+#define glCreatePerfQueryINTEL wrap_glCreatePerfQueryINTEL
+#define glCreateProgram wrap_glCreateProgram
+#define glCreateShader wrap_glCreateShader
+#define glCreateShaderProgramv wrap_glCreateShaderProgramv
+#define glCreateShaderProgramvEXT wrap_glCreateShaderProgramvEXT
+#define glCullFace wrap_glCullFace
+#define glCurrentPaletteMatrixOES wrap_glCurrentPaletteMatrixOES
+#define glDebugMessageCallback wrap_glDebugMessageCallback
+#define glDebugMessageCallbackKHR wrap_glDebugMessageCallbackKHR
+#define glDebugMessageControl wrap_glDebugMessageControl
+#define glDebugMessageControlKHR wrap_glDebugMessageControlKHR
+#define glDebugMessageInsert wrap_glDebugMessageInsert
+#define glDebugMessageInsertKHR wrap_glDebugMessageInsertKHR
+#define glDeleteBuffers wrap_glDeleteBuffers
+#define glDeleteFencesNV wrap_glDeleteFencesNV
+#define glDeleteFramebuffers wrap_glDeleteFramebuffers
+#define glDeleteFramebuffersOES wrap_glDeleteFramebuffersOES
+#define glDeletePathsNV wrap_glDeletePathsNV
+#define glDeletePerfMonitorsAMD wrap_glDeletePerfMonitorsAMD
+#define glDeletePerfQueryINTEL wrap_glDeletePerfQueryINTEL
+#define glDeleteProgram wrap_glDeleteProgram
+#define glDeleteProgramPipelines wrap_glDeleteProgramPipelines
+#define glDeleteProgramPipelinesEXT wrap_glDeleteProgramPipelinesEXT
+#define glDeleteQueries wrap_glDeleteQueries
+#define glDeleteQueriesEXT wrap_glDeleteQueriesEXT
+#define glDeleteRenderbuffers wrap_glDeleteRenderbuffers
+#define glDeleteRenderbuffersOES wrap_glDeleteRenderbuffersOES
+#define glDeleteSamplers wrap_glDeleteSamplers
+#define glDeleteShader wrap_glDeleteShader
+#define glDeleteSync wrap_glDeleteSync
+#define glDeleteSyncAPPLE wrap_glDeleteSyncAPPLE
+#define glDeleteTextures wrap_glDeleteTextures
+#define glDeleteTransformFeedbacks wrap_glDeleteTransformFeedbacks
+#define glDeleteVertexArrays wrap_glDeleteVertexArrays
+#define glDeleteVertexArraysOES wrap_glDeleteVertexArraysOES
+#define glDepthFunc wrap_glDepthFunc
+#define glDepthMask wrap_glDepthMask
+#define glDepthRangeArrayfvNV wrap_glDepthRangeArrayfvNV
+#define glDepthRangeIndexedfNV wrap_glDepthRangeIndexedfNV
+#define glDepthRangef wrap_glDepthRangef
+#define glDepthRangefOES wrap_glDepthRangefOES
+#define glDepthRangex wrap_glDepthRangex
+#define glDepthRangexOES wrap_glDepthRangexOES
+#define glDetachShader wrap_glDetachShader
+#define glDisable wrap_glDisable
+#define glDisableClientState wrap_glDisableClientState
+#define glDisableDriverControlQCOM wrap_glDisableDriverControlQCOM
+#define glDisableVertexAttribArray wrap_glDisableVertexAttribArray
+#define glDisablei wrap_glDisablei
+#define glDisableiEXT wrap_glDisableiEXT
+#define glDisableiNV wrap_glDisableiNV
+#define glDisableiOES wrap_glDisableiOES
+#define glDiscardFramebufferEXT wrap_glDiscardFramebufferEXT
+#define glDispatchCompute wrap_glDispatchCompute
+#define glDispatchComputeIndirect wrap_glDispatchComputeIndirect
+#define glDrawArrays wrap_glDrawArrays
+#define glDrawArraysIndirect wrap_glDrawArraysIndirect
+#define glDrawArraysInstanced wrap_glDrawArraysInstanced
+#define glDrawArraysInstancedANGLE wrap_glDrawArraysInstancedANGLE
+#define glDrawArraysInstancedBaseInstanceEXT wrap_glDrawArraysInstancedBaseInstanceEXT
+#define glDrawArraysInstancedEXT wrap_glDrawArraysInstancedEXT
+#define glDrawArraysInstancedNV wrap_glDrawArraysInstancedNV
+#define glDrawBuffers wrap_glDrawBuffers
+#define glDrawBuffersEXT wrap_glDrawBuffersEXT
+#define glDrawBuffersIndexedEXT wrap_glDrawBuffersIndexedEXT
+#define glDrawBuffersNV wrap_glDrawBuffersNV
+#define glDrawElements wrap_glDrawElements
+#define glDrawElementsBaseVertex wrap_glDrawElementsBaseVertex
+#define glDrawElementsBaseVertexEXT wrap_glDrawElementsBaseVertexEXT
+#define glDrawElementsBaseVertexOES wrap_glDrawElementsBaseVertexOES
+#define glDrawElementsIndirect wrap_glDrawElementsIndirect
+#define glDrawElementsInstanced wrap_glDrawElementsInstanced
+#define glDrawElementsInstancedANGLE wrap_glDrawElementsInstancedANGLE
+#define glDrawElementsInstancedBaseInstanceEXT wrap_glDrawElementsInstancedBaseInstanceEXT
+#define glDrawElementsInstancedBaseVertex wrap_glDrawElementsInstancedBaseVertex
+#define glDrawElementsInstancedBaseVertexBaseInstanceEXT wrap_glDrawElementsInstancedBaseVertexBaseInstanceEXT
+#define glDrawElementsInstancedBaseVertexEXT wrap_glDrawElementsInstancedBaseVertexEXT
+#define glDrawElementsInstancedBaseVertexOES wrap_glDrawElementsInstancedBaseVertexOES
+#define glDrawElementsInstancedEXT wrap_glDrawElementsInstancedEXT
+#define glDrawElementsInstancedNV wrap_glDrawElementsInstancedNV
+#define glDrawRangeElements wrap_glDrawRangeElements
+#define glDrawRangeElementsBaseVertex wrap_glDrawRangeElementsBaseVertex
+#define glDrawRangeElementsBaseVertexEXT wrap_glDrawRangeElementsBaseVertexEXT
+#define glDrawRangeElementsBaseVertexOES wrap_glDrawRangeElementsBaseVertexOES
+#define glDrawTexfOES wrap_glDrawTexfOES
+#define glDrawTexfvOES wrap_glDrawTexfvOES
+#define glDrawTexiOES wrap_glDrawTexiOES
+#define glDrawTexivOES wrap_glDrawTexivOES
+#define glDrawTexsOES wrap_glDrawTexsOES
+#define glDrawTexsvOES wrap_glDrawTexsvOES
+#define glDrawTexxOES wrap_glDrawTexxOES
+#define glDrawTexxvOES wrap_glDrawTexxvOES
+#define glEGLImageTargetRenderbufferStorageOES wrap_glEGLImageTargetRenderbufferStorageOES
+#define glEGLImageTargetTexture2DOES wrap_glEGLImageTargetTexture2DOES
+#define glEnable wrap_glEnable
+#define glEnableClientState wrap_glEnableClientState
+#define glEnableDriverControlQCOM wrap_glEnableDriverControlQCOM
+#define glEnableVertexAttribArray wrap_glEnableVertexAttribArray
+#define glEnablei wrap_glEnablei
+#define glEnableiEXT wrap_glEnableiEXT
+#define glEnableiNV wrap_glEnableiNV
+#define glEnableiOES wrap_glEnableiOES
+#define glEndConditionalRenderNV wrap_glEndConditionalRenderNV
+#define glEndPerfMonitorAMD wrap_glEndPerfMonitorAMD
+#define glEndPerfQueryINTEL wrap_glEndPerfQueryINTEL
+#define glEndQuery wrap_glEndQuery
+#define glEndQueryEXT wrap_glEndQueryEXT
+#define glEndTilingQCOM wrap_glEndTilingQCOM
+#define glEndTransformFeedback wrap_glEndTransformFeedback
+#define glExtGetBufferPointervQCOM wrap_glExtGetBufferPointervQCOM
+#define glExtGetBuffersQCOM wrap_glExtGetBuffersQCOM
+#define glExtGetFramebuffersQCOM wrap_glExtGetFramebuffersQCOM
+#define glExtGetProgramBinarySourceQCOM wrap_glExtGetProgramBinarySourceQCOM
+#define glExtGetProgramsQCOM wrap_glExtGetProgramsQCOM
+#define glExtGetRenderbuffersQCOM wrap_glExtGetRenderbuffersQCOM
+#define glExtGetShadersQCOM wrap_glExtGetShadersQCOM
+#define glExtGetTexLevelParameterivQCOM wrap_glExtGetTexLevelParameterivQCOM
+#define glExtGetTexSubImageQCOM wrap_glExtGetTexSubImageQCOM
+#define glExtGetTexturesQCOM wrap_glExtGetTexturesQCOM
+#define glExtIsProgramBinaryQCOM wrap_glExtIsProgramBinaryQCOM
+#define glExtTexObjectStateOverrideiQCOM wrap_glExtTexObjectStateOverrideiQCOM
+#define glFenceSync wrap_glFenceSync
+#define glFenceSyncAPPLE wrap_glFenceSyncAPPLE
+#define glFinish wrap_glFinish
+#define glFinishFenceNV wrap_glFinishFenceNV
+#define glFlush wrap_glFlush
+#define glFlushMappedBufferRange wrap_glFlushMappedBufferRange
+#define glFlushMappedBufferRangeEXT wrap_glFlushMappedBufferRangeEXT
+#define glFogf wrap_glFogf
+#define glFogfv wrap_glFogfv
+#define glFogx wrap_glFogx
+#define glFogxOES wrap_glFogxOES
+#define glFogxv wrap_glFogxv
+#define glFogxvOES wrap_glFogxvOES
+#define glFragmentCoverageColorNV wrap_glFragmentCoverageColorNV
+#define glFramebufferParameteri wrap_glFramebufferParameteri
+#define glFramebufferRenderbuffer wrap_glFramebufferRenderbuffer
+#define glFramebufferRenderbufferOES wrap_glFramebufferRenderbufferOES
+#define glFramebufferSampleLocationsfvNV wrap_glFramebufferSampleLocationsfvNV
+#define glFramebufferTexture wrap_glFramebufferTexture
+#define glFramebufferTexture2D wrap_glFramebufferTexture2D
+#define glFramebufferTexture2DMultisampleEXT wrap_glFramebufferTexture2DMultisampleEXT
+#define glFramebufferTexture2DMultisampleIMG wrap_glFramebufferTexture2DMultisampleIMG
+#define glFramebufferTexture2DOES wrap_glFramebufferTexture2DOES
+#define glFramebufferTexture3DOES wrap_glFramebufferTexture3DOES
+#define glFramebufferTextureEXT wrap_glFramebufferTextureEXT
+#define glFramebufferTextureLayer wrap_glFramebufferTextureLayer
+#define glFramebufferTextureMultisampleMultiviewOVR wrap_glFramebufferTextureMultisampleMultiviewOVR
+#define glFramebufferTextureMultiviewOVR wrap_glFramebufferTextureMultiviewOVR
+#define glFramebufferTextureOES wrap_glFramebufferTextureOES
+#define glFrontFace wrap_glFrontFace
+#define glFrustumf wrap_glFrustumf
+#define glFrustumfOES wrap_glFrustumfOES
+#define glFrustumx wrap_glFrustumx
+#define glFrustumxOES wrap_glFrustumxOES
+#define glGenBuffers wrap_glGenBuffers
+#define glGenFencesNV wrap_glGenFencesNV
+#define glGenFramebuffers wrap_glGenFramebuffers
+#define glGenFramebuffersOES wrap_glGenFramebuffersOES
+#define glGenPathsNV wrap_glGenPathsNV
+#define glGenPerfMonitorsAMD wrap_glGenPerfMonitorsAMD
+#define glGenProgramPipelines wrap_glGenProgramPipelines
+#define glGenProgramPipelinesEXT wrap_glGenProgramPipelinesEXT
+#define glGenQueries wrap_glGenQueries
+#define glGenQueriesEXT wrap_glGenQueriesEXT
+#define glGenRenderbuffers wrap_glGenRenderbuffers
+#define glGenRenderbuffersOES wrap_glGenRenderbuffersOES
+#define glGenSamplers wrap_glGenSamplers
+#define glGenTextures wrap_glGenTextures
+#define glGenTransformFeedbacks wrap_glGenTransformFeedbacks
+#define glGenVertexArrays wrap_glGenVertexArrays
+#define glGenVertexArraysOES wrap_glGenVertexArraysOES
+#define glGenerateMipmap wrap_glGenerateMipmap
+#define glGenerateMipmapOES wrap_glGenerateMipmapOES
+#define glGetActiveAttrib wrap_glGetActiveAttrib
+#define glGetActiveUniform wrap_glGetActiveUniform
+#define glGetActiveUniformBlockName wrap_glGetActiveUniformBlockName
+#define glGetActiveUniformBlockiv wrap_glGetActiveUniformBlockiv
+#define glGetActiveUniformsiv wrap_glGetActiveUniformsiv
+#define glGetAttachedShaders wrap_glGetAttachedShaders
+#define glGetAttribLocation wrap_glGetAttribLocation
+#define glGetBooleani_v wrap_glGetBooleani_v
+#define glGetBooleanv wrap_glGetBooleanv
+#define glGetBufferParameteri64v wrap_glGetBufferParameteri64v
+#define glGetBufferParameteriv wrap_glGetBufferParameteriv
+#define glGetBufferPointerv wrap_glGetBufferPointerv
+#define glGetBufferPointervOES wrap_glGetBufferPointervOES
+#define glGetClipPlanef wrap_glGetClipPlanef
+#define glGetClipPlanefOES wrap_glGetClipPlanefOES
+#define glGetClipPlanex wrap_glGetClipPlanex
+#define glGetClipPlanexOES wrap_glGetClipPlanexOES
+#define glGetCoverageModulationTableNV wrap_glGetCoverageModulationTableNV
+#define glGetDebugMessageLog wrap_glGetDebugMessageLog
+#define glGetDebugMessageLogKHR wrap_glGetDebugMessageLogKHR
+#define glGetDriverControlStringQCOM wrap_glGetDriverControlStringQCOM
+#define glGetDriverControlsQCOM wrap_glGetDriverControlsQCOM
+#define glGetError wrap_glGetError
+#define glGetFenceivNV wrap_glGetFenceivNV
+#define glGetFirstPerfQueryIdINTEL wrap_glGetFirstPerfQueryIdINTEL
+#define glGetFixedv wrap_glGetFixedv
+#define glGetFixedvOES wrap_glGetFixedvOES
+#define glGetFloati_vNV wrap_glGetFloati_vNV
+#define glGetFloatv wrap_glGetFloatv
+#define glGetFragDataIndexEXT wrap_glGetFragDataIndexEXT
+#define glGetFragDataLocation wrap_glGetFragDataLocation
+#define glGetFramebufferAttachmentParameteriv wrap_glGetFramebufferAttachmentParameteriv
+#define glGetFramebufferAttachmentParameterivOES wrap_glGetFramebufferAttachmentParameterivOES
+#define glGetFramebufferParameteriv wrap_glGetFramebufferParameteriv
+#define glGetGraphicsResetStatus wrap_glGetGraphicsResetStatus
+#define glGetGraphicsResetStatusEXT wrap_glGetGraphicsResetStatusEXT
+#define glGetGraphicsResetStatusKHR wrap_glGetGraphicsResetStatusKHR
+#define glGetImageHandleNV wrap_glGetImageHandleNV
+#define glGetInteger64i_v wrap_glGetInteger64i_v
+#define glGetInteger64v wrap_glGetInteger64v
+#define glGetInteger64vAPPLE wrap_glGetInteger64vAPPLE
+#define glGetIntegeri_v wrap_glGetIntegeri_v
+#define glGetIntegeri_vEXT wrap_glGetIntegeri_vEXT
+#define glGetIntegerv wrap_glGetIntegerv
+#define glGetInternalformatSampleivNV wrap_glGetInternalformatSampleivNV
+#define glGetInternalformativ wrap_glGetInternalformativ
+#define glGetLightfv wrap_glGetLightfv
+#define glGetLightxv wrap_glGetLightxv
+#define glGetLightxvOES wrap_glGetLightxvOES
+#define glGetMaterialfv wrap_glGetMaterialfv
+#define glGetMaterialxv wrap_glGetMaterialxv
+#define glGetMaterialxvOES wrap_glGetMaterialxvOES
+#define glGetMultisamplefv wrap_glGetMultisamplefv
+#define glGetNextPerfQueryIdINTEL wrap_glGetNextPerfQueryIdINTEL
+#define glGetObjectLabel wrap_glGetObjectLabel
+#define glGetObjectLabelEXT wrap_glGetObjectLabelEXT
+#define glGetObjectLabelKHR wrap_glGetObjectLabelKHR
+#define glGetObjectPtrLabel wrap_glGetObjectPtrLabel
+#define glGetObjectPtrLabelKHR wrap_glGetObjectPtrLabelKHR
+#define glGetPathCommandsNV wrap_glGetPathCommandsNV
+#define glGetPathCoordsNV wrap_glGetPathCoordsNV
+#define glGetPathDashArrayNV wrap_glGetPathDashArrayNV
+#define glGetPathLengthNV wrap_glGetPathLengthNV
+#define glGetPathMetricRangeNV wrap_glGetPathMetricRangeNV
+#define glGetPathMetricsNV wrap_glGetPathMetricsNV
+#define glGetPathParameterfvNV wrap_glGetPathParameterfvNV
+#define glGetPathParameterivNV wrap_glGetPathParameterivNV
+#define glGetPathSpacingNV wrap_glGetPathSpacingNV
+#define glGetPerfCounterInfoINTEL wrap_glGetPerfCounterInfoINTEL
+#define glGetPerfMonitorCounterDataAMD wrap_glGetPerfMonitorCounterDataAMD
+#define glGetPerfMonitorCounterInfoAMD wrap_glGetPerfMonitorCounterInfoAMD
+#define glGetPerfMonitorCounterStringAMD wrap_glGetPerfMonitorCounterStringAMD
+#define glGetPerfMonitorCountersAMD wrap_glGetPerfMonitorCountersAMD
+#define glGetPerfMonitorGroupStringAMD wrap_glGetPerfMonitorGroupStringAMD
+#define glGetPerfMonitorGroupsAMD wrap_glGetPerfMonitorGroupsAMD
+#define glGetPerfQueryDataINTEL wrap_glGetPerfQueryDataINTEL
+#define glGetPerfQueryIdByNameINTEL wrap_glGetPerfQueryIdByNameINTEL
+#define glGetPerfQueryInfoINTEL wrap_glGetPerfQueryInfoINTEL
+#define glGetPointerv wrap_glGetPointerv
+#define glGetPointervKHR wrap_glGetPointervKHR
+#define glGetProgramBinary wrap_glGetProgramBinary
+#define glGetProgramBinaryOES wrap_glGetProgramBinaryOES
+#define glGetProgramInfoLog wrap_glGetProgramInfoLog
+#define glGetProgramInterfaceiv wrap_glGetProgramInterfaceiv
+#define glGetProgramPipelineInfoLog wrap_glGetProgramPipelineInfoLog
+#define glGetProgramPipelineInfoLogEXT wrap_glGetProgramPipelineInfoLogEXT
+#define glGetProgramPipelineiv wrap_glGetProgramPipelineiv
+#define glGetProgramPipelineivEXT wrap_glGetProgramPipelineivEXT
+#define glGetProgramResourceIndex wrap_glGetProgramResourceIndex
+#define glGetProgramResourceLocation wrap_glGetProgramResourceLocation
+#define glGetProgramResourceLocationIndexEXT wrap_glGetProgramResourceLocationIndexEXT
+#define glGetProgramResourceName wrap_glGetProgramResourceName
+#define glGetProgramResourcefvNV wrap_glGetProgramResourcefvNV
+#define glGetProgramResourceiv wrap_glGetProgramResourceiv
+#define glGetProgramiv wrap_glGetProgramiv
+#define glGetQueryObjecti64vEXT wrap_glGetQueryObjecti64vEXT
+#define glGetQueryObjectivEXT wrap_glGetQueryObjectivEXT
+#define glGetQueryObjectui64vEXT wrap_glGetQueryObjectui64vEXT
+#define glGetQueryObjectuiv wrap_glGetQueryObjectuiv
+#define glGetQueryObjectuivEXT wrap_glGetQueryObjectuivEXT
+#define glGetQueryiv wrap_glGetQueryiv
+#define glGetQueryivEXT wrap_glGetQueryivEXT
+#define glGetRenderbufferParameteriv wrap_glGetRenderbufferParameteriv
+#define glGetRenderbufferParameterivOES wrap_glGetRenderbufferParameterivOES
+#define glGetSamplerParameterIiv wrap_glGetSamplerParameterIiv
+#define glGetSamplerParameterIivEXT wrap_glGetSamplerParameterIivEXT
+#define glGetSamplerParameterIivOES wrap_glGetSamplerParameterIivOES
+#define glGetSamplerParameterIuiv wrap_glGetSamplerParameterIuiv
+#define glGetSamplerParameterIuivEXT wrap_glGetSamplerParameterIuivEXT
+#define glGetSamplerParameterIuivOES wrap_glGetSamplerParameterIuivOES
+#define glGetSamplerParameterfv wrap_glGetSamplerParameterfv
+#define glGetSamplerParameteriv wrap_glGetSamplerParameteriv
+#define glGetShaderInfoLog wrap_glGetShaderInfoLog
+#define glGetShaderPrecisionFormat wrap_glGetShaderPrecisionFormat
+#define glGetShaderSource wrap_glGetShaderSource
+#define glGetShaderiv wrap_glGetShaderiv
+#define glGetString wrap_glGetString
+#define glGetStringi wrap_glGetStringi
+#define glGetSynciv wrap_glGetSynciv
+#define glGetSyncivAPPLE wrap_glGetSyncivAPPLE
+#define glGetTexEnvfv wrap_glGetTexEnvfv
+#define glGetTexEnviv wrap_glGetTexEnviv
+#define glGetTexEnvxv wrap_glGetTexEnvxv
+#define glGetTexEnvxvOES wrap_glGetTexEnvxvOES
+#define glGetTexGenfvOES wrap_glGetTexGenfvOES
+#define glGetTexGenivOES wrap_glGetTexGenivOES
+#define glGetTexGenxvOES wrap_glGetTexGenxvOES
+#define glGetTexLevelParameterfv wrap_glGetTexLevelParameterfv
+#define glGetTexLevelParameteriv wrap_glGetTexLevelParameteriv
+#define glGetTexParameterIiv wrap_glGetTexParameterIiv
+#define glGetTexParameterIivEXT wrap_glGetTexParameterIivEXT
+#define glGetTexParameterIivOES wrap_glGetTexParameterIivOES
+#define glGetTexParameterIuiv wrap_glGetTexParameterIuiv
+#define glGetTexParameterIuivEXT wrap_glGetTexParameterIuivEXT
+#define glGetTexParameterIuivOES wrap_glGetTexParameterIuivOES
+#define glGetTexParameterfv wrap_glGetTexParameterfv
+#define glGetTexParameteriv wrap_glGetTexParameteriv
+#define glGetTexParameterxv wrap_glGetTexParameterxv
+#define glGetTexParameterxvOES wrap_glGetTexParameterxvOES
+#define glGetTextureHandleNV wrap_glGetTextureHandleNV
+#define glGetTextureSamplerHandleNV wrap_glGetTextureSamplerHandleNV
+#define glGetTransformFeedbackVarying wrap_glGetTransformFeedbackVarying
+#define glGetTranslatedShaderSourceANGLE wrap_glGetTranslatedShaderSourceANGLE
+#define glGetUniformBlockIndex wrap_glGetUniformBlockIndex
+#define glGetUniformIndices wrap_glGetUniformIndices
+#define glGetUniformLocation wrap_glGetUniformLocation
+#define glGetUniformfv wrap_glGetUniformfv
+#define glGetUniformiv wrap_glGetUniformiv
+#define glGetUniformuiv wrap_glGetUniformuiv
+#define glGetVertexAttribIiv wrap_glGetVertexAttribIiv
+#define glGetVertexAttribIuiv wrap_glGetVertexAttribIuiv
+#define glGetVertexAttribPointerv wrap_glGetVertexAttribPointerv
+#define glGetVertexAttribfv wrap_glGetVertexAttribfv
+#define glGetVertexAttribiv wrap_glGetVertexAttribiv
+#define glGetnUniformfv wrap_glGetnUniformfv
+#define glGetnUniformfvEXT wrap_glGetnUniformfvEXT
+#define glGetnUniformfvKHR wrap_glGetnUniformfvKHR
+#define glGetnUniformiv wrap_glGetnUniformiv
+#define glGetnUniformivEXT wrap_glGetnUniformivEXT
+#define glGetnUniformivKHR wrap_glGetnUniformivKHR
+#define glGetnUniformuiv wrap_glGetnUniformuiv
+#define glGetnUniformuivKHR wrap_glGetnUniformuivKHR
+#define glHint wrap_glHint
+#define glInsertEventMarkerEXT wrap_glInsertEventMarkerEXT
+#define glInterpolatePathsNV wrap_glInterpolatePathsNV
+#define glInvalidateFramebuffer wrap_glInvalidateFramebuffer
+#define glInvalidateSubFramebuffer wrap_glInvalidateSubFramebuffer
+#define glIsBuffer wrap_glIsBuffer
+#define glIsEnabled wrap_glIsEnabled
+#define glIsEnabledi wrap_glIsEnabledi
+#define glIsEnablediEXT wrap_glIsEnablediEXT
+#define glIsEnablediNV wrap_glIsEnablediNV
+#define glIsEnablediOES wrap_glIsEnablediOES
+#define glIsFenceNV wrap_glIsFenceNV
+#define glIsFramebuffer wrap_glIsFramebuffer
+#define glIsFramebufferOES wrap_glIsFramebufferOES
+#define glIsImageHandleResidentNV wrap_glIsImageHandleResidentNV
+#define glIsPathNV wrap_glIsPathNV
+#define glIsPointInFillPathNV wrap_glIsPointInFillPathNV
+#define glIsPointInStrokePathNV wrap_glIsPointInStrokePathNV
+#define glIsProgram wrap_glIsProgram
+#define glIsProgramPipeline wrap_glIsProgramPipeline
+#define glIsProgramPipelineEXT wrap_glIsProgramPipelineEXT
+#define glIsQuery wrap_glIsQuery
+#define glIsQueryEXT wrap_glIsQueryEXT
+#define glIsRenderbuffer wrap_glIsRenderbuffer
+#define glIsRenderbufferOES wrap_glIsRenderbufferOES
+#define glIsSampler wrap_glIsSampler
+#define glIsShader wrap_glIsShader
+#define glIsSync wrap_glIsSync
+#define glIsSyncAPPLE wrap_glIsSyncAPPLE
+#define glIsTexture wrap_glIsTexture
+#define glIsTextureHandleResidentNV wrap_glIsTextureHandleResidentNV
+#define glIsTransformFeedback wrap_glIsTransformFeedback
+#define glIsVertexArray wrap_glIsVertexArray
+#define glIsVertexArrayOES wrap_glIsVertexArrayOES
+#define glLabelObjectEXT wrap_glLabelObjectEXT
+#define glLightModelf wrap_glLightModelf
+#define glLightModelfv wrap_glLightModelfv
+#define glLightModelx wrap_glLightModelx
+#define glLightModelxOES wrap_glLightModelxOES
+#define glLightModelxv wrap_glLightModelxv
+#define glLightModelxvOES wrap_glLightModelxvOES
+#define glLightf wrap_glLightf
+#define glLightfv wrap_glLightfv
+#define glLightx wrap_glLightx
+#define glLightxOES wrap_glLightxOES
+#define glLightxv wrap_glLightxv
+#define glLightxvOES wrap_glLightxvOES
+#define glLineWidth wrap_glLineWidth
+#define glLineWidthx wrap_glLineWidthx
+#define glLineWidthxOES wrap_glLineWidthxOES
+#define glLinkProgram wrap_glLinkProgram
+#define glLoadIdentity wrap_glLoadIdentity
+#define glLoadMatrixf wrap_glLoadMatrixf
+#define glLoadMatrixx wrap_glLoadMatrixx
+#define glLoadMatrixxOES wrap_glLoadMatrixxOES
+#define glLoadPaletteFromModelViewMatrixOES wrap_glLoadPaletteFromModelViewMatrixOES
+#define glLogicOp wrap_glLogicOp
+#define glMakeImageHandleNonResidentNV wrap_glMakeImageHandleNonResidentNV
+#define glMakeImageHandleResidentNV wrap_glMakeImageHandleResidentNV
+#define glMakeTextureHandleNonResidentNV wrap_glMakeTextureHandleNonResidentNV
+#define glMakeTextureHandleResidentNV wrap_glMakeTextureHandleResidentNV
+#define glMapBufferOES wrap_glMapBufferOES
+#define glMapBufferRange wrap_glMapBufferRange
+#define glMapBufferRangeEXT wrap_glMapBufferRangeEXT
+#define glMaterialf wrap_glMaterialf
+#define glMaterialfv wrap_glMaterialfv
+#define glMaterialx wrap_glMaterialx
+#define glMaterialxOES wrap_glMaterialxOES
+#define glMaterialxv wrap_glMaterialxv
+#define glMaterialxvOES wrap_glMaterialxvOES
+#define glMatrixIndexPointerOES wrap_glMatrixIndexPointerOES
+#define glMatrixLoad3x2fNV wrap_glMatrixLoad3x2fNV
+#define glMatrixLoad3x3fNV wrap_glMatrixLoad3x3fNV
+#define glMatrixLoadTranspose3x3fNV wrap_glMatrixLoadTranspose3x3fNV
+#define glMatrixMode wrap_glMatrixMode
+#define glMatrixMult3x2fNV wrap_glMatrixMult3x2fNV
+#define glMatrixMult3x3fNV wrap_glMatrixMult3x3fNV
+#define glMatrixMultTranspose3x3fNV wrap_glMatrixMultTranspose3x3fNV
+#define glMemoryBarrier wrap_glMemoryBarrier
+#define glMemoryBarrierByRegion wrap_glMemoryBarrierByRegion
+#define glMinSampleShading wrap_glMinSampleShading
+#define glMinSampleShadingOES wrap_glMinSampleShadingOES
+#define glMultMatrixf wrap_glMultMatrixf
+#define glMultMatrixx wrap_glMultMatrixx
+#define glMultMatrixxOES wrap_glMultMatrixxOES
+#define glMultiDrawArraysEXT wrap_glMultiDrawArraysEXT
+#define glMultiDrawArraysIndirectEXT wrap_glMultiDrawArraysIndirectEXT
+#define glMultiDrawElementsBaseVertexEXT wrap_glMultiDrawElementsBaseVertexEXT
+#define glMultiDrawElementsBaseVertexOES wrap_glMultiDrawElementsBaseVertexOES
+#define glMultiDrawElementsEXT wrap_glMultiDrawElementsEXT
+#define glMultiDrawElementsIndirectEXT wrap_glMultiDrawElementsIndirectEXT
+#define glMultiTexCoord4f wrap_glMultiTexCoord4f
+#define glMultiTexCoord4x wrap_glMultiTexCoord4x
+#define glMultiTexCoord4xOES wrap_glMultiTexCoord4xOES
+#define glNamedFramebufferSampleLocationsfvNV wrap_glNamedFramebufferSampleLocationsfvNV
+#define glNormal3f wrap_glNormal3f
+#define glNormal3x wrap_glNormal3x
+#define glNormal3xOES wrap_glNormal3xOES
+#define glNormalPointer wrap_glNormalPointer
+#define glObjectLabel wrap_glObjectLabel
+#define glObjectLabelKHR wrap_glObjectLabelKHR
+#define glObjectPtrLabel wrap_glObjectPtrLabel
+#define glObjectPtrLabelKHR wrap_glObjectPtrLabelKHR
+#define glOrthof wrap_glOrthof
+#define glOrthofOES wrap_glOrthofOES
+#define glOrthox wrap_glOrthox
+#define glOrthoxOES wrap_glOrthoxOES
+#define glPatchParameteri wrap_glPatchParameteri
+#define glPatchParameteriEXT wrap_glPatchParameteriEXT
+#define glPatchParameteriOES wrap_glPatchParameteriOES
+#define glPathCommandsNV wrap_glPathCommandsNV
+#define glPathCoordsNV wrap_glPathCoordsNV
+#define glPathCoverDepthFuncNV wrap_glPathCoverDepthFuncNV
+#define glPathDashArrayNV wrap_glPathDashArrayNV
+#define glPathGlyphIndexArrayNV wrap_glPathGlyphIndexArrayNV
+#define glPathGlyphIndexRangeNV wrap_glPathGlyphIndexRangeNV
+#define glPathGlyphRangeNV wrap_glPathGlyphRangeNV
+#define glPathGlyphsNV wrap_glPathGlyphsNV
+#define glPathMemoryGlyphIndexArrayNV wrap_glPathMemoryGlyphIndexArrayNV
+#define glPathParameterfNV wrap_glPathParameterfNV
+#define glPathParameterfvNV wrap_glPathParameterfvNV
+#define glPathParameteriNV wrap_glPathParameteriNV
+#define glPathParameterivNV wrap_glPathParameterivNV
+#define glPathStencilDepthOffsetNV wrap_glPathStencilDepthOffsetNV
+#define glPathStencilFuncNV wrap_glPathStencilFuncNV
+#define glPathStringNV wrap_glPathStringNV
+#define glPathSubCommandsNV wrap_glPathSubCommandsNV
+#define glPathSubCoordsNV wrap_glPathSubCoordsNV
+#define glPauseTransformFeedback wrap_glPauseTransformFeedback
+#define glPixelStorei wrap_glPixelStorei
+#define glPointAlongPathNV wrap_glPointAlongPathNV
+#define glPointParameterf wrap_glPointParameterf
+#define glPointParameterfv wrap_glPointParameterfv
+#define glPointParameterx wrap_glPointParameterx
+#define glPointParameterxOES wrap_glPointParameterxOES
+#define glPointParameterxv wrap_glPointParameterxv
+#define glPointParameterxvOES wrap_glPointParameterxvOES
+#define glPointSize wrap_glPointSize
+#define glPointSizePointerOES wrap_glPointSizePointerOES
+#define glPointSizex wrap_glPointSizex
+#define glPointSizexOES wrap_glPointSizexOES
+#define glPolygonModeNV wrap_glPolygonModeNV
+#define glPolygonOffset wrap_glPolygonOffset
+#define glPolygonOffsetx wrap_glPolygonOffsetx
+#define glPolygonOffsetxOES wrap_glPolygonOffsetxOES
+#define glPopDebugGroup wrap_glPopDebugGroup
+#define glPopDebugGroupKHR wrap_glPopDebugGroupKHR
+#define glPopGroupMarkerEXT wrap_glPopGroupMarkerEXT
+#define glPopMatrix wrap_glPopMatrix
+#define glPrimitiveBoundingBox wrap_glPrimitiveBoundingBox
+#define glPrimitiveBoundingBoxEXT wrap_glPrimitiveBoundingBoxEXT
+#define glPrimitiveBoundingBoxOES wrap_glPrimitiveBoundingBoxOES
+#define glProgramBinary wrap_glProgramBinary
+#define glProgramBinaryOES wrap_glProgramBinaryOES
+#define glProgramParameteri wrap_glProgramParameteri
+#define glProgramParameteriEXT wrap_glProgramParameteriEXT
+#define glProgramPathFragmentInputGenNV wrap_glProgramPathFragmentInputGenNV
+#define glProgramUniform1f wrap_glProgramUniform1f
+#define glProgramUniform1fEXT wrap_glProgramUniform1fEXT
+#define glProgramUniform1fv wrap_glProgramUniform1fv
+#define glProgramUniform1fvEXT wrap_glProgramUniform1fvEXT
+#define glProgramUniform1i wrap_glProgramUniform1i
+#define glProgramUniform1iEXT wrap_glProgramUniform1iEXT
+#define glProgramUniform1iv wrap_glProgramUniform1iv
+#define glProgramUniform1ivEXT wrap_glProgramUniform1ivEXT
+#define glProgramUniform1ui wrap_glProgramUniform1ui
+#define glProgramUniform1uiEXT wrap_glProgramUniform1uiEXT
+#define glProgramUniform1uiv wrap_glProgramUniform1uiv
+#define glProgramUniform1uivEXT wrap_glProgramUniform1uivEXT
+#define glProgramUniform2f wrap_glProgramUniform2f
+#define glProgramUniform2fEXT wrap_glProgramUniform2fEXT
+#define glProgramUniform2fv wrap_glProgramUniform2fv
+#define glProgramUniform2fvEXT wrap_glProgramUniform2fvEXT
+#define glProgramUniform2i wrap_glProgramUniform2i
+#define glProgramUniform2iEXT wrap_glProgramUniform2iEXT
+#define glProgramUniform2iv wrap_glProgramUniform2iv
+#define glProgramUniform2ivEXT wrap_glProgramUniform2ivEXT
+#define glProgramUniform2ui wrap_glProgramUniform2ui
+#define glProgramUniform2uiEXT wrap_glProgramUniform2uiEXT
+#define glProgramUniform2uiv wrap_glProgramUniform2uiv
+#define glProgramUniform2uivEXT wrap_glProgramUniform2uivEXT
+#define glProgramUniform3f wrap_glProgramUniform3f
+#define glProgramUniform3fEXT wrap_glProgramUniform3fEXT
+#define glProgramUniform3fv wrap_glProgramUniform3fv
+#define glProgramUniform3fvEXT wrap_glProgramUniform3fvEXT
+#define glProgramUniform3i wrap_glProgramUniform3i
+#define glProgramUniform3iEXT wrap_glProgramUniform3iEXT
+#define glProgramUniform3iv wrap_glProgramUniform3iv
+#define glProgramUniform3ivEXT wrap_glProgramUniform3ivEXT
+#define glProgramUniform3ui wrap_glProgramUniform3ui
+#define glProgramUniform3uiEXT wrap_glProgramUniform3uiEXT
+#define glProgramUniform3uiv wrap_glProgramUniform3uiv
+#define glProgramUniform3uivEXT wrap_glProgramUniform3uivEXT
+#define glProgramUniform4f wrap_glProgramUniform4f
+#define glProgramUniform4fEXT wrap_glProgramUniform4fEXT
+#define glProgramUniform4fv wrap_glProgramUniform4fv
+#define glProgramUniform4fvEXT wrap_glProgramUniform4fvEXT
+#define glProgramUniform4i wrap_glProgramUniform4i
+#define glProgramUniform4iEXT wrap_glProgramUniform4iEXT
+#define glProgramUniform4iv wrap_glProgramUniform4iv
+#define glProgramUniform4ivEXT wrap_glProgramUniform4ivEXT
+#define glProgramUniform4ui wrap_glProgramUniform4ui
+#define glProgramUniform4uiEXT wrap_glProgramUniform4uiEXT
+#define glProgramUniform4uiv wrap_glProgramUniform4uiv
+#define glProgramUniform4uivEXT wrap_glProgramUniform4uivEXT
+#define glProgramUniformHandleui64NV wrap_glProgramUniformHandleui64NV
+#define glProgramUniformHandleui64vNV wrap_glProgramUniformHandleui64vNV
+#define glProgramUniformMatrix2fv wrap_glProgramUniformMatrix2fv
+#define glProgramUniformMatrix2fvEXT wrap_glProgramUniformMatrix2fvEXT
+#define glProgramUniformMatrix2x3fv wrap_glProgramUniformMatrix2x3fv
+#define glProgramUniformMatrix2x3fvEXT wrap_glProgramUniformMatrix2x3fvEXT
+#define glProgramUniformMatrix2x4fv wrap_glProgramUniformMatrix2x4fv
+#define glProgramUniformMatrix2x4fvEXT wrap_glProgramUniformMatrix2x4fvEXT
+#define glProgramUniformMatrix3fv wrap_glProgramUniformMatrix3fv
+#define glProgramUniformMatrix3fvEXT wrap_glProgramUniformMatrix3fvEXT
+#define glProgramUniformMatrix3x2fv wrap_glProgramUniformMatrix3x2fv
+#define glProgramUniformMatrix3x2fvEXT wrap_glProgramUniformMatrix3x2fvEXT
+#define glProgramUniformMatrix3x4fv wrap_glProgramUniformMatrix3x4fv
+#define glProgramUniformMatrix3x4fvEXT wrap_glProgramUniformMatrix3x4fvEXT
+#define glProgramUniformMatrix4fv wrap_glProgramUniformMatrix4fv
+#define glProgramUniformMatrix4fvEXT wrap_glProgramUniformMatrix4fvEXT
+#define glProgramUniformMatrix4x2fv wrap_glProgramUniformMatrix4x2fv
+#define glProgramUniformMatrix4x2fvEXT wrap_glProgramUniformMatrix4x2fvEXT
+#define glProgramUniformMatrix4x3fv wrap_glProgramUniformMatrix4x3fv
+#define glProgramUniformMatrix4x3fvEXT wrap_glProgramUniformMatrix4x3fvEXT
+#define glPushDebugGroup wrap_glPushDebugGroup
+#define glPushDebugGroupKHR wrap_glPushDebugGroupKHR
+#define glPushGroupMarkerEXT wrap_glPushGroupMarkerEXT
+#define glPushMatrix wrap_glPushMatrix
+#define glQueryCounterEXT wrap_glQueryCounterEXT
+#define glQueryMatrixxOES wrap_glQueryMatrixxOES
+#define glRasterSamplesEXT wrap_glRasterSamplesEXT
+#define glReadBuffer wrap_glReadBuffer
+#define glReadBufferIndexedEXT wrap_glReadBufferIndexedEXT
+#define glReadBufferNV wrap_glReadBufferNV
+#define glReadPixels wrap_glReadPixels
+#define glReadnPixels wrap_glReadnPixels
+#define glReadnPixelsEXT wrap_glReadnPixelsEXT
+#define glReadnPixelsKHR wrap_glReadnPixelsKHR
+#define glReleaseShaderCompiler wrap_glReleaseShaderCompiler
+#define glRenderbufferStorage wrap_glRenderbufferStorage
+#define glRenderbufferStorageMultisample wrap_glRenderbufferStorageMultisample
+#define glRenderbufferStorageMultisampleANGLE wrap_glRenderbufferStorageMultisampleANGLE
+#define glRenderbufferStorageMultisampleAPPLE wrap_glRenderbufferStorageMultisampleAPPLE
+#define glRenderbufferStorageMultisampleEXT wrap_glRenderbufferStorageMultisampleEXT
+#define glRenderbufferStorageMultisampleIMG wrap_glRenderbufferStorageMultisampleIMG
+#define glRenderbufferStorageMultisampleNV wrap_glRenderbufferStorageMultisampleNV
+#define glRenderbufferStorageOES wrap_glRenderbufferStorageOES
+#define glResolveDepthValuesNV wrap_glResolveDepthValuesNV
+#define glResolveMultisampleFramebufferAPPLE wrap_glResolveMultisampleFramebufferAPPLE
+#define glResumeTransformFeedback wrap_glResumeTransformFeedback
+#define glRotatef wrap_glRotatef
+#define glRotatex wrap_glRotatex
+#define glRotatexOES wrap_glRotatexOES
+#define glSampleCoverage wrap_glSampleCoverage
+#define glSampleCoveragex wrap_glSampleCoveragex
+#define glSampleCoveragexOES wrap_glSampleCoveragexOES
+#define glSampleMaski wrap_glSampleMaski
+#define glSamplerParameterIiv wrap_glSamplerParameterIiv
+#define glSamplerParameterIivEXT wrap_glSamplerParameterIivEXT
+#define glSamplerParameterIivOES wrap_glSamplerParameterIivOES
+#define glSamplerParameterIuiv wrap_glSamplerParameterIuiv
+#define glSamplerParameterIuivEXT wrap_glSamplerParameterIuivEXT
+#define glSamplerParameterIuivOES wrap_glSamplerParameterIuivOES
+#define glSamplerParameterf wrap_glSamplerParameterf
+#define glSamplerParameterfv wrap_glSamplerParameterfv
+#define glSamplerParameteri wrap_glSamplerParameteri
+#define glSamplerParameteriv wrap_glSamplerParameteriv
+#define glScalef wrap_glScalef
+#define glScalex wrap_glScalex
+#define glScalexOES wrap_glScalexOES
+#define glScissor wrap_glScissor
+#define glScissorArrayvNV wrap_glScissorArrayvNV
+#define glScissorIndexedNV wrap_glScissorIndexedNV
+#define glScissorIndexedvNV wrap_glScissorIndexedvNV
+#define glSelectPerfMonitorCountersAMD wrap_glSelectPerfMonitorCountersAMD
+#define glSetFenceNV wrap_glSetFenceNV
+#define glShadeModel wrap_glShadeModel
+#define glShaderBinary wrap_glShaderBinary
+#define glShaderSource wrap_glShaderSource
+#define glStartTilingQCOM wrap_glStartTilingQCOM
+#define glStencilFillPathInstancedNV wrap_glStencilFillPathInstancedNV
+#define glStencilFillPathNV wrap_glStencilFillPathNV
+#define glStencilFunc wrap_glStencilFunc
+#define glStencilFuncSeparate wrap_glStencilFuncSeparate
+#define glStencilMask wrap_glStencilMask
+#define glStencilMaskSeparate wrap_glStencilMaskSeparate
+#define glStencilOp wrap_glStencilOp
+#define glStencilOpSeparate wrap_glStencilOpSeparate
+#define glStencilStrokePathInstancedNV wrap_glStencilStrokePathInstancedNV
+#define glStencilStrokePathNV wrap_glStencilStrokePathNV
+#define glStencilThenCoverFillPathInstancedNV wrap_glStencilThenCoverFillPathInstancedNV
+#define glStencilThenCoverFillPathNV wrap_glStencilThenCoverFillPathNV
+#define glStencilThenCoverStrokePathInstancedNV wrap_glStencilThenCoverStrokePathInstancedNV
+#define glStencilThenCoverStrokePathNV wrap_glStencilThenCoverStrokePathNV
+#define glSubpixelPrecisionBiasNV wrap_glSubpixelPrecisionBiasNV
+#define glTestFenceNV wrap_glTestFenceNV
+#define glTexBuffer wrap_glTexBuffer
+#define glTexBufferEXT wrap_glTexBufferEXT
+#define glTexBufferOES wrap_glTexBufferOES
+#define glTexBufferRange wrap_glTexBufferRange
+#define glTexBufferRangeEXT wrap_glTexBufferRangeEXT
+#define glTexBufferRangeOES wrap_glTexBufferRangeOES
+#define glTexCoordPointer wrap_glTexCoordPointer
+#define glTexEnvf wrap_glTexEnvf
+#define glTexEnvfv wrap_glTexEnvfv
+#define glTexEnvi wrap_glTexEnvi
+#define glTexEnviv wrap_glTexEnviv
+#define glTexEnvx wrap_glTexEnvx
+#define glTexEnvxOES wrap_glTexEnvxOES
+#define glTexEnvxv wrap_glTexEnvxv
+#define glTexEnvxvOES wrap_glTexEnvxvOES
+#define glTexGenfOES wrap_glTexGenfOES
+#define glTexGenfvOES wrap_glTexGenfvOES
+#define glTexGeniOES wrap_glTexGeniOES
+#define glTexGenivOES wrap_glTexGenivOES
+#define glTexGenxOES wrap_glTexGenxOES
+#define glTexGenxvOES wrap_glTexGenxvOES
+#define glTexImage2D wrap_glTexImage2D
+#define glTexImage3D wrap_glTexImage3D
+#define glTexImage3DOES wrap_glTexImage3DOES
+#define glTexPageCommitmentEXT wrap_glTexPageCommitmentEXT
+#define glTexParameterIiv wrap_glTexParameterIiv
+#define glTexParameterIivEXT wrap_glTexParameterIivEXT
+#define glTexParameterIivOES wrap_glTexParameterIivOES
+#define glTexParameterIuiv wrap_glTexParameterIuiv
+#define glTexParameterIuivEXT wrap_glTexParameterIuivEXT
+#define glTexParameterIuivOES wrap_glTexParameterIuivOES
+#define glTexParameterf wrap_glTexParameterf
+#define glTexParameterfv wrap_glTexParameterfv
+#define glTexParameteri wrap_glTexParameteri
+#define glTexParameteriv wrap_glTexParameteriv
+#define glTexParameterx wrap_glTexParameterx
+#define glTexParameterxOES wrap_glTexParameterxOES
+#define glTexParameterxv wrap_glTexParameterxv
+#define glTexParameterxvOES wrap_glTexParameterxvOES
+#define glTexStorage1DEXT wrap_glTexStorage1DEXT
+#define glTexStorage2D wrap_glTexStorage2D
+#define glTexStorage2DEXT wrap_glTexStorage2DEXT
+#define glTexStorage2DMultisample wrap_glTexStorage2DMultisample
+#define glTexStorage3D wrap_glTexStorage3D
+#define glTexStorage3DEXT wrap_glTexStorage3DEXT
+#define glTexStorage3DMultisample wrap_glTexStorage3DMultisample
+#define glTexStorage3DMultisampleOES wrap_glTexStorage3DMultisampleOES
+#define glTexSubImage2D wrap_glTexSubImage2D
+#define glTexSubImage3D wrap_glTexSubImage3D
+#define glTexSubImage3DOES wrap_glTexSubImage3DOES
+#define glTextureStorage1DEXT wrap_glTextureStorage1DEXT
+#define glTextureStorage2DEXT wrap_glTextureStorage2DEXT
+#define glTextureStorage3DEXT wrap_glTextureStorage3DEXT
+#define glTextureViewEXT wrap_glTextureViewEXT
+#define glTextureViewOES wrap_glTextureViewOES
+#define glTransformFeedbackVaryings wrap_glTransformFeedbackVaryings
+#define glTransformPathNV wrap_glTransformPathNV
+#define glTranslatef wrap_glTranslatef
+#define glTranslatex wrap_glTranslatex
+#define glTranslatexOES wrap_glTranslatexOES
+#define glUniform1f wrap_glUniform1f
+#define glUniform1fv wrap_glUniform1fv
+#define glUniform1i wrap_glUniform1i
+#define glUniform1iv wrap_glUniform1iv
+#define glUniform1ui wrap_glUniform1ui
+#define glUniform1uiv wrap_glUniform1uiv
+#define glUniform2f wrap_glUniform2f
+#define glUniform2fv wrap_glUniform2fv
+#define glUniform2i wrap_glUniform2i
+#define glUniform2iv wrap_glUniform2iv
+#define glUniform2ui wrap_glUniform2ui
+#define glUniform2uiv wrap_glUniform2uiv
+#define glUniform3f wrap_glUniform3f
+#define glUniform3fv wrap_glUniform3fv
+#define glUniform3i wrap_glUniform3i
+#define glUniform3iv wrap_glUniform3iv
+#define glUniform3ui wrap_glUniform3ui
+#define glUniform3uiv wrap_glUniform3uiv
+#define glUniform4f wrap_glUniform4f
+#define glUniform4fv wrap_glUniform4fv
+#define glUniform4i wrap_glUniform4i
+#define glUniform4iv wrap_glUniform4iv
+#define glUniform4ui wrap_glUniform4ui
+#define glUniform4uiv wrap_glUniform4uiv
+#define glUniformBlockBinding wrap_glUniformBlockBinding
+#define glUniformHandleui64NV wrap_glUniformHandleui64NV
+#define glUniformHandleui64vNV wrap_glUniformHandleui64vNV
+#define glUniformMatrix2fv wrap_glUniformMatrix2fv
+#define glUniformMatrix2x3fv wrap_glUniformMatrix2x3fv
+#define glUniformMatrix2x3fvNV wrap_glUniformMatrix2x3fvNV
+#define glUniformMatrix2x4fv wrap_glUniformMatrix2x4fv
+#define glUniformMatrix2x4fvNV wrap_glUniformMatrix2x4fvNV
+#define glUniformMatrix3fv wrap_glUniformMatrix3fv
+#define glUniformMatrix3x2fv wrap_glUniformMatrix3x2fv
+#define glUniformMatrix3x2fvNV wrap_glUniformMatrix3x2fvNV
+#define glUniformMatrix3x4fv wrap_glUniformMatrix3x4fv
+#define glUniformMatrix3x4fvNV wrap_glUniformMatrix3x4fvNV
+#define glUniformMatrix4fv wrap_glUniformMatrix4fv
+#define glUniformMatrix4x2fv wrap_glUniformMatrix4x2fv
+#define glUniformMatrix4x2fvNV wrap_glUniformMatrix4x2fvNV
+#define glUniformMatrix4x3fv wrap_glUniformMatrix4x3fv
+#define glUniformMatrix4x3fvNV wrap_glUniformMatrix4x3fvNV
+#define glUnmapBuffer wrap_glUnmapBuffer
+#define glUnmapBufferOES wrap_glUnmapBufferOES
+#define glUseProgram wrap_glUseProgram
+#define glUseProgramStages wrap_glUseProgramStages
+#define glUseProgramStagesEXT wrap_glUseProgramStagesEXT
+#define glValidateProgram wrap_glValidateProgram
+#define glValidateProgramPipeline wrap_glValidateProgramPipeline
+#define glValidateProgramPipelineEXT wrap_glValidateProgramPipelineEXT
+#define glVertexAttrib1f wrap_glVertexAttrib1f
+#define glVertexAttrib1fv wrap_glVertexAttrib1fv
+#define glVertexAttrib2f wrap_glVertexAttrib2f
+#define glVertexAttrib2fv wrap_glVertexAttrib2fv
+#define glVertexAttrib3f wrap_glVertexAttrib3f
+#define glVertexAttrib3fv wrap_glVertexAttrib3fv
+#define glVertexAttrib4f wrap_glVertexAttrib4f
+#define glVertexAttrib4fv wrap_glVertexAttrib4fv
+#define glVertexAttribBinding wrap_glVertexAttribBinding
+#define glVertexAttribDivisor wrap_glVertexAttribDivisor
+#define glVertexAttribDivisorANGLE wrap_glVertexAttribDivisorANGLE
+#define glVertexAttribDivisorEXT wrap_glVertexAttribDivisorEXT
+#define glVertexAttribDivisorNV wrap_glVertexAttribDivisorNV
+#define glVertexAttribFormat wrap_glVertexAttribFormat
+#define glVertexAttribI4i wrap_glVertexAttribI4i
+#define glVertexAttribI4iv wrap_glVertexAttribI4iv
+#define glVertexAttribI4ui wrap_glVertexAttribI4ui
+#define glVertexAttribI4uiv wrap_glVertexAttribI4uiv
+#define glVertexAttribIFormat wrap_glVertexAttribIFormat
+#define glVertexAttribIPointer wrap_glVertexAttribIPointer
+#define glVertexAttribPointer wrap_glVertexAttribPointer
+#define glVertexBindingDivisor wrap_glVertexBindingDivisor
+#define glVertexPointer wrap_glVertexPointer
+#define glViewport wrap_glViewport
+#define glViewportArrayvNV wrap_glViewportArrayvNV
+#define glViewportIndexedfNV wrap_glViewportIndexedfNV
+#define glViewportIndexedfvNV wrap_glViewportIndexedfvNV
+#define glWaitSync wrap_glWaitSync
+#define glWaitSyncAPPLE wrap_glWaitSyncAPPLE
+#define glWeightPathsNV wrap_glWeightPathsNV
+#define glWeightPointerOES wrap_glWeightPointerOES
\ No newline at end of file
diff --git a/libs/hwui/debug/wrap_gles.h b/libs/hwui/debug/wrap_gles.h
index ecd46e2..27a29aa 100644
--- a/libs/hwui/debug/wrap_gles.h
+++ b/libs/hwui/debug/wrap_gles.h
@@ -20,7 +20,16 @@
 #endif
 #define HWUI_GLES_WRAP_ENABLED
 
-#include "GlesDriver.h"
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl31.h>
+#include <GLES3/gl32.h>
+
+// Generate stubs that route all the calls to our function table
+#include "gles_redefine.h"
 
 #define GL_ENTRY(ret, api, ...) ret api(__VA_ARGS__);
 
diff --git a/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp b/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp
new file mode 100644
index 0000000..0f8906e
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+
+#include "TestSceneBase.h"
+
+#include <vector>
+
+class RoundRectClippingAnimation : public TestScene {
+public:
+    int mSpacing, mSize;
+
+    RoundRectClippingAnimation(int spacing, int size)
+            : mSpacing(spacing), mSize(size) {}
+
+    std::vector< sp<RenderNode> > cards;
+    void createContent(int width, int height, Canvas& canvas) override {
+        canvas.drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+        canvas.insertReorderBarrier(true);
+        int ci = 0;
+
+        for (int x = 0; x < width; x += mSpacing) {
+            for (int y = 0; y < height; y += mSpacing) {
+                auto color = BrightColors[ci++ % BrightColorsCount];
+                auto card = TestUtils::createNode(x, y, x + mSize, y + mSize,
+                        [&](RenderProperties& props, Canvas& canvas) {
+                    canvas.drawColor(color, SkXfermode::kSrcOver_Mode);
+                    props.mutableOutline().setRoundRect(0, 0,
+                            props.getWidth(), props.getHeight(), mSize * .25, 1);
+                    props.mutableOutline().setShouldClip(true);
+                });
+                canvas.drawRenderNode(card.get());
+                cards.push_back(card);
+            }
+        }
+
+        canvas.insertReorderBarrier(false);
+    }
+    void doFrame(int frameNr) override {
+        int curFrame = frameNr % 50;
+        if (curFrame > 25) curFrame = 50 - curFrame;
+        for (auto& card : cards) {
+            card->mutateStagingProperties().setTranslationX(curFrame);
+            card->mutateStagingProperties().setTranslationY(curFrame);
+            card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+        }
+    }
+};
+
+static TestScene::Registrar _RoundRectClippingGpu(TestScene::Info{
+    "roundRectClipping-gpu",
+    "A bunch of RenderNodes with round rect clipping outlines that's GPU limited.",
+    [](const TestScene::Options&) -> test::TestScene* {
+        return new RoundRectClippingAnimation(dp(40), dp(200));
+    }
+});
+
+static TestScene::Registrar _RoundRectClippingCpu(TestScene::Info{
+    "roundRectClipping-cpu",
+    "A bunch of RenderNodes with round rect clipping outlines that's CPU limited.",
+    [](const TestScene::Options&) -> test::TestScene* {
+        return new RoundRectClippingAnimation(dp(20), dp(20));
+    }
+});
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index d413083..01c89ba 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -30,6 +30,7 @@
 import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
 import java.io.DataInputStream;
+import java.io.DataInput;
 import java.io.EOFException;
 import java.io.File;
 import java.io.FileDescriptor;
@@ -692,8 +693,8 @@
 
         private Object getValue(ByteOrder byteOrder) {
             try {
-                ByteOrderAwarenessDataInputStream inputStream =
-                        new ByteOrderAwarenessDataInputStream(bytes);
+                ByteOrderedDataInputStream inputStream =
+                        new ByteOrderedDataInputStream(bytes);
                 inputStream.setByteOrder(byteOrder);
                 switch (format) {
                     case IFD_FORMAT_BYTE:
@@ -1677,21 +1678,24 @@
             in = new BufferedInputStream(in, SIGNATURE_CHECK_SIZE);
             mMimeType = getMimeType((BufferedInputStream) in);
 
+            // Create byte-ordered input stream
+            ByteOrderedDataInputStream inputStream = new ByteOrderedDataInputStream(in);
+
             switch (mMimeType) {
                 case IMAGE_TYPE_JPEG: {
-                    getJpegAttributes(in, 0, IFD_TYPE_PRIMARY); // 0 is offset
+                    getJpegAttributes(inputStream, 0, IFD_TYPE_PRIMARY); // 0 is offset
                     break;
                 }
                 case IMAGE_TYPE_RAF: {
-                    getRafAttributes(in);
+                    getRafAttributes(inputStream);
                     break;
                 }
                 case IMAGE_TYPE_ORF: {
-                    getOrfAttributes(in);
+                    getOrfAttributes(inputStream);
                     break;
                 }
                 case IMAGE_TYPE_RW2: {
-                    getRw2Attributes(in);
+                    getRw2Attributes(inputStream);
                     break;
                 }
                 case IMAGE_TYPE_ARW:
@@ -1702,7 +1706,7 @@
                 case IMAGE_TYPE_PEF:
                 case IMAGE_TYPE_SRW:
                 case IMAGE_TYPE_UNKNOWN: {
-                    getRawAttributes(in);
+                    getRawAttributes(inputStream);
                     break;
                 }
                 default: {
@@ -1710,7 +1714,7 @@
                 }
             }
             // Set thumbnail image offset and length
-            setThumbnailData(in);
+            setThumbnailData(inputStream);
         } catch (IOException e) {
             // Ignore exceptions in order to keep the compatibility with the old versions of
             // ExifInterface.
@@ -2144,8 +2148,8 @@
      * http://fileformats.archiveteam.org/wiki/Olympus_ORF
      */
     private boolean isOrfFormat(byte[] signatureCheckBytes) throws IOException {
-        ByteOrderAwarenessDataInputStream signatureInputStream =
-                new ByteOrderAwarenessDataInputStream(signatureCheckBytes);
+        ByteOrderedDataInputStream signatureInputStream =
+                new ByteOrderedDataInputStream(signatureCheckBytes);
         // Read byte order
         mExifByteOrder = readByteOrder(signatureInputStream);
         // Set byte order
@@ -2163,8 +2167,8 @@
      * See http://lclevy.free.fr/raw/
      */
     private boolean isRw2Format(byte[] signatureCheckBytes) throws IOException {
-        ByteOrderAwarenessDataInputStream signatureInputStream =
-                new ByteOrderAwarenessDataInputStream(signatureCheckBytes);
+        ByteOrderedDataInputStream signatureInputStream =
+                new ByteOrderedDataInputStream(signatureCheckBytes);
         // Read byte order
         mExifByteOrder = readByteOrder(signatureInputStream);
         // Set byte order
@@ -2187,39 +2191,36 @@
      *                   IFD_TYPE_THUMBNAIL for thumbnail image.
      * @throws IOException If the data contains invalid JPEG markers, offsets, or length values.
      */
-    private void getJpegAttributes(InputStream inputStream, int jpegOffset, int imageType)
+    private void getJpegAttributes(ByteOrderedDataInputStream in, int jpegOffset, int imageType)
             throws IOException {
         // See JPEG File Interchange Format Specification, "JFIF Specification"
         if (DEBUG) {
-            Log.d(TAG, "getJpegAttributes starting with: " + inputStream);
+            Log.d(TAG, "getJpegAttributes starting with: " + in);
         }
 
-        DataInputStream dataInputStream = new DataInputStream(inputStream);
-        // Mark current position to reset after retrieving data
-        dataInputStream.mark(dataInputStream.available());
+        // JPEG uses Big Endian by default. See https://people.cs.umass.edu/~verts/cs32/endian.html
+        in.setByteOrder(ByteOrder.BIG_ENDIAN);
 
         // Skip to JPEG data
-        if (dataInputStream.skip(jpegOffset) != jpegOffset) {
-            throw new IOException("Invalid JPEG offset");
-        }
+        in.seek(jpegOffset);
         int bytesRead = jpegOffset;
 
         byte marker;
-        if ((marker = dataInputStream.readByte()) != MARKER) {
+        if ((marker = in.readByte()) != MARKER) {
             throw new IOException("Invalid marker: " + Integer.toHexString(marker & 0xff));
         }
         ++bytesRead;
-        if (dataInputStream.readByte() != MARKER_SOI) {
+        if (in.readByte() != MARKER_SOI) {
             throw new IOException("Invalid marker: " + Integer.toHexString(marker & 0xff));
         }
         ++bytesRead;
         while (true) {
-            marker = dataInputStream.readByte();
+            marker = in.readByte();
             if (marker != MARKER) {
                 throw new IOException("Invalid marker:" + Integer.toHexString(marker & 0xff));
             }
             ++bytesRead;
-            marker = dataInputStream.readByte();
+            marker = in.readByte();
             if (DEBUG) {
                 Log.d(TAG, "Found JPEG segment indicator: " + Integer.toHexString(marker & 0xff));
             }
@@ -2230,7 +2231,7 @@
             if (marker == MARKER_EOI || marker == MARKER_SOS) {
                 break;
             }
-            int length = dataInputStream.readUnsignedShort() - 2;
+            int length = in.readUnsignedShort() - 2;
             bytesRead += 2;
             if (DEBUG) {
                 Log.d(TAG, "JPEG segment: " + Integer.toHexString(marker & 0xff) + " (length: "
@@ -2249,7 +2250,7 @@
                         break;
                     }
                     byte[] identifier = new byte[6];
-                    if (inputStream.read(identifier) != 6) {
+                    if (in.read(identifier) != 6) {
                         throw new IOException("Invalid exif");
                     }
                     bytesRead += 6;
@@ -2268,7 +2269,7 @@
                     mExifOffset = bytesRead;
 
                     byte[] bytes = new byte[length];
-                    if (dataInputStream.read(bytes) != length) {
+                    if (in.read(bytes) != length) {
                         throw new IOException("Invalid exif");
                     }
                     bytesRead += length;
@@ -2280,7 +2281,7 @@
 
                 case MARKER_COM: {
                     byte[] bytes = new byte[length];
-                    if (dataInputStream.read(bytes) != length) {
+                    if (in.read(bytes) != length) {
                         throw new IOException("Invalid exif");
                     }
                     length = 0;
@@ -2304,13 +2305,13 @@
                 case MARKER_SOF13:
                 case MARKER_SOF14:
                 case MARKER_SOF15: {
-                    if (dataInputStream.skipBytes(1) != 1) {
+                    if (in.skipBytes(1) != 1) {
                         throw new IOException("Invalid SOFx");
                     }
                     mAttributes[imageType].put(TAG_IMAGE_LENGTH, ExifAttribute.createULong(
-                            dataInputStream.readUnsignedShort(), mExifByteOrder));
+                            in.readUnsignedShort(), mExifByteOrder));
                     mAttributes[imageType].put(TAG_IMAGE_WIDTH, ExifAttribute.createULong(
-                            dataInputStream.readUnsignedShort(), mExifByteOrder));
+                            in.readUnsignedShort(), mExifByteOrder));
                     length -= 5;
                     break;
                 }
@@ -2322,30 +2323,21 @@
             if (length < 0) {
                 throw new IOException("Invalid length");
             }
-            if (dataInputStream.skipBytes(length) != length) {
+            if (in.skipBytes(length) != length) {
                 throw new IOException("Invalid JPEG segment");
             }
             bytesRead += length;
         }
-        // Reset dataInputStream to marked position
-        dataInputStream.reset();
+        // Restore original byte order
+        in.setByteOrder(mExifByteOrder);
     }
 
-    private void getRawAttributes(InputStream in) throws IOException {
-        int totalBytes = in.available();
-        byte[] exifBytes = new byte[totalBytes];
-        in.mark(in.available());
-        in.read(exifBytes);
-        in.reset();
-
-        ByteOrderAwarenessDataInputStream dataInputStream =
-                new ByteOrderAwarenessDataInputStream(exifBytes);
-
+    private void getRawAttributes(ByteOrderedDataInputStream in) throws IOException {
         // Parse TIFF Headers. See JEITA CP-3451C Section 4.5.2. Table 1.
-        parseTiffHeaders(dataInputStream, exifBytes.length);
+        parseTiffHeaders(in, in.available());
 
         // Read TIFF image file directories. See JEITA CP-3451C Section 4.5.2. Figure 6.
-        readImageFileDirectory(dataInputStream, IFD_TYPE_PRIMARY);
+        readImageFileDirectory(in, IFD_TYPE_PRIMARY);
 
         // Update ImageLength/Width tags for all image data.
         updateImageSizeValues(in, IFD_TYPE_PRIMARY);
@@ -2362,8 +2354,8 @@
                     (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_MAKER_NOTE);
             if (makerNoteAttribute != null) {
                 // Create an ordered DataInputStream for MakerNote
-                ByteOrderAwarenessDataInputStream makerNoteDataInputStream =
-                        new ByteOrderAwarenessDataInputStream(makerNoteAttribute.bytes);
+                ByteOrderedDataInputStream makerNoteDataInputStream =
+                        new ByteOrderedDataInputStream(makerNoteAttribute.bytes);
                 makerNoteDataInputStream.setByteOrder(mExifByteOrder);
 
                 // Seek to MakerNote data
@@ -2391,45 +2383,27 @@
      * then parses the CFA metadata to retrieve the primary image length/width values.
      * For data format details, see http://fileformats.archiveteam.org/wiki/Fujifilm_RAF
      */
-    private void getRafAttributes(InputStream in) throws IOException {
+    private void getRafAttributes(ByteOrderedDataInputStream in) throws IOException {
         // Retrieve offset & length values
-        in.mark(RAF_INFO_SIZE);
-        in.skip(RAF_OFFSET_TO_JPEG_IMAGE_OFFSET);
+        in.skipBytes(RAF_OFFSET_TO_JPEG_IMAGE_OFFSET);
         byte[] jpegOffsetBytes = new byte[4];
         byte[] cfaHeaderOffsetBytes = new byte[4];
-        byte[] cfaHeaderLengthBytes = new byte[4];
         in.read(jpegOffsetBytes);
         // Skip JPEG length value since it is not needed
-        in.skip(RAF_JPEG_LENGTH_VALUE_SIZE);
+        in.skipBytes(RAF_JPEG_LENGTH_VALUE_SIZE);
         in.read(cfaHeaderOffsetBytes);
-        in.read(cfaHeaderLengthBytes);
         int rafJpegOffset = ByteBuffer.wrap(jpegOffsetBytes).getInt();
         int rafCfaHeaderOffset = ByteBuffer.wrap(cfaHeaderOffsetBytes).getInt();
-        int rafCfaHeaderLength = ByteBuffer.wrap(cfaHeaderLengthBytes).getInt();
-        in.reset();
 
         // Retrieve JPEG image metadata
         getJpegAttributes(in, rafJpegOffset, IFD_TYPE_PREVIEW);
 
         // Skip to CFA header offset.
-        // A while loop is used because the skip method may not be able to skip the requested amount
-        // at once because the size of the buffer may be restricted.
-        in.mark(rafCfaHeaderOffset + rafCfaHeaderLength);
-        int totalSkip = rafCfaHeaderOffset;
-        while (totalSkip > 0) {
-            long skipped = in.skip(totalSkip);
-            totalSkip -= skipped;
-        }
+        in.seek(rafCfaHeaderOffset);
 
         // Retrieve primary image length/width values, if TAG_RAF_IMAGE_SIZE exists
-        byte[] exifBytes = new byte[rafCfaHeaderLength];
-        if (in.read(exifBytes) != rafCfaHeaderLength) {
-            throw new EOFException();
-        }
-        in.reset();
-        ByteOrderAwarenessDataInputStream dataInputStream =
-                new ByteOrderAwarenessDataInputStream(exifBytes);
-        int numberOfDirectoryEntry = dataInputStream.readInt();
+        in.setByteOrder(ByteOrder.BIG_ENDIAN);
+        int numberOfDirectoryEntry = in.readInt();
         if (DEBUG) {
             Log.d(TAG, "numberOfDirectoryEntry: " + numberOfDirectoryEntry);
         }
@@ -2437,11 +2411,11 @@
         // find and retrieve image size information tags, while skipping others.
         // See piex.cc RafGetDimension()
         for (int i = 0; i < numberOfDirectoryEntry; ++i) {
-            int tagNumber = dataInputStream.readUnsignedShort();
-            int numberOfBytes = dataInputStream.readUnsignedShort();
+            int tagNumber = in.readUnsignedShort();
+            int numberOfBytes = in.readUnsignedShort();
             if (tagNumber == TAG_RAF_IMAGE_SIZE.number) {
-                int imageLength = dataInputStream.readShort();
-                int imageWidth = dataInputStream.readShort();
+                int imageLength = in.readShort();
+                int imageWidth = in.readShort();
                 ExifAttribute imageLengthAttribute =
                         ExifAttribute.createUShort(imageLength, mExifByteOrder);
                 ExifAttribute imageWidthAttribute =
@@ -2453,7 +2427,7 @@
                 }
                 return;
             }
-            dataInputStream.skip(numberOfBytes);
+            in.skipBytes(numberOfBytes);
         }
     }
 
@@ -2467,7 +2441,7 @@
      * http://fileformats.archiveteam.org/wiki/Olympus_ORF
      * https://libopenraw.freedesktop.org/wiki/Olympus_ORF
      */
-    private void getOrfAttributes(InputStream in) throws IOException {
+    private void getOrfAttributes(ByteOrderedDataInputStream in) throws IOException {
         // Retrieve primary image data
         // Other Exif data will be located in the Makernote.
         getRawAttributes(in);
@@ -2479,8 +2453,8 @@
                 (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_MAKER_NOTE);
         if (makerNoteAttribute != null) {
             // Create an ordered DataInputStream for MakerNote
-            ByteOrderAwarenessDataInputStream makerNoteDataInputStream =
-                    new ByteOrderAwarenessDataInputStream(makerNoteAttribute.bytes);
+            ByteOrderedDataInputStream makerNoteDataInputStream =
+                    new ByteOrderedDataInputStream(makerNoteAttribute.bytes);
             makerNoteDataInputStream.setByteOrder(mExifByteOrder);
 
             // There are two types of headers for Olympus MakerNotes
@@ -2546,7 +2520,7 @@
     // RW2 contains the primary image data in IFD0 and the preview and/or thumbnail image data in
     // the JpgFromRaw tag
     // See https://libopenraw.freedesktop.org/wiki/Panasonic_RAW/ and piex.cc Rw2GetPreviewData()
-    private void getRw2Attributes(InputStream in) throws IOException {
+    private void getRw2Attributes(ByteOrderedDataInputStream in) throws IOException {
         // Retrieve primary image data
         getRawAttributes(in);
 
@@ -2577,8 +2551,8 @@
                     + ", outputStream: " + outputStream + ")");
         }
         DataInputStream dataInputStream = new DataInputStream(inputStream);
-        ByteOrderAwarenessDataOutputStream dataOutputStream =
-                new ByteOrderAwarenessDataOutputStream(outputStream, ByteOrder.BIG_ENDIAN);
+        ByteOrderedDataOutputStream dataOutputStream =
+                new ByteOrderedDataOutputStream(outputStream, ByteOrder.BIG_ENDIAN);
         if (dataInputStream.readByte() != MARKER) {
             throw new IOException("Invalid marker");
         }
@@ -2614,7 +2588,7 @@
                         }
                         if (Arrays.equals(identifier, IDENTIFIER_EXIF_APP1)) {
                             // Skip the original EXIF APP1 segment.
-                            if (dataInputStream.skip(length - 6) != length - 6) {
+                            if (dataInputStream.skipBytes(length - 6) != length - 6) {
                                 throw new IOException("Invalid length");
                             }
                             break;
@@ -2668,8 +2642,8 @@
 
     // Reads the given EXIF byte area and save its tag data into attributes.
     private void readExifSegment(byte[] exifBytes, int imageType) throws IOException {
-        ByteOrderAwarenessDataInputStream dataInputStream =
-                new ByteOrderAwarenessDataInputStream(exifBytes);
+        ByteOrderedDataInputStream dataInputStream =
+                new ByteOrderedDataInputStream(exifBytes);
 
         // Parse TIFF Headers. See JEITA CP-3451C Section 4.5.2. Table 1.
         parseTiffHeaders(dataInputStream, exifBytes.length);
@@ -2705,7 +2679,7 @@
         }
     }
 
-    private ByteOrder readByteOrder(ByteOrderAwarenessDataInputStream dataInputStream)
+    private ByteOrder readByteOrder(ByteOrderedDataInputStream dataInputStream)
             throws IOException {
         // Read byte order.
         short byteOrder = dataInputStream.readShort();
@@ -2725,7 +2699,7 @@
         }
     }
 
-    private void parseTiffHeaders(ByteOrderAwarenessDataInputStream dataInputStream,
+    private void parseTiffHeaders(ByteOrderedDataInputStream dataInputStream,
             int exifBytesLength) throws IOException {
         // Read byte order
         mExifByteOrder = readByteOrder(dataInputStream);
@@ -2745,22 +2719,22 @@
         }
         firstIfdOffset -= 8;
         if (firstIfdOffset > 0) {
-            if (dataInputStream.skip(firstIfdOffset) != firstIfdOffset) {
+            if (dataInputStream.skipBytes(firstIfdOffset) != firstIfdOffset) {
                 throw new IOException("Couldn't jump to first Ifd: " + firstIfdOffset);
             }
         }
     }
 
     // Reads image file directory, which is a tag group in EXIF.
-    private void readImageFileDirectory(ByteOrderAwarenessDataInputStream dataInputStream,
+    private void readImageFileDirectory(ByteOrderedDataInputStream dataInputStream,
             @IfdType int ifdType) throws IOException {
-        if (dataInputStream.peek() + 2 > dataInputStream.mLength) {
+        if (dataInputStream.mPosition + 2 > dataInputStream.mLength) {
             // Return if there is no data from the offset.
             return;
         }
         // See TIFF 6.0 Section 2: TIFF Structure, Figure 1.
         short numberOfDirectoryEntry = dataInputStream.readShort();
-        if (dataInputStream.peek() + 12 * numberOfDirectoryEntry > dataInputStream.mLength) {
+        if (dataInputStream.mPosition + 12 * numberOfDirectoryEntry > dataInputStream.mLength) {
             // Return if the size of entries is too big.
             return;
         }
@@ -2789,10 +2763,12 @@
             if (tag == null || dataFormat <= 0 ||
                     dataFormat >= IFD_FORMAT_BYTES_PER_FORMAT.length) {
                 // Skip if the parsed tag number is not defined or invalid data format.
-                if (tag == null) {
-                    Log.w(TAG, "Skip the tag entry since tag number is not defined: " + tagNumber);
-                } else {
-                    Log.w(TAG, "Skip the tag entry since data format is invalid: " + dataFormat);
+                if (DEBUG) {
+                    if (tag == null) {
+                        Log.w(TAG, "Skip tag entry since tag number is not defined: " + tagNumber);
+                    } else {
+                        Log.w(TAG, "Skip tag entry since data format is invalid: " + dataFormat);
+                    }
                 }
                 dataInputStream.seek(nextEntryOffset);
                 continue;
@@ -2908,7 +2884,7 @@
             if (((tag.name == TAG_MAKE || tag.name == TAG_MODEL)
                     && attribute.getStringValue(mExifByteOrder).contains(PEF_SIGNATURE))
                     || (tag.name == TAG_COMPRESSION
-                            && attribute.getIntValue(mExifByteOrder) == 65535)) {
+                    && attribute.getIntValue(mExifByteOrder) == 65535)) {
                 mMimeType = IMAGE_TYPE_PEF;
             }
 
@@ -2943,7 +2919,8 @@
      * to locate SOF(Start of Frame) marker and update the image length & width values.
      * See JEITA CP-3451C Table 5 and Section 4.8.1. B.
      */
-    private void retrieveJpegImageSize(InputStream in, int imageType) throws IOException {
+    private void retrieveJpegImageSize(ByteOrderedDataInputStream in, int imageType)
+            throws IOException {
         // Check if image already has IMAGE_LENGTH & IMAGE_WIDTH values
         ExifAttribute imageLengthAttribute =
                 (ExifAttribute) mAttributes[imageType].get(TAG_IMAGE_LENGTH);
@@ -2965,7 +2942,7 @@
     }
 
     // Sets thumbnail offset & length attributes based on JpegInterchangeFormat or StripOffsets tags
-    private void setThumbnailData(InputStream in) throws IOException {
+    private void setThumbnailData(ByteOrderedDataInputStream in) throws IOException {
         HashMap thumbnailData = mAttributes[IFD_TYPE_THUMBNAIL];
 
         ExifAttribute compressionAttribute =
@@ -2994,7 +2971,8 @@
 
     // Check JpegInterchangeFormat(JFIF) tags to retrieve thumbnail offset & length values
     // and reads the corresponding bytes if stream does not support seek function
-    private void handleThumbnailFromJfif(InputStream in, HashMap thumbnailData) throws IOException {
+    private void handleThumbnailFromJfif(ByteOrderedDataInputStream in, HashMap thumbnailData)
+            throws IOException {
         ExifAttribute jpegInterchangeFormatAttribute =
                 (ExifAttribute) thumbnailData.get(TAG_JPEG_INTERCHANGE_FORMAT);
         ExifAttribute jpegInterchangeFormatLengthAttribute =
@@ -3025,8 +3003,8 @@
                         && mSeekableFileDescriptor == null) {
                     // Save the thumbnail in memory if the input doesn't support reading again.
                     byte[] thumbnailBytes = new byte[thumbnailLength];
-                    in.skip(thumbnailOffset);
-                    in.read(thumbnailBytes);
+                    in.seek(thumbnailOffset);
+                    in.readFully(thumbnailBytes);
                     mThumbnailBytes = thumbnailBytes;
                 }
             }
@@ -3034,7 +3012,7 @@
     }
 
     // Check StripOffsets & StripByteCounts tags to retrieve thumbnail offset & length values
-    private void handleThumbnailFromStrips(InputStream in, HashMap thumbnailData)
+    private void handleThumbnailFromStrips(ByteOrderedDataInputStream in, HashMap thumbnailData)
             throws IOException {
         ExifAttribute stripOffsetsAttribute =
                 (ExifAttribute) thumbnailData.get(TAG_STRIP_OFFSETS);
@@ -3062,7 +3040,7 @@
                 if (skipBytes < 0) {
                     Log.d(TAG, "Invalid strip offset value");
                 }
-                in.skip(skipBytes);
+                in.seek(skipBytes);
                 bytesRead += skipBytes;
 
                 // Read strip bytes
@@ -3140,6 +3118,18 @@
         swapBasedOnImageSize(IFD_TYPE_PRIMARY, IFD_TYPE_THUMBNAIL);
         swapBasedOnImageSize(IFD_TYPE_PREVIEW, IFD_TYPE_THUMBNAIL);
 
+        // Check if image has PixelXDimension/PixelYDimension tags, which contain valid image
+        // sizes, excluding padding at the right end or bottom end of the image to make sure that
+        // the values are multiples of 64. See JEITA CP-3451C Table 5 and Section 4.8.1. B.
+        ExifAttribute pixelXDimAttribute =
+                (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_PIXEL_X_DIMENSION);
+        ExifAttribute pixelYDimAttribute =
+                (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_PIXEL_Y_DIMENSION);
+        if (pixelXDimAttribute != null && pixelYDimAttribute != null) {
+            mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_WIDTH, pixelXDimAttribute);
+            mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_LENGTH, pixelYDimAttribute);
+        }
+
         // Check whether thumbnail image exists and whether preview image satisfies the thumbnail
         // image requirements
         if (mAttributes[IFD_TYPE_THUMBNAIL].isEmpty()) {
@@ -3162,17 +3152,11 @@
      * This method corrects those tag values by checking first the values of TAG_DEFAULT_CROP_SIZE
      * See DNG Specification 1.4.0.0. Section 4. (DefaultCropSize)
      *
-     * If image is JPEG compressed, PixelXDimension/PixelYDimension tags are used for size info.
-     * However, an image may have padding at the right end or bottom end of the image to make sure
-     * that the values are multiples of 64. If so, the increased value will be saved in the
-     * SOF(Start of Frame). In order to assure that valid image size values are stored, this method
-     * checks TAG_PIXEL_X_DIMENSION & TAG_PIXEL_Y_DIMENSION and updates values if necessary.
-     * See JEITA CP-3451C Table 5 and Section 4.8.1. B.
-     *
      * If image is a RW2 file, valid image sizes are stored in SensorBorder tags.
      * See tiff_parser.cc GetFullDimension32()
      * */
-    private void updateImageSizeValues(InputStream in, int imageType) throws IOException {
+    private void updateImageSizeValues(ByteOrderedDataInputStream in, int imageType)
+            throws IOException {
         // Uncompressed image valid image size values
         ExifAttribute defaultCropSizeAttribute =
                 (ExifAttribute) mAttributes[imageType].get(TAG_DEFAULT_CROP_SIZE);
@@ -3224,33 +3208,12 @@
                 mAttributes[imageType].put(TAG_IMAGE_WIDTH, imageWidthAttribute);
             }
         } else {
-            // Update for JPEG image
-            ExifAttribute newSubfileTypeAttribute =
-                    (ExifAttribute) mAttributes[imageType].get(TAG_NEW_SUBFILE_TYPE);
-
-            if (newSubfileTypeAttribute != null) {
-                int newSubfileTypeValue = newSubfileTypeAttribute.getIntValue(mExifByteOrder);
-
-                if (newSubfileTypeValue == ORIGINAL_RESOLUTION_IMAGE) {
-                    // Update only for the primary image (OriginalResolutionImage)
-                    ExifAttribute pixelXDimAttribute =
-                            (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_PIXEL_X_DIMENSION);
-                    ExifAttribute pixelYDimAttribute =
-                            (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_PIXEL_Y_DIMENSION);
-
-                    if (pixelXDimAttribute != null && pixelYDimAttribute != null) {
-                        mAttributes[imageType].put(TAG_IMAGE_WIDTH, pixelXDimAttribute);
-                        mAttributes[imageType].put(TAG_IMAGE_LENGTH, pixelYDimAttribute);
-                        return;
-                    }
-                }
-            }
             retrieveJpegImageSize(in, imageType);
         }
     }
 
     // Writes an Exif segment into the given output stream.
-    private int writeExifSegment(ByteOrderAwarenessDataOutputStream dataOutputStream,
+    private int writeExifSegment(ByteOrderedDataOutputStream dataOutputStream,
             int exifOffsetFromBeginning) throws IOException {
         // The following variables are for calculating each IFD tag group size in bytes.
         int[] ifdOffsets = new int[EXIF_TAGS.length];
@@ -3414,7 +3377,7 @@
 
         // Write thumbnail
         if (mHasThumbnail) {
-            dataOutputStream.write(getThumbnail());
+            dataOutputStream.write(getThumbnailBytes());
         }
 
         // Reset the byte order to big endian in order to write remaining parts of the JPEG file.
@@ -3507,18 +3470,26 @@
 
     // An input stream to parse EXIF data area, which can be written in either little or big endian
     // order.
-    private static class ByteOrderAwarenessDataInputStream extends ByteArrayInputStream {
+    private static class ByteOrderedDataInputStream extends InputStream implements DataInput {
         private static final ByteOrder LITTLE_ENDIAN = ByteOrder.LITTLE_ENDIAN;
         private static final ByteOrder BIG_ENDIAN = ByteOrder.BIG_ENDIAN;
 
+        private DataInputStream mDataInputStream;
+        private InputStream mInputStream;
         private ByteOrder mByteOrder = ByteOrder.BIG_ENDIAN;
-        private final long mLength;
-        private long mPosition;
+        private final int mLength;
+        private int mPosition;
 
-        public ByteOrderAwarenessDataInputStream(byte[] bytes) {
-            super(bytes);
-            mLength = bytes.length;
-            mPosition = 0L;
+        public ByteOrderedDataInputStream(InputStream in) throws IOException {
+            mInputStream = in;
+            mDataInputStream = new DataInputStream(in);
+            mLength = mDataInputStream.available();
+            mPosition = 0;
+            mDataInputStream.mark(mLength);
+        }
+
+        public ByteOrderedDataInputStream(byte[] bytes) throws IOException {
+            this(new ByteArrayInputStream(bytes));
         }
 
         public void setByteOrder(ByteOrder byteOrder) {
@@ -3527,49 +3498,106 @@
 
         public void seek(long byteCount) throws IOException {
             if (mPosition > byteCount) {
-                mPosition = 0L;
-                reset();
+                mPosition = 0;
+                mDataInputStream.reset();
+                mDataInputStream.mark(mLength);
             } else {
                 byteCount -= mPosition;
             }
-            if (skip(byteCount) != byteCount) {
+
+            if (skipBytes((int) byteCount) != (int) byteCount) {
                 throw new IOException("Couldn't seek up to the byteCount");
             }
         }
 
-        public long peek() {
+        public int peek() {
             return mPosition;
         }
 
+        @Override
+        public int available() throws IOException {
+            return mDataInputStream.available();
+        }
+
+        @Override
+        public int read() throws IOException {
+            ++mPosition;
+            return mDataInputStream.read();
+        }
+
+        @Override
+        public int readUnsignedByte() throws IOException {
+            ++mPosition;
+            return mDataInputStream.readUnsignedByte();
+        }
+
+        @Override
+        public String readLine() throws IOException {
+            Log.d(TAG, "Currently unsupported");
+            return null;
+        }
+
+        @Override
+        public boolean readBoolean() throws IOException {
+            ++mPosition;
+            return mDataInputStream.readBoolean();
+        }
+
+        @Override
+        public char readChar() throws IOException {
+            mPosition += 2;
+            return mDataInputStream.readChar();
+        }
+
+        @Override
+        public String readUTF() throws IOException {
+            mPosition += 2;
+            return mDataInputStream.readUTF();
+        }
+
+        @Override
+        public void readFully(byte[] buffer, int offset, int length) throws IOException {
+            mPosition += length;
+            if (mPosition > mLength) {
+                throw new EOFException();
+            }
+            if (mDataInputStream.read(buffer, offset, length) != length) {
+                throw new IOException("Couldn't read up to the length of buffer");
+            }
+        }
+
+        @Override
         public void readFully(byte[] buffer) throws IOException {
             mPosition += buffer.length;
             if (mPosition > mLength) {
                 throw new EOFException();
             }
-            if (super.read(buffer, 0, buffer.length) != buffer.length) {
+            if (mDataInputStream.read(buffer, 0, buffer.length) != buffer.length) {
                 throw new IOException("Couldn't read up to the length of buffer");
             }
         }
 
+        @Override
         public byte readByte() throws IOException {
             ++mPosition;
             if (mPosition > mLength) {
                 throw new EOFException();
             }
-            int ch = super.read();
+            int ch = mDataInputStream.read();
             if (ch < 0) {
                 throw new EOFException();
             }
             return (byte) ch;
         }
 
+        @Override
         public short readShort() throws IOException {
             mPosition += 2;
             if (mPosition > mLength) {
                 throw new EOFException();
             }
-            int ch1 = super.read();
-            int ch2 = super.read();
+            int ch1 = mDataInputStream.read();
+            int ch2 = mDataInputStream.read();
             if ((ch1 | ch2) < 0) {
                 throw new EOFException();
             }
@@ -3581,15 +3609,16 @@
             throw new IOException("Invalid byte order: " + mByteOrder);
         }
 
+        @Override
         public int readInt() throws IOException {
             mPosition += 4;
             if (mPosition > mLength) {
                 throw new EOFException();
             }
-            int ch1 = super.read();
-            int ch2 = super.read();
-            int ch3 = super.read();
-            int ch4 = super.read();
+            int ch1 = mDataInputStream.read();
+            int ch2 = mDataInputStream.read();
+            int ch3 = mDataInputStream.read();
+            int ch4 = mDataInputStream.read();
             if ((ch1 | ch2 | ch3 | ch4) < 0) {
                 throw new EOFException();
             }
@@ -3602,8 +3631,12 @@
         }
 
         @Override
-        public long skip(long byteCount) {
-            long skipped = super.skip(Math.min(byteCount, mLength - mPosition));
+        public int skipBytes(int byteCount) throws IOException {
+            int totalSkip = Math.min(byteCount, mLength - mPosition);
+            int skipped = 0;
+            while (skipped < totalSkip) {
+                skipped += mDataInputStream.skipBytes(totalSkip - skipped);
+            }
             mPosition += skipped;
             return skipped;
         }
@@ -3613,8 +3646,8 @@
             if (mPosition > mLength) {
                 throw new EOFException();
             }
-            int ch1 = super.read();
-            int ch2 = super.read();
+            int ch1 = mDataInputStream.read();
+            int ch2 = mDataInputStream.read();
             if ((ch1 | ch2) < 0) {
                 throw new EOFException();
             }
@@ -3630,19 +3663,20 @@
             return readInt() & 0xffffffffL;
         }
 
+        @Override
         public long readLong() throws IOException {
             mPosition += 8;
             if (mPosition > mLength) {
                 throw new EOFException();
             }
-            int ch1 = super.read();
-            int ch2 = super.read();
-            int ch3 = super.read();
-            int ch4 = super.read();
-            int ch5 = super.read();
-            int ch6 = super.read();
-            int ch7 = super.read();
-            int ch8 = super.read();
+            int ch1 = mDataInputStream.read();
+            int ch2 = mDataInputStream.read();
+            int ch3 = mDataInputStream.read();
+            int ch4 = mDataInputStream.read();
+            int ch5 = mDataInputStream.read();
+            int ch6 = mDataInputStream.read();
+            int ch7 = mDataInputStream.read();
+            int ch8 = mDataInputStream.read();
             if ((ch1 | ch2 | ch3 | ch4 | ch5 | ch6 | ch7 | ch8) < 0) {
                 throw new EOFException();
             }
@@ -3658,10 +3692,12 @@
             throw new IOException("Invalid byte order: " + mByteOrder);
         }
 
+        @Override
         public float readFloat() throws IOException {
             return Float.intBitsToFloat(readInt());
         }
 
+        @Override
         public double readDouble() throws IOException {
             return Double.longBitsToDouble(readLong());
         }
@@ -3669,11 +3705,11 @@
 
     // An output stream to write EXIF data area, which can be written in either little or big endian
     // order.
-    private static class ByteOrderAwarenessDataOutputStream extends FilterOutputStream {
+    private static class ByteOrderedDataOutputStream extends FilterOutputStream {
         private final OutputStream mOutputStream;
         private ByteOrder mByteOrder;
 
-        public ByteOrderAwarenessDataOutputStream(OutputStream out, ByteOrder byteOrder) {
+        public ByteOrderedDataOutputStream(OutputStream out, ByteOrder byteOrder) {
             super(out);
             mOutputStream = out;
             mByteOrder = byteOrder;
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 30395b8..dd26799 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -992,7 +992,7 @@
             // Try cached ringtone first since the actual provider may not be
             // encryption aware, or it may be stored on CE media storage
             final int type = RingtoneManager.getDefaultType(uri);
-            final Uri cacheUri = RingtoneManager.getCacheForType(type);
+            final Uri cacheUri = RingtoneManager.getCacheForType(type, context.getUserId());
             final Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(context, type);
             if (attemptDataSource(resolver, cacheUri)) {
                 return;
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 101facd..5b4443b 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -66,7 +66,7 @@
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     static class Static implements DisplayManager.DisplayListener {
-        final Context mAppContext;
+        final String mPackageName;
         final Resources mResources;
         final IAudioService mAudioService;
         final DisplayManager mDisplayService;
@@ -110,8 +110,8 @@
         };
 
         Static(Context appContext) {
-            mAppContext = appContext;
-            mResources = Resources.getSystem();
+            mPackageName = appContext.getPackageName();
+            mResources = appContext.getResources();
             mHandler = new Handler(appContext.getMainLooper());
 
             IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
@@ -357,8 +357,7 @@
 
                 try {
                     Client client = new Client();
-                    mMediaRouterService.registerClientAsUser(client,
-                            mAppContext.getPackageName(), userId);
+                    mMediaRouterService.registerClientAsUser(client, mPackageName, userId);
                     mClient = client;
                 } catch (RemoteException ex) {
                     Log.e(TAG, "Unable to register media router client.", ex);
@@ -1627,7 +1626,7 @@
 
         CharSequence getName(Resources res) {
             if (mNameResId != 0) {
-                return mName = res.getText(mNameResId);
+                return res.getText(mNameResId);
             }
             return mName;
         }
@@ -2079,6 +2078,7 @@
          * @param name Name to display to the user to describe this route
          */
         public void setName(CharSequence name) {
+            mNameResId = 0;
             mName = name;
             routeUpdated();
         }
@@ -2275,7 +2275,7 @@
         private void configureSessionVolume() {
             if (mRcc == null) {
                 if (DEBUG) {
-                    Log.d(TAG, "No Rcc to configure volume for route " + mName);
+                    Log.d(TAG, "No Rcc to configure volume for route " + getName());
                 }
                 return;
             }
@@ -2590,8 +2590,10 @@
             for (int i = 0; i < count; i++) {
                 final RouteInfo info = mRoutes.get(i);
                 // TODO: There's probably a much more correct way to localize this.
-                if (i > 0) sb.append(", ");
-                sb.append(info.mName);
+                if (i > 0) {
+                    sb.append(", ");
+                }
+                sb.append(info.getName());
             }
             mName = sb.toString();
             mUpdateName = false;
@@ -2716,7 +2718,7 @@
 
         @Override
         public String toString() {
-            return "RouteCategory{ name=" + mName + " types=" + typesToString(mTypes) +
+            return "RouteCategory{ name=" + getName() + " types=" + typesToString(mTypes) +
                     " groupable=" + mGroupable + " }";
         }
     }
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index c2bcd93..8935b72 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -16,6 +16,7 @@
 
 package android.media;
 
+import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
@@ -206,11 +207,11 @@
     public static String getTitle(
             Context context, Uri uri, boolean followSettingsUri, boolean allowRemote) {
         ContentResolver res = context.getContentResolver();
-        
+
         String title = null;
 
         if (uri != null) {
-            String authority = uri.getAuthority();
+            String authority = ContentProvider.getAuthorityWithoutUserId(uri.getAuthority());
 
             if (Settings.AUTHORITY.equals(authority)) {
                 if (followSettingsUri) {
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 86ebae1..664765a 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -16,18 +16,24 @@
 
 package android.media;
 
+import android.Manifest;
+import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.Activity;
+import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.MediaStore;
 import android.provider.Settings;
 import android.provider.Settings.System;
@@ -43,6 +49,9 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import static android.content.ContentProvider.maybeAddUserId;
+import static android.content.pm.PackageManager.NameNotFoundException;
+
 /**
  * RingtoneManager provides access to ringtones, notification, and other types
  * of sounds. It manages querying the different media providers and combines the
@@ -82,6 +91,10 @@
      * All types of sounds.
      */
     public static final int TYPE_ALL = TYPE_RINGTONE | TYPE_NOTIFICATION | TYPE_ALARM;
+
+    private static final int[] RINGTONE_TYPES = {
+            TYPE_RINGTONE, TYPE_NOTIFICATION, TYPE_ALARM
+    };
     
     // </attr>
     
@@ -629,6 +642,48 @@
     }
     
     /**
+     * Disables Settings.System.SYNC_PARENT_SOUNDS, copying the parent's ringtones to the current
+     * profile
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+    public static void disableSyncFromParent(Context userContext) {
+        // Must disable sync first so that ringtone copy below doesn't get redirected to parent
+        Settings.Secure.putIntForUser(userContext.getContentResolver(),
+                Settings.Secure.SYNC_PARENT_SOUNDS, 0 /* false */, userContext.getUserId());
+
+        // Copy ringtones from parent profile
+        UserManager um = UserManager.get(userContext);
+        UserInfo parentInfo = um.getProfileParent(userContext.getUserId());
+        if (parentInfo != null) {
+            try {
+                Context targetContext = userContext.createPackageContextAsUser(
+                        userContext.getPackageName(), 0 /* flags */, UserHandle.of(parentInfo.id));
+                for (int ringtoneType : RINGTONE_TYPES) {
+                    Uri ringtoneUri = getActualDefaultRingtoneUri(targetContext, ringtoneType);
+                    // Add user id of parent so that custom ringtones can be read and played
+                    RingtoneManager.setActualDefaultRingtoneUri(userContext, ringtoneType,
+                            maybeAddUserId(ringtoneUri, parentInfo.id));
+                }
+            } catch (NameNotFoundException e) {
+                Log.e(TAG, "Unable to create parent context", e);
+            }
+        }
+    }
+
+    /**
+     * Enables Settings.System.SYNC_PARENT_SOUNDS for the content's user
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+    public static void enableSyncFromParent(Context userContext) {
+        Settings.Secure.putIntForUser(userContext.getContentResolver(),
+                Settings.Secure.SYNC_PARENT_SOUNDS, 1 /* true */, userContext.getUserId());
+    }
+
+    /**
      * Gets the current default sound's {@link Uri}. This will give the actual
      * sound {@link Uri}, instead of using this, most clients can use
      * {@link System#DEFAULT_RINGTONE_URI}.
@@ -645,7 +700,16 @@
         if (setting == null) return null;
         final String uriString = Settings.System.getStringForUser(context.getContentResolver(),
                 setting, context.getUserId());
-        return uriString != null ? Uri.parse(uriString) : null;
+        Uri ringtoneUri = uriString != null ? Uri.parse(uriString) : null;
+
+        // If this doesn't verify, the user id must be kept in the uri to ensure it resolves in the
+        // correct user storage
+        if (ringtoneUri != null
+                && ContentProvider.getUserIdFromUri(ringtoneUri) == context.getUserId()) {
+            ringtoneUri = ContentProvider.getUriWithoutUserId(ringtoneUri);
+        }
+
+        return ringtoneUri;
     }
     
     /**
@@ -663,13 +727,14 @@
 
         String setting = getSettingForType(type);
         if (setting == null) return;
+        ringtoneUri = ContentProvider.maybeAddUserId(ringtoneUri, context.getUserId());
         Settings.System.putStringForUser(resolver, setting,
                 ringtoneUri != null ? ringtoneUri.toString() : null, context.getUserId());
 
         // Stream selected ringtone into cache so it's available for playback
         // when CE storage is still locked
         if (ringtoneUri != null) {
-            final Uri cacheUri = getCacheForType(type);
+            final Uri cacheUri = getCacheForType(type, context.getUserId());
             try (InputStream in = openRingtone(context, ringtoneUri);
                     OutputStream out = resolver.openOutputStream(cacheUri)) {
                 Streams.copy(in, out);
@@ -715,15 +780,20 @@
 
     /** {@hide} */
     public static Uri getCacheForType(int type) {
+        return getCacheForType(type, UserHandle.getCallingUserId());
+    }
+
+    /** {@hide} */
+    public static Uri getCacheForType(int type, int userId) {
         if ((type & TYPE_RINGTONE) != 0) {
-            return Settings.System.RINGTONE_CACHE_URI;
+            return ContentProvider.maybeAddUserId(Settings.System.RINGTONE_CACHE_URI, userId);
         } else if ((type & TYPE_NOTIFICATION) != 0) {
-            return Settings.System.NOTIFICATION_SOUND_CACHE_URI;
+            return ContentProvider.maybeAddUserId(Settings.System.NOTIFICATION_SOUND_CACHE_URI,
+                    userId);
         } else if ((type & TYPE_ALARM) != 0) {
-            return Settings.System.ALARM_ALERT_CACHE_URI;
-        } else {
-            return null;
+            return ContentProvider.maybeAddUserId(Settings.System.ALARM_ALERT_CACHE_URI, userId);
         }
+        return null;
     }
 
     /**
diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk
index 7e438a1..5d73730 100644
--- a/media/tests/MediaFrameworkTest/Android.mk
+++ b/media/tests/MediaFrameworkTest/Android.mk
@@ -9,7 +9,7 @@
 
 LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 
-LOCAL_STATIC_JAVA_LIBRARIES := easymocklib \
+LOCAL_STATIC_JAVA_LIBRARIES := \
     mockito-target \
     android-support-test \
     android-ex-camera2
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
index 06efa90..86c2284 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
@@ -16,6 +16,14 @@
 
 package com.android.mediaframeworktest.unit;
 
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+
 import android.content.ContentProviderClient;
 import android.content.ContentValues;
 import android.content.IContentProvider;
@@ -28,14 +36,16 @@
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import org.easymock.EasyMock;
-import org.easymock.IArgumentMatcher;
+import org.hamcrest.Description;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 public class MediaInserterTest extends InstrumentationTestCase {
 
     private MediaInserter mMediaInserter;
     private static final int TEST_BUFFER_SIZE = 10;
-    private IContentProvider mMockProvider;
+    private @Mock IContentProvider mMockProvider;
     private String mPackageName;
 
     private int mFilesCounter;
@@ -49,8 +59,8 @@
     private static final Uri sImagesUri = Images.Media.getContentUri(sVolumeName);
     private static final Uri sFilesUri = Files.getContentUri(sVolumeName);
 
-    private static class MediaUriMatcher implements IArgumentMatcher {
-        private Uri mUri;
+    private static class MediaUriMatcher extends ArgumentMatcher<Uri> {
+        private final Uri mUri;
 
         private MediaUriMatcher(Uri uri) {
             mUri = uri;
@@ -63,25 +73,30 @@
             }
 
             Uri actualUri = (Uri) argument;
-            if (actualUri == mUri) return true;
+            if (actualUri == mUri)
+                return true;
             return false;
         }
 
         @Override
-        public void appendTo(StringBuffer buffer) {
-            buffer.append("expected a TableUri '").append(mUri).append("'");
+        public void describeTo(Description description) {
+            description
+                    .appendText("expected a TableUri '")
+                    .appendText(mUri.toString())
+                    .appendText("'");
         }
 
-        private static Uri expectMediaUri(Uri in) {
-            EasyMock.reportMatcher(new MediaUriMatcher(in));
-            return null;
-        }
+    }
+
+    private static Uri eqUri(Uri in) {
+        return argThat(new MediaUriMatcher(in));
     }
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mMockProvider = EasyMock.createMock(IContentProvider.class);
+        MockitoAnnotations.initMocks(this);
+
         final ContentProviderClient client = new ContentProviderClient(
                 getInstrumentation().getContext().getContentResolver(), mMockProvider, true);
         mMediaInserter = new MediaInserter(client, TEST_BUFFER_SIZE);
@@ -134,61 +149,46 @@
 
     @SmallTest
     public void testInsertContentsLessThanBufferSize() throws Exception {
-        EasyMock.replay(mMockProvider);
-
         fillBuffer(sFilesUri, TEST_BUFFER_SIZE - 4);
         fillBuffer(sAudioUri, TEST_BUFFER_SIZE - 3);
         fillBuffer(sVideoUri, TEST_BUFFER_SIZE - 2);
         fillBuffer(sImagesUri, TEST_BUFFER_SIZE - 1);
 
-        EasyMock.verify(mMockProvider);
+        verify(mMockProvider, never()).bulkInsert(eq(mPackageName), any(), any());
     }
 
     @SmallTest
     public void testInsertContentsEqualToBufferSize() throws Exception {
-        EasyMock.expect(mMockProvider.bulkInsert(mPackageName,
-                (Uri) EasyMock.anyObject(), (ContentValues[]) EasyMock.anyObject())).andReturn(1);
-        EasyMock.expectLastCall().times(4);
-        EasyMock.replay(mMockProvider);
+        when(mMockProvider.bulkInsert(eq(mPackageName), any(), any())).thenReturn(1);
 
         fillBuffer(sFilesUri, TEST_BUFFER_SIZE);
         fillBuffer(sAudioUri, TEST_BUFFER_SIZE);
         fillBuffer(sVideoUri, TEST_BUFFER_SIZE);
         fillBuffer(sImagesUri, TEST_BUFFER_SIZE);
 
-        EasyMock.verify(mMockProvider);
+        verify(mMockProvider, times(4)).bulkInsert(eq(mPackageName), any(), any());
     }
 
     @SmallTest
     public void testInsertContentsMoreThanBufferSize() throws Exception {
-        EasyMock.expect(mMockProvider.bulkInsert(mPackageName,
-                (Uri) EasyMock.anyObject(), (ContentValues[]) EasyMock.anyObject())).andReturn(1);
-        EasyMock.expectLastCall().times(4);
-        EasyMock.replay(mMockProvider);
+        when(mMockProvider.bulkInsert(eq(mPackageName), any(), any())).thenReturn(1);
 
         fillBuffer(sFilesUri, TEST_BUFFER_SIZE + 1);
         fillBuffer(sAudioUri, TEST_BUFFER_SIZE + 2);
         fillBuffer(sVideoUri, TEST_BUFFER_SIZE + 3);
         fillBuffer(sImagesUri, TEST_BUFFER_SIZE + 4);
 
-        EasyMock.verify(mMockProvider);
+        verify(mMockProvider, times(4)).bulkInsert(eq(mPackageName), any(), any());
     }
 
     @SmallTest
     public void testFlushAllWithEmptyContents() throws Exception {
-        EasyMock.replay(mMockProvider);
-
         mMediaInserter.flushAll();
-
-        EasyMock.verify(mMockProvider);
     }
 
     @SmallTest
     public void testFlushAllWithSomeContents() throws Exception {
-        EasyMock.expect(mMockProvider.bulkInsert(mPackageName,
-                (Uri) EasyMock.anyObject(), (ContentValues[]) EasyMock.anyObject())).andReturn(1);
-        EasyMock.expectLastCall().times(4);
-        EasyMock.replay(mMockProvider);
+        when(mMockProvider.bulkInsert(eq(mPackageName), any(), any())).thenReturn(1);
 
         fillBuffer(sFilesUri, TEST_BUFFER_SIZE - 4);
         fillBuffer(sAudioUri, TEST_BUFFER_SIZE - 3);
@@ -196,15 +196,12 @@
         fillBuffer(sImagesUri, TEST_BUFFER_SIZE - 1);
         mMediaInserter.flushAll();
 
-        EasyMock.verify(mMockProvider);
+        verify(mMockProvider, times(4)).bulkInsert(eq(mPackageName), any(), any());
     }
 
     @SmallTest
     public void testInsertContentsAfterFlushAll() throws Exception {
-        EasyMock.expect(mMockProvider.bulkInsert(mPackageName,
-                (Uri) EasyMock.anyObject(), (ContentValues[]) EasyMock.anyObject())).andReturn(1);
-        EasyMock.expectLastCall().times(8);
-        EasyMock.replay(mMockProvider);
+        when(mMockProvider.bulkInsert(eq(mPackageName), any(), any())).thenReturn(1);
 
         fillBuffer(sFilesUri, TEST_BUFFER_SIZE - 4);
         fillBuffer(sAudioUri, TEST_BUFFER_SIZE - 3);
@@ -217,28 +214,15 @@
         fillBuffer(sVideoUri, TEST_BUFFER_SIZE + 3);
         fillBuffer(sImagesUri, TEST_BUFFER_SIZE + 4);
 
-        EasyMock.verify(mMockProvider);
+        verify(mMockProvider, times(8)).bulkInsert(eq(mPackageName), any(), any());
     }
 
     @SmallTest
     public void testInsertContentsWithDifferentSizePerContentType() throws Exception {
-        EasyMock.expect(mMockProvider.bulkInsert(mPackageName,
-        MediaUriMatcher.expectMediaUri(sFilesUri),
-                (ContentValues[]) EasyMock.anyObject())).andReturn(1);
-        EasyMock.expectLastCall().times(1);
-        EasyMock.expect(mMockProvider.bulkInsert(mPackageName,
-        MediaUriMatcher.expectMediaUri(sAudioUri),
-                (ContentValues[]) EasyMock.anyObject())).andReturn(1);
-        EasyMock.expectLastCall().times(2);
-        EasyMock.expect(mMockProvider.bulkInsert(mPackageName,
-        MediaUriMatcher.expectMediaUri(sVideoUri),
-                (ContentValues[]) EasyMock.anyObject())).andReturn(1);
-        EasyMock.expectLastCall().times(3);
-        EasyMock.expect(mMockProvider.bulkInsert(mPackageName,
-        MediaUriMatcher.expectMediaUri(sImagesUri),
-                (ContentValues[]) EasyMock.anyObject())).andReturn(1);
-        EasyMock.expectLastCall().times(4);
-        EasyMock.replay(mMockProvider);
+        when(mMockProvider.bulkInsert(eq(mPackageName), eqUri(sFilesUri), any())).thenReturn(1);
+        when(mMockProvider.bulkInsert(eq(mPackageName), eqUri(sAudioUri), any())).thenReturn(1);
+        when(mMockProvider.bulkInsert(eq(mPackageName), eqUri(sVideoUri), any())).thenReturn(1);
+        when(mMockProvider.bulkInsert(eq(mPackageName), eqUri(sImagesUri), any())).thenReturn(1);
 
         for (int i = 0; i < TEST_BUFFER_SIZE; ++i) {
             fillBuffer(sFilesUri, 1);
@@ -247,6 +231,9 @@
             fillBuffer(sImagesUri, 4);
         }
 
-        EasyMock.verify(mMockProvider);
+        verify(mMockProvider, times(1)).bulkInsert(eq(mPackageName), eqUri(sFilesUri), any());
+        verify(mMockProvider, times(2)).bulkInsert(eq(mPackageName), eqUri(sAudioUri), any());
+        verify(mMockProvider, times(3)).bulkInsert(eq(mPackageName), eqUri(sVideoUri), any());
+        verify(mMockProvider, times(4)).bulkInsert(eq(mPackageName), eqUri(sImagesUri), any());
     }
 }
diff --git a/obex/javax/obex/ClientOperation.java b/obex/javax/obex/ClientOperation.java
index eb7e280..c627dfb 100644
--- a/obex/javax/obex/ClientOperation.java
+++ b/obex/javax/obex/ClientOperation.java
@@ -207,7 +207,6 @@
      *         object
      */
     public synchronized int getResponseCode() throws IOException {
-        //avoid dup validateConnection
         if ((mReplyHeader.responseCode == -1)
                 || (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
             validateConnection();
@@ -423,8 +422,9 @@
     private void validateConnection() throws IOException {
         ensureOpen();
 
-        // to sure only one privateInput object exist.
-        if (mPrivateInput == null) {
+        // Make sure that a response has been recieved from remote
+        // before continuing
+        if (mPrivateInput == null || mReplyHeader.responseCode == -1) {
             startProcessing();
         }
     }
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 1341476..2812a63 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -573,6 +573,7 @@
             throws FileNotFoundException {
         final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
 
+        query = query.toLowerCase();
         final File parent;
         synchronized (mRootsLock) {
             parent = mRoots.get(rootId).path;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 2c61372..0566177 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -178,6 +178,7 @@
     private boolean mBouncer;
     private boolean mBootCompleted;
     private boolean mUserUnlocked;
+    private boolean mHasLockscreenWallpaper;
 
     // Device provisioning state
     private boolean mDeviceProvisioned;
@@ -1173,6 +1174,30 @@
     }
 
     /**
+     * Update the state whether Keyguard currently has a lockscreen wallpaper.
+     *
+     * @param hasLockscreenWallpaper Whether Keyguard has a lockscreen wallpaper.
+     */
+    public void setHasLockscreenWallpaper(boolean hasLockscreenWallpaper) {
+        if (hasLockscreenWallpaper != mHasLockscreenWallpaper) {
+            mHasLockscreenWallpaper = hasLockscreenWallpaper;
+            for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+                KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+                if (cb != null) {
+                    cb.onHasLockscreenWallpaperChanged(hasLockscreenWallpaper);
+                }
+            }
+        }
+    }
+
+    /**
+     * @return Whether Keyguard has a lockscreen wallpaper.
+     */
+    public boolean hasLockscreenWallpaper() {
+        return mHasLockscreenWallpaper;
+    }
+
+    /**
      * Handle {@link #MSG_DPM_STATE_CHANGED}
      */
     protected void handleDevicePolicyManagerStateChanged() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index bd6c51c..4a2d356 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -240,4 +240,9 @@
      * has changed.
      */
     public void onStrongAuthStateChanged(int userId) { }
+
+    /**
+     * Called when the state whether we have a lockscreen wallpaper has changed.
+     */
+    public void onHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper) { }
 }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
index cce619e..4950af3 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -873,7 +873,7 @@
     }
 
     private static int getRootFlags(int[] operationsSupported) {
-        int rootFlag = Root.FLAG_SUPPORTS_IS_CHILD;
+        int rootFlag = Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_LOCAL_ONLY;
         if (MtpDeviceRecord.isWritingSupported(operationsSupported)) {
             rootFlag |= Root.FLAG_SUPPORTS_CREATE;
         }
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
index 031090f..7fe6cb9 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
@@ -128,7 +128,7 @@
             cursor.moveToNext();
             assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
             assertEquals(
-                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE,
+                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY,
                     getInt(cursor, Root.COLUMN_FLAGS));
             assertEquals(R.drawable.ic_root_mtp, getInt(cursor, Root.COLUMN_ICON));
             assertEquals("Device Storage", getString(cursor, Root.COLUMN_TITLE));
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 53bccdc..3f7e8b6 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -210,7 +210,11 @@
             assertEquals(2, cursor.getCount());
             cursor.moveToNext();
             assertEquals("1", cursor.getString(0));
-            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
+            assertEquals(
+                    Root.FLAG_SUPPORTS_IS_CHILD |
+                    Root.FLAG_SUPPORTS_CREATE |
+                    Root.FLAG_LOCAL_ONLY,
+                    cursor.getInt(1));
             assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
             assertEquals("Device A Storage A", cursor.getString(3));
             assertEquals("1", cursor.getString(4));
@@ -225,7 +229,8 @@
             cursor.moveToNext();
             cursor.moveToNext();
             assertEquals("2", cursor.getString(0));
-            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD, cursor.getInt(1));
+            assertEquals(
+                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_LOCAL_ONLY, cursor.getInt(1));
             assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
             assertEquals("Device B Storage B", cursor.getString(3));
             assertEquals("2", cursor.getString(4));
@@ -271,7 +276,9 @@
 
             cursor.moveToNext();
             assertEquals("1", cursor.getString(0));
-            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
+            assertEquals(
+                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY,
+                    cursor.getInt(1));
             assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
             assertEquals("Device A", cursor.getString(3));
             assertEquals("1", cursor.getString(4));
@@ -279,7 +286,9 @@
 
             cursor.moveToNext();
             assertEquals("2", cursor.getString(0));
-            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
+            assertEquals(
+                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY,
+                    cursor.getInt(1));
             assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
             assertEquals("Device B Storage B", cursor.getString(3));
             assertEquals("2", cursor.getString(4));
diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
index 5e9d9c8..79f2f8b 100644
--- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
@@ -60,7 +60,7 @@
       <item quantity="one">找到 <xliff:g id="COUNT_0">%1$s</xliff:g> 台打印机</item>
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
-    <string name="printer_info_desc" msgid="7181988788991581654">"关于此打印机的更多信息"</string>
+    <string name="printer_info_desc" msgid="7181988788991581654">"此打印机的详细信息"</string>
     <string name="could_not_create_file" msgid="3425025039427448443">"无法创建文件"</string>
     <string name="print_services_disabled_toast" msgid="9089060734685174685">"部分打印服务已停用"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"正在搜索打印机"</string>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 0ca36f6..11235ef 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Grootste"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Gepasmaak (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Hulp en terugvoer"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Kieslys"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index d40691c..dbfd5d8 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"በጣም ተለቅ ያለ"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ብጁ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"እገዛ እና ግብረመልስ"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"ምናሌ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 12b9302..092cf63 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"أكبر مستوى"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"مخصص (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"المساعدة والتعليقات"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"القائمة"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-az-rAZ/strings.xml b/packages/SettingsLib/res/values-az-rAZ/strings.xml
index 296725f..2e58ae9 100644
--- a/packages/SettingsLib/res/values-az-rAZ/strings.xml
+++ b/packages/SettingsLib/res/values-az-rAZ/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Ən böyük"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Fərdi (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Yardım və rəy"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menyu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index fb0bf54..1f0ed53 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najveći"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagođeni (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Meni"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-be-rBY/strings.xml b/packages/SettingsLib/res/values-be-rBY/strings.xml
index e9c7f9b..b8de297 100644
--- a/packages/SettingsLib/res/values-be-rBY/strings.xml
+++ b/packages/SettingsLib/res/values-be-rBY/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Найвялікшы"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Карыстальніцкі (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Даведка і водгукі"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index f5e1386..683a4d9 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Най-голямо"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Персонализирано (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Помощ и отзиви"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-bn-rBD/strings.xml b/packages/SettingsLib/res/values-bn-rBD/strings.xml
index 6146372..9ba656f 100644
--- a/packages/SettingsLib/res/values-bn-rBD/strings.xml
+++ b/packages/SettingsLib/res/values-bn-rBD/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"বৃহত্তম"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"কাস্টম (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"সহায়তা ও মতামত"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"মেনু"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-bs-rBA/strings.xml b/packages/SettingsLib/res/values-bs-rBA/strings.xml
index 6426ac8..f2c7323 100644
--- a/packages/SettingsLib/res/values-bs-rBA/strings.xml
+++ b/packages/SettingsLib/res/values-bs-rBA/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najveće"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagodi (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Meni"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 46baecd..332daf3 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Màxim"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalitzat (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda i suggeriments"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 8743c0f..d0dbe74 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Největší"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Vlastní (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Nápověda a zpětná vazba"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Nabídka"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 9c7e76c..3c4b955 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Størst"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tilpasset (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Hjælp og feedback"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index c878d93..0fca8b9 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Am größten"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Benutzerdefiniert (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Hilfe &amp; Feedback"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menü"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index bda970a..da1b03c 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Μεγαλύτερα"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Προσαρμοσμένη (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Βοήθεια και σχόλια"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Μενού"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 0f41d19..70fa5017 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Largest"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Help &amp; feedback"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 0f41d19..70fa5017 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Largest"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Help &amp; feedback"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 0f41d19..70fa5017 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Largest"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Help &amp; feedback"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index aa98329..63a5d87 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Máximo"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Ayuda y comentarios"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 23e01ea..6b67b11 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Lo más grande posible"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Ayuda y sugerencias"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-et-rEE/strings.xml b/packages/SettingsLib/res/values-et-rEE/strings.xml
index 6b98a19..de9255a 100644
--- a/packages/SettingsLib/res/values-et-rEE/strings.xml
+++ b/packages/SettingsLib/res/values-et-rEE/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Suurim"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Kohandatud (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Abi ja tagasiside"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menüü"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-eu-rES/strings.xml b/packages/SettingsLib/res/values-eu-rES/strings.xml
index c7525fb..bd8c11d 100644
--- a/packages/SettingsLib/res/values-eu-rES/strings.xml
+++ b/packages/SettingsLib/res/values-eu-rES/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Handiena"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Pertsonalizatua (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Laguntza eta iritziak"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menua"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index ab4f70b..027987f 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"بزرگ‌ترین"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"سفارشی (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"راهنما و بازخورد"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"منو"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index d2d6959..a988ccf 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Suurin"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Muokattu (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Ohje ja palaute"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Valikko"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 8230f87..e22e938 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"La plus grande"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personnalisée (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Aide et commentaires"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index bad9ab2..e4a34d6 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Le plus grand"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personnalisé (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Aide et commentaires"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-gl-rES/strings.xml b/packages/SettingsLib/res/values-gl-rES/strings.xml
index ed0d3f3..10a3957 100644
--- a/packages/SettingsLib/res/values-gl-rES/strings.xml
+++ b/packages/SettingsLib/res/values-gl-rES/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"O máis grande"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Axuda e suxestións"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-gu-rIN/strings.xml b/packages/SettingsLib/res/values-gu-rIN/strings.xml
index 79014b6..0f3079d 100644
--- a/packages/SettingsLib/res/values-gu-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-gu-rIN/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"સૌથી મોટું"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"કસ્ટમ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"સહાય અને પ્રતિસાદ"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"મેનુ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 5edb828..5407c21 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सबसे बड़ा"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"कस्टम (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"सहायता और फ़ीडबैक"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"मेनू"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 803a995e..e52f441 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najveće"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagođeno (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Izbornik"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 328fa2d..ac4a43c 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Legnagyobb"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Egyéni (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Súgó és visszajelzés"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menü"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hy-rAM/strings.xml b/packages/SettingsLib/res/values-hy-rAM/strings.xml
index d515274..a31489c 100644
--- a/packages/SettingsLib/res/values-hy-rAM/strings.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Ամենամեծ"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Հատուկ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Օգնություն և հետադարձ կապ"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Ընտրացանկ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index c56d58d..5711ea7 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Terbesar"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"(<xliff:g id="DENSITYDPI">%d</xliff:g>) khusus"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Bantuan &amp; masukan"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-is-rIS/strings.xml b/packages/SettingsLib/res/values-is-rIS/strings.xml
index 5ce6be4..44226ee 100644
--- a/packages/SettingsLib/res/values-is-rIS/strings.xml
+++ b/packages/SettingsLib/res/values-is-rIS/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Stærst"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Sérsniðið (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Hjálp og ábendingar"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Valmynd"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 24ec277..b90fe66 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -328,7 +328,7 @@
     <string name="disabled_by_admin" msgid="3669999613095206948">"Disattivata dall\'amministratore"</string>
     <string name="home" msgid="3256884684164448244">"Home page Impostazioni"</string>
   <string-array name="battery_labels">
-    <item msgid="8494684293649631252">"0%%"</item>
+    <item msgid="8494684293649631252">"0%"</item>
     <item msgid="8934126114226089439">"50%%"</item>
     <item msgid="1286113608943010849">"100%%"</item>
   </string-array>
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Massimo"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizzato (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Guida e feedback"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index f223565..6f7460a 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"הכי גדול"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"מותאם אישית (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"עזרה ומשוב"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"תפריט"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index f356b95..025b7fd 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -343,6 +343,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"カスタム(<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"ヘルプとフィードバック"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"メニュー"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ka-rGE/strings.xml b/packages/SettingsLib/res/values-ka-rGE/strings.xml
index 22a1f8a..0eda6a9 100644
--- a/packages/SettingsLib/res/values-ka-rGE/strings.xml
+++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"უდიდესი"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"მორგებული (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"დახმარება და გამოხმაურება"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"მენიუ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-kk-rKZ/strings.xml b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
index 30bae8b..369a10f 100644
--- a/packages/SettingsLib/res/values-kk-rKZ/strings.xml
+++ b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Ең үлкен"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Арнаулы (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Анықтама және пікір"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Mәзір"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-km-rKH/strings.xml b/packages/SettingsLib/res/values-km-rKH/strings.xml
index 8daf338..3e934ba 100644
--- a/packages/SettingsLib/res/values-km-rKH/strings.xml
+++ b/packages/SettingsLib/res/values-km-rKH/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ធំបំផុត"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ផ្ទាល់ខ្លួន (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"ជំនួយ និងមតិស្ថាបនា"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"ម៉ឺនុយ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-kn-rIN/strings.xml b/packages/SettingsLib/res/values-kn-rIN/strings.xml
index 8ca9035..5a8d53c 100644
--- a/packages/SettingsLib/res/values-kn-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-kn-rIN/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ದೊಡ್ಡ"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ಕಸ್ಟಮ್ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"ಸಹಾಯ ಮತ್ತು ಪ್ರತಿಕ್ರಿಯೆ"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"ಮೆನು"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 4778145..bd96334 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"가장 크게"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"맞춤(<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"고객센터"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"메뉴"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml
index eff06a4..5ca4e7c 100644
--- a/packages/SettingsLib/res/values-ky-rKG/strings.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Эң чоң"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Ыңгайлаштырылган (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Жардам жана жооп пикир"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lo-rLA/strings.xml b/packages/SettingsLib/res/values-lo-rLA/strings.xml
index 87449fa..b47629a 100644
--- a/packages/SettingsLib/res/values-lo-rLA/strings.xml
+++ b/packages/SettingsLib/res/values-lo-rLA/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ໃຫຍ່ທີ່ສຸດ"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ປັບແຕ່ງເອງ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"ຊ່ວຍເຫຼືອ &amp; ຄຳຕິຊົມ"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"ເມນູ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index fa4812a..7ac54a8 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Didžiausias"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tinkintas (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Pagalba ir atsiliepimai"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Meniu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 568ab4c..933d374 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Vislielākais"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Pielāgots (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Palīdzība un atsauksmes"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Izvēlne"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mk-rMK/strings.xml b/packages/SettingsLib/res/values-mk-rMK/strings.xml
index 991d60c..1e1c857 100644
--- a/packages/SettingsLib/res/values-mk-rMK/strings.xml
+++ b/packages/SettingsLib/res/values-mk-rMK/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Најголем"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Приспособен (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Помош и повратни информации"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Мени"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ml-rIN/strings.xml b/packages/SettingsLib/res/values-ml-rIN/strings.xml
index 38d56e0..6f75886 100644
--- a/packages/SettingsLib/res/values-ml-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ml-rIN/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ഏറ്റവും വലുത്"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ഇഷ്ടാനുസൃതം ( <xliff:g id="DENSITYDPI">%d</xliff:g> )"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"സഹായവും പ്രതികരണവും"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"മെനു"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mn-rMN/strings.xml b/packages/SettingsLib/res/values-mn-rMN/strings.xml
index beb80e8..bf7d7ce 100644
--- a/packages/SettingsLib/res/values-mn-rMN/strings.xml
+++ b/packages/SettingsLib/res/values-mn-rMN/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Хамгийн том"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Тогтмол утга (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Тусламж, санал хүсэлт"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Цэс"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mr-rIN/strings.xml b/packages/SettingsLib/res/values-mr-rIN/strings.xml
index 10aa560..a1123bc 100644
--- a/packages/SettingsLib/res/values-mr-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-mr-rIN/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सर्वात मोठा"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"सानुकूल करा (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"मदत आणि अभिप्राय"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"मेनू"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ms-rMY/strings.xml b/packages/SettingsLib/res/values-ms-rMY/strings.xml
index 5c66ddb..8f11589 100644
--- a/packages/SettingsLib/res/values-ms-rMY/strings.xml
+++ b/packages/SettingsLib/res/values-ms-rMY/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Terbesar"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tersuai (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Bantuan &amp; maklum balas"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-my-rMM/strings.xml b/packages/SettingsLib/res/values-my-rMM/strings.xml
index 4f5ea65..cfba5da 100644
--- a/packages/SettingsLib/res/values-my-rMM/strings.xml
+++ b/packages/SettingsLib/res/values-my-rMM/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"အကြီးဆုံး"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"စိတ်ကြိုက် (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"အကူအညီနှင့် အကြံပြုချက်"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"မီနူး"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 1a07614..2da378a 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Størst"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Egendefinert (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Hjelp og tilbakemelding"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Meny"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml
index e73b07e..a56b655 100644
--- a/packages/SettingsLib/res/values-ne-rNP/strings.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सबैभन्दा ठूलो"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"अनुकूलन (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"मद्दत र प्रतिक्रिया"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"मेनु"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 83b6c74..11d92e5 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Grootst"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Aangepast (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Help en feedback"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pa-rIN/strings.xml b/packages/SettingsLib/res/values-pa-rIN/strings.xml
index 47ed7e3..d526064 100644
--- a/packages/SettingsLib/res/values-pa-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-pa-rIN/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ਸਭ ਤੋਂ ਵੱਡਾ"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ਵਿਸ਼ੇਸ਼-ਵਿਉਂਤਬੱਧ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"ਮਦਦ ਅਤੇ ਪ੍ਰਤੀਕਰਮ"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"ਮੀਨੂ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 1f07580..dcbb934 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Największy"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Niestandardowe (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Pomoc i opinie"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index dca0f8e..fc22225 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Maior"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizada (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e feedback"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index d5910ac..c297de5 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"O maior"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e comentários"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index dca0f8e..fc22225 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Maior"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizada (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e feedback"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index cfc0ea8..70912f9 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Cel mai mare"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizat (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Ajutor și feedback"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Meniu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 38c8f0e..b8de0c3 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Максимальный"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Другой (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Справка/отзыв"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-si-rLK/strings.xml b/packages/SettingsLib/res/values-si-rLK/strings.xml
index d73df8a..d9fed96 100644
--- a/packages/SettingsLib/res/values-si-rLK/strings.xml
+++ b/packages/SettingsLib/res/values-si-rLK/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"විශාලතම"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"අභිරුචි (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"උදව් සහ ප්‍රතිපෝෂණ"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"මෙනුව"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 10413d6..951d9fb 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Najväčšie"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Vlastné (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Pomocník a spätná väzba"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Ponuka"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index dba5453..2428076 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Največje"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Po meri (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Pomoč in povratne informacije"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Meni"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sq-rAL/strings.xml b/packages/SettingsLib/res/values-sq-rAL/strings.xml
index 326e8ea..1645f10 100644
--- a/packages/SettingsLib/res/values-sq-rAL/strings.xml
+++ b/packages/SettingsLib/res/values-sq-rAL/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Më i madhi"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"I personalizuar (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Ndihma dhe komentet"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menyja"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index bb1515d..04dfb24 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Највећи"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Прилагођени (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Помоћ и повратне информације"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Мени"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index ecbdd91..4b42db5 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Störst"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Anpassad (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Hjälp och feedback"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Meny"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index b68dcb7..f70a1fa 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Kubwa zaidi"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Kiwango maalum (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Usaidizi na maoni"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menyu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ta-rIN/strings.xml b/packages/SettingsLib/res/values-ta-rIN/strings.xml
index 03623bf..5f6b121 100644
--- a/packages/SettingsLib/res/values-ta-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ta-rIN/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"மிகப் பெரியது"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"தனிப்பயன் (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"உதவி &amp; கருத்து"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"மெனு"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-te-rIN/strings.xml b/packages/SettingsLib/res/values-te-rIN/strings.xml
index ec6aa02..ff8b855 100644
--- a/packages/SettingsLib/res/values-te-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-te-rIN/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"అతి పెద్దగా"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"అనుకూలం (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"సహాయం &amp; అభిప్రాయం"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"మెను"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 01348e0..4d0a2e4 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"ใหญ่ที่สุด"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"กำหนดเอง (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"ความช่วยเหลือและความคิดเห็น"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"เมนู"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index b58fb31..95897a3 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Pinakamalaki"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Tulong at feedback"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index f50eeb0..3c5b46d 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"En büyük"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Özel (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Yardım ve geri bildirim"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menü"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 1ba1055..ef30a69 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Найбільші елементи"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Спеціальний масштаб (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Довідка й відгуки"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ur-rPK/strings.xml b/packages/SettingsLib/res/values-ur-rPK/strings.xml
index 4211dd2..57b0b63 100644
--- a/packages/SettingsLib/res/values-ur-rPK/strings.xml
+++ b/packages/SettingsLib/res/values-ur-rPK/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"سب سے بڑا"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"حسب ضرورت (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"مدد اور تاثرات"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"مینو"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
index af30901..b4e0505 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Eng katta"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Moslashtirilgan (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Yordam va fikr-mulohaza"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menyu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index bb038e3..494cb7c 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Lớn nhất"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Tùy chỉnh (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Trợ giúp và phản hồi"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index c4468e6..1c58a11 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自定义 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"帮助和反馈"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"菜单"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 498988c..45918f0 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自訂 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"說明與意見反映"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"選單"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 69999c1..b2e0d12 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"最大"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"自訂 (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"說明與意見回饋"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"選單"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index ccf607a..d137908 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -341,6 +341,5 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"Okukhulu kakhulu"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Ngokwezifiso (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="help_feedback_label" msgid="6815040660801785649">"Usizo nempendulo"</string>
-    <!-- no translation found for content_description_menu_button (8182594799812351266) -->
-    <skip />
+    <string name="content_description_menu_button" msgid="8182594799812351266">"Imenyu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values/config.xml b/packages/SettingsLib/res/values/config.xml
index 299a5b7..d9473fa 100755
--- a/packages/SettingsLib/res/values/config.xml
+++ b/packages/SettingsLib/res/values/config.xml
@@ -19,4 +19,7 @@
 <resources>
     <!-- Configuration for automotive -->
     <bool name="enable_pbap_pce_profile">false</bool>
+
+    <!-- Default data warning level in mb -->
+    <integer name="default_data_warning_level_mb">2048</integer>
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java b/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java
index 687b3fc..2e77f42 100644
--- a/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java
+++ b/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java
@@ -178,8 +178,9 @@
     public void setPolicyWarningBytes(NetworkTemplate template, long warningBytes) {
         long limitBytes = getPolicyLimitBytes(template);
 
-        // If the warningBytes are larger than limitBytes, set the warningBytes to limitBytes
-        warningBytes = Math.min(warningBytes, limitBytes);
+        warningBytes =
+            (limitBytes == LIMIT_DISABLED) ? warningBytes : Math.min(warningBytes, limitBytes);
+
         setPolicyWarningBytesInner(template, warningBytes);
     }
 
@@ -192,8 +193,7 @@
     public void setPolicyLimitBytes(NetworkTemplate template, long limitBytes) {
         long warningBytes = getPolicyWarningBytes(template);
 
-        // If the warningBytes are larger than limitBytes, set the warningBytes to limitBytes
-        if (warningBytes > limitBytes) {
+        if (warningBytes > limitBytes && limitBytes != LIMIT_DISABLED) {
             setPolicyWarningBytesInner(template, limitBytes);
         }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
index e53dd2f..994ea88 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
@@ -32,6 +32,8 @@
 import android.text.format.Time;
 import android.util.Log;
 
+import com.android.settingslib.R;
+
 import java.util.Date;
 import java.util.Locale;
 
@@ -41,12 +43,12 @@
 import static android.telephony.TelephonyManager.SIM_STATE_READY;
 import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
 import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
+import static android.net.TrafficStats.MB_IN_BYTES;
 
 public class DataUsageController {
+
     private static final String TAG = "DataUsageController";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-    public static final long DEFAULT_WARNING_LEVEL = 2L * 1024 * 1024 * 1024;
     private static final int FIELDS = FIELD_RX_BYTES | FIELD_TX_BYTES;
     private static final StringBuilder PERIOD_BUILDER = new StringBuilder(50);
     private static final java.util.Formatter PERIOD_FORMATTER = new java.util.Formatter(
@@ -75,6 +77,14 @@
         mNetworkController = networkController;
     }
 
+    /**
+     * Returns the default warning level in bytes.
+     */
+    public long getDefaultWarningLevel() {
+        return MB_IN_BYTES
+                * mContext.getResources().getInteger(R.integer.default_data_warning_level_mb);
+    }
+
     private INetworkStatsSession getSession() {
         if (mSession == null) {
             try {
@@ -169,7 +179,7 @@
                 usage.limitLevel = policy.limitBytes > 0 ? policy.limitBytes : 0;
                 usage.warningLevel = policy.warningBytes > 0 ? policy.warningBytes : 0;
             } else {
-                usage.warningLevel = DEFAULT_WARNING_LEVEL;
+                usage.warningLevel = getDefaultWarningLevel();
             }
             if (usage != null && mNetworkController != null) {
                 usage.carrier = mNetworkController.getMobileDataNetworkName();
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
index 5c8849d..c189e1d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
@@ -31,6 +31,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.support.annotation.VisibleForTesting;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.inputmethod.InputMethodInfo;
@@ -49,6 +50,7 @@
     private static final boolean DEBUG = false;
     private static final String TAG = "AppRestrictionsHelper";
 
+    private final Injector mInjector;
     private final Context mContext;
     private final PackageManager mPackageManager;
     private final IPackageManager mIPm;
@@ -61,11 +63,17 @@
     private List<SelectableAppInfo> mVisibleApps;
 
     public AppRestrictionsHelper(Context context, UserHandle user) {
-        mContext = context;
-        mPackageManager = context.getPackageManager();
-        mIPm = AppGlobals.getPackageManager();
-        mUser = user;
-        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        this(new Injector(context, user));
+    }
+
+    @VisibleForTesting
+    AppRestrictionsHelper(Injector injector) {
+        mInjector = injector;
+        mContext = mInjector.getContext();
+        mPackageManager = mInjector.getPackageManager();
+        mIPm = mInjector.getIPackageManager();
+        mUser = mInjector.getUser();
+        mUserManager = mInjector.getUserManager();
         mRestrictedProfile = mUserManager.getUserInfo(mUser.getIdentifier()).isRestricted();
     }
 
@@ -86,8 +94,7 @@
     }
 
     public void applyUserAppsStates(OnDisableUiForPackageListener listener) {
-        final int userId = mUser.getIdentifier();
-        if (!mUserManager.getUserInfo(userId).isRestricted() && userId != UserHandle.myUserId()) {
+        if (!mRestrictedProfile && mUser.getIdentifier() != UserHandle.myUserId()) {
             Log.e(TAG, "Cannot apply application restrictions on another user!");
             return;
         }
@@ -130,8 +137,8 @@
                 ApplicationInfo info = mIPm.getApplicationInfo(packageName, 0, userId);
                 if (info != null) {
                     if (mRestrictedProfile) {
-                        mIPm.deletePackageAsUser(packageName, null, mUser.getIdentifier(),
-                                PackageManager.DELETE_SYSTEM_APP);
+                        mPackageManager.deletePackageAsUser(packageName, null,
+                                PackageManager.DELETE_SYSTEM_APP, mUser.getIdentifier());
                         if (DEBUG) {
                             Log.d(TAG, "Uninstalling " + packageName);
                         }
@@ -268,9 +275,7 @@
      * @param excludePackages the set of package names to append to
      */
     private void addSystemImes(Set<String> excludePackages) {
-        InputMethodManager imm = (InputMethodManager)
-                mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
-        List<InputMethodInfo> imis = imm.getInputMethodList();
+        List<InputMethodInfo> imis = mInjector.getInputMethodList();
         for (InputMethodInfo imi : imis) {
             try {
                 if (imi.isDefault(mContext) && isSystemPackage(imi.getPackageName())) {
@@ -376,4 +381,44 @@
             return lhsLabel.toLowerCase().compareTo(rhsLabel.toLowerCase());
         }
     }
+
+    /**
+     * Unit test will subclass it to inject mocks.
+     */
+    @VisibleForTesting
+    static class Injector {
+        private Context mContext;
+        private UserHandle mUser;
+
+        Injector(Context context, UserHandle user) {
+            mContext = context;
+            mUser = user;
+        }
+
+        Context getContext() {
+            return mContext;
+        }
+
+        UserHandle getUser() {
+            return mUser;
+        }
+
+        PackageManager getPackageManager() {
+            return mContext.getPackageManager();
+        }
+
+        IPackageManager getIPackageManager() {
+            return AppGlobals.getPackageManager();
+        }
+
+        UserManager getUserManager() {
+            return mContext.getSystemService(UserManager.class);
+        }
+
+        List<InputMethodInfo> getInputMethodList() {
+            InputMethodManager imm = (InputMethodManager) getContext().getSystemService(
+                    Context.INPUT_METHOD_SERVICE);
+            return imm.getInputMethodList();
+        }
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 380fcd4..0a3f0c0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -36,6 +36,7 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.support.annotation.NonNull;
 import android.text.Spannable;
@@ -43,12 +44,13 @@
 import android.text.TextUtils;
 import android.text.style.TtsSpan;
 import android.util.Log;
-import android.util.LruCache;
 
 import com.android.settingslib.R;
 
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 
 public class AccessPoint implements Comparable<AccessPoint> {
@@ -81,7 +83,9 @@
      *  For now this data is used only with Verbose Logging so as to show the band and number
      *  of BSSIDs on which that network is seen.
      */
-    public LruCache<String, ScanResult> mScanResultCache = new LruCache<String, ScanResult>(32);
+    private final ConcurrentHashMap<String, ScanResult> mScanResultCache =
+            new ConcurrentHashMap<String, ScanResult>(32);
+    private static final long MAX_SCAN_RESULT_AGE_MS = 15000;
 
     private static final String KEY_NETWORKINFO = "key_networkinfo";
     private static final String KEY_WIFIINFO = "key_wifiinfo";
@@ -149,7 +153,7 @@
         if (savedState.containsKey(KEY_SCANRESULTCACHE)) {
             ArrayList<ScanResult> scanResultArrayList =
                     savedState.getParcelableArrayList(KEY_SCANRESULTCACHE);
-            mScanResultCache.evictAll();
+            mScanResultCache.clear();
             for (ScanResult result : scanResultArrayList) {
                 mScanResultCache.put(result.BSSID, result);
             }
@@ -233,6 +237,17 @@
         return builder.append(')').toString();
     }
 
+    private void evictOldScanResults() {
+        long nowMs = SystemClock.elapsedRealtime();
+        for (Iterator<ScanResult> iter = mScanResultCache.values().iterator(); iter.hasNext(); ) {
+            ScanResult result = iter.next();
+            // result timestamp is in microseconds
+            if (nowMs - result.timestamp / 1000 > MAX_SCAN_RESULT_AGE_MS) {
+                iter.remove();
+            }
+        }
+    }
+
     public boolean matches(ScanResult result) {
         return ssid.equals(result.SSID) && security == getSecurity(result);
     }
@@ -268,8 +283,9 @@
     }
 
     public int getRssi() {
+        evictOldScanResults();
         int rssi = Integer.MIN_VALUE;
-        for (ScanResult result : mScanResultCache.snapshot().values()) {
+        for (ScanResult result : mScanResultCache.values()) {
             if (result.level > rssi) {
                 rssi = result.level;
             }
@@ -279,8 +295,9 @@
     }
 
     public long getSeen() {
+        evictOldScanResults();
         long seen = 0;
-        for (ScanResult result : mScanResultCache.snapshot().values()) {
+        for (ScanResult result : mScanResultCache.values()) {
             if (result.timestamp > seen) {
                 seen = result.timestamp;
             }
@@ -505,9 +522,9 @@
         int numBlackListed = 0;
         int n24 = 0; // Number scan results we included in the string
         int n5 = 0; // Number scan results we included in the string
-        Map<String, ScanResult> list = mScanResultCache.snapshot();
+        evictOldScanResults();
         // TODO: sort list by RSSI or age
-        for (ScanResult result : list.values()) {
+        for (ScanResult result : mScanResultCache.values()) {
 
             if (result.frequency >= LOWER_FREQ_5GHZ
                     && result.frequency <= HIGHER_FREQ_5GHZ) {
@@ -684,8 +701,9 @@
         savedState.putInt(KEY_PSKTYPE, pskType);
         if (mConfig != null) savedState.putParcelable(KEY_CONFIG, mConfig);
         savedState.putParcelable(KEY_WIFIINFO, mInfo);
+        evictOldScanResults();
         savedState.putParcelableArrayList(KEY_SCANRESULTCACHE,
-                new ArrayList<ScanResult>(mScanResultCache.snapshot().values()));
+                new ArrayList<ScanResult>(mScanResultCache.values()));
         if (mNetworkInfo != null) {
             savedState.putParcelable(KEY_NETWORKINFO, mNetworkInfo);
         }
@@ -697,9 +715,6 @@
 
     boolean update(ScanResult result) {
         if (matches(result)) {
-            /* Update the LRU timestamp, if BSSID exists */
-            mScanResultCache.get(result.BSSID);
-
             /* Add or update the scan result for the BSSID */
             mScanResultCache.put(result.BSSID, result);
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index 284827b..aae9cf6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -29,7 +29,6 @@
 import android.util.AttributeSet;
 import android.util.SparseArray;
 import android.widget.TextView;
-
 import com.android.settingslib.R;
 
 public class AccessPointPreference extends Preference {
@@ -44,13 +43,14 @@
     private final StateListDrawable mWifiSld;
     private final int mBadgePadding;
     private final UserBadgeCache mBadgeCache;
-
     private TextView mTitleView;
+
     private boolean mForSavedNetworks = false;
     private AccessPoint mAccessPoint;
     private Drawable mBadge;
     private int mLevel;
     private CharSequence mContentDescription;
+    private int mDefaultIconResId;
 
     static final int[] WIFI_CONNECTION_STRENGTH = {
             R.string.accessibility_wifi_one_bar,
@@ -85,6 +85,24 @@
         refresh();
     }
 
+    public AccessPointPreference(AccessPoint accessPoint, Context context, UserBadgeCache cache,
+            int iconResId, boolean forSavedNetworks) {
+        super(context);
+        mBadgeCache = cache;
+        mAccessPoint = accessPoint;
+        mForSavedNetworks = forSavedNetworks;
+        mAccessPoint.setTag(this);
+        mLevel = -1;
+        mDefaultIconResId = iconResId;
+
+        mWifiSld = (StateListDrawable) context.getTheme()
+                .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0);
+
+        // Distance from the end of the title at which this AP's user badge should sit.
+        mBadgePadding = context.getResources()
+                .getDimensionPixelSize(R.dimen.wifi_preference_badge_padding);
+    }
+
     public AccessPoint getAccessPoint() {
         return mAccessPoint;
     }
@@ -112,7 +130,7 @@
 
     protected void updateIcon(int level, Context context) {
         if (level == -1) {
-            setIcon(null);
+            safeSetDefaultIcon();
         } else {
             if (getIcon() == null) {
                 // To avoid a drawing race condition, we first set the state (SECURE/NONE) and then
@@ -124,16 +142,24 @@
                             ? STATE_SECURED
                             : STATE_NONE);
                     Drawable drawable = mWifiSld.getCurrent();
-                    if (!mForSavedNetworks) {
+                    if (!mForSavedNetworks && drawable != null) {
                         setIcon(drawable);
-                    } else {
-                        setIcon(null);
+                        return;
                     }
                 }
+                safeSetDefaultIcon();
             }
         }
     }
 
+    private void safeSetDefaultIcon() {
+        if (mDefaultIconResId != 0) {
+            setIcon(mDefaultIconResId);
+        } else {
+            setIcon(null);
+        }
+    }
+
     protected void updateBadge(Context context) {
         WifiConfiguration config = mAccessPoint.getConfig();
         if (config != null) {
diff --git a/packages/SettingsLib/tests/src/com/android/settingslib/users/AppRestrictionsHelperTest.java b/packages/SettingsLib/tests/src/com/android/settingslib/users/AppRestrictionsHelperTest.java
new file mode 100644
index 0000000..3f989bd
--- /dev/null
+++ b/packages/SettingsLib/tests/src/com/android/settingslib/users/AppRestrictionsHelperTest.java
@@ -0,0 +1,305 @@
+/*
+ * 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
+ */
+
+package com.android.settingslib.users;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+
+import android.appwidget.AppWidgetManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.inputmethod.InputMethodInfo;
+import com.android.settingslib.BaseTest;
+
+import org.hamcrest.Description;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@SmallTest
+public class AppRestrictionsHelperTest extends BaseTest {
+    private @Mock Context mContext;
+    private @Mock PackageManager mPm;
+    private @Mock IPackageManager mIpm;
+    private @Mock UserManager mUm;
+
+    private TestInjector mInjector;
+    private UserHandle mTestUser = UserHandle.of(1111);
+    private AppRestrictionsHelper mHelper;
+
+    private ArrayList<String> mInstalledApps;
+    private ArrayList<ApplicationInfo> mInstalledAppInfos;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        MockitoAnnotations.initMocks(this);
+
+        mInjector = new TestInjector();
+        final UserInfo user = new UserInfo(
+                mTestUser.getIdentifier(), "test_user", UserInfo.FLAG_RESTRICTED);
+        when(mUm.getUserInfo(mTestUser.getIdentifier())).thenReturn(user);
+        mHelper = new AppRestrictionsHelper(mInjector);
+        mInstalledApps = new ArrayList<>();
+        mInstalledAppInfos = new ArrayList<>();
+    }
+
+    public void testFetchAndMergeApps() throws Exception {
+        addSystemAppsWithRequiredAccounts("sys.app0");
+        addsystemImes(new String[] {"sys.app1", "sys.app2"},
+                new String[] {"sys.app3", "sys.app4", "sys.app5"});
+        addSystemAppsForIntent(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER),
+                "sys.app1", "sys.app4", "sys.app6");
+        addSystemAppsForIntent(new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE),
+                "sys.app2", "sys.app5", "sys.app7");
+        addDownloadedApps("app1", "app2");
+        when(mPm.getInstalledApplications(anyInt())).thenReturn(mInstalledAppInfos);
+
+        mHelper.fetchAndMergeApps();
+
+        final ArrayList<String> notExpectedInVisibleApps = new ArrayList<>();
+        // System apps that require an account and doesn't see restricted account are
+        // not part of visibleApps.
+        notExpectedInVisibleApps.add("sys.app0");
+        // Default system IMEs are not part of visibleApps.
+        notExpectedInVisibleApps.add("sys.app1");
+        notExpectedInVisibleApps.add("sys.app2");
+
+        final ArrayList<String> expectedInVisibleApps = new ArrayList<>();
+        expectedInVisibleApps.add("sys.app4");
+        expectedInVisibleApps.add("sys.app5");
+        expectedInVisibleApps.add("sys.app6");
+        expectedInVisibleApps.add("sys.app7");
+        expectedInVisibleApps.add("app1");
+        expectedInVisibleApps.add("app2");
+
+        for (AppRestrictionsHelper.SelectableAppInfo info : mHelper.getVisibleApps()) {
+            if (expectedInVisibleApps.contains(info.packageName)) {
+                expectedInVisibleApps.remove(info.packageName);
+            } else if (notExpectedInVisibleApps.contains(info.packageName)) {
+                fail("Package: " + info.packageName + " should not be included in visibleApps");
+            } else {
+                fail("Unknown package: " + info.packageName);
+            }
+        }
+        assertEquals("Some expected apps are not inclued in visibleApps: " + expectedInVisibleApps,
+                0, expectedInVisibleApps.size());
+
+        assertFalse("System apps that require an account and doesn't see restricted account "
+                + "should be marked for removal", mHelper.isPackageSelected("sys.app0"));
+    }
+
+    public void testApplyUserAppsStates() throws Exception {
+        final int testUserId = mTestUser.getIdentifier();
+        mHelper.setPackageSelected("app1", true);
+
+        mHelper.setPackageSelected("app2", true);
+        ApplicationInfo info = new ApplicationInfo();
+        info.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
+        info.flags |= ApplicationInfo.FLAG_INSTALLED;
+        when(mIpm.getApplicationInfo(eq("app2"), anyInt(), eq(testUserId)))
+                .thenReturn(info);
+
+        mHelper.setPackageSelected("app3", false);
+        info = new ApplicationInfo();
+        when(mIpm.getApplicationInfo(eq("app3"), anyInt(), eq(testUserId)))
+                .thenReturn(info);
+
+        AppRestrictionsHelper.OnDisableUiForPackageListener mockListener =
+                mock(AppRestrictionsHelper.OnDisableUiForPackageListener.class);
+        mHelper.applyUserAppsStates(mockListener);
+
+        verify(mIpm, times(1)).installExistingPackageAsUser("app1", testUserId);
+        verify(mIpm, times(1)).setApplicationHiddenSettingAsUser("app2", false, testUserId);
+        verify(mockListener).onDisableUiForPackage("app2");
+        verify(mPm, times(1)).deletePackageAsUser(eq("app3"), any(IPackageDeleteObserver.class),
+                anyInt(), eq(mTestUser.getIdentifier()));
+    }
+
+    private void addsystemImes(String[] defaultImes, String[] otherImes) throws
+            PackageManager.NameNotFoundException, RemoteException {
+        final ArrayList<InputMethodInfo> inputMethods = new ArrayList<>();
+        for (String pkg : defaultImes) {
+            final ResolveInfo ri = createResolveInfoForSystemApp(pkg);
+            final InputMethodInfo inputMethodInfo = new InputMethodInfo(
+                    ri, false, null, null, 0, true, true);
+            inputMethods.add(inputMethodInfo);
+            addInstalledApp(ri);
+        }
+        for (String pkg : otherImes) {
+            final ResolveInfo ri = createResolveInfoForSystemApp(pkg);
+            final InputMethodInfo inputMethodInfo = new InputMethodInfo(
+                    ri, false, null, null, 0, false, true);
+            inputMethods.add(inputMethodInfo);
+            addInstalledApp(ri);
+        }
+
+        mInjector.setInputMethodList(inputMethods);
+    }
+
+    private void addSystemAppsForIntent(Intent intent, String... packages) throws Exception {
+        List<ResolveInfo> resolveInfos = new ArrayList<>();
+        for (String pkg : packages) {
+            final ResolveInfo ri = createResolveInfoForSystemApp(pkg);
+            resolveInfos.add(ri);
+            addInstalledApp(ri);
+        }
+        when(mPm.queryIntentActivities(argThat(new IntentMatcher(intent)), anyInt()))
+                .thenReturn(resolveInfos);
+    }
+
+    private void addSystemAppsWithRequiredAccounts(String... packages) throws Exception {
+        for (String pkg : packages) {
+            final ResolveInfo ri = createResolveInfoForSystemApp(pkg);
+            final PackageInfo packageInfo = new PackageInfo();
+            packageInfo.applicationInfo = ri.activityInfo.applicationInfo;
+            packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
+            packageInfo.requiredAccountType = "account";
+            packageInfo.restrictedAccountType = null;
+            mInstalledAppInfos.add(packageInfo.applicationInfo);
+            when(mPm.getPackageInfo(eq(pkg), anyInt())).thenReturn(packageInfo);
+        }
+    }
+
+    private void addDownloadedApps(String... packages) throws Exception {
+        for (String pkg : packages) {
+            final ResolveInfo ri = createResolveInfo(pkg);
+            addInstalledApp(ri);
+        }
+    }
+
+    private void addInstalledApp(ResolveInfo ri) throws PackageManager.NameNotFoundException {
+        final String pkgName = ri.activityInfo.packageName;
+        if (mInstalledApps.contains(pkgName)) {
+            return;
+        }
+        final PackageInfo packageInfo = new PackageInfo();
+        packageInfo.applicationInfo = ri.activityInfo.applicationInfo;
+        packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
+        mInstalledAppInfos.add(packageInfo.applicationInfo);
+        when(mPm.getPackageInfo(eq(pkgName), anyInt())).thenReturn(packageInfo);
+    }
+
+    private ResolveInfo createResolveInfoForSystemApp(String packageName) {
+        final ResolveInfo ri = createResolveInfo(packageName);
+        ri.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+        ri.serviceInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+        return ri;
+    }
+
+    private ResolveInfo createResolveInfo(String packageName) {
+        final ResolveInfo ri = new ResolveInfo();
+        final ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.packageName = packageName;
+        final ActivityInfo activityInfo = new ActivityInfo();
+        activityInfo.applicationInfo = applicationInfo;
+        activityInfo.packageName = packageName;
+        activityInfo.name = "";
+        ri.activityInfo = activityInfo;
+        final ServiceInfo serviceInfo = new ServiceInfo();
+        serviceInfo.applicationInfo = applicationInfo;
+        serviceInfo.packageName = packageName;
+        serviceInfo.name = "";
+        ri.serviceInfo = serviceInfo;
+        return ri;
+    }
+
+    private class IntentMatcher extends ArgumentMatcher<Intent> {
+        private final Intent mIntent;
+
+        IntentMatcher(Intent intent) {
+            mIntent = intent;
+        }
+
+        @Override
+        public boolean matches(Object argument) {
+            if (argument instanceof Intent) {
+                return ((Intent) argument).filterEquals(mIntent);
+            }
+            return false;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("Expected: " + mIntent);
+        }
+    }
+
+    private class TestInjector extends AppRestrictionsHelper.Injector {
+        List<InputMethodInfo> mImis;
+
+        TestInjector() {
+            super(mContext, mTestUser);
+        }
+
+        @Override
+        Context getContext() {
+            return mContext;
+        }
+
+        @Override
+        UserHandle getUser() {
+            return mTestUser;
+        }
+
+        @Override
+        PackageManager getPackageManager() {
+            return mPm;
+        }
+
+        @Override
+        IPackageManager getIPackageManager() {
+            return mIpm;
+        }
+
+        @Override
+        UserManager getUserManager() {
+            return mUm;
+        }
+
+        @Override
+        List<InputMethodInfo> getInputMethodList() {
+            return mImis;
+        }
+
+        void setInputMethodList(List<InputMethodInfo> imis) {
+            mImis = imis;
+        }
+    }
+}
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index fad102f..c1e4e2a 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -89,6 +89,9 @@
     <!-- Default for Settings.System.VIBRATE_IN_SILENT -->
     <bool name="def_vibrate_in_silent">true</bool>
 
+    <!-- Default for Settings.Secure.SYNC_PARENT_SOUNDS -->
+    <bool name="def_sync_parent_sounds">true</bool>
+
     <!-- Default for Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION -->
     <bool name="def_accessibility_script_injection">false</bool>
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index ac311ba..37e7442 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -58,6 +58,7 @@
 import android.os.UserManagerInternal;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -76,6 +77,7 @@
 import java.security.SecureRandom;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.regex.Pattern;
 
@@ -195,6 +197,13 @@
         Settings.System.getCloneToManagedProfileSettings(sSystemCloneToManagedSettings);
     }
 
+    // Per user system settings that are cloned from the profile's parent when a dependency
+    // in {@link Settings.Secure} is set to "1".
+    public static final Map<String, String> sSystemCloneFromParentOnDependency = new ArrayMap<>();
+    static {
+        Settings.System.getCloneFromParentOnValueSettings(sSystemCloneFromParentOnDependency);
+    }
+
     private final Object mLock = new Object();
 
     @GuardedBy("mLock")
@@ -518,19 +527,29 @@
         }
         uri = ContentProvider.getUriWithoutUserId(uri);
 
+        final String cacheRingtoneSetting;
         final String cacheName;
         if (Settings.System.RINGTONE_CACHE_URI.equals(uri)) {
+            cacheRingtoneSetting = Settings.System.RINGTONE;
             cacheName = Settings.System.RINGTONE_CACHE;
         } else if (Settings.System.NOTIFICATION_SOUND_CACHE_URI.equals(uri)) {
+            cacheRingtoneSetting = Settings.System.NOTIFICATION_SOUND;
             cacheName = Settings.System.NOTIFICATION_SOUND_CACHE;
         } else if (Settings.System.ALARM_ALERT_CACHE_URI.equals(uri)) {
+            cacheRingtoneSetting = Settings.System.ALARM_ALERT;
             cacheName = Settings.System.ALARM_ALERT_CACHE;
         } else {
             throw new FileNotFoundException("Direct file access no longer supported; "
                     + "ringtone playback is available through android.media.Ringtone");
         }
 
-        final File cacheFile = new File(getRingtoneCacheDir(userId), cacheName);
+        int actualCacheOwner;
+        // Redirect cache to parent if ringtone setting is owned by profile parent
+        synchronized (mLock) {
+            actualCacheOwner = resolveOwningUserIdForSystemSettingLocked(userId,
+                    cacheRingtoneSetting);
+        }
+        final File cacheFile = new File(getRingtoneCacheDir(actualCacheOwner), cacheName);
         return ParcelFileDescriptor.open(cacheFile, ParcelFileDescriptor.parseMode(mode));
     }
 
@@ -1102,7 +1121,7 @@
         }
         if (cacheName != null) {
             final File cacheFile = new File(
-                    getRingtoneCacheDir(UserHandle.getCallingUserId()), cacheName);
+                    getRingtoneCacheDir(owningUserId), cacheName);
             cacheFile.delete();
         }
 
@@ -1242,6 +1261,16 @@
     }
 
     private int resolveOwningUserIdForSystemSettingLocked(int userId, String setting) {
+        final int parentId;
+        // Resolves dependency if setting has a dependency and the calling user has a parent
+        if (sSystemCloneFromParentOnDependency.containsKey(setting)
+                && (parentId = getGroupParentLocked(userId)) != userId) {
+            // The setting has a dependency and the profile has a parent
+            String dependency = sSystemCloneFromParentOnDependency.get(setting);
+            if (getSecureSetting(dependency, userId).getValue().equals("1")) {
+                return parentId;
+            }
+        }
         return resolveOwningUserIdLocked(userId, sSystemCloneToManagedSettings, setting);
     }
 
@@ -2108,7 +2137,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 131;
+            private static final int SETTINGS_VERSION = 132;
 
             private final int mUserId;
 
@@ -2432,6 +2461,18 @@
                     currentVersion = 131;
                 }
 
+                if (currentVersion == 131) {
+                    // Version 131: Allow managed profile to optionally use the parent's ringtones
+                    final SettingsState systemSecureSettings = getSecureSettingsLocked(userId);
+                    String defaultSyncParentSounds = (getContext().getResources()
+                            .getBoolean(R.bool.def_sync_parent_sounds) ? "1" : "0");
+                    systemSecureSettings.insertSettingLocked(
+                            Settings.Secure.SYNC_PARENT_SOUNDS,
+                            defaultSyncParentSounds,
+                            SettingsState.SYSTEM_PACKAGE_NAME);
+                    currentVersion = 132;
+                }
+
                 if (currentVersion != newVersion) {
                     Slog.w("SettingsProvider", "warning: upgrading settings database to version "
                             + newVersion + " left it at "
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_carmode.png
index 6242084..95e5778 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_carmode.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_carmode.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_carmode.png
index 1b37a47..6421146 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_carmode.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_carmode.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_carmode.png
index 9e05758..151d5fe 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_carmode.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_carmode.png
index 2fcfdde..b954aa7 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_carmode.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_carmode.png
index 48708a5..61d5db6 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_carmode.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_carmode.png
index 3d73184..7b98c1f 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_carmode.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_carmode.png
index 786935d..aad1320 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_carmode.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_carmode.png
index e4bd4bc..754b2d9 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_carmode.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_carmode.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_carmode.png
index 94ccf79..873ed7f 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_carmode.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_carmode.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_carmode.png
index 980bbbc..7696d87 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_carmode.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_carmode.png
index 201be3b..c98f55e 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_carmode.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_carmode.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_carmode.png
index 2770d62..187a566 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_carmode.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_carmode.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_carmode.png
index 8ac6493..c66f8be 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_carmode.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_carmode.png
index 8e3678b..3a3a119 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_carmode.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_carmode.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_carmode.png
index 6c7cb05..7198c82 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_carmode.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_carmode.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_carmode.png
index ea2b108..b1fc02e 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_carmode.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_carmode.png
index 3e11023..c06bfda 100644
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_carmode.png
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_carmode.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_carmode.png
index fe8213d..a8c76bf 100644
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_carmode.png
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_carmode.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_carmode.png
index c117efd..b798e3d 100644
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_carmode.png
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 23d7ab6..ae66d79 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -32,7 +32,7 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ծանուցումներ չկան"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ընթացիկ"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ծանուցումներ"</string>
-    <string name="battery_low_title" msgid="6456385927409742437">"Մարտկոցը լիցքաթափվում է"</string>
+    <string name="battery_low_title" msgid="6456385927409742437">"Մարտկոցի լիցքը սպառվում է"</string>
     <string name="battery_low_percent_format" msgid="2900940511201380775">"Մնաց <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Մնաց <xliff:g id="PERCENTAGE">%s</xliff:g>: Մարտկոցի տնտեսումը միացված է:"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"USB լիցքավորումը չի աջակցվում:\nՕգտվեք միայն գործող լիցքավորիչից:"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index c2897cd..8d44048 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -218,12 +218,6 @@
     <!-- Doze: should notifications be used as a pulse signal? -->
     <bool name="doze_pulse_on_notifications">true</bool>
 
-    <!-- Doze: when to pulse after a buzzworthy notification arrives -->
-    <string name="doze_pulse_schedule" translatable="false">10s,30s,60s</string>
-
-    <!-- Doze: maximum number of times the notification pulse schedule can be reset -->
-    <integer name="doze_pulse_schedule_resets">2</integer>
-
     <!-- Doze: duration to avoid false pickup gestures triggered by notification vibrations -->
     <integer name="doze_pickup_vibration_threshold">2000</integer>
 
@@ -253,7 +247,7 @@
     <integer name="doze_pulse_duration_in_pickup">130</integer>
 
     <!-- Doze: pulse parameter - once faded in, how long does it stay visible? -->
-    <integer name="doze_pulse_duration_visible">3000</integer>
+    <integer name="doze_pulse_duration_visible">6000</integer>
 
     <!-- Doze: pulse parameter - how long does it take to fade out? -->
     <integer name="doze_pulse_duration_out">600</integer>
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java
index bad739fd..4585fe9 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java
@@ -62,36 +62,36 @@
     @Override
     public float getFalseTouchEvaluation(int type, Stroke stroke) {
         Data data = mStrokeMap.get(stroke);
-        return SpeedRatioEvaluator.evaluate(data.maxSpeedRatio)
-                + DistanceRatioEvaluator.evaluate(data.maxDistanceRatio);
+        return 2 * SpeedRatioEvaluator.evaluate(data.maxSpeedRatio);
     }
 
     private static class Data {
-        public Point previousPoint;
-        public float previousSpeed;
-        public float previousDistance;
-        public float maxSpeedRatio;
-        public float maxDistanceRatio;
+
+        static final float MILLIS_TO_NANOS = 1e6f;
+
+        Point previousPoint;
+        float previousSpeed = 0;
+        float maxSpeedRatio = 0;
 
         public Data(Point point) {
             previousPoint = point;
-            previousSpeed = previousDistance = 0.0f;
-            maxDistanceRatio = maxSpeedRatio = 0.0f;
         }
 
         public void addPoint(Point point) {
             float distance = previousPoint.dist(point);
             float duration = (float) (point.timeOffsetNano - previousPoint.timeOffsetNano + 1);
             float speed = distance / duration;
-            if (previousDistance != 0.0f) {
-                maxDistanceRatio = Math.max(maxDistanceRatio, distance / previousDistance);
-            }
 
+            if (duration > 20 * MILLIS_TO_NANOS || duration < 5 * MILLIS_TO_NANOS) {
+                // reject this segment and ensure we won't use data about it in the next round.
+                previousSpeed = 0;
+                previousPoint = point;
+                return;
+            }
             if (previousSpeed != 0.0f) {
                 maxSpeedRatio = Math.max(maxSpeedRatio, speed / previousSpeed);
             }
 
-            previousDistance = distance;
             previousSpeed = speed;
             previousPoint = point;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java
deleted file mode 100644
index 8acb009..0000000
--- a/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.classifier;
-
-public class DistanceRatioEvaluator {
-    public static float evaluate(float value) {
-        float evaluation = 0.0f;
-        if (value <= 1.0) evaluation++;
-        if (value <= 0.5) evaluation++;
-        if (value > 4.0) evaluation++;
-        if (value > 7.0) evaluation++;
-        if (value > 14.0) evaluation++;
-        return evaluation;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java
index 4c6cea0..e34f222 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java
@@ -19,6 +19,7 @@
 public class SpeedRatioEvaluator {
     public static float evaluate(float value) {
         float evaluation = 0.0f;
+        if (value == 0) return 0;
         if (value <= 1.0) evaluation++;
         if (value <= 0.5) evaluation++;
         if (value > 9.0) evaluation++;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 7c8d0f6..874021a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -33,7 +33,7 @@
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private static final boolean ENABLED = true;
     private static final int SIZE = Build.IS_DEBUGGABLE ? 400 : 50;
-    private static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
+    static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
 
     private static final int PULSE_REASONS = 4;
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index fc0d8bb..ec4f447 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.doze;
 
-import android.app.AlarmManager;
-import android.app.PendingIntent;
 import android.app.UiModeManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -43,7 +41,6 @@
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.SystemUIApplication;
 import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.phone.DozeParameters.PulseSchedule;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -55,19 +52,6 @@
 
     private static final String ACTION_BASE = "com.android.systemui.doze";
     private static final String PULSE_ACTION = ACTION_BASE + ".pulse";
-    private static final String NOTIFICATION_PULSE_ACTION = ACTION_BASE + ".notification_pulse";
-    private static final String EXTRA_INSTANCE = "instance";
-
-    /**
-     * Earliest time we pulse due to a notification light after the service started.
-     *
-     * <p>Incoming notification light events during the blackout period are
-     * delayed to the earliest time defined by this constant.</p>
-     *
-     * <p>This delay avoids a pulse immediately after screen off, at which
-     * point the notification light is re-enabled again by NoMan.</p>
-     */
-    private static final int EARLIEST_LIGHT_PULSE_AFTER_START_MS = 10 * 1000;
 
     private final String mTag = String.format(TAG + ".%08x", hashCode());
     private final Context mContext = this;
@@ -80,19 +64,14 @@
     private TriggerSensor mPickupSensor;
     private PowerManager mPowerManager;
     private PowerManager.WakeLock mWakeLock;
-    private AlarmManager mAlarmManager;
     private UiModeManager mUiModeManager;
     private boolean mDreaming;
     private boolean mPulsing;
     private boolean mBroadcastReceiverRegistered;
     private boolean mDisplayStateSupported;
-    private boolean mNotificationLightOn;
     private boolean mPowerSaveActive;
     private boolean mCarMode;
     private long mNotificationPulseTime;
-    private long mLastScheduleResetTime;
-    private long mEarliestPulseDueToLight;
-    private int mScheduleResetsRemaining;
 
     public DozeService() {
         if (DEBUG) Log.d(mTag, "new DozeService()");
@@ -110,11 +89,11 @@
         pw.print("  mSigMotionSensor: "); pw.println(mSigMotionSensor);
         pw.print("  mPickupSensor:"); pw.println(mPickupSensor);
         pw.print("  mDisplayStateSupported: "); pw.println(mDisplayStateSupported);
-        pw.print("  mNotificationLightOn: "); pw.println(mNotificationLightOn);
         pw.print("  mPowerSaveActive: "); pw.println(mPowerSaveActive);
         pw.print("  mCarMode: "); pw.println(mCarMode);
-        pw.print("  mNotificationPulseTime: "); pw.println(mNotificationPulseTime);
-        pw.print("  mScheduleResetsRemaining: "); pw.println(mScheduleResetsRemaining);
+        pw.print("  mNotificationPulseTime: "); pw.println(
+                DozeLog.FORMAT.format(new Date(mNotificationPulseTime
+                        - SystemClock.elapsedRealtime() + System.currentTimeMillis())));
         mDozeParameters.dump(pw);
     }
 
@@ -141,7 +120,6 @@
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
         mWakeLock.setReferenceCounted(true);
-        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
         mDisplayStateSupported = mDozeParameters.getDisplayStateSupported();
         mUiModeManager = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
         turnDisplayOff();
@@ -176,8 +154,6 @@
         }
 
         mDreaming = true;
-        rescheduleNotificationPulse(false /*predicate*/);  // cancel any pending pulse alarms
-        mEarliestPulseDueToLight = System.currentTimeMillis() + EARLIEST_LIGHT_PULSE_AFTER_START_MS;
         listenForPulseSignals(true);
 
         // Ask the host to get things ready to start dozing.
@@ -316,7 +292,6 @@
     private void listenForBroadcasts(boolean listen) {
         if (listen) {
             final IntentFilter filter = new IntentFilter(PULSE_ACTION);
-            filter.addAction(NOTIFICATION_PULSE_ACTION);
             filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE);
             mContext.registerReceiver(mBroadcastReceiver, filter);
             mBroadcastReceiverRegistered = true;
@@ -330,93 +305,17 @@
 
     private void listenForNotifications(boolean listen) {
         if (listen) {
-            resetNotificationResets();
             mHost.addCallback(mHostCallback);
-
-            // Continue to pulse for existing LEDs.
-            mNotificationLightOn = mHost.isNotificationLightOn();
-            if (mNotificationLightOn) {
-                updateNotificationPulseDueToLight();
-            }
         } else {
             mHost.removeCallback(mHostCallback);
         }
     }
 
-    private void resetNotificationResets() {
-        if (DEBUG) Log.d(mTag, "resetNotificationResets");
-        mScheduleResetsRemaining = mDozeParameters.getPulseScheduleResets();
-    }
-
-    private void updateNotificationPulseDueToLight() {
-        long timeMs = System.currentTimeMillis();
-        timeMs = Math.max(timeMs, mEarliestPulseDueToLight);
-        updateNotificationPulse(timeMs);
-    }
-
-    private void updateNotificationPulse(long notificationTimeMs) {
-        if (DEBUG) Log.d(mTag, "updateNotificationPulse notificationTimeMs=" + notificationTimeMs);
+    private void requestNotificationPulse() {
+        if (DEBUG) Log.d(mTag, "requestNotificationPulse");
         if (!mDozeParameters.getPulseOnNotifications()) return;
-        if (mScheduleResetsRemaining <= 0) {
-            if (DEBUG) Log.d(mTag, "No more schedule resets remaining");
-            return;
-        }
-        final long pulseDuration = mDozeParameters.getPulseDuration(false /*pickup*/);
-        boolean pulseImmediately = System.currentTimeMillis() >= notificationTimeMs;
-        if ((notificationTimeMs - mLastScheduleResetTime) >= pulseDuration) {
-            mScheduleResetsRemaining--;
-            mLastScheduleResetTime = notificationTimeMs;
-        } else if (!pulseImmediately){
-            if (DEBUG) Log.d(mTag, "Recently updated, not resetting schedule");
-            return;
-        }
-        if (DEBUG) Log.d(mTag, "mScheduleResetsRemaining = " + mScheduleResetsRemaining);
-        mNotificationPulseTime = notificationTimeMs;
-        if (pulseImmediately) {
-            DozeLog.traceNotificationPulse(mContext, 0);
-            requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
-        }
-        // schedule the rest of the pulses
-        rescheduleNotificationPulse(true /*predicate*/);
-    }
-
-    private PendingIntent notificationPulseIntent(long instance) {
-        return PendingIntent.getBroadcast(mContext, 0,
-                new Intent(NOTIFICATION_PULSE_ACTION)
-                        .setPackage(getPackageName())
-                        .putExtra(EXTRA_INSTANCE, instance)
-                        .setFlags(Intent.FLAG_RECEIVER_FOREGROUND),
-                PendingIntent.FLAG_UPDATE_CURRENT);
-    }
-
-    private void rescheduleNotificationPulse(boolean predicate) {
-        if (DEBUG) Log.d(mTag, "rescheduleNotificationPulse predicate=" + predicate);
-        final PendingIntent notificationPulseIntent = notificationPulseIntent(0);
-        mAlarmManager.cancel(notificationPulseIntent);
-        if (!predicate) {
-            if (DEBUG) Log.d(mTag, "  don't reschedule: predicate is false");
-            return;
-        }
-        final PulseSchedule schedule = mDozeParameters.getPulseSchedule();
-        if (schedule == null) {
-            if (DEBUG) Log.d(mTag, "  don't reschedule: schedule is null");
-            return;
-        }
-        final long now = System.currentTimeMillis();
-        final long time = schedule.getNextTime(now, mNotificationPulseTime);
-        if (time <= 0) {
-            if (DEBUG) Log.d(mTag, "  don't reschedule: time is " + time);
-            return;
-        }
-        final long delta = time - now;
-        if (delta <= 0) {
-            if (DEBUG) Log.d(mTag, "  don't reschedule: delta is " + delta);
-            return;
-        }
-        final long instance = time - mNotificationPulseTime;
-        if (DEBUG) Log.d(mTag, "Scheduling pulse " + instance + " in " + delta + "ms for "
-                + new Date(time));
-        mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, time, notificationPulseIntent(instance));
+        mNotificationPulseTime = SystemClock.elapsedRealtime();
+        requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
     }
 
     private static String triggerEventToString(TriggerEvent event) {
@@ -439,13 +338,6 @@
                 if (DEBUG) Log.d(mTag, "Received pulse intent");
                 requestPulse(DozeLog.PULSE_REASON_INTENT);
             }
-            if (NOTIFICATION_PULSE_ACTION.equals(intent.getAction())) {
-                final long instance = intent.getLongExtra(EXTRA_INSTANCE, -1);
-                if (DEBUG) Log.d(mTag, "Received notification pulse intent instance=" + instance);
-                DozeLog.traceNotificationPulse(mContext, instance);
-                requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
-                rescheduleNotificationPulse(mNotificationLightOn);
-            }
             if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
                 mCarMode = true;
                 if (mCarMode && mDreaming) {
@@ -465,17 +357,13 @@
         @Override
         public void onBuzzBeepBlinked() {
             if (DEBUG) Log.d(mTag, "onBuzzBeepBlinked");
-            updateNotificationPulse(System.currentTimeMillis());
+            requestNotificationPulse();
         }
 
         @Override
         public void onNotificationLight(boolean on) {
-            if (DEBUG) Log.d(mTag, "onNotificationLight on=" + on);
-            if (mNotificationLightOn == on) return;
-            mNotificationLightOn = on;
-            if (mNotificationLightOn) {
-                updateNotificationPulseDueToLight();
-            }
+            if (DEBUG) Log.d(mTag, "onNotificationLight (noop) on=" + on);
+            // noop for now
         }
 
         @Override
@@ -564,17 +452,12 @@
                 requestPulse(mPulseReason, sensorPerformsProxCheck);
                 updateListener();  // reregister, this sensor only fires once
 
-                // reset the notification pulse schedule, but only if we think we were not triggered
-                // by a notification-related vibration
-                final long timeSinceNotification = System.currentTimeMillis()
+                // record pickup gesture, also keep track of whether we might have been triggered
+                // by recent vibration.
+                final long timeSinceNotification = SystemClock.elapsedRealtime()
                         - mNotificationPulseTime;
                 final boolean withinVibrationThreshold =
                         timeSinceNotification < mDozeParameters.getPickupVibrationThreshold();
-                if (withinVibrationThreshold) {
-                   if (DEBUG) Log.d(mTag, "Not resetting schedule, recent notification");
-                } else {
-                    resetNotificationResets();
-                }
                 if (mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) {
                     DozeLog.tracePickupPulse(mContext, withinVibrationThreshold);
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index c4ef80f..2ab2a8c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -16,7 +16,11 @@
 
 package com.android.systemui.keyguard;
 
-import android.annotation.UserIdInt;
+import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
+
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
@@ -82,12 +86,6 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.List;
-
-import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
-import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
-import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
-import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
 
 /**
  * Mediates requests related to the keyguard.  This includes queries about the
@@ -512,7 +510,12 @@
             }
         }
 
-
+        @Override
+        public void onHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper) {
+            synchronized (KeyguardViewMediator.this) {
+                notifyHasLockscreenWallpaperChanged(hasLockscreenWallpaper);
+            }
+        }
     };
 
     ViewMediatorCallback mViewMediatorCallback = new ViewMediatorCallback() {
@@ -2035,6 +2038,21 @@
         }
     }
 
+    private void notifyHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper) {
+        int size = mKeyguardStateCallbacks.size();
+        for (int i = size - 1; i >= 0; i--) {
+            try {
+                mKeyguardStateCallbacks.get(i).onHasLockscreenWallpaperChanged(
+                        hasLockscreenWallpaper);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed to call onHasLockscreenWallpaperChanged", e);
+                if (e instanceof DeadObjectException) {
+                    mKeyguardStateCallbacks.remove(i);
+                }
+            }
+        }
+    }
+
     public void addStateMonitorCallback(IKeyguardStateCallback callback) {
         synchronized (this) {
             mKeyguardStateCallbacks.add(callback);
@@ -2044,6 +2062,7 @@
                 callback.onInputRestrictedStateChanged(mInputRestricted);
                 callback.onTrustedChanged(mUpdateMonitor.getUserHasTrust(
                         KeyguardUpdateMonitor.getCurrentUser()));
+                callback.onHasLockscreenWallpaperChanged(mUpdateMonitor.hasLockscreenWallpaper());
             } catch (RemoteException e) {
                 Slog.w(TAG, "Failed to call to IKeyguardStateCallback", e);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 02fdd3f..68de16b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -507,7 +507,7 @@
         int intrinsicHeight = getIntrinsicHeight();
         mIsPinned = pinned;
         if (intrinsicHeight != getIntrinsicHeight()) {
-            notifyHeightChanged(false);
+            notifyHeightChanged(false /* needsAnimation */);
         }
         if (pinned) {
             setIconAnimationRunning(true);
@@ -840,8 +840,6 @@
     }
 
     public void resetHeight() {
-        mMaxExpandHeight = 0;
-        mHeadsUpHeight = 0;
         onHeightReset();
         requestLayout();
     }
@@ -1290,7 +1288,7 @@
         }
         mHeadsUpHeight = headsUpChild.getHeight();
         if (intrinsicBefore != getIntrinsicHeight()) {
-            notifyHeightChanged(false  /* needsAnimation */);
+            notifyHeightChanged(true  /* needsAnimation */);
         }
     }
 
@@ -1398,7 +1396,7 @@
         if (isChildInGroup()) {
             mGroupManager.setGroupExpanded(mStatusBarNotification, true);
         }
-        notifyHeightChanged(false);
+        notifyHeightChanged(false /* needsAnimation */);
     }
 
     public void setChildrenExpanded(boolean expanded, boolean animate) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 6d73ccb..cf962df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -93,8 +93,10 @@
                 ServiceManager.getService(BatteryStats.SERVICE_NAME));
 
         KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitor);
-        context.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM,
+        context.registerReceiverAsUser(mTickReceiver, UserHandle.SYSTEM,
                 new IntentFilter(Intent.ACTION_TIME_TICK), null, null);
+        context.registerReceiverAsUser(mUnlockReceiver, UserHandle.ALL,
+                new IntentFilter(Intent.ACTION_USER_UNLOCKED), null, null);
     }
 
     public void setVisible(boolean visible) {
@@ -322,7 +324,16 @@
         }
     };
 
-    BroadcastReceiver mReceiver = new BroadcastReceiver() {
+    BroadcastReceiver mTickReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (mVisible) {
+                updateIndication();
+            }
+        }
+    };
+
+    BroadcastReceiver mUnlockReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             if (mVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 9b3ed33..efceed1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -38,8 +38,6 @@
 
     private final Context mContext;
 
-    private static PulseSchedule sPulseSchedule;
-
     private static IntInOutMatcher sPickupSubtypePerformsProxMatcher;
 
     public DozeParameters(Context context) {
@@ -61,8 +59,6 @@
         pw.print("    getVibrateOnPickup(): "); pw.println(getVibrateOnPickup());
         pw.print("    getProxCheckBeforePulse(): "); pw.println(getProxCheckBeforePulse());
         pw.print("    getPulseOnNotifications(): "); pw.println(getPulseOnNotifications());
-        pw.print("    getPulseSchedule(): "); pw.println(getPulseSchedule());
-        pw.print("    getPulseScheduleResets(): "); pw.println(getPulseScheduleResets());
         pw.print("    getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold());
         pw.print("    getPickupSubtypePerformsProxCheck(): ");pw.println(
                 dumpPickupSubtypePerformsProxCheck());
@@ -126,18 +122,6 @@
         return getBoolean("doze.pulse.notifications", R.bool.doze_pulse_on_notifications);
     }
 
-    public PulseSchedule getPulseSchedule() {
-        final String spec = getString("doze.pulse.schedule", R.string.doze_pulse_schedule);
-        if (sPulseSchedule == null || !sPulseSchedule.mSpec.equals(spec)) {
-            sPulseSchedule = PulseSchedule.parse(spec);
-        }
-        return sPulseSchedule;
-    }
-
-    public int getPulseScheduleResets() {
-        return getInt("doze.pulse.schedule.resets", R.integer.doze_pulse_schedule_resets);
-    }
-
     public int getPickupVibrationThreshold() {
         return getInt("doze.pickup.vibration.threshold", R.integer.doze_pickup_vibration_threshold);
     }
@@ -249,44 +233,4 @@
             return (mIsIn.get(value, mDefaultIsIn));
         }
     }
-
-    public static class PulseSchedule {
-        private static final Pattern PATTERN = Pattern.compile("(\\d+?)s", 0);
-
-        private String mSpec;
-        private int[] mSchedule;
-
-        public static PulseSchedule parse(String spec) {
-            if (TextUtils.isEmpty(spec)) return null;
-            try {
-                final PulseSchedule rt = new PulseSchedule();
-                rt.mSpec = spec;
-                final String[] tokens = spec.split(",");
-                rt.mSchedule = new int[tokens.length];
-                for (int i = 0; i < tokens.length; i++) {
-                    final Matcher m = PATTERN.matcher(tokens[i]);
-                    if (!m.matches()) throw new IllegalArgumentException("Bad token: " + tokens[i]);
-                    rt.mSchedule[i] = Integer.parseInt(m.group(1));
-                }
-                if (DEBUG) Log.d(TAG, "Parsed spec [" + spec + "] as: " + rt);
-                return rt;
-            } catch (RuntimeException e) {
-                Log.w(TAG, "Error parsing spec: " + spec, e);
-                return null;
-            }
-        }
-
-        @Override
-        public String toString() {
-            return Arrays.toString(mSchedule);
-        }
-
-        public long getNextTime(long now, long notificationTime) {
-            for (int i = 0; i < mSchedule.length; i++) {
-                final long time = notificationTime + mSchedule[i] * 1000;
-                if (time > now) return time;
-            }
-            return 0;
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
index f98b9e5..df4566b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightStatusBarController.java
@@ -27,7 +27,7 @@
 /**
  * Controls how light status bar flag applies to the icons.
  */
-public class LightStatusBarController {
+public class LightStatusBarController implements BatteryController.BatteryStateChangeCallback {
 
     private final StatusBarIconController mIconController;
     private final BatteryController mBatteryController;
@@ -37,6 +37,7 @@
     private int mDockedStackVisibility;
     private boolean mFullscreenLight;
     private boolean mDockedLight;
+    private int mLastStatusBarMode;
 
     private final Rect mLastFullscreenBounds = new Rect();
     private final Rect mLastDockedBounds = new Rect();
@@ -45,6 +46,7 @@
             BatteryController batteryController) {
         mIconController = iconController;
         mBatteryController = batteryController;
+        batteryController.addStateChangedCallback(this);
     }
 
     public void setFingerprintUnlockController(
@@ -73,6 +75,7 @@
         }
         mFullscreenStackVisibility = newFullscreen;
         mDockedStackVisibility = newDocked;
+        mLastStatusBarMode = statusBarMode;
         mLastFullscreenBounds.set(fullscreenStackBounds);
         mLastDockedBounds.set(dockedStackBounds);
     }
@@ -123,4 +126,16 @@
             mIconController.setIconsDark(true, animateChange());
         }
     }
+
+    @Override
+    public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+
+    }
+
+    @Override
+    public void onPowerSaveChanged(boolean isPowerSave) {
+        onSystemUiVisibilityChanged(mFullscreenStackVisibility, mDockedStackVisibility,
+                0 /* mask */, mLastFullscreenBounds, mLastDockedBounds, true /* sbModeChange*/,
+                mLastStatusBarMode);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index 1343c3a..af6e259 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -38,6 +38,8 @@
 import android.os.UserHandle;
 import android.util.Log;
 
+import com.android.keyguard.KeyguardUpdateMonitor;
+
 import libcore.io.IoUtils;
 
 import java.util.Objects;
@@ -52,6 +54,7 @@
     private final PhoneStatusBar mBar;
     private final WallpaperManager mWallpaperManager;
     private final Handler mH;
+    private final KeyguardUpdateMonitor mUpdateMonitor;
 
     private boolean mCached;
     private Bitmap mCache;
@@ -66,6 +69,7 @@
         mH = h;
         mWallpaperManager = (WallpaperManager) ctx.getSystemService(Context.WALLPAPER_SERVICE);
         mCurrentUserId = ActivityManager.getCurrentUser();
+        mUpdateMonitor = KeyguardUpdateMonitor.getInstance(ctx);
 
         IWallpaperManager service = IWallpaperManager.Stub.asInterface(
                 ServiceManager.getService(Context.WALLPAPER_SERVICE));
@@ -89,6 +93,7 @@
         LoaderResult result = loadBitmap(mCurrentUserId, mSelectedUser);
         if (result.success) {
             mCached = true;
+            mUpdateMonitor.setHasLockscreenWallpaper(result.bitmap != null);
             mCache = result.bitmap;
         }
         return mCache;
@@ -181,6 +186,7 @@
                 if (result.success) {
                     mCached = true;
                     mCache = result.bitmap;
+                    mUpdateMonitor.setHasLockscreenWallpaper(result.bitmap != null);
                     mBar.updateMediaMetaData(
                             true /* metaDataChanged */, true /* allowEnterAnimation */);
                 }
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 aae91b1..222e8df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -54,7 +54,7 @@
 
 public class NavigationBarView extends LinearLayout {
     final static boolean DEBUG = false;
-    final static String TAG = "PhoneStatusBar/NavigationBarView";
+    final static String TAG = "StatusBar/NavBarView";
 
     // slippery nav bar when everything is disabled, e.g. during setup
     final static boolean SLIPPERY_WHEN_DISABLED = true;
@@ -527,8 +527,8 @@
         updateCurrentView();
     }
 
-    public boolean needsReorient() {
-        return mCurrentRotation != mDisplay.getRotation();
+    public boolean needsReorient(int rotation) {
+        return mCurrentRotation != rotation;
     }
 
     private void updateCurrentView() {
@@ -567,7 +567,7 @@
         setMenuVisibility(mShowMenu, true /* force */);
 
         if (DEBUG) {
-            Log.d(TAG, "reorient(): rot=" + mDisplay.getRotation());
+            Log.d(TAG, "reorient(): rot=" + mCurrentRotation);
         }
 
         updateTaskSwitchHelper();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index 1755cc6..2c8339a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -42,7 +42,7 @@
     private int mBarState = -1;
     private HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>();
     private HeadsUpManager mHeadsUpManager;
-    private boolean mUpdatingSuppressionBlocked;
+    private boolean mIsUpdatingUnchangedGroup;
 
     public void setOnGroupChangeListener(OnGroupChangeListener listener) {
         mListener = listener;
@@ -141,7 +141,7 @@
     }
 
     private void updateSuppression(NotificationGroup group) {
-        if (group == null || mUpdatingSuppressionBlocked) {
+        if (group == null) {
             return;
         }
         boolean prevSuppressed = group.suppressed;
@@ -154,7 +154,9 @@
             if (group.suppressed) {
                 handleSuppressedSummaryHeadsUpped(group.summary);
             }
-            mListener.onGroupsChanged();
+            if (!mIsUpdatingUnchangedGroup) {
+                mListener.onGroupsChanged();
+            }
         }
     }
 
@@ -188,12 +190,12 @@
         boolean groupKeysChanged = !oldKey.equals(newKey);
         boolean wasGroupChild = isGroupChild(oldNotification);
         boolean isGroupChild = isGroupChild(entry.notification);
-        mUpdatingSuppressionBlocked = !groupKeysChanged && wasGroupChild == isGroupChild;
+        mIsUpdatingUnchangedGroup = !groupKeysChanged && wasGroupChild == isGroupChild;
         if (mGroupMap.get(getGroupKey(oldNotification)) != null) {
             onEntryRemovedInternal(entry, oldNotification);
         }
         onEntryAdded(entry);
-        mUpdatingSuppressionBlocked = false;
+        mIsUpdatingUnchangedGroup = false;
         if (isIsolated(entry.notification)) {
             mIsolatedEntries.put(entry.key, entry.notification);
             if (groupKeysChanged) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 8db7c37..d2bb405 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -65,7 +65,6 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.hardware.display.DisplayManager;
 import android.inputmethodservice.InputMethodService;
 import android.media.AudioAttributes;
 import android.media.MediaMetadata;
@@ -100,6 +99,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.view.Display;
+import android.view.IRotationWatcher;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -207,7 +207,7 @@
 
 public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
         DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,
-        HeadsUpManager.OnHeadsUpChangedListener, DisplayManager.DisplayListener {
+        HeadsUpManager.OnHeadsUpChangedListener {
     static final String TAG = "PhoneStatusBar";
     public static final boolean DEBUG = BaseStatusBar.DEBUG;
     public static final boolean SPEW = false;
@@ -694,8 +694,6 @@
         mUnlockMethodCache.addListener(this);
         startKeyguard();
 
-        mContext.getSystemService(DisplayManager.class).registerDisplayListener(this, null);
-
         mDozeServiceHost = new DozeServiceHost();
         KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mDozeServiceHost);
         putComponent(DozeHost.class, mDozeServiceHost);
@@ -1415,6 +1413,27 @@
         if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
         if (mNavigationBarView == null) return;
 
+        try {
+            WindowManagerGlobal.getWindowManagerService()
+                    .watchRotation(new IRotationWatcher.Stub() {
+                @Override
+                public void onRotationChanged(int rotation) throws RemoteException {
+                    // We need this to be scheduled as early as possible to beat the redrawing of
+                    // window in response to the orientation change.
+                    Message msg = Message.obtain(mHandler, () -> {
+                        if (mNavigationBarView != null
+                                && mNavigationBarView.needsReorient(rotation)) {
+                            repositionNavigationBar();
+                        }
+                    });
+                    msg.setAsynchronous(true);
+                    mHandler.sendMessageAtFrontOfQueue(msg);
+                }
+            });
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+
         prepareNavigationBarView();
 
         mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());
@@ -3599,22 +3618,6 @@
     }
 
     @Override
-    public void onDisplayAdded(int displayId) {
-    }
-
-    @Override
-    public void onDisplayRemoved(int displayId) {
-    }
-
-    @Override
-    public void onDisplayChanged(int displayId) {
-        if (displayId == Display.DEFAULT_DISPLAY
-                && mNavigationBarView != null && mNavigationBarView.needsReorient()) {
-            repositionNavigationBar();
-        }
-    }
-
-    @Override
     public void userSwitched(int newUserId) {
         super.userSwitched(newUserId);
         if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index ea9ec5f..c744771 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -217,7 +217,6 @@
     private float mTopPaddingOverflow;
     private boolean mDontReportNextOverScroll;
     private boolean mDontClampNextScroll;
-    private boolean mRequestViewResizeAnimationOnLayout;
     private boolean mNeedViewResizeAnimation;
     private View mExpandedGroupView;
     private boolean mEverythingNeedsAnimation;
@@ -519,10 +518,6 @@
         setMaxLayoutHeight(getHeight());
         updateContentHeight();
         clampScrollPosition();
-        if (mRequestViewResizeAnimationOnLayout) {
-            requestAnimationOnViewResize(null);
-            mRequestViewResizeAnimationOnLayout = false;
-        }
         requestChildrenUpdate();
         updateFirstAndLastBackgroundViews();
     }
@@ -2001,9 +1996,9 @@
     }
 
     private void applyCurrentBackgroundBounds() {
-        if (!mFadingOut) {
-            mScrimController.setExcludedBackgroundArea(mCurrentBounds);
-        }
+        mScrimController.setExcludedBackgroundArea(
+                mFadingOut || mParentFadingOut || mAmbientState.isDark() ? null
+                        : mCurrentBounds);
         invalidate();
     }
 
@@ -3144,9 +3139,6 @@
 
     @Override
     public void onReset(ExpandableView view) {
-        if (mIsExpanded && mAnimationsEnabled) {
-            mRequestViewResizeAnimationOnLayout = true;
-        }
         updateAnimationState(view);
         updateChronometerForChild(view);
     }
@@ -3495,7 +3487,7 @@
                         notifyHeightChangeListener(mEmptyShadeView);
                     }
                 };
-                if (mAnimationsEnabled) {
+                if (mAnimationsEnabled && mIsExpanded) {
                     mEmptyShadeView.setWillBeGone(true);
                     mEmptyShadeView.performVisibilityAnimation(false, onFinishedRunnable);
                 } else {
@@ -3887,11 +3879,7 @@
     }
 
     private void updateFadingState() {
-        if (mFadingOut || mParentFadingOut || mAmbientState.isDark()) {
-            mScrimController.setExcludedBackgroundArea(null);
-        } else {
-            applyCurrentBackgroundBounds();
-        }
+        applyCurrentBackgroundBounds();
         updateSrcDrawing();
     }
 
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 8c8b391..00707e4 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2270,6 +2270,15 @@
     //   SUBTYPE: sub settings classname
     ACTION_SETTING_HELP_AND_FEEDBACK = 513;
 
+    // OPEN: Settings > Language & input > Personal dictionary (single locale)
+    USER_DICTIONARY_SETTINGS = 514;
+
+    // OPEN: Settings > Date & time > Select time zone
+    ZONE_PICKER = 515;
+
+    // OPEN: Settings > Security > Device administrators
+    DEVICE_ADMIN_SETTINGS = 516;
+
     // ---- End O Constants, all O constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index ea25f74..806289f 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -279,6 +279,31 @@
             }
 
             @Override
+            public void onPackageUpdateFinished(String packageName, int uid) {
+                // Unbind all services from this package, and then update the user state to
+                // re-bind new versions of them.
+                synchronized (mLock) {
+                    final int userId = getChangingUserId();
+                    if (userId != mCurrentUserId) {
+                        return;
+                    }
+                    UserState userState = getUserStateLocked(userId);
+                    boolean unboundAService = false;
+                    for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
+                        Service boundService = userState.mBoundServices.get(i);
+                        String servicePkg = boundService.mComponentName.getPackageName();
+                        if (servicePkg.equals(packageName)) {
+                            boundService.unbindLocked();
+                            unboundAService = true;
+                        }
+                    }
+                    if (unboundAService) {
+                        onUserStateChangedLocked(userState);
+                    }
+                }
+            }
+
+            @Override
             public void onPackageRemoved(String packageName, int uid) {
                 synchronized (mLock) {
                     final int userId = getChangingUserId();
@@ -426,7 +451,7 @@
     }
 
     @Override
-    public boolean sendAccessibilityEvent(AccessibilityEvent event, int userId) {
+    public void sendAccessibilityEvent(AccessibilityEvent event, int userId) {
         boolean dispatchEvent = false;
 
         synchronized (mLock) {
@@ -436,18 +461,19 @@
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
             // This method does nothing for a background user.
-            if (resolvedUserId != mCurrentUserId) {
-                return true; // yes, recycle the event
-            }
-            if (mSecurityPolicy.canDispatchAccessibilityEventLocked(event)) {
-                mSecurityPolicy.updateActiveAndAccessibilityFocusedWindowLocked(event.getWindowId(),
-                        event.getSourceNodeId(), event.getEventType(), event.getAction());
-                mSecurityPolicy.updateEventSourceLocked(event);
-                dispatchEvent = true;
-            }
-            if (mHasInputFilter && mInputFilter != null) {
-                mMainHandler.obtainMessage(MainHandler.MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER,
-                        AccessibilityEvent.obtain(event)).sendToTarget();
+            if (resolvedUserId == mCurrentUserId) {
+                if (mSecurityPolicy.canDispatchAccessibilityEventLocked(event)) {
+                    mSecurityPolicy.updateActiveAndAccessibilityFocusedWindowLocked(
+                            event.getWindowId(), event.getSourceNodeId(),
+                            event.getEventType(), event.getAction());
+                    mSecurityPolicy.updateEventSourceLocked(event);
+                    dispatchEvent = true;
+                }
+                if (mHasInputFilter && mInputFilter != null) {
+                    mMainHandler.obtainMessage(
+                            MainHandler.MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER,
+                            AccessibilityEvent.obtain(event)).sendToTarget();
+                }
             }
         }
 
@@ -466,9 +492,23 @@
             }
         }
 
-        event.recycle();
+        if (OWN_PROCESS_ID != Binder.getCallingPid()) {
+            event.recycle();
+        }
+    }
 
-        return (OWN_PROCESS_ID != Binder.getCallingPid());
+    @Override
+    public void sendAccessibilityEvents(ParceledListSlice events, int userId) {
+        List<AccessibilityEvent> a11yEvents = events.getList();
+        // Grab the lock once for the entire batch
+        synchronized (mLock) {
+            int numEventsToProcess = Math.min(a11yEvents.size(),
+                    AccessibilityManager.MAX_A11Y_EVENTS_PER_SERVICE_CALL);
+            for (int i = 0; i < numEventsToProcess; i++) {
+                AccessibilityEvent event = a11yEvents.get(i);
+                sendAccessibilityEvent(event, userId);
+            }
+        }
     }
 
     @Override
@@ -2281,7 +2321,7 @@
 
         @Override
         public boolean onKeyEvent(KeyEvent keyEvent, int sequenceNumber) {
-            if (!mRequestFilterKeyEvents) {
+            if (!mRequestFilterKeyEvents || (mServiceInterface == null)) {
                 return false;
             }
             if((mAccessibilityServiceInfo.getCapabilities()
@@ -3603,6 +3643,7 @@
                 case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
                 case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL:
                 case WindowManager.LayoutParams.TYPE_BASE_APPLICATION:
+                case WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION:
                 case WindowManager.LayoutParams.TYPE_PHONE:
                 case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
                 case WindowManager.LayoutParams.TYPE_TOAST:
diff --git a/services/core/java/com/android/server/AnyMotionDetector.java b/services/core/java/com/android/server/AnyMotionDetector.java
index f93c716..d564925 100644
--- a/services/core/java/com/android/server/AnyMotionDetector.java
+++ b/services/core/java/com/android/server/AnyMotionDetector.java
@@ -97,6 +97,15 @@
     /** True if an orientation measurement is in progress. */
     private boolean mMeasurementInProgress;
 
+    /** True if sendMessageDelayed() for the mMeasurementTimeout callback has been scheduled */
+    private boolean mMeasurementTimeoutIsActive;
+
+    /** True if sendMessageDelayed() for the mWakelockTimeout callback has been scheduled */
+    private boolean mWakelockTimeoutIsActive;
+
+    /** True if sendMessageDelayed() for the mSensorRestart callback has been scheduled */
+    private boolean mSensorRestartIsActive;
+
     /** The most recent gravity vector. */
     private Vector3 mCurrentGravityVector = null;
 
@@ -118,6 +127,9 @@
             mSensorManager = sm;
             mAccelSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
             mMeasurementInProgress = false;
+            mMeasurementTimeoutIsActive = false;
+            mWakelockTimeoutIsActive = false;
+            mSensorRestartIsActive = false;
             mState = STATE_INACTIVE;
             mCallback = callback;
             mThresholdAngle = thresholdAngle;
@@ -146,6 +158,7 @@
                 mWakeLock.acquire();
                 Message wakelockTimeoutMsg = Message.obtain(mHandler, mWakelockTimeout);
                 mHandler.sendMessageDelayed(wakelockTimeoutMsg, WAKELOCK_TIMEOUT_MILLIS);
+                mWakelockTimeoutIsActive = true;
                 startOrientationMeasurementLocked();
             }
         }
@@ -157,17 +170,20 @@
                 mState = STATE_INACTIVE;
                 if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE.");
             }
+            mHandler.removeCallbacks(mMeasurementTimeout);
+            mHandler.removeCallbacks(mSensorRestart);
+            mMeasurementTimeoutIsActive = false;
+            mSensorRestartIsActive = false;
             if (mMeasurementInProgress) {
                 mMeasurementInProgress = false;
                 mSensorManager.unregisterListener(mListener);
             }
-            mHandler.removeCallbacks(mMeasurementTimeout);
-            mHandler.removeCallbacks(mSensorRestart);
             mCurrentGravityVector = null;
             mPreviousGravityVector = null;
             if (mWakeLock.isHeld()) {
-                mWakeLock.release();
                 mHandler.removeCallbacks(mWakelockTimeout);
+                mWakelockTimeoutIsActive = false;
+                mWakeLock.release();
             }
         }
     }
@@ -183,6 +199,7 @@
             }
             Message measurementTimeoutMsg = Message.obtain(mHandler, mMeasurementTimeout);
             mHandler.sendMessageDelayed(measurementTimeoutMsg, ACCELEROMETER_DATA_TIMEOUT_MILLIS);
+            mMeasurementTimeoutIsActive = true;
         }
     }
 
@@ -191,8 +208,9 @@
                 mMeasurementInProgress);
         int status = RESULT_UNKNOWN;
         if (mMeasurementInProgress) {
-            mSensorManager.unregisterListener(mListener);
             mHandler.removeCallbacks(mMeasurementTimeout);
+            mMeasurementTimeoutIsActive = false;
+            mSensorManager.unregisterListener(mListener);
             mMeasurementInProgress = false;
             mPreviousGravityVector = mCurrentGravityVector;
             mCurrentGravityVector = mRunningStats.getRunningAverage();
@@ -213,8 +231,9 @@
             if (DEBUG) Slog.d(TAG, "getStationaryStatus() returned " + status);
             if (status != RESULT_UNKNOWN) {
                 if (mWakeLock.isHeld()) {
-                    mWakeLock.release();
                     mHandler.removeCallbacks(mWakelockTimeout);
+                    mWakelockTimeoutIsActive = false;
+                    mWakeLock.release();
                 }
                 if (DEBUG) {
                     Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE. status = " + status);
@@ -230,6 +249,7 @@
                         " milliseconds.");
                 Message msg = Message.obtain(mHandler, mSensorRestart);
                 mHandler.sendMessageDelayed(msg, ORIENTATION_MEASUREMENT_INTERVAL_MILLIS);
+                mSensorRestartIsActive = true;
             }
         }
         return status;
@@ -283,6 +303,7 @@
             }
             if (status != RESULT_UNKNOWN) {
                 mHandler.removeCallbacks(mWakelockTimeout);
+                mWakelockTimeoutIsActive = false;
                 mCallback.onAnyMotionResult(status);
             }
         }
@@ -296,7 +317,10 @@
         @Override
         public void run() {
             synchronized (mLock) {
-                startOrientationMeasurementLocked();
+                if (mSensorRestartIsActive == true) {
+                    mSensorRestartIsActive = false;
+                    startOrientationMeasurementLocked();
+                }
             }
         }
     };
@@ -306,14 +330,18 @@
         public void run() {
             int status = RESULT_UNKNOWN;
             synchronized (mLock) {
-                if (DEBUG) Slog.i(TAG, "mMeasurementTimeout. Failed to collect sufficient accel " +
-                      "data within " + ACCELEROMETER_DATA_TIMEOUT_MILLIS + " ms. Stopping " +
-                      "orientation measurement.");
-                status = stopOrientationMeasurementLocked();
-            }
-            if (status != RESULT_UNKNOWN) {
-                mHandler.removeCallbacks(mWakelockTimeout);
-                mCallback.onAnyMotionResult(status);
+                if (mMeasurementTimeoutIsActive == true) {
+                    mMeasurementTimeoutIsActive = false;
+                    if (DEBUG) Slog.i(TAG, "mMeasurementTimeout. Failed to collect sufficient accel " +
+                          "data within " + ACCELEROMETER_DATA_TIMEOUT_MILLIS + " ms. Stopping " +
+                          "orientation measurement.");
+                    status = stopOrientationMeasurementLocked();
+                    if (status != RESULT_UNKNOWN) {
+                        mHandler.removeCallbacks(mWakelockTimeout);
+                        mWakelockTimeoutIsActive = false;
+                        mCallback.onAnyMotionResult(status);
+                    }
+                }
             }
         }
     };
@@ -322,7 +350,10 @@
         @Override
         public void run() {
             synchronized (mLock) {
-                stop();
+                if (mWakelockTimeoutIsActive == true) {
+                    mWakelockTimeoutIsActive = false;
+                    stop();
+                }
             }
         }
     };
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index b5b0cd8..4caeba8 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -875,7 +875,7 @@
             return AppOpsManager.MODE_IGNORED;
         }
         synchronized (this) {
-            if (isOpRestricted(uid, code, resolvedPackageName)) {
+            if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
                 return AppOpsManager.MODE_IGNORED;
             }
             code = AppOpsManager.opToSwitch(code);
@@ -1024,7 +1024,7 @@
                 return AppOpsManager.MODE_ERRORED;
             }
             Op op = getOpLocked(ops, code, true);
-            if (isOpRestricted(uid, code, packageName)) {
+            if (isOpRestrictedLocked(uid, code, packageName)) {
                 return AppOpsManager.MODE_IGNORED;
             }
             if (op.duration == -1) {
@@ -1082,7 +1082,7 @@
                 return AppOpsManager.MODE_ERRORED;
             }
             Op op = getOpLocked(ops, code, true);
-            if (isOpRestricted(uid, code, resolvedPackageName)) {
+            if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
                 return AppOpsManager.MODE_IGNORED;
             }
             final int switchCode = AppOpsManager.opToSwitch(code);
@@ -1308,7 +1308,7 @@
         return op;
     }
 
-    private boolean isOpRestricted(int uid, int code, String packageName) {
+    private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
         int userHandle = UserHandle.getUserId(uid);
         final int restrictionSetCount = mOpUserRestrictions.size();
 
@@ -2210,25 +2210,33 @@
 
     private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
             int userHandle, String[] exceptionPackages) {
-        ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
+        boolean notifyChange = false;
 
-        if (restrictionState == null) {
-            try {
-                restrictionState = new ClientRestrictionState(token);
-            } catch (RemoteException e) {
-                return;
+        synchronized (AppOpsService.this) {
+            ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
+
+            if (restrictionState == null) {
+                try {
+                    restrictionState = new ClientRestrictionState(token);
+                } catch (RemoteException e) {
+                    return;
+                }
+                mOpUserRestrictions.put(token, restrictionState);
             }
-            mOpUserRestrictions.put(token, restrictionState);
+
+            if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
+                notifyChange = true;
+            }
+
+            if (restrictionState.isDefault()) {
+                mOpUserRestrictions.remove(token);
+                restrictionState.destroy();
+            }
         }
 
-        if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
+        if (notifyChange) {
             notifyWatchersOfChange(code);
         }
-
-        if (restrictionState.isDefault()) {
-            mOpUserRestrictions.remove(token);
-            restrictionState.destroy();
-        }
     }
 
     private void notifyWatchersOfChange(int code) {
@@ -2263,10 +2271,12 @@
     @Override
     public void removeUser(int userHandle) throws RemoteException {
         checkSystemUid("removeUser");
-        final int tokenCount = mOpUserRestrictions.size();
-        for (int i = tokenCount - 1; i >= 0; i--) {
-            ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
-            opRestrictions.removeUser(userHandle);
+        synchronized (AppOpsService.this) {
+            final int tokenCount = mOpUserRestrictions.size();
+            for (int i = tokenCount - 1; i >= 0; i--) {
+                ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
+                opRestrictions.removeUser(userHandle);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 8b243e7..9d88020 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -28,6 +28,7 @@
 import android.bluetooth.IBluetoothManagerCallback;
 import android.bluetooth.IBluetoothProfileServiceConnection;
 import android.bluetooth.IBluetoothStateChangeCallback;
+import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -248,8 +249,7 @@
 
         mContext = context;
 
-        mPermissionReviewRequired = Build.PERMISSIONS_REVIEW_REQUIRED
-                    || context.getResources().getBoolean(
+        mPermissionReviewRequired = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_permissionReviewRequired);
 
         mBluetooth = null;
@@ -742,7 +742,15 @@
             // Legacy apps in permission review mode trigger a user prompt
             if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
                 Intent intent = new Intent(intentAction);
-                mContext.startActivity(intent);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                try {
+                    mContext.startActivity(intent);
+                } catch (ActivityNotFoundException e) {
+                    // Shouldn't happen
+                    Slog.e(TAG, "Intent to handle action " + intentAction + " missing");
+                    return false;
+                }
                 return true;
             }
         } catch (PackageManager.NameNotFoundException e) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 70f39db..c99db0d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -38,7 +38,6 @@
 
 import android.annotation.Nullable;
 import android.app.BroadcastOptions;
-import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -135,6 +134,8 @@
 import com.android.server.connectivity.NetworkAgentInfo;
 import com.android.server.connectivity.NetworkDiagnostics;
 import com.android.server.connectivity.NetworkMonitor;
+import com.android.server.connectivity.NetworkNotificationManager;
+import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
 import com.android.server.connectivity.PacManager;
 import com.android.server.connectivity.PermissionMonitor;
 import com.android.server.connectivity.Tethering;
@@ -436,6 +437,7 @@
     TelephonyManager mTelephonyManager;
 
     private KeepaliveTracker mKeepaliveTracker;
+    private NetworkNotificationManager mNotifier;
 
     // sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
     private final static int MIN_NET_ID = 100; // some reserved marks
@@ -832,6 +834,8 @@
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
 
         mKeepaliveTracker = new KeepaliveTracker(mHandler);
+        mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager,
+                mContext.getSystemService(NotificationManager.class));
     }
 
     private NetworkRequest createInternetRequestForTransport(int transportType) {
@@ -2233,16 +2237,15 @@
                         updateCapabilities(nai, nai.networkCapabilities);
                     }
                     if (!visible) {
-                        setProvNotificationVisibleIntent(false, netId, null, 0, null, null, false);
+                        mNotifier.clearNotification(netId);
                     } else {
                         if (nai == null) {
                             loge("EVENT_PROVISIONING_NOTIFICATION from unknown NetworkMonitor");
                             break;
                         }
                         if (!nai.networkMisc.provisioningNotificationDisabled) {
-                            setProvNotificationVisibleIntent(true, netId, NotificationType.SIGN_IN,
-                                    nai.networkInfo.getType(), nai.networkInfo.getExtraInfo(),
-                                    (PendingIntent)msg.obj, nai.networkMisc.explicitlySelected);
+                            mNotifier.showNotification(netId, NotificationType.SIGN_IN, nai,
+                                    (PendingIntent) msg.obj, nai.networkMisc.explicitlySelected);
                         }
                     }
                     break;
@@ -2539,14 +2542,28 @@
                 "request NetworkCapabilities", ConnectivityManager.CALLBACK_CAP_CHANGED);
     }
 
+    private void handleTimedOutNetworkRequest(final NetworkRequestInfo nri) {
+        if (mNetworkRequests.get(nri.request) != null && mNetworkForRequestId.get(
+                nri.request.requestId) == null) {
+            handleRemoveNetworkRequest(nri, ConnectivityManager.CALLBACK_UNAVAIL);
+        }
+    }
+
     private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) {
         final NetworkRequestInfo nri = getNriForAppRequest(
                 request, callingUid, "release NetworkRequest");
-        if (nri == null) return;
+        if (nri != null) {
+            handleRemoveNetworkRequest(nri, ConnectivityManager.CALLBACK_RELEASED);
+        }
+    }
 
-        if (VDBG || (DBG && nri.request.isRequest())) log("releasing " + request);
+    private void handleRemoveNetworkRequest(final NetworkRequestInfo nri, final int whichCallback) {
+        final String logCallbackType = ConnectivityManager.getCallbackName(whichCallback);
+        if (VDBG || (DBG && nri.request.isRequest())) {
+            log("releasing " + nri.request + " (" + logCallbackType + ")");
+        }
         nri.unlinkDeathRecipient();
-        mNetworkRequests.remove(request);
+        mNetworkRequests.remove(nri.request);
         synchronized (mUidToNetworkRequestCount) {
             int requests = mUidToNetworkRequestCount.get(nri.mUid, 0);
             if (requests < 1) {
@@ -2635,7 +2652,7 @@
                 }
             }
         }
-        callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED, 0);
+        callCallbackForRequest(nri, null, whichCallback, 0);
     }
 
     @Override
@@ -2713,8 +2730,8 @@
         PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
                 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
 
-        setProvNotificationVisibleIntent(true, nai.network.netId, NotificationType.NO_INTERNET,
-                nai.networkInfo.getType(), nai.networkInfo.getExtraInfo(), pendingIntent, true);
+        mNotifier.showNotification(nai.network.netId, NotificationType.NO_INTERNET, nai,
+                pendingIntent, true);
     }
 
     private class InternalHandler extends Handler {
@@ -2778,6 +2795,11 @@
                     handleRegisterNetworkRequestWithIntent(msg);
                     break;
                 }
+                case EVENT_TIMEOUT_NETWORK_REQUEST: {
+                    NetworkRequestInfo nri = (NetworkRequestInfo) msg.obj;
+                    handleTimedOutNetworkRequest(nri);
+                    break;
+                }
                 case EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT: {
                     handleReleaseNetworkRequestWithIntent((PendingIntent) msg.obj, msg.arg1);
                     break;
@@ -3620,118 +3642,6 @@
         return -1;
     }
 
-    private static final String NOTIFICATION_ID = "CaptivePortal.Notification";
-    private static enum NotificationType { SIGN_IN, NO_INTERNET; };
-
-    private void setProvNotificationVisible(boolean visible, int networkType, String action) {
-        Intent intent = new Intent(action);
-        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
-        // Concatenate the range of types onto the range of NetIDs.
-        int id = MAX_NET_ID + 1 + (networkType - ConnectivityManager.TYPE_NONE);
-        setProvNotificationVisibleIntent(visible, id, NotificationType.SIGN_IN,
-                networkType, null, pendingIntent, false);
-    }
-
-    /**
-     * Show or hide network provisioning notifications.
-     *
-     * We use notifications for two purposes: to notify that a network requires sign in
-     * (NotificationType.SIGN_IN), or to notify that a network does not have Internet access
-     * (NotificationType.NO_INTERNET). We display at most one notification per ID, so on a
-     * particular network we can display the notification type that was most recently requested.
-     * So for example if a captive portal fails to reply within a few seconds of connecting, we
-     * might first display NO_INTERNET, and then when the captive portal check completes, display
-     * SIGN_IN.
-     *
-     * @param id an identifier that uniquely identifies this notification.  This must match
-     *         between show and hide calls.  We use the NetID value but for legacy callers
-     *         we concatenate the range of types with the range of NetIDs.
-     */
-    private void setProvNotificationVisibleIntent(boolean visible, int id,
-            NotificationType notifyType, int networkType, String extraInfo, PendingIntent intent,
-            boolean highPriority) {
-        if (VDBG || (DBG && visible)) {
-            log("setProvNotificationVisibleIntent " + notifyType + " visible=" + visible
-                    + " networkType=" + getNetworkTypeName(networkType)
-                    + " extraInfo=" + extraInfo + " highPriority=" + highPriority);
-        }
-
-        Resources r = Resources.getSystem();
-        NotificationManager notificationManager = (NotificationManager) mContext
-            .getSystemService(Context.NOTIFICATION_SERVICE);
-
-        if (visible) {
-            CharSequence title;
-            CharSequence details;
-            int icon;
-            if (notifyType == NotificationType.NO_INTERNET &&
-                    networkType == ConnectivityManager.TYPE_WIFI) {
-                title = r.getString(R.string.wifi_no_internet, 0);
-                details = r.getString(R.string.wifi_no_internet_detailed);
-                icon = R.drawable.stat_notify_wifi_in_range;  // TODO: Need new icon.
-            } else if (notifyType == NotificationType.SIGN_IN) {
-                switch (networkType) {
-                    case ConnectivityManager.TYPE_WIFI:
-                        title = r.getString(R.string.wifi_available_sign_in, 0);
-                        details = r.getString(R.string.network_available_sign_in_detailed,
-                                extraInfo);
-                        icon = R.drawable.stat_notify_wifi_in_range;
-                        break;
-                    case ConnectivityManager.TYPE_MOBILE:
-                    case ConnectivityManager.TYPE_MOBILE_HIPRI:
-                        title = r.getString(R.string.network_available_sign_in, 0);
-                        // TODO: Change this to pull from NetworkInfo once a printable
-                        // name has been added to it
-                        details = mTelephonyManager.getNetworkOperatorName();
-                        icon = R.drawable.stat_notify_rssi_in_range;
-                        break;
-                    default:
-                        title = r.getString(R.string.network_available_sign_in, 0);
-                        details = r.getString(R.string.network_available_sign_in_detailed,
-                                extraInfo);
-                        icon = R.drawable.stat_notify_rssi_in_range;
-                        break;
-                }
-            } else {
-                Slog.wtf(TAG, "Unknown notification type " + notifyType + "on network type "
-                        + getNetworkTypeName(networkType));
-                return;
-            }
-
-            Notification notification = new Notification.Builder(mContext)
-                    .setWhen(0)
-                    .setSmallIcon(icon)
-                    .setAutoCancel(true)
-                    .setTicker(title)
-                    .setColor(mContext.getColor(
-                            com.android.internal.R.color.system_notification_accent_color))
-                    .setContentTitle(title)
-                    .setContentText(details)
-                    .setContentIntent(intent)
-                    .setLocalOnly(true)
-                    .setPriority(highPriority ?
-                            Notification.PRIORITY_HIGH :
-                            Notification.PRIORITY_DEFAULT)
-                    .setDefaults(highPriority ? Notification.DEFAULT_ALL : 0)
-                    .setOnlyAlertOnce(true)
-                    .build();
-
-            try {
-                notificationManager.notifyAsUser(NOTIFICATION_ID, id, notification, UserHandle.ALL);
-            } catch (NullPointerException npe) {
-                loge("setNotificationVisible: visible notificationManager npe=" + npe);
-                npe.printStackTrace();
-            }
-        } else {
-            try {
-                notificationManager.cancelAsUser(NOTIFICATION_ID, id, UserHandle.ALL);
-            } catch (NullPointerException npe) {
-                loge("setNotificationVisible: cancel notificationManager npe=" + npe);
-                npe.printStackTrace();
-            }
-        }
-    }
-
     /** Location to an updatable file listing carrier provisioning urls.
      *  An example:
      *
@@ -3835,7 +3745,9 @@
         enforceConnectivityInternalPermission();
         final long ident = Binder.clearCallingIdentity();
         try {
-            setProvNotificationVisible(visible, networkType, action);
+            // Concatenate the range of types onto the range of NetIDs.
+            int id = MAX_NET_ID + 1 + (networkType - ConnectivityManager.TYPE_NONE);
+            mNotifier.setProvNotificationVisible(visible, id, action);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index 129fbaa..040d22c 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -179,20 +179,6 @@
 
     @Override
     public void onStart() {
-        // Set up intent receivers
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW);
-        getContext().registerReceiver(mReceiver, filter);
-
-        mContentResolver.registerContentObserver(
-            Settings.Global.CONTENT_URI, true,
-            new ContentObserver(new Handler()) {
-                @Override
-                public void onChange(boolean selfChange) {
-                    mReceiver.onReceive(getContext(), (Intent) null);
-                }
-            });
-
         publishBinderService(Context.DROPBOX_SERVICE, mStub);
 
         // The real work gets done lazily in init() -- that way service creation always
@@ -202,6 +188,21 @@
     @Override
     public void onBootPhase(int phase) {
         switch (phase) {
+            case PHASE_SYSTEM_SERVICES_READY:
+                IntentFilter filter = new IntentFilter();
+                filter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW);
+                getContext().registerReceiver(mReceiver, filter);
+
+                mContentResolver.registerContentObserver(
+                    Settings.Global.CONTENT_URI, true,
+                    new ContentObserver(new Handler()) {
+                        @Override
+                        public void onChange(boolean selfChange) {
+                            mReceiver.onReceive(getContext(), (Intent) null);
+                        }
+                    });
+                break;
+
             case PHASE_BOOT_COMPLETED:
                 mBooted = true;
                 break;
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 801a436..0cad814 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -1223,6 +1223,9 @@
             long challenge, int userId, ICheckCredentialProgressCallback progressCallback)
             throws RemoteException {
        checkPasswordReadPermission(userId);
+       if (TextUtils.isEmpty(pattern)) {
+           throw new IllegalArgumentException("Pattern can't be null or empty");
+       }
        CredentialHash storedHash = mStorage.readPatternHash(userId);
        return doVerifyPattern(pattern, storedHash, hasChallenge, challenge, userId,
                progressCallback);
@@ -1324,6 +1327,9 @@
             long challenge, int userId, ICheckCredentialProgressCallback progressCallback)
             throws RemoteException {
        checkPasswordReadPermission(userId);
+       if (TextUtils.isEmpty(password)) {
+           throw new IllegalArgumentException("Password can't be null or empty");
+       }
        CredentialHash storedHash = mStorage.readPasswordHash(userId);
        return doVerifyPassword(password, storedHash, hasChallenge, challenge, userId,
                progressCallback);
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index cdd977b..0023e4b 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -1056,6 +1056,10 @@
                         || mForceAdoptable) {
                     flags |= DiskInfo.FLAG_ADOPTABLE;
                 }
+                // Adoptable storage isn't currently supported on FBE devices
+                if (StorageManager.isFileEncryptedNativeOnly()) {
+                    flags &= ~DiskInfo.FLAG_ADOPTABLE;
+                }
                 mDisks.put(id, new DiskInfo(id, flags));
                 break;
             }
@@ -1985,6 +1989,11 @@
         }
 
         if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
+            if (StorageManager.isFileEncryptedNativeOnly()) {
+                throw new IllegalStateException(
+                        "Adoptable storage not available on device with native FBE");
+            }
+
             synchronized (mLock) {
                 mForceAdoptable = (flags & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0;
 
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 5a44205..8f16504 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1310,8 +1310,9 @@
             mConnector.execute("tether", "interface", "remove", iface);
         } catch (NativeDaemonConnectorException e) {
             throw e.rethrowAsParcelableException();
+        } finally {
+            removeInterfaceFromLocalNetwork(iface);
         }
-        removeInterfaceFromLocalNetwork(iface);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index 90f507c..fb8a815 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -138,6 +138,7 @@
             final int serviceLen = mServices.size();
             for (int i = 0; i < serviceLen; i++) {
                 final SystemService service = mServices.get(i);
+                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, service.getClass().getName());
                 try {
                     service.onBootPhase(mCurrentPhase);
                 } catch (Exception ex) {
@@ -146,6 +147,7 @@
                             + ": onBootPhase threw an exception during phase "
                             + mCurrentPhase, ex);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index acab1af..3c41894 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -22,6 +22,7 @@
 import android.accounts.AccountAndUser;
 import android.accounts.AccountAuthenticatorResponse;
 import android.accounts.AccountManager;
+import android.accounts.AccountManagerInternal;
 import android.accounts.AuthenticatorDescription;
 import android.accounts.CantAddAccountActivity;
 import android.accounts.GrantCredentialsPermissionActivity;
@@ -29,11 +30,14 @@
 import android.accounts.IAccountAuthenticatorResponse;
 import android.accounts.IAccountManager;
 import android.accounts.IAccountManagerResponse;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
+import android.app.ActivityThread;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
+import android.app.INotificationManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -46,9 +50,11 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.IntentSender;
 import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -72,11 +78,14 @@
 import android.os.Message;
 import android.os.Parcel;
 import android.os.Process;
+import android.os.RemoteCallback;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.StorageManager;
+import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
@@ -86,6 +95,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.content.PackageMonitor;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
@@ -110,7 +120,6 @@
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
@@ -246,6 +255,13 @@
             + " AND " + ACCOUNTS_NAME + "=?"
             + " AND " + ACCOUNTS_TYPE + "=?";
 
+    private static final String COUNT_OF_MATCHING_GRANTS_ANY_TOKEN = ""
+            + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
+            + " WHERE " + GRANTS_ACCOUNTS_ID + "=" + ACCOUNTS_ID
+            + " AND " + GRANTS_GRANTEE_UID + "=?"
+            + " AND " + ACCOUNTS_NAME + "=?"
+            + " AND " + ACCOUNTS_TYPE + "=?";
+
     private static final String SELECTION_AUTHTOKENS_BY_ACCOUNT =
             AUTHTOKENS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
 
@@ -279,11 +295,9 @@
         private final HashMap<String, Account[]> accountCache =
                 new LinkedHashMap<String, Account[]>();
         /** protected by the {@link #cacheLock} */
-        private final HashMap<Account, HashMap<String, String>> userDataCache =
-                new HashMap<Account, HashMap<String, String>>();
+        private final Map<Account, Map<String, String>> userDataCache = new HashMap<>();
         /** protected by the {@link #cacheLock} */
-        private final HashMap<Account, HashMap<String, String>> authTokenCache =
-                new HashMap<Account, HashMap<String, String>>();
+        private final Map<Account, Map<String, String>> authTokenCache = new HashMap<>();
 
         /** protected by the {@link #cacheLock} */
         private final TokenCache accountTokenCaches = new TokenCache();
@@ -442,6 +456,118 @@
                 }
             }
         }, UserHandle.ALL, userFilter, null, null);
+
+        LocalServices.addService(AccountManagerInternal.class, new AccountManagerInternalImpl());
+
+        // Need to cancel account request notifications if the update/install can access the account
+        new PackageMonitor() {
+            @Override
+            public void onPackageAdded(String packageName, int uid) {
+                // Called on a handler, and running as the system
+                cancelAccountAccessRequestNotificationIfNeeded(uid, true);
+            }
+
+            @Override
+            public void onPackageUpdateFinished(String packageName, int uid) {
+                // Called on a handler, and running as the system
+                cancelAccountAccessRequestNotificationIfNeeded(uid, true);
+            }
+        }.register(mContext, mMessageHandler.getLooper(), UserHandle.ALL, true);
+
+        // Cancel account request notification if an app op was preventing the account access
+        mAppOpsManager.startWatchingMode(AppOpsManager.OP_GET_ACCOUNTS, null,
+                new AppOpsManager.OnOpChangedInternalListener() {
+            @Override
+            public void onOpChanged(int op, String packageName) {
+                try {
+                    final int userId = ActivityManager.getCurrentUser();
+                    final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+                    final int mode = mAppOpsManager.checkOpNoThrow(
+                            AppOpsManager.OP_GET_ACCOUNTS, uid, packageName);
+                    if (mode == AppOpsManager.MODE_ALLOWED) {
+                        final long identity = Binder.clearCallingIdentity();
+                        try {
+                            cancelAccountAccessRequestNotificationIfNeeded(packageName, uid, true);
+                        } finally {
+                            Binder.restoreCallingIdentity(identity);
+                        }
+                    }
+                } catch (NameNotFoundException e) {
+                    /* ignore */
+                }
+            }
+        });
+
+        // Cancel account request notification if a permission was preventing the account access
+        mPackageManager.addOnPermissionsChangeListener(
+                (int uid) -> {
+            Account[] accounts = null;
+            String[] packageNames = mPackageManager.getPackagesForUid(uid);
+            if (packageNames != null) {
+                final int userId = UserHandle.getUserId(uid);
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    for (String packageName : packageNames) {
+                        if (mContext.getPackageManager().checkPermission(
+                                Manifest.permission.GET_ACCOUNTS, packageName)
+                                        != PackageManager.PERMISSION_GRANTED) {
+                            continue;
+                        }
+
+                        if (accounts == null) {
+                            accounts = getAccountsAsUser(null, userId, "android");
+                            if (ArrayUtils.isEmpty(accounts)) {
+                                return;
+                            }
+                        }
+
+                        for (Account account : accounts) {
+                            cancelAccountAccessRequestNotificationIfNeeded(
+                                    account, uid, packageName, true);
+                        }
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+        });
+    }
+
+    private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
+            boolean checkAccess) {
+        Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
+        for (Account account : accounts) {
+            cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess);
+        }
+    }
+
+    private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid,
+            boolean checkAccess) {
+        Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
+        for (Account account : accounts) {
+            cancelAccountAccessRequestNotificationIfNeeded(account, uid, packageName, checkAccess);
+        }
+    }
+
+    private void cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid,
+            boolean checkAccess) {
+        String[] packageNames = mPackageManager.getPackagesForUid(uid);
+        if (packageNames != null) {
+            for (String packageName : packageNames) {
+                cancelAccountAccessRequestNotificationIfNeeded(account, uid,
+                        packageName, checkAccess);
+            }
+        }
+    }
+
+    private void cancelAccountAccessRequestNotificationIfNeeded(Account account,
+            int uid, String packageName, boolean checkAccess) {
+        if (!checkAccess || hasAccountAccess(account, packageName,
+                UserHandle.getUserHandleForUid(uid))) {
+            cancelNotification(getCredentialPermissionNotificationId(account,
+                    AccountManager.ACCOUNT_ACCESS_TOKEN, uid), packageName,
+                    UserHandle.getUserHandleForUid(uid));
+        }
     }
 
     @Override
@@ -978,106 +1104,74 @@
             final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
             boolean accountDeleted = false;
 
-            // Get a list of stored authenticator type and UID
-            Cursor metaCursor = db.query(
-                    TABLE_META,
-                    new String[] {META_KEY, META_VALUE},
-                    SELECTION_META_BY_AUTHENTICATOR_TYPE,
-                    new String[] {META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + "%"},
-                    null /* groupBy */,
-                    null /* having */,
-                    META_KEY);
+            // Get a map of stored authenticator types to UID
+            Map<String, Integer> metaAuthUid = AccountsDbUtils.findMetaAuthUid(db);
             // Create a list of authenticator type whose previous uid no longer exists
             HashSet<String> obsoleteAuthType = Sets.newHashSet();
-            try {
-                SparseBooleanArray knownUids = null;
-                while (metaCursor.moveToNext()) {
-                    String type = TextUtils.split(metaCursor.getString(0), META_KEY_DELIMITER)[1];
-                    String uid = metaCursor.getString(1);
-                    if (TextUtils.isEmpty(type) || TextUtils.isEmpty(uid)) {
-                        // Should never happen.
-                        Slog.e(TAG, "Auth type empty: " + TextUtils.isEmpty(type)
-                                + ", uid empty: " + TextUtils.isEmpty(uid));
-                        continue;
+            SparseBooleanArray knownUids = null;
+            for (Entry<String, Integer> authToUidEntry : metaAuthUid.entrySet()) {
+                String type = authToUidEntry.getKey();
+                int uid = authToUidEntry.getValue();
+                Integer knownUid = knownAuth.get(type);
+                if (knownUid != null && uid == knownUid) {
+                    // Remove it from the knownAuth list if it's unchanged.
+                    knownAuth.remove(type);
+                } else {
+                    /*
+                     * The authenticator is presently not cached and should only be triggered
+                     * when we think an authenticator has been removed (or is being updated).
+                     * But we still want to check if any data with the associated uid is
+                     * around. This is an (imperfect) signal that the package may be updating.
+                     *
+                     * A side effect of this is that an authenticator sharing a uid with
+                     * multiple apps won't get its credentials wiped as long as some app with
+                     * that uid is still on the device. But I suspect that this is a rare case.
+                     * And it isn't clear to me how an attacker could really exploit that
+                     * feature.
+                     *
+                     * The upshot is that we don't have to worry about accounts getting
+                     * uninstalled while the authenticator's package is being updated.
+                     *
+                     */
+                    if (knownUids == null) {
+                        knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId);
                     }
-                    Integer knownUid = knownAuth.get(type);
-                    if (knownUid != null && uid.equals(knownUid.toString())) {
-                        // Remove it from the knownAuth list if it's unchanged.
-                        knownAuth.remove(type);
-                    } else {
-                        /*
-                         * The authenticator is presently not cached and should only be triggered
-                         * when we think an authenticator has been removed (or is being updated).
-                         * But we still want to check if any data with the associated uid is
-                         * around. This is an (imperfect) signal that the package may be updating.
-                         *
-                         * A side effect of this is that an authenticator sharing a uid with
-                         * multiple apps won't get its credentials wiped as long as some app with
-                         * that uid is still on the device. But I suspect that this is a rare case.
-                         * And it isn't clear to me how an attacker could really exploit that
-                         * feature.
-                         *
-                         * The upshot is that we don't have to worry about accounts getting
-                         * uninstalled while the authenticator's package is being updated.
-                         *
-                         */
-                        if (knownUids == null) {
-                            knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId); 
-                        }
-                        if (!knownUids.get(Integer.parseInt(uid))) {
-                            // The authenticator is not presently available to the cache. And the
-                            // package no longer has a data directory (so we surmise it isn't updating).
-                            // So purge its data from the account databases.
-                            obsoleteAuthType.add(type);
-                            // And delete it from the TABLE_META
-                            db.delete(
-                                    TABLE_META,
-                                    META_KEY + "=? AND " + META_VALUE + "=?",
-                                    new String[] {
-                                            META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + type,
-                                            uid}
-                                    );
-                        }
+                    if (!knownUids.get(uid)) {
+                        // The authenticator is not presently available to the cache. And the
+                        // package no longer has a data directory (so we surmise it isn't updating).
+                        // So purge its data from the account databases.
+                        obsoleteAuthType.add(type);
+                        // And delete it from the TABLE_META
+                        AccountsDbUtils.deleteMetaByAuthTypeAndUid(db, type, uid);
                     }
                 }
-            } finally {
-                metaCursor.close();
             }
 
             // Add the newly registered authenticator to TABLE_META. If old authenticators have
-            // been renabled (after being updated for example), then we just overwrite the old
+            // been re-enabled (after being updated for example), then we just overwrite the old
             // values.
-            Iterator<Entry<String, Integer>> iterator = knownAuth.entrySet().iterator();
-            while (iterator.hasNext()) {
-                Entry<String, Integer> entry = iterator.next();
-                ContentValues values = new ContentValues();
-                values.put(META_KEY,
-                        META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + entry.getKey());
-                values.put(META_VALUE, entry.getValue());
-                db.insertWithOnConflict(TABLE_META, null, values, SQLiteDatabase.CONFLICT_REPLACE);
+            for (Entry<String, Integer> entry : knownAuth.entrySet()) {
+                AccountsDbUtils.insertOrReplaceMetaAuthTypeAndUid(db, entry.getKey(),
+                        entry.getValue());
             }
 
-            Cursor cursor = db.query(TABLE_ACCOUNTS,
-                    new String[]{ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME},
-                    null, null, null, null, ACCOUNTS_ID);
+            final Map<Long, Account> accountsMap = AccountsDbUtils.findAllAccounts(db);
             try {
                 accounts.accountCache.clear();
                 final HashMap<String, ArrayList<String>> accountNamesByType = new LinkedHashMap<>();
-                while (cursor.moveToNext()) {
-                    final long accountId = cursor.getLong(0);
-                    final String accountType = cursor.getString(1);
-                    final String accountName = cursor.getString(2);
-
-                    if (obsoleteAuthType.contains(accountType)) {
-                        Slog.w(TAG, "deleting account " + accountName + " because type "
-                                + accountType + "'s registered authenticator no longer exist.");
+                for (Entry<Long, Account> accountEntry : accountsMap.entrySet()) {
+                    final long accountId = accountEntry.getKey();
+                    final Account account = accountEntry.getValue();
+                    if (obsoleteAuthType.contains(account.type)) {
+                        Slog.w(TAG, "deleting account " + account.name + " because type "
+                                + account.type + "'s registered authenticator no longer exist.");
                         db.beginTransaction();
                         try {
-                            db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null);
+                            AccountsDbUtils.deleteAccount(db, accountId);
                             // Also delete from CE table if user is unlocked; if user is currently
                             // locked the account will be removed later by syncDeCeAccountsLocked
                             if (userUnlocked) {
-                                db.delete(CE_TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null);
+                                AccountsDbUtils.deleteCeAccount(db, accountId);
                             }
                             db.setTransactionSuccessful();
                         } finally {
@@ -1088,17 +1182,16 @@
                         logRecord(db, DebugDbHelper.ACTION_AUTHENTICATOR_REMOVE, TABLE_ACCOUNTS,
                                 accountId, accounts);
 
-                        final Account account = new Account(accountName, accountType);
                         accounts.userDataCache.remove(account);
                         accounts.authTokenCache.remove(account);
                         accounts.accountTokenCaches.remove(account);
                     } else {
-                        ArrayList<String> accountNames = accountNamesByType.get(accountType);
+                        ArrayList<String> accountNames = accountNamesByType.get(account.type);
                         if (accountNames == null) {
                             accountNames = new ArrayList<>();
-                            accountNamesByType.put(accountType, accountNames);
+                            accountNamesByType.put(account.type, accountNames);
                         }
-                        accountNames.add(accountName);
+                        accountNames.add(account.name);
                     }
                 }
                 for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) {
@@ -1111,7 +1204,6 @@
                     accounts.accountCache.put(accountType, accountsForType);
                 }
             } finally {
-                cursor.close();
                 if (accountDeleted) {
                     sendAccountsChangedBroadcast(accounts.userId);
                 }
@@ -1192,7 +1284,7 @@
     private void syncDeCeAccountsLocked(UserAccounts accounts) {
         Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
         final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
-        List<Account> accountsToRemove = CeDatabaseHelper.findCeAccountsNotInDe(db);
+        List<Account> accountsToRemove = AccountsDbUtils.findCeAccountsNotInDe(db);
         if (!accountsToRemove.isEmpty()) {
             Slog.i(TAG, "Accounts " + accountsToRemove + " were previously deleted while user "
                     + accounts.userId + " was locked. Removing accounts from CE tables");
@@ -1215,23 +1307,15 @@
     private void purgeOldGrants(UserAccounts accounts) {
         synchronized (accounts.cacheLock) {
             final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
-            final Cursor cursor = db.query(TABLE_GRANTS,
-                    new String[]{GRANTS_GRANTEE_UID},
-                    null, null, GRANTS_GRANTEE_UID, null, null);
-            try {
-                while (cursor.moveToNext()) {
-                    final int uid = cursor.getInt(0);
-                    final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
-                    if (packageExists) {
-                        continue;
-                    }
-                    Log.d(TAG, "deleting grants for UID " + uid
-                            + " because its package is no longer installed");
-                    db.delete(TABLE_GRANTS, GRANTS_GRANTEE_UID + "=?",
-                            new String[]{Integer.toString(uid)});
+            List<Integer> uids = AccountsDbUtils.findAllUidGrants(db);
+            for (int uid : uids) {
+                final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
+                if (packageExists) {
+                    continue;
                 }
-            } finally {
-                cursor.close();
+                Log.d(TAG, "deleting grants for UID " + uid
+                        + " because its package is no longer installed");
+                AccountsDbUtils.deleteGrantsByUid(db, uid);
             }
         }
     }
@@ -1350,7 +1434,7 @@
 
         synchronized (accounts.cacheLock) {
             final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
-            return CeDatabaseHelper.findAccountPasswordByNameAndType(db, account.name,
+            return AccountsDbUtils.findAccountPasswordByNameAndType(db, account.name,
                     account.type);
         }
     }
@@ -1381,26 +1465,10 @@
             AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
             if (previousNameRef == null) {
                 final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
-                Cursor cursor = db.query(
-                        TABLE_ACCOUNTS,
-                        new String[]{ ACCOUNTS_PREVIOUS_NAME },
-                        ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
-                        new String[] { account.name, account.type },
-                        null,
-                        null,
-                        null);
-                try {
-                    if (cursor.moveToNext()) {
-                        String previousName = cursor.getString(0);
-                        previousNameRef = new AtomicReference<>(previousName);
-                        accounts.previousNameCache.put(account, previousNameRef);
-                        return previousName;
-                    } else {
-                        return null;
-                    }
-                } finally {
-                    cursor.close();
-                }
+                String previousName = AccountsDbUtils.findAccountPreviousName(db, account);
+                previousNameRef = new AtomicReference<>(previousName);
+                accounts.previousNameCache.put(account, previousNameRef);
+                return previousName;
             } else {
                 return previousNameRef.get();
             }
@@ -1753,7 +1821,7 @@
                 if (extras != null) {
                     for (String key : extras.keySet()) {
                         final String value = extras.getString(key);
-                        if (insertExtraLocked(db, accountId, key, value) < 0) {
+                        if (AccountsDbUtils.insertExtra(db, accountId, key, value) < 0) {
                             Log.w(TAG, "insertAccountIntoDatabase: " + account
                                     + ", skipping since insertExtra failed for key " + key);
                             return false;
@@ -1804,14 +1872,6 @@
         }
     }
 
-    private long insertExtraLocked(SQLiteDatabase db, long accountId, String key, String value) {
-        ContentValues values = new ContentValues();
-        values.put(EXTRAS_KEY, key);
-        values.put(EXTRAS_ACCOUNTS_ID, accountId);
-        values.put(EXTRAS_VALUE, value);
-        return db.insert(CE_TABLE_EXTRAS, EXTRAS_KEY, values);
-    }
-
     @Override
     public void hasFeatures(IAccountManagerResponse response,
             Account account, String[] features, String opPackageName) {
@@ -1960,7 +2020,7 @@
             db.beginTransaction();
             Account renamedAccount = new Account(newName, accountToRename.type);
             try {
-                final long accountId = getAccountIdLocked(db, accountToRename);
+                final long accountId = AccountsDbUtils.findAccountId(db, accountToRename);
                 if (accountId >= 0) {
                     final ContentValues values = new ContentValues();
                     values.put(ACCOUNTS_NAME, newName);
@@ -1986,8 +2046,8 @@
              * old account to preserve the user data associated with
              * the account.
              */
-            HashMap<String, String> tmpData = accounts.userDataCache.get(accountToRename);
-            HashMap<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
+            Map<String, String> tmpData = accounts.userDataCache.get(accountToRename);
+            Map<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename);
             removeAccountFromCacheLocked(accounts, accountToRename);
             /*
              * Update the cached data associated with the renamed
@@ -1997,7 +2057,7 @@
             accounts.authTokenCache.put(renamedAccount, tmpTokens);
             accounts.previousNameCache.put(
                     renamedAccount,
-                    new AtomicReference<String>(accountToRename.name));
+                    new AtomicReference<>(accountToRename.name));
             resultAccount = renamedAccount;
 
             int parentUserId = accounts.userId;
@@ -2098,7 +2158,7 @@
             }
         }
         SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
-        final long accountId = getAccountIdLocked(db, account);
+        final long accountId = AccountsDbUtils.findAccountId(db, account);
         logRecord(
                 db,
                 DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE,
@@ -2139,7 +2199,7 @@
         removeVisibleListFunctionality(account, getUserAccounts(UserHandle.getUserId(callingUid)));
         UserAccounts accounts = getUserAccountsForCaller();
         SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
-        final long accountId = getAccountIdLocked(db, account);
+        final long accountId = AccountsDbUtils.findAccountId(db, account);
         logRecord(
                 db,
                 DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE,
@@ -2225,18 +2285,12 @@
             // transaction succeeds.
             long accountId = -1;
             try {
-                accountId = getAccountIdLocked(db, account);
+                accountId = AccountsDbUtils.findAccountId(db, account);
                 if (accountId >= 0) {
-                    db.delete(
-                            TABLE_ACCOUNTS,
-                            ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
-                            new String[]{ account.name, account.type });
+                    AccountsDbUtils.deleteAccount(db, accountId);
                     if (userUnlocked) {
                         // Delete from CE table
-                        db.delete(
-                                CE_TABLE_ACCOUNTS,
-                                ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
-                                new String[]{ account.name, account.type });
+                        AccountsDbUtils.deleteCeAccount(db, accountId);
                     }
                     db.setTransactionSuccessful();
                     isChanged = true;
@@ -2268,6 +2322,21 @@
         } finally {
             Binder.restoreCallingIdentity(id);
         }
+
+        if (isChanged) {
+            synchronized (accounts.credentialsPermissionNotificationIds) {
+                for (Pair<Pair<Account, String>, Integer> key
+                        : accounts.credentialsPermissionNotificationIds.keySet()) {
+                    if (account.equals(key.first.first)
+                            && AccountManager.ACCOUNT_ACCESS_TOKEN.equals(key.first.second)) {
+                        final int uid = (Integer) key.second;
+                        mMessageHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded(
+                                account, uid, false));
+                    }
+                }
+            }
+        }
+
         return isChanged;
     }
 
@@ -2317,23 +2386,13 @@
         if (authToken == null || accountType == null) {
             return;
         }
-        Cursor cursor = db.rawQuery(
-                "SELECT " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
-                        + ", " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
-                        + ", " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
-                        + " FROM " + CE_TABLE_ACCOUNTS
-                        + " JOIN " + CE_TABLE_AUTHTOKENS
-                        + " ON " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_ID
-                        + " = " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_ACCOUNTS_ID
-                        + " WHERE " + CE_TABLE_AUTHTOKENS + "."  + AUTHTOKENS_AUTHTOKEN
-                        + " = ? AND " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
-                new String[]{authToken, accountType});
+        Cursor cursor = AccountsDbUtils.findAuthtokenForAllAccounts(db, accountType, authToken);
         try {
             while (cursor.moveToNext()) {
-                long authTokenId = cursor.getLong(0);
+                String authTokenId = cursor.getString(0);
                 String accountName = cursor.getString(1);
                 String authTokenType = cursor.getString(2);
-                db.delete(CE_TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
+                AccountsDbUtils.deleteAuthToken(db, authTokenId);
                 writeAuthTokenIntoCacheLocked(
                         accounts,
                         db,
@@ -2377,18 +2436,12 @@
             final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
             db.beginTransaction();
             try {
-                long accountId = getAccountIdLocked(db, account);
+                long accountId = AccountsDbUtils.findAccountId(db, account);
                 if (accountId < 0) {
                     return false;
                 }
-                db.delete(CE_TABLE_AUTHTOKENS,
-                        AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
-                        new String[]{type});
-                ContentValues values = new ContentValues();
-                values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
-                values.put(AUTHTOKENS_TYPE, type);
-                values.put(AUTHTOKENS_AUTHTOKEN, authToken);
-                if (db.insert(CE_TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
+                AccountsDbUtils.deleteAuthtokensByAccountIdAndType(db, accountId, type);
+                if (AccountsDbUtils.insertAuthToken(db, accountId, type, authToken) >= 0) {
                     db.setTransactionSuccessful();
                     writeAuthTokenIntoCacheLocked(accounts, db, account, type, authToken);
                     return true;
@@ -2497,15 +2550,10 @@
             final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
             db.beginTransaction();
             try {
-                final ContentValues values = new ContentValues();
-                values.put(ACCOUNTS_PASSWORD, password);
-                final long accountId = getAccountIdLocked(db, account);
+                final long accountId = AccountsDbUtils.findAccountId(db, account);
                 if (accountId >= 0) {
-                    final String[] argsAccountId = {String.valueOf(accountId)};
-                    db.update(
-                            CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
-                    db.delete(
-                            CE_TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
+                    AccountsDbUtils.updateAccountPassword(db, accountId, password);
+                    AccountsDbUtils.deleteAuthTokensByAccountId(db, accountId);
                     accounts.authTokenCache.remove(account);
                     accounts.accountTokenCaches.remove(account);
                     db.setTransactionSuccessful();
@@ -2612,22 +2660,18 @@
         final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
         db.beginTransaction();
         try {
-            long accountId = getAccountIdLocked(db, account);
+            long accountId = AccountsDbUtils.findAccountId(db, account);
             if (accountId < 0) {
                 return;
             }
-            long extrasId = getExtrasIdLocked(db, accountId, key);
+            long extrasId = AccountsDbUtils.findExtrasIdByAccountId(db, accountId, key);
             if (extrasId < 0) {
-                extrasId = insertExtraLocked(db, accountId, key, value);
+                extrasId = AccountsDbUtils.insertExtra(db, accountId, key, value);
                 if (extrasId < 0) {
                     return;
                 }
-            } else {
-                ContentValues values = new ContentValues();
-                values.put(EXTRAS_VALUE, value);
-                if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
-                    return;
-                }
+            } else if (!AccountsDbUtils.updateExtra(db, extrasId, value)) {
+                return;
             }
             writeUserDataIntoCacheLocked(accounts, db, account, key, value);
             db.setTransactionSuccessful();
@@ -2864,9 +2908,11 @@
                         if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
                             Intent intent = newGrantCredentialsPermissionIntent(
                                     account,
+                                    null,
                                     callerUid,
                                     new AccountAuthenticatorResponse(this),
-                                    authTokenType);
+                                    authTokenType,
+                                    true);
                             Bundle bundle = new Bundle();
                             bundle.putParcelable(AccountManager.KEY_INTENT, intent);
                             onResult(bundle);
@@ -2917,7 +2963,7 @@
                                     intent);
                             doNotification(mAccounts,
                                     account, result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
-                                    intent, accounts.userId);
+                                    intent, "android", accounts.userId);
                         }
                     }
                     super.onResult(result);
@@ -2948,7 +2994,7 @@
     }
 
     private void createNoCredentialsPermissionNotification(Account account, Intent intent,
-            int userId) {
+            String packageName, int userId) {
         int uid = intent.getIntExtra(
                 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
         String authTokenType = intent.getStringExtra(
@@ -2963,7 +3009,7 @@
             title = titleAndSubtitle.substring(0, index);
             subtitle = titleAndSubtitle.substring(index + 1);
         }
-        UserHandle user = new UserHandle(userId);
+        UserHandle user = UserHandle.of(userId);
         Context contextForUser = getContextForUser(user);
         Notification n = new Notification.Builder(contextForUser)
                 .setSmallIcon(android.R.drawable.stat_sys_warning)
@@ -2976,20 +3022,23 @@
                         PendingIntent.FLAG_CANCEL_CURRENT, null, user))
                 .build();
         installNotification(getCredentialPermissionNotificationId(
-                account, authTokenType, uid), n, user);
+                account, authTokenType, uid), n, packageName, user.getIdentifier());
     }
 
-    private Intent newGrantCredentialsPermissionIntent(Account account, int uid,
-            AccountAuthenticatorResponse response, String authTokenType) {
+    private Intent newGrantCredentialsPermissionIntent(Account account, String packageName,
+            int uid, AccountAuthenticatorResponse response, String authTokenType,
+            boolean startInNewTask) {
 
         Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
-        // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
-        // Since it was set in Eclair+ we can't change it without breaking apps using
-        // the intent from a non-Activity context.
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.addCategory(
-                String.valueOf(getCredentialPermissionNotificationId(account, authTokenType, uid)));
 
+        if (startInNewTask) {
+            // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
+            // Since it was set in Eclair+ we can't change it without breaking apps using
+            // the intent from a non-Activity context. This is the default behavior.
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        }
+        intent.addCategory(String.valueOf(getCredentialPermissionNotificationId(account,
+                authTokenType, uid) + (packageName != null ? packageName : "")));
         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
         intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
@@ -3242,10 +3291,9 @@
         boolean isPasswordForwardingAllowed = isPermitted(
                 callerPkg, uid, Manifest.permission.GET_PASSWORD);
 
-        int usrId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
-            UserAccounts accounts = getUserAccounts(usrId);
+            UserAccounts accounts = getUserAccounts(userId);
             logRecordWithUid(accounts, DebugDbHelper.ACTION_CALLED_START_ACCOUNT_ADD,
                     TABLE_ACCOUNTS, uid);
             new StartAccountSession(
@@ -3306,10 +3354,6 @@
                 checkKeyIntent(
                         Binder.getCallingUid(),
                         intent);
-                // Omit passwords if the caller isn't permitted to see them.
-                if (!mIsPasswordForwardingAllowed) {
-                    result.remove(AccountManager.KEY_PASSWORD);
-                }
             }
             IAccountManagerResponse response;
             if (mExpectActivityLaunch && result != null
@@ -3339,6 +3383,11 @@
                 return;
             }
 
+            // Omit passwords if the caller isn't permitted to see them.
+            if (!mIsPasswordForwardingAllowed) {
+                result.remove(AccountManager.KEY_PASSWORD);
+            }
+
             // Strip auth token from result.
             result.remove(AccountManager.KEY_AUTHTOKEN);
 
@@ -3520,7 +3569,9 @@
         final DevicePolicyManagerInternal dpmi =
                 LocalServices.getService(DevicePolicyManagerInternal.class);
         Intent intent = null;
-        if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) {
+        if (dpmi == null) {
+            intent = getDefaultCantAddAccountIntent(errorCode);
+        } else if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) {
             intent = dpmi.createUserRestrictionSupportIntent(userId,
                     UserManager.DISALLOW_MODIFY_ACCOUNTS);
         } else if (errorCode == AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
@@ -3826,6 +3877,118 @@
     }
 
     @Override
+    public boolean hasAccountAccess(@NonNull Account account,  @NonNull String packageName,
+            @NonNull UserHandle userHandle) {
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+            throw new SecurityException("Can be called only by system UID");
+        }
+        Preconditions.checkNotNull(account, "account cannot be null");
+        Preconditions.checkNotNull(packageName, "packageName cannot be null");
+        Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
+
+        final int userId = userHandle.getIdentifier();
+
+        Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
+
+        try {
+
+            final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+            // Use null token which means any token. Having a token means the package
+            // is trusted by the authenticator, hence it is fine to access the account.
+            if (permissionIsGranted(account, null, uid, userId)) {
+                return true;
+            }
+            // In addition to the permissions required to get an auth token we also allow
+            // the account to be accessed by holders of the get accounts permissions.
+            return checkUidPermission(Manifest.permission.GET_ACCOUNTS_PRIVILEGED, uid, packageName)
+                    || checkUidPermission(Manifest.permission.GET_ACCOUNTS, uid, packageName);
+        } catch (NameNotFoundException e) {
+            return false;
+        }
+    }
+
+    private boolean checkUidPermission(String permission, int uid, String opPackageName) {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            IPackageManager pm = ActivityThread.getPackageManager();
+            if (pm.checkUidPermission(permission, uid) != PackageManager.PERMISSION_GRANTED) {
+                return false;
+            }
+            final int opCode = AppOpsManager.permissionToOpCode(permission);
+            return (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow(
+                    opCode, uid, opPackageName) == AppOpsManager.MODE_ALLOWED);
+        } catch (RemoteException e) {
+            /* ignore - local call */
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+        return false;
+    }
+
+    @Override
+    public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
+            @NonNull String packageName, @NonNull UserHandle userHandle) {
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+            throw new SecurityException("Can be called only by system UID");
+        }
+
+        Preconditions.checkNotNull(account, "account cannot be null");
+        Preconditions.checkNotNull(packageName, "packageName cannot be null");
+        Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
+
+        final int userId = userHandle.getIdentifier();
+
+        Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
+
+        final int uid;
+        try {
+            uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+        } catch (NameNotFoundException e) {
+            Slog.e(TAG, "Unknown package " + packageName);
+            return null;
+        }
+
+        Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null);
+
+        return PendingIntent.getActivityAsUser(
+                mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
+                        | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
+                null, new UserHandle(userId)).getIntentSender();
+    }
+
+    private Intent newRequestAccountAccessIntent(Account account, String packageName,
+            int uid, RemoteCallback callback) {
+        return newGrantCredentialsPermissionIntent(account, packageName, uid,
+                new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
+            @Override
+            public void onResult(Bundle value) throws RemoteException {
+                handleAuthenticatorResponse(true);
+            }
+
+            @Override
+            public void onRequestContinued() {
+                /* ignore */
+            }
+
+            @Override
+            public void onError(int errorCode, String errorMessage) throws RemoteException {
+                handleAuthenticatorResponse(false);
+            }
+
+            private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException {
+                cancelNotification(getCredentialPermissionNotificationId(account,
+                        AccountManager.ACCOUNT_ACCESS_TOKEN, uid), packageName,
+                        UserHandle.getUserHandleForUid(uid));
+                if (callback != null) {
+                    Bundle result = new Bundle();
+                    result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted);
+                    callback.sendResult(result);
+                }
+            }
+        }), AccountManager.ACCOUNT_ACCESS_TOKEN, false);
+    }
+
+    @Override
     public boolean someUserHasAccount(@NonNull final Account account) {
         if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
             throw new SecurityException("Only system can check for accounts across users");
@@ -4125,12 +4288,8 @@
         userId = handleIncomingUser(userId);
         UserAccounts accounts = getUserAccounts(userId);
         SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
-        ContentValues values = new ContentValues();
-        values.put(ACCOUNTS_NAME, account.name);
-        values.put(ACCOUNTS_TYPE, account.type);
-        db.delete(TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
-                new String[] {account.name, account.type});
-        long accountId = db.insert(TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME, values);
+        AccountsDbUtils.deleteSharedAccount(db, account);
+        long accountId = AccountsDbUtils.insertSharedAccount(db, account);
         if (accountId < 0) {
             Log.w(TAG, "insertAccountIntoDatabase: " + account
                     + ", skipping the DB insert failed");
@@ -4145,14 +4304,8 @@
         userId = handleIncomingUser(userId);
         UserAccounts accounts = getUserAccounts(userId);
         SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
-        long sharedTableAccountId = getAccountIdFromSharedTable(db, account);
-        final ContentValues values = new ContentValues();
-        values.put(ACCOUNTS_NAME, newName);
-        int r = db.update(
-                TABLE_SHARED_ACCOUNTS,
-                values,
-                ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
-                new String[] { account.name, account.type });
+        long sharedTableAccountId = AccountsDbUtils.findSharedAccountId(db, account);
+        int r = AccountsDbUtils.renameSharedAccount(db, account, newName);
         if (r > 0) {
             int callingUid = getCallingUid();
             logRecord(db, DebugDbHelper.ACTION_ACCOUNT_RENAME, TABLE_SHARED_ACCOUNTS,
@@ -4172,40 +4325,21 @@
         userId = handleIncomingUser(userId);
         UserAccounts accounts = getUserAccounts(userId);
         SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
-        long sharedTableAccountId = getAccountIdFromSharedTable(db, account);
-        int r = db.delete(TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
-                new String[] {account.name, account.type});
-        if (r > 0) {
+        long sharedTableAccountId = AccountsDbUtils.findSharedAccountId(db, account);
+        boolean deleted = AccountsDbUtils.deleteSharedAccount(db, account);
+        if (deleted) {
             logRecord(db, DebugDbHelper.ACTION_ACCOUNT_REMOVE, TABLE_SHARED_ACCOUNTS,
                     sharedTableAccountId, accounts, callingUid);
             removeAccountInternal(accounts, account, callingUid);
         }
-        return r > 0;
+        return deleted;
     }
 
     @Override
     public Account[] getSharedAccountsAsUser(int userId) {
         userId = handleIncomingUser(userId);
-        UserAccounts accounts = getUserAccounts(userId);
-        ArrayList<Account> accountList = new ArrayList<>();
-        Cursor cursor = null;
-        try {
-            cursor = accounts.openHelper.getReadableDatabase()
-                    .query(TABLE_SHARED_ACCOUNTS, new String[]{ACCOUNTS_NAME, ACCOUNTS_TYPE},
-                    null, null, null, null, null);
-            if (cursor != null && cursor.moveToFirst()) {
-                int nameIndex = cursor.getColumnIndex(ACCOUNTS_NAME);
-                int typeIndex = cursor.getColumnIndex(ACCOUNTS_TYPE);
-                do {
-                    accountList.add(new Account(cursor.getString(nameIndex),
-                            cursor.getString(typeIndex)));
-                } while (cursor.moveToNext());
-            }
-        } finally {
-            if (cursor != null) {
-                cursor.close();
-            }
-        }
+        SQLiteDatabase db = getUserAccounts(userId).openHelper.getReadableDatabase();
+        List<Account> accountList = AccountsDbUtils.getSharedAccounts(db);
         Account[] accountArray = new Account[accountList.size()];
         accountList.toArray(accountArray);
         return accountArray;
@@ -4301,46 +4435,6 @@
         }
     }
 
-    private long getAccountIdFromSharedTable(SQLiteDatabase db, Account account) {
-        Cursor cursor = db.query(TABLE_SHARED_ACCOUNTS, new String[]{ACCOUNTS_ID},
-                "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
-        try {
-            if (cursor.moveToNext()) {
-                return cursor.getLong(0);
-            }
-            return -1;
-        } finally {
-            cursor.close();
-        }
-    }
-
-    private long getAccountIdLocked(SQLiteDatabase db, Account account) {
-        Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
-                "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
-        try {
-            if (cursor.moveToNext()) {
-                return cursor.getLong(0);
-            }
-            return -1;
-        } finally {
-            cursor.close();
-        }
-    }
-
-    private long getExtrasIdLocked(SQLiteDatabase db, long accountId, String key) {
-        Cursor cursor = db.query(CE_TABLE_EXTRAS, new String[]{EXTRAS_ID},
-                EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
-                new String[]{key}, null, null, null);
-        try {
-            if (cursor.moveToNext()) {
-                return cursor.getLong(0);
-            }
-            return -1;
-        } finally {
-            cursor.close();
-        }
-    }
-
     private abstract class Session extends IAccountAuthenticatorResponse.Stub
             implements IBinder.DeathRecipient, ServiceConnection {
         IAccountManagerResponse mResponse;
@@ -5013,17 +5107,10 @@
                     +   "," + GRANTS_GRANTEE_UID + "))");
         }
 
-        private void populateMetaTableWithAuthTypeAndUID(
-                SQLiteDatabase db,
+        private void populateMetaTableWithAuthTypeAndUID(SQLiteDatabase db,
                 Map<String, Integer> authTypeAndUIDMap) {
-            Iterator<Entry<String, Integer>> iterator = authTypeAndUIDMap.entrySet().iterator();
-            while (iterator.hasNext()) {
-                Entry<String, Integer> entry = iterator.next();
-                ContentValues values = new ContentValues();
-                values.put(META_KEY,
-                        META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + entry.getKey());
-                values.put(META_VALUE, entry.getValue());
-                db.insert(TABLE_META, null, values);
+            for (Entry<String, Integer> entry : authTypeAndUIDMap.entrySet()) {
+                AccountsDbUtils.insertMetaAuthTypeAndUid(db, entry.getKey(), entry.getValue());
             }
         }
 
@@ -5076,7 +5163,7 @@
             if (oldVersion == 8) {
                 populateMetaTableWithAuthTypeAndUID(
                         db,
-                        AccountManagerService.getAuthenticatorTypeAndUIDForUser(mContext, mUserId));
+                        getAuthenticatorTypeAndUIDForUser(mContext, mUserId));
                 oldVersion++;
             }
 
@@ -5336,42 +5423,6 @@
             if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + CE_DATABASE_NAME);
         }
 
-        static String findAccountPasswordByNameAndType(SQLiteDatabase db, String name,
-                String type) {
-            Cursor cursor = db.query(CE_TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
-                    ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
-                    new String[]{name, type}, null, null, null);
-            try {
-                if (cursor.moveToNext()) {
-                    return cursor.getString(0);
-                }
-                return null;
-            } finally {
-                cursor.close();
-            }
-        }
-
-        static List<Account> findCeAccountsNotInDe(SQLiteDatabase db) {
-            // Select accounts from CE that do not exist in DE
-            Cursor cursor = db.rawQuery(
-                    "SELECT " + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE
-                            + " FROM " + CE_TABLE_ACCOUNTS
-                            + " WHERE NOT EXISTS "
-                            + " (SELECT " + ACCOUNTS_ID + " FROM " + TABLE_ACCOUNTS
-                            + " WHERE " + ACCOUNTS_ID + "=" + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_ID
-                            + " )", null);
-            try {
-                List<Account> accounts = new ArrayList<>(cursor.getCount());
-                while (cursor.moveToNext()) {
-                    String accountName = cursor.getString(0);
-                    String accountType = cursor.getString(1);
-                    accounts.add(new Account(accountName, accountType));
-                }
-                return accounts;
-            } finally {
-                cursor.close();
-            }
-        }
 
         /**
          * Creates a new {@code CeDatabaseHelper}. If pre-N db file is present at the old location,
@@ -5470,18 +5521,7 @@
 
             if (isCheckinRequest) {
                 // This is a checkin request. *Only* upload the account types and the count of each.
-                Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_TYPE_COUNT_PROJECTION,
-                        null, null, ACCOUNTS_TYPE, null, null);
-                try {
-                    while (cursor.moveToNext()) {
-                        // print type,count
-                        fout.println(cursor.getString(0) + "," + cursor.getString(1));
-                    }
-                } finally {
-                    if (cursor != null) {
-                        cursor.close();
-                    }
-                }
+                AccountsDbUtils.dumpAccountsTable(db, fout);
             } else {
                 Account[] accounts = getAccountsFromCacheLocked(userAccounts, null /* type */,
                         Process.myUid(), null);
@@ -5492,21 +5532,7 @@
 
                 // Add debug information.
                 fout.println();
-                Cursor cursor = db.query(DebugDbHelper.TABLE_DEBUG, null,
-                        null, null, null, null, DebugDbHelper.TIMESTAMP);
-                fout.println("AccountId, Action_Type, timestamp, UID, TableName, Key");
-                fout.println("Accounts History");
-                try {
-                    while (cursor.moveToNext()) {
-                        // print type,count
-                        fout.println(cursor.getString(0) + "," + cursor.getString(1) + "," +
-                                cursor.getString(2) + "," + cursor.getString(3) + ","
-                                + cursor.getString(4) + "," + cursor.getString(5));
-                    }
-                } finally {
-                    cursor.close();
-                }
-
+                AccountsDbUtils.dumpDebugTable(db, fout);
                 fout.println();
                 synchronized (mSessions) {
                     final long now = SystemClock.elapsedRealtime();
@@ -5523,7 +5549,7 @@
     }
 
     private void doNotification(UserAccounts accounts, Account account, CharSequence message,
-            Intent intent, int userId) {
+            Intent intent, String packageName, final int userId) {
         long identityToken = clearCallingIdentity();
         try {
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -5533,12 +5559,12 @@
             if (intent.getComponent() != null &&
                     GrantCredentialsPermissionActivity.class.getName().equals(
                             intent.getComponent().getClassName())) {
-                createNoCredentialsPermissionNotification(account, intent, userId);
+                createNoCredentialsPermissionNotification(account, intent, packageName, userId);
             } else {
+                Context contextForUser = getContextForUser(new UserHandle(userId));
                 final Integer notificationId = getSigninRequiredNotificationId(accounts, account);
                 intent.addCategory(String.valueOf(notificationId));
-                UserHandle user = new UserHandle(userId);
-                Context contextForUser = getContextForUser(user);
+
                 final String notificationTitleFormat =
                         contextForUser.getText(R.string.notification_title).toString();
                 Notification n = new Notification.Builder(contextForUser)
@@ -5550,9 +5576,9 @@
                         .setContentText(message)
                         .setContentIntent(PendingIntent.getActivityAsUser(
                                 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
-                                null, user))
+                                null, new UserHandle(userId)))
                         .build();
-                installNotification(notificationId, n, user);
+                installNotification(notificationId, n, packageName, userId);
             }
         } finally {
             restoreCallingIdentity(identityToken);
@@ -5560,18 +5586,40 @@
     }
 
     @VisibleForTesting
-    protected void installNotification(final int notificationId, final Notification n,
+    protected void installNotification(int notificationId, final Notification notification,
             UserHandle user) {
-        ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
-                .notifyAsUser(null, notificationId, n, user);
+        installNotification(notificationId, notification, "android", user.getIdentifier());
+    }
+
+    private void installNotification(int notificationId, final Notification notification,
+            String packageName, int userId) {
+        final long token = clearCallingIdentity();
+        try {
+            INotificationManager notificationManager = NotificationManager.getService();
+            try {
+                notificationManager.enqueueNotificationWithTag(packageName, packageName, null,
+                        notificationId, notification, new int[1], userId);
+            } catch (RemoteException e) {
+                /* ignore - local call */
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     @VisibleForTesting
     protected void cancelNotification(int id, UserHandle user) {
+        cancelNotification(id, mContext.getPackageName(), user);
+    }
+
+    protected void cancelNotification(int id, String packageName, UserHandle user) {
         long identityToken = clearCallingIdentity();
         try {
-            ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
-                .cancelAsUser(null, id, user);
+            INotificationManager service = INotificationManager.Stub.asInterface(
+                    ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+            service.cancelNotificationWithTag(packageName, null, id, user.getIdentifier());
+        } catch (RemoteException e) {
+            /* ignore - local call */
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -5632,18 +5680,40 @@
 
     private boolean permissionIsGranted(
             Account account, String authTokenType, int callerUid, int userId) {
-        final boolean isPrivileged = isPrivileged(callerUid);
-        final boolean fromAuthenticator = account != null
-                && isAccountManagedByCaller(account.type, callerUid, userId);
-        final boolean hasExplicitGrants = account != null
-                && hasExplicitlyGrantedPermission(account, authTokenType, callerUid);
-        if (Log.isLoggable(TAG, Log.VERBOSE)) {
-            Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid "
-                    + callerUid + ", " + account
-                    + ": is authenticator? " + fromAuthenticator
-                    + ", has explicit permission? " + hasExplicitGrants);
+        if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "Access to " + account + " granted calling uid is system");
+            }
+            return true;
         }
-        return fromAuthenticator || hasExplicitGrants || isPrivileged;
+
+        if (isPrivileged(callerUid)) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "Access to " + account + " granted calling uid "
+                        + callerUid + " privileged");
+            }
+            return true;
+        }
+        if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "Access to " + account + " granted calling uid "
+                        + callerUid + " manages the account");
+            }
+            return true;
+        }
+        if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "Access to " + account + " granted calling uid "
+                        + callerUid + " user granted access");
+            }
+            return true;
+        }
+
+        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+            Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid);
+        }
+
+        return false;
     }
 
     private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
@@ -5733,10 +5803,20 @@
         UserAccounts accounts = getUserAccountsForCaller();
         synchronized (accounts.cacheLock) {
             final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
-            String[] args = { String.valueOf(callerUid), authTokenType,
-                    account.name, account.type};
-            final boolean permissionGranted =
-                    DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0;
+            final String query;
+            final String[] args;
+
+            if (authTokenType != null) {
+                query = COUNT_OF_MATCHING_GRANTS;
+                args = new String[] {String.valueOf(callerUid), authTokenType,
+                        account.name, account.type};
+            } else {
+                query = COUNT_OF_MATCHING_GRANTS_ANY_TOKEN;
+                args = new String[] {String.valueOf(callerUid), account.name,
+                        account.type};
+            }
+            final boolean permissionGranted = DatabaseUtils.longForQuery(db, query, args) != 0;
+
             if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
                 // TODO: Skip this check when running automated tests. Replace this
                 // with a more general solution.
@@ -5861,22 +5941,14 @@
         UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
         synchronized (accounts.cacheLock) {
             final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
-            db.beginTransaction();
-            try {
-                long accountId = getAccountIdLocked(db, account);
-                if (accountId >= 0) {
-                    ContentValues values = new ContentValues();
-                    values.put(GRANTS_ACCOUNTS_ID, accountId);
-                    values.put(GRANTS_AUTH_TOKEN_TYPE, authTokenType);
-                    values.put(GRANTS_GRANTEE_UID, uid);
-                    db.insert(TABLE_GRANTS, GRANTS_ACCOUNTS_ID, values);
-                    db.setTransactionSuccessful();
-                }
-            } finally {
-                db.endTransaction();
+            long accountId = AccountsDbUtils.findAccountId(db, account);
+            if (accountId >= 0) {
+                AccountsDbUtils.insertGrant(db, accountId, authTokenType, uid);
             }
             cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
                     UserHandle.of(accounts.userId));
+
+            cancelAccountAccessRequestNotificationIfNeeded(account, uid, true);
         }
     }
 
@@ -5898,13 +5970,10 @@
             final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
             db.beginTransaction();
             try {
-                long accountId = getAccountIdLocked(db, account);
+                long accountId = AccountsDbUtils.findAccountId(db, account);
                 if (accountId >= 0) {
-                    db.delete(TABLE_GRANTS,
-                            GRANTS_ACCOUNTS_ID + "=? AND " + GRANTS_AUTH_TOKEN_TYPE + "=? AND "
-                                    + GRANTS_GRANTEE_UID + "=?",
-                            new String[]{String.valueOf(accountId), authTokenType,
-                                    String.valueOf(uid)});
+                    AccountsDbUtils.deleteGrantsByAccountIdAuthTokenTypeAndUid(
+                            db, accountId, authTokenType, uid);
                     db.setTransactionSuccessful();
                 }
             } finally {
@@ -6057,9 +6126,9 @@
 
     protected void writeUserDataIntoCacheLocked(UserAccounts accounts, final SQLiteDatabase db,
             Account account, String key, String value) {
-        HashMap<String, String> userDataForAccount = accounts.userDataCache.get(account);
+        Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
         if (userDataForAccount == null) {
-            userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account);
+            userDataForAccount = AccountsDbUtils.findUserExtrasForAccount(db, account);
             accounts.userDataCache.put(account, userDataForAccount);
         }
         if (value == null) {
@@ -6083,9 +6152,9 @@
 
     protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts, final SQLiteDatabase db,
             Account account, String key, String value) {
-        HashMap<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
+        Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
         if (authTokensForAccount == null) {
-            authTokensForAccount = readAuthTokensForAccountFromDatabaseLocked(db, account);
+            authTokensForAccount = AccountsDbUtils.findAuthTokensByAccount(db, account);
             accounts.authTokenCache.put(account, authTokensForAccount);
         }
         if (value == null) {
@@ -6098,11 +6167,12 @@
     protected String readAuthTokenInternal(UserAccounts accounts, Account account,
             String authTokenType) {
         synchronized (accounts.cacheLock) {
-            HashMap<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
+            Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
             if (authTokensForAccount == null) {
                 // need to populate the cache for this account
                 final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
-                authTokensForAccount = readAuthTokensForAccountFromDatabaseLocked(db, account);
+                authTokensForAccount = AccountsDbUtils
+                        .findAuthTokensByAccount(db, account);
                 accounts.authTokenCache.put(account, authTokensForAccount);
             }
             return authTokensForAccount.get(authTokenType);
@@ -6111,56 +6181,16 @@
 
     protected String readUserDataInternalLocked(
             UserAccounts accounts, Account account, String key) {
-        HashMap<String, String> userDataForAccount = accounts.userDataCache.get(account);
+        Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
         if (userDataForAccount == null) {
             // need to populate the cache for this account
             final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
-            userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account);
+            userDataForAccount = AccountsDbUtils.findUserExtrasForAccount(db, account);
             accounts.userDataCache.put(account, userDataForAccount);
         }
         return userDataForAccount.get(key);
     }
 
-    protected HashMap<String, String> readUserDataForAccountFromDatabaseLocked(
-            final SQLiteDatabase db, Account account) {
-        HashMap<String, String> userDataForAccount = new HashMap<>();
-        Cursor cursor = db.query(CE_TABLE_EXTRAS,
-                COLUMNS_EXTRAS_KEY_AND_VALUE,
-                SELECTION_USERDATA_BY_ACCOUNT,
-                new String[]{account.name, account.type},
-                null, null, null);
-        try {
-            while (cursor.moveToNext()) {
-                final String tmpkey = cursor.getString(0);
-                final String value = cursor.getString(1);
-                userDataForAccount.put(tmpkey, value);
-            }
-        } finally {
-            cursor.close();
-        }
-        return userDataForAccount;
-    }
-
-    protected HashMap<String, String> readAuthTokensForAccountFromDatabaseLocked(
-            final SQLiteDatabase db, Account account) {
-        HashMap<String, String> authTokensForAccount = new HashMap<>();
-        Cursor cursor = db.query(CE_TABLE_AUTHTOKENS,
-                COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN,
-                SELECTION_AUTHTOKENS_BY_ACCOUNT,
-                new String[]{account.name, account.type},
-                null, null, null);
-        try {
-            while (cursor.moveToNext()) {
-                final String type = cursor.getString(0);
-                final String authToken = cursor.getString(1);
-                authTokensForAccount.put(type, authToken);
-            }
-        } finally {
-            cursor.close();
-        }
-        return authTokensForAccount;
-    }
-
     private Context getContextForUser(UserHandle user) {
         try {
             return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
@@ -6194,4 +6224,457 @@
             }
         }
     }
+
+    static class AccountsDbUtils {
+
+        static String findAccountPasswordByNameAndType(SQLiteDatabase db, String name,
+                String type) {
+            Cursor cursor = db.query(CE_TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
+                    ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+                    new String[]{name, type}, null, null, null);
+            try {
+                if (cursor.moveToNext()) {
+                    return cursor.getString(0);
+                }
+                return null;
+            } finally {
+                cursor.close();
+            }
+        }
+
+        static Map<Long, Account> findAllAccounts(SQLiteDatabase db) {
+            LinkedHashMap<Long, Account> map = new LinkedHashMap<>();
+            Cursor cursor = db.query(TABLE_ACCOUNTS,
+                    new String[] {ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME},
+                    null, null, null, null, ACCOUNTS_ID);
+            try {
+                while (cursor.moveToNext()) {
+                    final long accountId = cursor.getLong(0);
+                    final String accountType = cursor.getString(1);
+                    final String accountName = cursor.getString(2);
+
+                    final Account account = new Account(accountName, accountType);
+                    map.put(accountId, account);
+                }
+            } finally {
+                cursor.close();
+            }
+            return map;
+        }
+
+        static String findAccountPreviousName(SQLiteDatabase db, Account account) {
+            Cursor cursor = db.query(
+                    TABLE_ACCOUNTS,
+                    new String[]{ ACCOUNTS_PREVIOUS_NAME },
+                    ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+                    new String[] { account.name, account.type },
+                    null,
+                    null,
+                    null);
+            try {
+                if (cursor.moveToNext()) {
+                    return cursor.getString(0);
+                }
+            } finally {
+                cursor.close();
+            }
+            return null;
+        }
+
+        static List<Account> findCeAccountsNotInDe(SQLiteDatabase db) {
+            // Select accounts from CE that do not exist in DE
+            Cursor cursor = db.rawQuery(
+                    "SELECT " + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE
+                            + " FROM " + CE_TABLE_ACCOUNTS
+                            + " WHERE NOT EXISTS "
+                            + " (SELECT " + ACCOUNTS_ID + " FROM " + TABLE_ACCOUNTS
+                            + " WHERE " + ACCOUNTS_ID + "=" + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_ID
+                            + " )", null);
+            try {
+                List<Account> accounts = new ArrayList<>(cursor.getCount());
+                while (cursor.moveToNext()) {
+                    String accountName = cursor.getString(0);
+                    String accountType = cursor.getString(1);
+                    accounts.add(new Account(accountName, accountType));
+                }
+                return accounts;
+            } finally {
+                cursor.close();
+            }
+        }
+
+        static boolean deleteAccount(SQLiteDatabase db, long accountId) {
+            return db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null) > 0;
+        }
+
+        static boolean deleteCeAccount(SQLiteDatabase db, long accountId) {
+            return db.delete(CE_TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null) > 0;
+        }
+
+        /**
+         * Returns information about auth tokens and their account for the specified query parameters.
+         * Output is in the format:
+         * <pre><code> | AUTHTOKEN_ID |  ACCOUNT_NAME | AUTH_TOKEN_TYPE |</code></pre>
+         */
+        static Cursor findAuthtokenForAllAccounts(SQLiteDatabase db, String accountType,
+                String authToken) {
+            return db.rawQuery(
+                    "SELECT " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
+                            + ", " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
+                            + ", " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
+                            + " FROM " + CE_TABLE_ACCOUNTS
+                            + " JOIN " + CE_TABLE_AUTHTOKENS
+                            + " ON " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_ID
+                            + " = " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_ACCOUNTS_ID
+                            + " WHERE " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_AUTHTOKEN
+                            + " = ? AND " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
+                    new String[]{authToken, accountType});
+        }
+
+        static boolean deleteAuthtokensByAccountIdAndType(SQLiteDatabase db, long accountId,
+                String authtokenType) {
+            return db.delete(CE_TABLE_AUTHTOKENS,
+                    AUTHTOKENS_ACCOUNTS_ID + "=?" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
+                    new String[] {String.valueOf(accountId), authtokenType}) > 0;
+        }
+
+        static boolean deleteAuthToken(SQLiteDatabase db, String authTokenId) {
+            return db.delete(CE_TABLE_AUTHTOKENS, AUTHTOKENS_ID + "= ?",
+                    new String[] {authTokenId}) > 0;
+        }
+
+        static long insertAuthToken(SQLiteDatabase db, long accountId, String authTokenType,
+                String authToken) {
+            ContentValues values = new ContentValues();
+            values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
+            values.put(AUTHTOKENS_TYPE, authTokenType);
+            values.put(AUTHTOKENS_AUTHTOKEN, authToken);
+            return db.insert(CE_TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values);
+        }
+
+        static Map<String, String> findAuthTokensByAccount(final SQLiteDatabase db, Account account) {
+            HashMap<String, String> authTokensForAccount = new HashMap<>();
+            Cursor cursor = db.query(CE_TABLE_AUTHTOKENS,
+                    COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN,
+                    SELECTION_AUTHTOKENS_BY_ACCOUNT,
+                    new String[]{account.name, account.type},
+                    null, null, null);
+            try {
+                while (cursor.moveToNext()) {
+                    final String type = cursor.getString(0);
+                    final String authToken = cursor.getString(1);
+                    authTokensForAccount.put(type, authToken);
+                }
+            } finally {
+                cursor.close();
+            }
+            return authTokensForAccount;
+        }
+
+        static int updateAccountPassword(SQLiteDatabase db, long accountId, String password) {
+            final ContentValues values = new ContentValues();
+            values.put(ACCOUNTS_PASSWORD, password);
+            return db.update(CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?",
+                    new String[] {String.valueOf(accountId)});
+        }
+
+        static boolean deleteAuthTokensByAccountId(SQLiteDatabase db, long accountId) {
+            return db.delete(CE_TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?",
+                    new String[] {String.valueOf(accountId)}) > 0;
+        }
+
+        static long insertSharedAccount(SQLiteDatabase db, Account account) {
+            ContentValues values = new ContentValues();
+            values.put(ACCOUNTS_NAME, account.name);
+            values.put(ACCOUNTS_TYPE, account.type);
+            return db.insert(TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME, values);
+        }
+
+        static boolean deleteSharedAccount(SQLiteDatabase db, Account account) {
+            return db.delete(TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+                    new String[] {account.name, account.type}) > 0;
+        }
+
+        static int renameSharedAccount(SQLiteDatabase db, Account account, String newName) {
+            final ContentValues values = new ContentValues();
+            values.put(ACCOUNTS_NAME, newName);
+            return db.update(TABLE_SHARED_ACCOUNTS,
+                    values,
+                    ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+                    new String[] { account.name, account.type });
+        }
+
+        static List<Account> getSharedAccounts(SQLiteDatabase db) {
+            ArrayList<Account> accountList = new ArrayList<>();
+            Cursor cursor = null;
+            try {
+                cursor = db.query(TABLE_SHARED_ACCOUNTS, new String[] {ACCOUNTS_NAME, ACCOUNTS_TYPE},
+                        null, null, null, null, null);
+                if (cursor != null && cursor.moveToFirst()) {
+                    int nameIndex = cursor.getColumnIndex(ACCOUNTS_NAME);
+                    int typeIndex = cursor.getColumnIndex(ACCOUNTS_TYPE);
+                    do {
+                        accountList.add(new Account(cursor.getString(nameIndex),
+                                cursor.getString(typeIndex)));
+                    } while (cursor.moveToNext());
+                }
+            } finally {
+                if (cursor != null) {
+                    cursor.close();
+                }
+            }
+            return accountList;
+        }
+
+        static long findSharedAccountId(SQLiteDatabase db, Account account) {
+            Cursor cursor = db.query(TABLE_SHARED_ACCOUNTS, new String[]{ACCOUNTS_ID},
+                    "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
+            try {
+                if (cursor.moveToNext()) {
+                    return cursor.getLong(0);
+                }
+                return -1;
+            } finally {
+                cursor.close();
+            }
+        }
+
+        static long findAccountId(SQLiteDatabase db, Account account) {
+            Cursor cursor = db.query(
+                    TABLE_ACCOUNTS, new String[] {ACCOUNTS_ID},
+                    "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
+            try {
+                if (cursor.moveToNext()) {
+                    return cursor.getLong(0);
+                }
+                return -1;
+            } finally {
+                cursor.close();
+            }
+        }
+
+        static long findExtrasIdByAccountId(SQLiteDatabase db, long accountId, String key) {
+            Cursor cursor = db.query(
+                    CE_TABLE_EXTRAS, new String[] {EXTRAS_ID},
+                    EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
+                    new String[]{key}, null, null, null);
+            try {
+                if (cursor.moveToNext()) {
+                    return cursor.getLong(0);
+                }
+                return -1;
+            } finally {
+                cursor.close();
+            }
+        }
+
+        static boolean updateExtra(SQLiteDatabase db, long extrasId, String value) {
+            ContentValues values = new ContentValues();
+            values.put(EXTRAS_VALUE, value);
+            int rows = db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=?",
+                    new String[]{String.valueOf(extrasId)});
+            return rows == 1;
+        }
+
+        static long insertExtra(SQLiteDatabase db, long accountId, String key, String value) {
+            ContentValues values = new ContentValues();
+            values.put(EXTRAS_KEY, key);
+            values.put(EXTRAS_ACCOUNTS_ID, accountId);
+            values.put(EXTRAS_VALUE, value);
+            return db.insert(CE_TABLE_EXTRAS, EXTRAS_KEY, values);
+        }
+
+        static Map<String, String> findUserExtrasForAccount(SQLiteDatabase db, Account account) {
+            Map<String, String> userExtrasForAccount = new HashMap<>();
+            Cursor cursor = db.query(CE_TABLE_EXTRAS,
+                    COLUMNS_EXTRAS_KEY_AND_VALUE,
+                    SELECTION_USERDATA_BY_ACCOUNT,
+                    new String[] {account.name, account.type},
+                    null, null, null);
+            try {
+                while (cursor.moveToNext()) {
+                    final String tmpkey = cursor.getString(0);
+                    final String value = cursor.getString(1);
+                    userExtrasForAccount.put(tmpkey, value);
+                }
+            } finally {
+                cursor.close();
+            }
+            return userExtrasForAccount;
+        }
+
+        static long insertGrant(SQLiteDatabase db, long accountId, String authTokenType, int uid) {
+            ContentValues values = new ContentValues();
+            values.put(GRANTS_ACCOUNTS_ID, accountId);
+            values.put(GRANTS_AUTH_TOKEN_TYPE, authTokenType);
+            values.put(GRANTS_GRANTEE_UID, uid);
+            return db.insert(TABLE_GRANTS, GRANTS_ACCOUNTS_ID, values);
+        }
+
+        static boolean deleteGrantsByUid(SQLiteDatabase db, int uid) {
+            return db.delete(TABLE_GRANTS, GRANTS_GRANTEE_UID + "=?",
+                    new String[] {Integer.toString(uid)}) > 0;
+        }
+
+        static boolean deleteGrantsByAccountIdAuthTokenTypeAndUid(SQLiteDatabase db, long accountId, String authTokenType, long uid) {
+            return db.delete(TABLE_GRANTS,
+                    GRANTS_ACCOUNTS_ID + "=? AND " + GRANTS_AUTH_TOKEN_TYPE + "=? AND "
+                            + GRANTS_GRANTEE_UID + "=?",
+                    new String[] {String.valueOf(accountId), authTokenType, String.valueOf(uid)}) > 0;
+        }
+
+        static List<Integer> findAllUidGrants(SQLiteDatabase db) {
+            List<Integer> result = new ArrayList<>();
+            final Cursor cursor = db.query(TABLE_GRANTS,
+                    new String[] {GRANTS_GRANTEE_UID},
+                    null, null, GRANTS_GRANTEE_UID, null, null);
+            try {
+                while (cursor.moveToNext()) {
+                    final int uid = cursor.getInt(0);
+                    result.add(uid);
+                }
+            } finally {
+                cursor.close();
+            }
+            return result;
+        }
+
+        static long findMatchingGrantsCount(SQLiteDatabase db,
+                int uid, String authTokenType, Account account) {
+            String[] args = { String.valueOf(uid), authTokenType,
+                    account.name, account.type};
+            return DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args);
+        }
+
+        static long insertMetaAuthTypeAndUid(SQLiteDatabase db, String authenticatorType, int uid) {
+            ContentValues values = new ContentValues();
+            values.put(META_KEY,
+                    META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + authenticatorType);
+            values.put(META_VALUE, uid);
+            return db.insert(TABLE_META, null, values);
+        }
+
+        static long insertOrReplaceMetaAuthTypeAndUid(SQLiteDatabase db, String authenticatorType,
+                int uid) {
+            ContentValues values = new ContentValues();
+            values.put(META_KEY,
+                    META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + authenticatorType);
+            values.put(META_VALUE, uid);
+            return db.insertWithOnConflict(TABLE_META, null, values,
+                    SQLiteDatabase.CONFLICT_REPLACE);
+        }
+
+
+        static Map<String, Integer> findMetaAuthUid(SQLiteDatabase db) {
+            Cursor metaCursor = db.query(
+                    TABLE_META,
+                    new String[] {META_KEY, META_VALUE},
+                    SELECTION_META_BY_AUTHENTICATOR_TYPE,
+                    new String[] {META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + "%"},
+                    null /* groupBy */,
+                    null /* having */,
+                    META_KEY);
+            Map<String, Integer> map = new LinkedHashMap<>();
+            try {
+                while (metaCursor.moveToNext()) {
+                    String type = TextUtils.split(metaCursor.getString(0), META_KEY_DELIMITER)[1];
+                    String uidStr = metaCursor.getString(1);
+                    if (TextUtils.isEmpty(type) || TextUtils.isEmpty(uidStr)) {
+                        // Should never happen.
+                        Slog.e(TAG, "Auth type empty: " + TextUtils.isEmpty(type)
+                                + ", uid empty: " + TextUtils.isEmpty(uidStr));
+                        continue;
+                    }
+                    int uid = Integer.parseInt(metaCursor.getString(1));
+                    map.put(type, uid);
+                }
+            } finally {
+                metaCursor.close();
+            }
+            return map;
+        }
+
+        static boolean deleteMetaByAuthTypeAndUid(SQLiteDatabase db, String type, int uid) {
+            return db.delete(
+                    TABLE_META,
+                    META_KEY + "=? AND " + META_VALUE + "=?",
+                    new String[] {
+                            META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + type,
+                            String.valueOf(uid)}
+            ) > 0;
+        }
+
+        static void dumpAccountsTable(SQLiteDatabase db, PrintWriter pw) {
+            Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_TYPE_COUNT_PROJECTION,
+                    null, null, ACCOUNTS_TYPE, null, null);
+            try {
+                while (cursor.moveToNext()) {
+                    // print type,count
+                    pw.println(cursor.getString(0) + "," + cursor.getString(1));
+                }
+            } finally {
+                if (cursor != null) {
+                    cursor.close();
+                }
+            }
+        }
+
+        static void dumpDebugTable(SQLiteDatabase db, PrintWriter pw) {
+            Cursor cursor = db.query(DebugDbHelper.TABLE_DEBUG, null,
+                    null, null, null, null, DebugDbHelper.TIMESTAMP);
+            pw.println("AccountId, Action_Type, timestamp, UID, TableName, Key");
+            pw.println("Accounts History");
+            try {
+                while (cursor.moveToNext()) {
+                    // print type,count
+                    pw.println(cursor.getString(0) + "," + cursor.getString(1) + "," +
+                            cursor.getString(2) + "," + cursor.getString(3) + ","
+                            + cursor.getString(4) + "," + cursor.getString(5));
+                }
+            } finally {
+                cursor.close();
+            }
+        }
+    }
+
+    private final class AccountManagerInternalImpl extends AccountManagerInternal {
+        @Override
+        public void requestAccountAccess(@NonNull Account account, @NonNull String packageName,
+                @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) {
+            if (account == null) {
+                Slog.w(TAG, "account cannot be null");
+                return;
+            }
+            if (packageName == null) {
+                Slog.w(TAG, "packageName cannot be null");
+                return;
+            }
+            if (userId < UserHandle.USER_SYSTEM) {
+                Slog.w(TAG, "user id must be concrete");
+                return;
+            }
+            if (callback == null) {
+                Slog.w(TAG, "callback cannot be null");
+                return;
+            }
+
+            if (hasAccountAccess(account, packageName, new UserHandle(userId))) {
+                Bundle result = new Bundle();
+                result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
+                callback.sendResult(result);
+                return;
+            }
+
+            final int uid;
+            try {
+                uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+            } catch (NameNotFoundException e) {
+                Slog.e(TAG, "Unknown package " + packageName);
+                return;
+            }
+
+            Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback);
+            doNotification(mUsers.get(userId), account, null, intent, packageName, userId);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 3ebd87c..fb4b010 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -200,24 +200,24 @@
             switch (msg.what) {
                 case MSG_BG_START_TIMEOUT: {
                     synchronized (mAm) {
-                        rescheduleDelayedStarts();
+                        rescheduleDelayedStartsLocked();
                     }
                 } break;
             }
         }
 
-        void ensureNotStartingBackground(ServiceRecord r) {
+        void ensureNotStartingBackgroundLocked(ServiceRecord r) {
             if (mStartingBackground.remove(r)) {
                 if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
                         "No longer background starting: " + r);
-                rescheduleDelayedStarts();
+                rescheduleDelayedStartsLocked();
             }
             if (mDelayedStartList.remove(r)) {
                 if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "No longer delaying start: " + r);
             }
         }
 
-        void rescheduleDelayedStarts() {
+        void rescheduleDelayedStartsLocked() {
             removeMessages(MSG_BG_START_TIMEOUT);
             final long now = SystemClock.uptimeMillis();
             for (int i=0, N=mStartingBackground.size(); i<N; i++) {
@@ -278,19 +278,19 @@
                 ? maxBg : ActivityManager.isLowRamDeviceStatic() ? 1 : 8;
     }
 
-    ServiceRecord getServiceByName(ComponentName name, int callingUser) {
+    ServiceRecord getServiceByNameLocked(ComponentName name, int callingUser) {
         // TODO: Deal with global services
         if (DEBUG_MU)
-            Slog.v(TAG_MU, "getServiceByName(" + name + "), callingUser = " + callingUser);
-        return getServiceMap(callingUser).mServicesByName.get(name);
+            Slog.v(TAG_MU, "getServiceByNameLocked(" + name + "), callingUser = " + callingUser);
+        return getServiceMapLocked(callingUser).mServicesByName.get(name);
     }
 
-    boolean hasBackgroundServices(int callingUser) {
+    boolean hasBackgroundServicesLocked(int callingUser) {
         ServiceMap smap = mServiceMap.get(callingUser);
         return smap != null ? smap.mStartingBackground.size() >= mMaxStartingBackground : false;
     }
 
-    private ServiceMap getServiceMap(int callingUser) {
+    private ServiceMap getServiceMapLocked(int callingUser) {
         ServiceMap smap = mServiceMap.get(callingUser);
         if (smap == null) {
             smap = new ServiceMap(mAm.mHandler.getLooper(), callingUser);
@@ -299,8 +299,8 @@
         return smap;
     }
 
-    ArrayMap<ComponentName, ServiceRecord> getServices(int callingUser) {
-        return getServiceMap(callingUser).mServicesByName;
+    ArrayMap<ComponentName, ServiceRecord> getServicesLocked(int callingUser) {
+        return getServiceMapLocked(callingUser).mServicesByName;
     }
 
     ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
@@ -368,7 +368,7 @@
         // we do not start the service and launch a review activity if the calling app
         // is in the foreground passing it a pending intent to start the service when
         // review is completed.
-        if (mAm.mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) {
+        if (mAm.mPermissionReviewRequired) {
             if (!requestStartTargetPermissionsReviewIfNeededLocked(r, callingPackage,
                     callingUid, service, callerFg, userId)) {
                 return null;
@@ -384,7 +384,7 @@
         r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                 service, neededGrants));
 
-        final ServiceMap smap = getServiceMap(r.userId);
+        final ServiceMap smap = getServiceMapLocked(r.userId);
         boolean addToStarting = false;
         if (!callerFg && r.app == null
                 && mAm.mUserController.hasStartedUserState(r.userId)) {
@@ -523,10 +523,10 @@
                 Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r);
             }
             if (first) {
-                smap.rescheduleDelayedStarts();
+                smap.rescheduleDelayedStartsLocked();
             }
         } else if (callerFg) {
-            smap.ensureNotStartingBackground(r);
+            smap.ensureNotStartingBackgroundLocked(r);
         }
 
         return r.name;
@@ -607,7 +607,7 @@
                 for (int i=stopping.size()-1; i>=0; i--) {
                     ServiceRecord service = stopping.get(i);
                     service.delayed = false;
-                    services.ensureNotStartingBackground(service);
+                    services.ensureNotStartingBackgroundLocked(service);
                     stopServiceLocked(service);
                 }
             }
@@ -709,7 +709,7 @@
                     if (r.app != null) {
                         updateServiceForegroundLocked(r.app, true);
                     }
-                    getServiceMap(r.userId).ensureNotStartingBackground(r);
+                    getServiceMapLocked(r.userId).ensureNotStartingBackgroundLocked(r);
                     mAm.notifyPackageUse(r.serviceInfo.packageName,
                                          PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE);
                 } else {
@@ -744,7 +744,7 @@
             // with the same notification ID.  If so, we shouldn't actually cancel it,
             // because that would wipe away the notification that still needs to be shown
             // due the other service.
-            ServiceMap sm = getServiceMap(r.userId);
+            ServiceMap sm = getServiceMapLocked(r.userId);
             if (sm != null) {
                 for (int i = sm.mServicesByName.size()-1; i >= 0; i--) {
                     ServiceRecord other = sm.mServicesByName.valueAt(i);
@@ -912,7 +912,7 @@
         // we schedule binding to the service but do not start its process, then
         // we launch a review activity to which is passed a callback to invoke
         // when done to start the bound service's process to completing the binding.
-        if (mAm.mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) {
+        if (mAm.mPermissionReviewRequired) {
             if (mAm.getPackageManagerInternalLocked().isPermissionsReviewRequired(
                     s.packageName, s.userId)) {
 
@@ -1088,7 +1088,7 @@
                 requestServiceBindingLocked(s, b.intent, callerFg, false);
             }
 
-            getServiceMap(s.userId).ensureNotStartingBackground(s);
+            getServiceMapLocked(s.userId).ensureNotStartingBackgroundLocked(s);
 
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -1230,7 +1230,7 @@
 
     private final ServiceRecord findServiceLocked(ComponentName name,
             IBinder token, int userId) {
-        ServiceRecord r = getServiceByName(name, userId);
+        ServiceRecord r = getServiceByNameLocked(name, userId);
         return r == token ? r : null;
     }
 
@@ -1268,7 +1268,7 @@
         userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
                 ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);
 
-        ServiceMap smap = getServiceMap(userId);
+        ServiceMap smap = getServiceMapLocked(userId);
         final ComponentName comp = service.getComponent();
         if (comp != null) {
             r = smap.mServicesByName.get(comp);
@@ -1335,7 +1335,7 @@
                             sInfo.name, sInfo.flags)
                             && mAm.isValidSingletonCall(callingUid, sInfo.applicationInfo.uid)) {
                         userId = 0;
-                        smap = getServiceMap(0);
+                        smap = getServiceMapLocked(0);
                     }
                     sInfo = new ServiceInfo(sInfo);
                     sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
@@ -1470,8 +1470,7 @@
         return true;
     }
 
-    private final boolean scheduleServiceRestartLocked(ServiceRecord r,
-            boolean allowCancel) {
+    private final boolean scheduleServiceRestartLocked(ServiceRecord r, boolean allowCancel) {
         boolean canceled = false;
 
         if (mAm.isShuttingDownLocked()) {
@@ -1480,7 +1479,7 @@
             return false;
         }
 
-        ServiceMap smap = getServiceMap(r.userId);
+        ServiceMap smap = getServiceMapLocked(r.userId);
         if (smap.mServicesByName.get(r.name) != r) {
             ServiceRecord cur = smap.mServicesByName.get(r.name);
             Slog.wtf(TAG, "Attempting to schedule restart of " + r
@@ -1594,7 +1593,7 @@
         if (!mRestartingServices.contains(r)) {
             return;
         }
-        if (!isServiceNeeded(r, false, false)) {
+        if (!isServiceNeededLocked(r, false, false)) {
             // Paranoia: is this service actually needed?  In theory a service that is not
             // needed should never remain on the restart list.  In practice...  well, there
             // have been bugs where this happens, and bad things happen because the process
@@ -1676,7 +1675,7 @@
         // Make sure this service is no longer considered delayed, we are starting it now.
         if (r.delayed) {
             if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (bring up): " + r);
-            getServiceMap(r.userId).mDelayedStartList.remove(r);
+            getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
             r.delayed = false;
         }
 
@@ -1858,7 +1857,7 @@
 
         if (r.delayed) {
             if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
-            getServiceMap(r.userId).mDelayedStartList.remove(r);
+            getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
             r.delayed = false;
         }
 
@@ -1939,7 +1938,8 @@
         }
     }
 
-    private final boolean isServiceNeeded(ServiceRecord r, boolean knowConn, boolean hasConn) {
+    private final boolean isServiceNeededLocked(ServiceRecord r, boolean knowConn,
+            boolean hasConn) {
         // Are we still explicitly being asked to run?
         if (r.startRequested) {
             return true;
@@ -1961,7 +1961,7 @@
         //Slog.i(TAG, "Bring down service:");
         //r.dump("  ");
 
-        if (isServiceNeeded(r, knowConn, hasConn)) {
+        if (isServiceNeededLocked(r, knowConn, hasConn)) {
             return;
         }
 
@@ -2025,7 +2025,7 @@
                     r.userId, System.identityHashCode(r), (r.app != null) ? r.app.pid : -1);
         }
 
-        final ServiceMap smap = getServiceMap(r.userId);
+        final ServiceMap smap = getServiceMapLocked(r.userId);
         smap.mServicesByName.remove(r.name);
         smap.mServicesByIntent.remove(r.intent);
         r.totalRestartCount = 0;
@@ -2097,7 +2097,7 @@
             }
         }
 
-        smap.ensureNotStartingBackground(r);
+        smap.ensureNotStartingBackgroundLocked(r);
     }
 
     void removeConnectionLocked(
@@ -2359,7 +2359,7 @@
                             mAm.mProcessStats);
                     realStartServiceLocked(sr, proc, sr.createdFromFg);
                     didSomething = true;
-                    if (!isServiceNeeded(sr, false, false)) {
+                    if (!isServiceNeededLocked(sr, false, false)) {
                         // We were waiting for this service to start, but it is actually no
                         // longer needed.  This could happen because bringDownServiceIfNeeded
                         // won't bring down a service that is pending...  so now the pending
@@ -2480,7 +2480,7 @@
 
     void cleanUpRemovedTaskLocked(TaskRecord tr, ComponentName component, Intent baseIntent) {
         ArrayList<ServiceRecord> services = new ArrayList<>();
-        ArrayMap<ComponentName, ServiceRecord> alls = getServices(tr.userId);
+        ArrayMap<ComponentName, ServiceRecord> alls = getServicesLocked(tr.userId);
         for (int i = alls.size() - 1; i >= 0; i--) {
             ServiceRecord sr = alls.valueAt(i);
             if (sr.packageName.equals(component.getPackageName())) {
@@ -2612,7 +2612,7 @@
             }
         }
 
-        ServiceMap smap = getServiceMap(app.userId);
+        ServiceMap smap = getServiceMapLocked(app.userId);
 
         // Now do remaining service cleanup.
         for (int i=app.services.size()-1; i>=0; i--) {
@@ -2747,8 +2747,7 @@
         return info;
     }
 
-    List<ActivityManager.RunningServiceInfo> getRunningServiceInfoLocked(int maxNum,
-            int flags) {
+    List<ActivityManager.RunningServiceInfo> getRunningServiceInfoLocked(int maxNum, int flags) {
         ArrayList<ActivityManager.RunningServiceInfo> res
                 = new ArrayList<ActivityManager.RunningServiceInfo>();
 
@@ -2760,7 +2759,7 @@
                     uid) == PackageManager.PERMISSION_GRANTED) {
                 int[] users = mAm.mUserController.getUsers();
                 for (int ui=0; ui<users.length && res.size() < maxNum; ui++) {
-                    ArrayMap<ComponentName, ServiceRecord> alls = getServices(users[ui]);
+                    ArrayMap<ComponentName, ServiceRecord> alls = getServicesLocked(users[ui]);
                     for (int i=0; i<alls.size() && res.size() < maxNum; i++) {
                         ServiceRecord sr = alls.valueAt(i);
                         res.add(makeRunningServiceInfoLocked(sr));
@@ -2776,7 +2775,7 @@
                 }
             } else {
                 int userId = UserHandle.getUserId(uid);
-                ArrayMap<ComponentName, ServiceRecord> alls = getServices(userId);
+                ArrayMap<ComponentName, ServiceRecord> alls = getServicesLocked(userId);
                 for (int i=0; i<alls.size() && res.size() < maxNum; i++) {
                     ServiceRecord sr = alls.valueAt(i);
                     res.add(makeRunningServiceInfoLocked(sr));
@@ -2801,7 +2800,7 @@
 
     public PendingIntent getRunningServiceControlPanelLocked(ComponentName name) {
         int userId = UserHandle.getUserId(Binder.getCallingUid());
-        ServiceRecord r = getServiceByName(name, userId);
+        ServiceRecord r = getServiceByNameLocked(name, userId);
         if (r != null) {
             for (int conni=r.connections.size()-1; conni>=0; conni--) {
                 ArrayList<ConnectionRecord> conn = r.connections.valueAt(conni);
@@ -2874,31 +2873,6 @@
                 proc.execServicesFg ? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT));
     }
 
-    /**
-     * Prints a list of ServiceRecords (dumpsys activity services)
-     */
-    List<ServiceRecord> collectServicesToDumpLocked(ItemMatcher matcher, String dumpPackage) {
-        final ArrayList<ServiceRecord> services = new ArrayList<>();
-        final int[] users = mAm.mUserController.getUsers();
-        for (int user : users) {
-            ServiceMap smap = getServiceMap(user);
-            if (smap.mServicesByName.size() > 0) {
-                for (int si=0; si<smap.mServicesByName.size(); si++) {
-                    ServiceRecord r = smap.mServicesByName.valueAt(si);
-                    if (!matcher.match(r, r.name)) {
-                        continue;
-                    }
-                    if (dumpPackage != null && !dumpPackage.equals(r.appInfo.packageName)) {
-                        continue;
-                    }
-                    services.add(r);
-                }
-            }
-        }
-
-        return services;
-    }
-
     final class ServiceDumper {
         private final FileDescriptor fd;
         private final PrintWriter pw;
@@ -2932,7 +2906,7 @@
 
             final int[] users = mAm.mUserController.getUsers();
             for (int user : users) {
-                ServiceMap smap = getServiceMap(user);
+                ServiceMap smap = getServiceMapLocked(user);
                 if (smap.mServicesByName.size() > 0) {
                     for (int si=0; si<smap.mServicesByName.size(); si++) {
                         ServiceRecord r = smap.mServicesByName.valueAt(si);
@@ -3113,7 +3087,7 @@
         }
 
         private void dumpUserRemainsLocked(int user) {
-            ServiceMap smap = getServiceMap(user);
+            ServiceMap smap = getServiceMapLocked(user);
             printed = false;
             for (int si=0, SN=smap.mDelayedStartList.size(); si<SN; si++) {
                 ServiceRecord r = smap.mDelayedStartList.get(si);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 09a3a17..96d411d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1154,6 +1154,7 @@
      * For example, references to the commonly used services.
      */
     HashMap<String, IBinder> mAppBindArgs;
+    HashMap<String, IBinder> mIsolatedAppBindArgs;
 
     /**
      * Temporary to avoid allocations.  Protected by main lock.
@@ -2957,18 +2958,24 @@
      * lazily setup to make sure the services are running when they're asked for.
      */
     private HashMap<String, IBinder> getCommonServicesLocked(boolean isolated) {
+        // Isolated processes won't get this optimization, so that we don't
+        // violate the rules about which services they have access to.
+        if (isolated) {
+            if (mIsolatedAppBindArgs == null) {
+                mIsolatedAppBindArgs = new HashMap<>();
+                mIsolatedAppBindArgs.put("package", ServiceManager.getService("package"));
+            }
+            return mIsolatedAppBindArgs;
+        }
+
         if (mAppBindArgs == null) {
             mAppBindArgs = new HashMap<>();
 
-            // Isolated processes won't get this optimization, so that we don't
-            // violate the rules about which services they have access to.
-            if (!isolated) {
-                // Setup the application init args
-                mAppBindArgs.put("package", ServiceManager.getService("package"));
-                mAppBindArgs.put("window", ServiceManager.getService("window"));
-                mAppBindArgs.put(Context.ALARM_SERVICE,
-                        ServiceManager.getService(Context.ALARM_SERVICE));
-            }
+            // Setup the application init args
+            mAppBindArgs.put("package", ServiceManager.getService("package"));
+            mAppBindArgs.put("window", ServiceManager.getService("window"));
+            mAppBindArgs.put(Context.ALARM_SERVICE,
+                    ServiceManager.getService(Context.ALARM_SERVICE));
         }
         return mAppBindArgs;
     }
@@ -10766,7 +10773,7 @@
                     // If permissions need a review before any of the app components can run,
                     // we return no provider and launch a review activity if the calling app
                     // is in the foreground.
-                    if (mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) {
+                    if (mPermissionReviewRequired) {
                         if (!requestTargetProviderPermissionsReviewIfNeededLocked(cpi, r, userId)) {
                             return null;
                         }
@@ -13727,11 +13734,12 @@
         // NOTE -- this must never acquire the ActivityManagerService lock,
         // otherwise the watchdog may be prevented from resetting the system.
 
-        final String dropboxTag = processClass(process) + "_" + eventType;
-        final DropBoxManager dbox = (DropBoxManager)
-                mContext.getSystemService(Context.DROPBOX_SERVICE);
+        // Bail early if not published yet
+        if (ServiceManager.getService(Context.DROPBOX_SERVICE) == null) return;
+        final DropBoxManager dbox = mContext.getSystemService(DropBoxManager.class);
 
         // Exit early if the dropbox isn't configured to accept this report type.
+        final String dropboxTag = processClass(process) + "_" + eventType;
         if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return;
 
         // Rate-limit how often we're willing to do the heavy lifting below to
@@ -17764,6 +17772,7 @@
                 || Intent.ACTION_MEDIA_BUTTON.equals(action)
                 || Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)
                 || Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(action)
+                || Intent.ACTION_MASTER_CLEAR.equals(action)
                 || AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
                 || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)
                 || LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index a5c19d6..cfb34b3 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -20,6 +20,7 @@
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.content.pm.ActivityInfo.FLAG_ON_TOP_LAUNCHER;
+import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
@@ -1290,6 +1291,13 @@
         return this;
     }
 
+    /** Checks whether the activity should be shown for current user. */
+    public boolean okToShowLocked() {
+        return (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0
+                || (mStackSupervisor.isCurrentProfileLocked(userId)
+                && !service.mUserController.isUserStoppingOrShuttingDownLocked(userId));
+    }
+
     /**
      * This method will return true if the activity is either visible, is becoming visible, is
      * currently pausing, or is resumed.
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index fa9f518..fbd0ab5 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -544,10 +544,6 @@
         }
     }
 
-    boolean okToShowLocked(ActivityRecord r) {
-        return mStackSupervisor.okToShowLocked(r);
-    }
-
     final ActivityRecord topRunningActivityLocked() {
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             ActivityRecord r = mTaskHistory.get(taskNdx).topRunningActivityLocked();
@@ -564,7 +560,7 @@
             final ArrayList<ActivityRecord> activities = task.mActivities;
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 ActivityRecord r = activities.get(activityNdx);
-                if (!r.finishing && !r.delayedResume && r != notTop && okToShowLocked(r)) {
+                if (!r.finishing && !r.delayedResume && r != notTop && r.okToShowLocked()) {
                     return r;
                 }
             }
@@ -591,7 +587,7 @@
             for (int i = activities.size() - 1; i >= 0; --i) {
                 final ActivityRecord r = activities.get(i);
                 // Note: the taskId check depends on real taskId fields being non-zero
-                if (!r.finishing && (token != r.appToken) && okToShowLocked(r)) {
+                if (!r.finishing && (token != r.appToken) && r.okToShowLocked()) {
                     return r;
                 }
             }
@@ -854,13 +850,11 @@
 
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
-            final boolean notCurrentUserTask =
-                    !mStackSupervisor.isCurrentProfileLocked(task.userId);
             final ArrayList<ActivityRecord> activities = task.mActivities;
 
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 ActivityRecord r = activities.get(activityNdx);
-                if (notCurrentUserTask && (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) == 0) {
+                if (!r.okToShowLocked()) {
                     continue;
                 }
                 if (!r.finishing && r.userId == userId) {
@@ -894,10 +888,7 @@
         for (int i = 0; i < index; ) {
             final TaskRecord task = mTaskHistory.get(i);
 
-            // NOTE: If {@link TaskRecord#topRunningActivityLocked} return is not null then it is
-            // okay to show the activity when locked.
-            if (mStackSupervisor.isCurrentProfileLocked(task.userId)
-                    || task.topRunningActivityLocked() != null) {
+            if (task.okToShowLocked()) {
                 if (DEBUG_TASKS) Slog.d(TAG_TASKS, "switchUserLocked: stack=" + getStackId() +
                         " moving " + task + " to top");
                 mTaskHistory.remove(i);
@@ -1898,7 +1889,7 @@
             boolean stackVisibleBehind, ActivityRecord visibleBehind,
             boolean behindFullscreenActivity) {
 
-        if (!okToShowLocked(r)) {
+        if (r == null || !r.okToShowLocked()) {
             return false;
         }
 
@@ -2655,8 +2646,7 @@
         }
         // Calculate maximum possible position for this task.
         int maxPosition = mTaskHistory.size();
-        if (!mStackSupervisor.isCurrentProfileLocked(task.userId)
-                && task.topRunningActivityLocked() == null) {
+        if (!task.okToShowLocked()) {
             // Put non-current user tasks below current user tasks.
             while (maxPosition > 0) {
                 final TaskRecord tmpTask = mTaskHistory.get(maxPosition - 1);
@@ -2717,9 +2707,9 @@
         // Now put task at top.
         int taskNdx = mTaskHistory.size();
         final boolean notShownWhenLocked =
-                (newActivity != null && (newActivity.info.flags & FLAG_SHOW_FOR_ALL_USERS) == 0)
-                || (newActivity == null && task.topRunningActivityLocked() == null);
-        if (!mStackSupervisor.isCurrentProfileLocked(task.userId) && notShownWhenLocked) {
+                (newActivity != null && !newActivity.okToShowLocked())
+                || (newActivity == null && !task.okToShowLocked());
+        if (notShownWhenLocked) {
             // Put non-current user tasks below current user tasks.
             while (--taskNdx >= 0) {
                 final TaskRecord tmpTask = mTaskHistory.get(taskNdx);
@@ -4375,7 +4365,7 @@
 
         // Don't refocus if invisible to current user
         ActivityRecord top = tr.getTopActivity();
-        if (!okToShowLocked(top)) {
+        if (top == null || !top.okToShowLocked()) {
             addRecentActivityLocked(top);
             ActivityOptions.abort(options);
             return;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 271483e..0a47e40 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -123,7 +123,6 @@
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
@@ -3080,13 +3079,6 @@
         return mService.mUserController.isCurrentProfileLocked(userId);
     }
 
-    /** Checks whether the activity should be shown for current user. */
-    boolean okToShowLocked(ActivityRecord r) {
-        return r != null && ((r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0
-                || (isCurrentProfileLocked(r.userId)
-                && !mService.mUserController.isUserStoppingOrShuttingDownLocked(r.userId)));
-    }
-
     final ArrayList<ActivityRecord> processStoppingActivitiesLocked(boolean remove) {
         ArrayList<ActivityRecord> stops = null;
 
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 9f875a1..117457f 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -416,8 +416,7 @@
         // If permissions need a review before any of the app components can run, we
         // launch the review activity and pass a pending intent to start the activity
         // we are to launching now after the review is completed.
-        if ((mService.mPermissionReviewRequired
-                || Build.PERMISSIONS_REVIEW_REQUIRED) && aInfo != null) {
+        if (mService.mPermissionReviewRequired && aInfo != null) {
             if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
                     aInfo.packageName, userId)) {
                 IIntentSender target = mService.getIntentSenderLocked(
@@ -1263,7 +1262,7 @@
         // of this in the record so that we can skip it when trying to find
         // the top running activity.
         mDoResume = doResume;
-        if (!doResume || !mSupervisor.okToShowLocked(r)) {
+        if (!doResume || !r.okToShowLocked()) {
             r.delayedResume = true;
             mDoResume = false;
         }
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 7eff773..576f2b2 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -575,6 +575,8 @@
     boolean handleAppCrashLocked(ProcessRecord app, String reason,
             String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
         long now = SystemClock.uptimeMillis();
+        boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
 
         Long crashTime;
         Long crashTimePersistent;
@@ -612,7 +614,9 @@
                 // processes run critical code.
                 mService.removeProcessLocked(app, false, false, "crash");
                 mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
-                return false;
+                if (!showBackground) {
+                    return false;
+                }
             }
             mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
         } else {
@@ -705,7 +709,7 @@
             }
             final boolean crashSilenced = mAppsNotReportingCrashes != null &&
                     mAppsNotReportingCrashes.contains(proc.info.packageName);
-            if (mService.canShowErrorDialogs() && !crashSilenced) {
+            if ((mService.canShowErrorDialogs() || showBackground) && !crashSilenced) {
                 proc.crashDialog = new AppErrorDialog(mContext, mService, data);
             } else {
                 // The device is asleep, so just pretend that the user
@@ -942,7 +946,9 @@
                     null, null, 0, null, null, null, AppOpsManager.OP_NONE,
                     null, false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */);
 
-            if (mService.canShowErrorDialogs()) {
+            boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
+                    Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
+            if (mService.canShowErrorDialogs() || showBackground) {
                 d = new AppNotRespondingDialog(mService,
                         mContext, proc, (ActivityRecord)data.get("activity"),
                         msg.arg1 != 0);
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 219e095..3b4b8d6 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -434,7 +434,7 @@
                 // but are on a queue that would like to wait for services to finish before moving
                 // on.  If there are background services currently starting, then we will go into a
                 // special state where we hold off on continuing this broadcast until they are done.
-                if (mService.mServices.hasBackgroundServices(r.userId)) {
+                if (mService.mServices.hasBackgroundServicesLocked(r.userId)) {
                     Slog.i(TAG, "Delay finish: " + r.curComponent.flattenToShortString());
                     r.state = BroadcastRecord.WAITING_SERVICES;
                     return false;
@@ -625,7 +625,7 @@
         // the broadcast and if the calling app is in the foreground and the broadcast is
         // explicit we launch the review UI passing it a pending intent to send the skipped
         // broadcast.
-        if (mService.mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) {
+        if (mService.mPermissionReviewRequired) {
             if (!requestStartTargetPermissionsReviewIfNeededLocked(r, filter.packageName,
                     filter.owningUserId)) {
                 r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
@@ -1131,8 +1131,7 @@
             // the broadcast and if the calling app is in the foreground and the broadcast is
             // explicit we launch the review UI passing it a pending intent to send the skipped
             // broadcast.
-            if ((mService.mPermissionReviewRequired
-                    || Build.PERMISSIONS_REVIEW_REQUIRED) && !skip) {
+            if (mService.mPermissionReviewRequired && !skip) {
                 if (!requestStartTargetPermissionsReviewIfNeededLocked(r,
                         info.activityInfo.packageName, UserHandle.getUserId(
                                 info.activityInfo.applicationInfo.uid))) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index c2c8e3d..0745a85 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -683,7 +683,7 @@
         if (stack != null) {
             for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
                 ActivityRecord r = mActivities.get(activityNdx);
-                if (!r.finishing && stack.okToShowLocked(r)) {
+                if (!r.finishing && r.okToShowLocked()) {
                     return r;
                 }
             }
@@ -696,7 +696,7 @@
             for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
                 ActivityRecord r = mActivities.get(activityNdx);
                 if (r.mStartingWindowState != STARTING_WINDOW_SHOWN
-                        || r.finishing || !stack.okToShowLocked(r)) {
+                        || r.finishing || !r.okToShowLocked()) {
                     continue;
                 }
                 return r;
@@ -705,6 +705,13 @@
         return null;
     }
 
+    boolean okToShowLocked() {
+        // NOTE: If {@link TaskRecord#topRunningActivityLocked} return is not null then it is
+        // okay to show the activity when locked.
+        return mService.mStackSupervisor.isCurrentProfileLocked(userId)
+                || topRunningActivityLocked() != null;
+    }
+
     void setFrontOfTask() {
         setFrontOfTask(null);
     }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 7587847..0d90832 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -209,7 +209,6 @@
     private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
     private static final int MSG_SET_ALL_VOLUMES = 10;
     private static final int MSG_REPORT_NEW_ROUTES = 12;
-    private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
     private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
     private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
     private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
@@ -514,6 +513,7 @@
     private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
 
     // Request to override default use of A2DP for media.
+    // FIXME: remove when MediaRouter does not use setBluetoothA2dpOn() anymore
     private boolean mBluetoothA2dpEnabled;
     private final Object mBluetoothA2dpEnabledLock = new Object();
 
@@ -848,12 +848,6 @@
             RotationHelper.updateOrientation();
         }
 
-        synchronized (mBluetoothA2dpEnabledLock) {
-            AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
-                    mBluetoothA2dpEnabled ?
-                            AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
-        }
-
         synchronized (mSettingsLock) {
             AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
                     mDockAudioMediaEnabled ?
@@ -2715,22 +2709,23 @@
         return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
     }
 
-    /** @see AudioManager#setBluetoothA2dpOn(boolean) */
+    /**
+     * Deprecated.
+     * Keep stub implementation until MediaRouter stops using it.
+     * @deprecated
+     * */
     public void setBluetoothA2dpOn(boolean on) {
-        synchronized (mBluetoothA2dpEnabledLock) {
-            mBluetoothA2dpEnabled = on;
-            sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
-                    AudioSystem.FOR_MEDIA,
-                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
-                    null, 0);
-        }
+        mBluetoothA2dpEnabled = on;
+        Log.e(TAG, "setBluetoothA2dpOn() is deprecated, now a no-op",
+                new Exception("Deprecated use of setBluetoothA2dpOn()"));
     }
 
-    /** @see AudioManager#isBluetoothA2dpOn() */
+    /** Deprecated.
+     * Keep stub implementation until MediaRouter stops using it
+     * @deprecated
+     * */
     public boolean isBluetoothA2dpOn() {
-        synchronized (mBluetoothA2dpEnabledLock) {
-            return mBluetoothA2dpEnabled;
-        }
+        return mBluetoothA2dpEnabled;
     }
 
     /** @see AudioManager#startBluetoothSco() */
@@ -4610,7 +4605,6 @@
                     break;
 
                 case MSG_SET_FORCE_USE:
-                case MSG_SET_FORCE_BT_A2DP_USE:
                     setForceUse(msg.arg1, msg.arg2);
                     break;
 
@@ -4780,7 +4774,6 @@
         VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
         sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
                 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
-        setBluetoothA2dpOnInt(true);
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
                 AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
         // Reset A2DP suspend state each time a new sink is connected
@@ -5113,11 +5106,6 @@
         }
 
         synchronized (mConnectedDevices) {
-            if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
-                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
-                    (device == AudioSystem.DEVICE_OUT_LINE))) {
-                setBluetoothA2dpOnInt(true);
-            }
             boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
                             (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
                              ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
@@ -5126,11 +5114,6 @@
                 return;
             }
             if (state != 0) {
-                if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
-                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
-                    (device == AudioSystem.DEVICE_OUT_LINE)) {
-                    setBluetoothA2dpOnInt(false);
-                }
                 if ((device & mSafeMediaVolumeDevices) != 0) {
                     sendMsg(mAudioHandler,
                             MSG_CHECK_MUSIC_ACTIVE,
@@ -5596,27 +5579,9 @@
         }
     }
 
-    // Handles request to override default use of A2DP for media.
-    // Must be called synchronized on mConnectedDevices
-    public void setBluetoothA2dpOnInt(boolean on) {
-        synchronized (mBluetoothA2dpEnabledLock) {
-            mBluetoothA2dpEnabled = on;
-            mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
-            setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
-                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
-        }
-    }
-
     // Must be called synchronized on mConnectedDevices
     private void setForceUseInt_SyncDevices(int usage, int config) {
         switch (usage) {
-            case AudioSystem.FOR_MEDIA:
-                if (config == AudioSystem.FORCE_NO_BT_A2DP) {
-                    mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ALL_A2DP;
-                } else { // config == AudioSystem.FORCE_NONE
-                    mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
-                }
-                break;
             case AudioSystem.FOR_DOCK:
                 if (config == AudioSystem.FORCE_ANALOG_DOCK) {
                     mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
new file mode 100644
index 0000000..4680a8a
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -0,0 +1,193 @@
+/*
+ * 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.
+ */
+
+package com.android.server.connectivity;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.net.NetworkCapabilities;
+import android.os.UserHandle;
+import android.telephony.TelephonyManager;
+import android.util.Slog;
+
+import com.android.internal.R;
+
+import static android.net.NetworkCapabilities.*;
+
+
+public class NetworkNotificationManager {
+
+    public static enum NotificationType { SIGN_IN, NO_INTERNET; };
+
+    private static final String NOTIFICATION_ID = "CaptivePortal.Notification";
+
+    private static final String TAG = NetworkNotificationManager.class.getSimpleName();
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
+
+    private final Context mContext;
+    private final TelephonyManager mTelephonyManager;
+    private final NotificationManager mNotificationManager;
+
+    public NetworkNotificationManager(Context c, TelephonyManager t, NotificationManager n) {
+        mContext = c;
+        mTelephonyManager = t;
+        mNotificationManager = n;
+    }
+
+    // TODO: deal more gracefully with multi-transport networks.
+    private static int getFirstTransportType(NetworkAgentInfo nai) {
+        for (int i = 0; i < 64; i++) {
+            if (nai.networkCapabilities.hasTransport(i)) return i;
+        }
+        return -1;
+    }
+
+    private static String getTransportName(int transportType) {
+        Resources r = Resources.getSystem();
+        String[] networkTypes = r.getStringArray(R.array.network_switch_type_name);
+        try {
+            return networkTypes[transportType];
+        } catch (IndexOutOfBoundsException e) {
+            return r.getString(R.string.network_switch_type_name_unknown);
+        }
+    }
+
+    private static int getIcon(int transportType) {
+        return (transportType == TRANSPORT_WIFI) ?
+                R.drawable.stat_notify_wifi_in_range :  // TODO: Distinguish ! from ?.
+                R.drawable.stat_notify_rssi_in_range;
+    }
+
+    /**
+     * Show or hide network provisioning notifications.
+     *
+     * We use notifications for two purposes: to notify that a network requires sign in
+     * (NotificationType.SIGN_IN), or to notify that a network does not have Internet access
+     * (NotificationType.NO_INTERNET). We display at most one notification per ID, so on a
+     * particular network we can display the notification type that was most recently requested.
+     * So for example if a captive portal fails to reply within a few seconds of connecting, we
+     * might first display NO_INTERNET, and then when the captive portal check completes, display
+     * SIGN_IN.
+     *
+     * @param id an identifier that uniquely identifies this notification.  This must match
+     *         between show and hide calls.  We use the NetID value but for legacy callers
+     *         we concatenate the range of types with the range of NetIDs.
+     */
+    public void showNotification(int id, NotificationType notifyType,
+            NetworkAgentInfo nai, PendingIntent intent, boolean highPriority) {
+        int transportType;
+        String extraInfo;
+        if (nai != null) {
+            transportType = getFirstTransportType(nai);
+            extraInfo = nai.networkInfo.getExtraInfo();
+            // Only notify for Internet-capable networks.
+            if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)) return;
+        } else {
+            // Legacy notifications.
+            transportType = TRANSPORT_CELLULAR;
+            extraInfo = null;
+        }
+
+        if (DBG) {
+            Slog.d(TAG, "showNotification " + notifyType
+                    + " transportType=" + getTransportName(transportType)
+                    + " extraInfo=" + extraInfo + " highPriority=" + highPriority);
+        }
+
+        Resources r = Resources.getSystem();
+        CharSequence title;
+        CharSequence details;
+        int icon = getIcon(transportType);
+        if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
+            title = r.getString(R.string.wifi_no_internet, 0);
+            details = r.getString(R.string.wifi_no_internet_detailed);
+        } else if (notifyType == NotificationType.SIGN_IN) {
+            switch (transportType) {
+                case TRANSPORT_WIFI:
+                    title = r.getString(R.string.wifi_available_sign_in, 0);
+                    details = r.getString(R.string.network_available_sign_in_detailed, extraInfo);
+                    break;
+                case TRANSPORT_CELLULAR:
+                    title = r.getString(R.string.network_available_sign_in, 0);
+                    // TODO: Change this to pull from NetworkInfo once a printable
+                    // name has been added to it
+                    details = mTelephonyManager.getNetworkOperatorName();
+                    break;
+                default:
+                    title = r.getString(R.string.network_available_sign_in, 0);
+                    details = r.getString(R.string.network_available_sign_in_detailed, extraInfo);
+                    break;
+            }
+        } else {
+            Slog.wtf(TAG, "Unknown notification type " + notifyType + "on network transport "
+                    + getTransportName(transportType));
+            return;
+        }
+
+        Notification notification = new Notification.Builder(mContext)
+                .setWhen(0)
+                .setSmallIcon(icon)
+                .setAutoCancel(true)
+                .setTicker(title)
+                .setColor(mContext.getColor(
+                        com.android.internal.R.color.system_notification_accent_color))
+                .setContentTitle(title)
+                .setContentText(details)
+                .setContentIntent(intent)
+                .setLocalOnly(true)
+                .setPriority(highPriority ?
+                        Notification.PRIORITY_HIGH :
+                        Notification.PRIORITY_DEFAULT)
+                .setDefaults(highPriority ? Notification.DEFAULT_ALL : 0)
+                .setOnlyAlertOnce(true)
+                .build();
+
+        try {
+            mNotificationManager.notifyAsUser(NOTIFICATION_ID, id, notification, UserHandle.ALL);
+        } catch (NullPointerException npe) {
+            Slog.d(TAG, "setNotificationVisible: visible notificationManager npe=" + npe);
+        }
+    }
+
+    public void clearNotification(int id) {
+        if (DBG) {
+            Slog.d(TAG, "clearNotification id=" + id);
+        }
+        try {
+            mNotificationManager.cancelAsUser(NOTIFICATION_ID, id, UserHandle.ALL);
+        } catch (NullPointerException npe) {
+            Slog.d(TAG, "setNotificationVisible: cancel notificationManager npe=" + npe);
+        }
+    }
+
+    /**
+     * Legacy provisioning notifications coming directly from DcTracker.
+     */
+    public void setProvNotificationVisible(boolean visible, int id, String action) {
+        if (visible) {
+            Intent intent = new Intent(action);
+            PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+            showNotification(id, NotificationType.SIGN_IN, null, pendingIntent, false);
+        } else {
+            clearNotification(id);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index e0d8373..927f8f9 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -1616,6 +1616,7 @@
                         if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
                         if (mNotifyList.indexOf(who) < 0) {
                             mNotifyList.add(who);
+                            mIPv6TetheringCoordinator.addActiveDownstream(who);
                         }
                         transitionTo(mTetherModeAliveState);
                         break;
@@ -1623,6 +1624,7 @@
                         who = (TetherInterfaceStateMachine)message.obj;
                         if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
                         mNotifyList.remove(who);
+                        mIPv6TetheringCoordinator.removeActiveDownstream(who);
                         break;
                     default:
                         retValue = false;
@@ -1661,17 +1663,19 @@
                 maybeLogMessage(this, message.what);
                 boolean retValue = true;
                 switch (message.what) {
-                    case CMD_TETHER_MODE_REQUESTED:
+                    case CMD_TETHER_MODE_REQUESTED: {
                         TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
                         if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
                         if (mNotifyList.indexOf(who) < 0) {
                             mNotifyList.add(who);
+                            mIPv6TetheringCoordinator.addActiveDownstream(who);
                         }
                         who.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
                                 mCurrentUpstreamIface);
                         break;
-                    case CMD_TETHER_MODE_UNREQUESTED:
-                        who = (TetherInterfaceStateMachine)message.obj;
+                    }
+                    case CMD_TETHER_MODE_UNREQUESTED: {
+                        TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
                         if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
                         if (mNotifyList.remove(who)) {
                             if (DBG) Log.d(TAG, "TetherModeAlive removing notifyee " + who);
@@ -1689,7 +1693,9 @@
                         } else {
                            Log.e(TAG, "TetherModeAliveState UNREQUESTED has unknown who: " + who);
                         }
+                        mIPv6TetheringCoordinator.removeActiveDownstream(who);
                         break;
+                    }
                     case CMD_UPSTREAM_CHANGED:
                         // need to try DUN immediately if Wifi goes down
                         mTryCell = true;
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
index e94b584..9173feb 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
@@ -29,6 +29,7 @@
 import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.util.ArrayList;
+import java.util.LinkedList;
 
 
 /**
@@ -45,10 +46,28 @@
     private static final boolean VDBG = false;
 
     private final ArrayList<TetherInterfaceStateMachine> mNotifyList;
+    private final LinkedList<TetherInterfaceStateMachine> mActiveDownstreams;
     private NetworkState mUpstreamNetworkState;
 
     public IPv6TetheringCoordinator(ArrayList<TetherInterfaceStateMachine> notifyList) {
         mNotifyList = notifyList;
+        mActiveDownstreams = new LinkedList<>();
+    }
+
+    public void addActiveDownstream(TetherInterfaceStateMachine downstream) {
+        if (mActiveDownstreams.indexOf(downstream) == -1) {
+            // Adding a new downstream appends it to the list. Adding a
+            // downstream a second time without first removing it has no effect.
+            mActiveDownstreams.offer(downstream);
+            updateIPv6TetheringInterfaces();
+        }
+    }
+
+    public void removeActiveDownstream(TetherInterfaceStateMachine downstream) {
+        stopIPv6TetheringOn(downstream);
+        if (mActiveDownstreams.remove(downstream)) {
+            updateIPv6TetheringInterfaces();
+        }
     }
 
     public void updateUpstreamNetworkState(NetworkState ns) {
@@ -72,8 +91,7 @@
 
     private void stopIPv6TetheringOnAllInterfaces() {
         for (TetherInterfaceStateMachine sm : mNotifyList) {
-            sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE,
-                    0, 0, null);
+            stopIPv6TetheringOn(sm);
         }
     }
 
@@ -98,28 +116,32 @@
 
     private void updateIPv6TetheringInterfaces() {
         for (TetherInterfaceStateMachine sm : mNotifyList) {
-            final LinkProperties lp = getInterfaceIPv6LinkProperties(sm.interfaceType());
+            final LinkProperties lp = getInterfaceIPv6LinkProperties(sm);
             sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, lp);
             break;
         }
     }
 
-    private LinkProperties getInterfaceIPv6LinkProperties(int interfaceType) {
+    private LinkProperties getInterfaceIPv6LinkProperties(TetherInterfaceStateMachine sm) {
         if (mUpstreamNetworkState == null) return null;
 
+        if (sm.interfaceType() == ConnectivityManager.TETHERING_BLUETOOTH) {
+            // TODO: Figure out IPv6 support on PAN interfaces.
+            return null;
+        }
+
         // NOTE: Here, in future, we would have policies to decide how to divvy
         // up the available dedicated prefixes among downstream interfaces.
         // At this time we have no such mechanism--we only support tethering
-        // IPv6 toward Wi-Fi interfaces.
+        // IPv6 toward the oldest (first requested) active downstream.
 
-        switch (interfaceType) {
-            case ConnectivityManager.TETHERING_WIFI:
-                final LinkProperties lp = getIPv6OnlyLinkProperties(
-                        mUpstreamNetworkState.linkProperties);
-                if (lp.hasIPv6DefaultRoute() && lp.hasGlobalIPv6Address()) {
-                    return lp;
-                }
-                break;
+        final TetherInterfaceStateMachine currentActive = mActiveDownstreams.peek();
+        if (currentActive != null && currentActive == sm) {
+            final LinkProperties lp = getIPv6OnlyLinkProperties(
+                    mUpstreamNetworkState.linkProperties);
+            if (lp.hasIPv6DefaultRoute() && lp.hasGlobalIPv6Address()) {
+                return lp;
+            }
         }
 
         return null;
@@ -250,4 +272,8 @@
                 ns.networkCapabilities,
                 ns.linkProperties);
     }
+
+    private static void stopIPv6TetheringOn(TetherInterfaceStateMachine sm) {
+        sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
+    }
 }
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
index edb4347..7525f30 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
@@ -26,6 +26,7 @@
 import android.net.ip.RouterAdvertisementDaemon;
 import android.net.ip.RouterAdvertisementDaemon.RaParams;
 import android.os.INetworkManagementService;
+import android.os.ServiceSpecificException;
 import android.os.RemoteException;
 import android.util.Log;
 import android.util.Slog;
@@ -205,7 +206,7 @@
                 final String dnsString = dns.getHostAddress();
                 try {
                     netd.interfaceDelAddress(mIfName, dnsString, RFC7421_IP_PREFIX_LENGTH);
-                } catch (RemoteException e) {
+                } catch (ServiceSpecificException | RemoteException e) {
                     Log.e(TAG, "Failed to remove local dns IP: " + dnsString, e);
                 }
             }
@@ -222,7 +223,7 @@
                 final String dnsString = dns.getHostAddress();
                 try {
                     netd.interfaceAddAddress(mIfName, dnsString, RFC7421_IP_PREFIX_LENGTH);
-                } catch (RemoteException e) {
+                } catch (ServiceSpecificException | RemoteException e) {
                     Log.e(TAG, "Failed to add local dns IP: " + dnsString, e);
                     newDnses.remove(dns);
                 }
@@ -231,7 +232,7 @@
 
         try {
             netd.tetherApplyDnsInterfaces();
-        } catch (RemoteException e) {
+        } catch (ServiceSpecificException | RemoteException e) {
             Log.e(TAG, "Failed to update local DNS caching server");
             if (newDnses != null) newDnses.clear();
         }
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 01b2393..12955f5 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -482,7 +482,6 @@
             SyncManager syncManager = getSyncManager();
             if (syncManager != null) {
                 syncManager.scheduleSync(account, userId, uId, authority, extras,
-                        0 /* no delay */, 0 /* no delay */,
                         false /* onlyThoseWithUnkownSyncableState */);
             }
         } finally {
@@ -547,11 +546,8 @@
                 getSyncManager().updateOrAddPeriodicSync(info, runAtTime,
                         flextime, extras);
             } else {
-                long beforeRuntimeMillis = (flextime) * 1000;
-                long runtimeMillis = runAtTime * 1000;
                 syncManager.scheduleSync(
                         request.getAccount(), userId, callerUid, request.getProvider(), extras,
-                        beforeRuntimeMillis, runtimeMillis,
                         false /* onlyThoseWithUnknownSyncableState */);
             }
         } finally {
@@ -841,7 +837,7 @@
         try {
             SyncManager syncManager = getSyncManager();
             if (syncManager != null) {
-                return syncManager.getIsSyncable(
+                return syncManager.computeSyncable(
                         account, userId, providerName);
             }
         } finally {
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 58e1af0..e4422dc 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -19,6 +19,7 @@
 import android.accounts.Account;
 import android.accounts.AccountAndUser;
 import android.accounts.AccountManager;
+import android.accounts.AccountManagerInternal;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
@@ -64,6 +65,7 @@
 import android.os.Message;
 import android.os.Messenger;
 import android.os.PowerManager;
+import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -79,6 +81,7 @@
 import android.util.Pair;
 import android.util.Slog;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.server.LocalServices;
 import com.android.server.job.JobSchedulerInternal;
 import com.google.android.collect.Lists;
@@ -133,6 +136,8 @@
 public class SyncManager {
     static final String TAG = "SyncManager";
 
+    private static final boolean DEBUG_ACCOUNT_ACCESS = false;
+
     /** Delay a sync due to local changes this long. In milliseconds */
     private static final long LOCAL_SYNC_DELAY;
 
@@ -194,6 +199,11 @@
     private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm";
     private static final String SYNC_LOOP_WAKE_LOCK = "SyncLoopWakeLock";
 
+
+    private static final int SYNC_OP_STATE_VALID = 0;
+    private static final int SYNC_OP_STATE_INVALID = 1;
+    private static final int SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS = 2;
+
     private Context mContext;
 
     private static final AccountAndUser[] INITIAL_ACCOUNTS_ARRAY = new AccountAndUser[0];
@@ -310,6 +320,10 @@
 
     private final UserManager mUserManager;
 
+    private final AccountManager mAccountManager;
+
+    private final AccountManagerInternal mAccountManagerInternal;
+
     private List<UserInfo> getAllUsers() {
         return mUserManager.getUsers();
     }
@@ -490,8 +504,6 @@
             @Override
             public void onSyncRequest(SyncStorageEngine.EndPoint info, int reason, Bundle extras) {
                 scheduleSync(info.account, info.userId, reason, info.provider, extras,
-                        0 /* no flexMillis */,
-                        0 /* run immediately */,
                         false);
             }
         });
@@ -522,8 +534,7 @@
                 if (!removed) {
                     scheduleSync(null, UserHandle.USER_ALL,
                             SyncOperation.REASON_SERVICE_CHANGED,
-                            type.authority, null, 0 /* no delay */, 0 /* no delay */,
-                            false /* onlyThoseWithUnkownSyncableState */);
+                            type.authority, null, false /* onlyThoseWithUnkownSyncableState */);
                 }
             }
         }, mSyncHandler);
@@ -562,6 +573,9 @@
         }
         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        mAccountManager = (AccountManager) mContext.getSystemService(Context.ACCOUNT_SERVICE);
+        mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class);
+
         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
                 BatteryStats.SERVICE_NAME));
 
@@ -655,7 +669,7 @@
         return mSyncStorageEngine;
     }
 
-    public int getIsSyncable(Account account, int userId, String providerName) {
+    private int getIsSyncable(Account account, int userId, String providerName) {
         int isSyncable = mSyncStorageEngine.getIsSyncable(account, userId, providerName);
         UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
 
@@ -666,22 +680,22 @@
         RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
                 mSyncAdapters.getServiceInfo(
                         SyncAdapterType.newKey(providerName, account.type), userId);
-        if (syncAdapterInfo == null) return isSyncable;
+        if (syncAdapterInfo == null) return AuthorityInfo.NOT_SYNCABLE;
 
         PackageInfo pInfo = null;
         try {
             pInfo = AppGlobals.getPackageManager().getPackageInfo(
                     syncAdapterInfo.componentName.getPackageName(), 0, userId);
-            if (pInfo == null) return isSyncable;
+            if (pInfo == null) return AuthorityInfo.NOT_SYNCABLE;
         } catch (RemoteException re) {
             // Shouldn't happen.
-            return isSyncable;
+            return AuthorityInfo.NOT_SYNCABLE;
         }
         if (pInfo.restrictedAccountType != null
                 && pInfo.restrictedAccountType.equals(account.type)) {
             return isSyncable;
         } else {
-            return 0;
+            return AuthorityInfo.NOT_SYNCABLE;
         }
     }
 
@@ -733,13 +747,10 @@
      * @param extras a Map of SyncAdapter-specific information to control
      *          syncs of a specific provider. Can be null. Is ignored
      *          if the url is null.
-     * @param beforeRuntimeMillis milliseconds before runtimeMillis that this sync can run.
-     * @param runtimeMillis maximum milliseconds in the future to wait before performing sync.
      * @param onlyThoseWithUnkownSyncableState Only sync authorities that have unknown state.
      */
     public void scheduleSync(Account requestedAccount, int userId, int reason,
-            String requestedAuthority, Bundle extras, long beforeRuntimeMillis,
-            long runtimeMillis, boolean onlyThoseWithUnkownSyncableState) {
+            String requestedAuthority, Bundle extras, boolean onlyThoseWithUnkownSyncableState) {
         final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
         if (extras == null) {
             extras = new Bundle();
@@ -749,17 +760,27 @@
                     + requestedAuthority);
         }
 
-        AccountAndUser[] accounts;
-        if (requestedAccount != null && userId != UserHandle.USER_ALL) {
-            accounts = new AccountAndUser[] { new AccountAndUser(requestedAccount, userId) };
+        AccountAndUser[] accounts = null;
+        if (requestedAccount != null) {
+            if (userId != UserHandle.USER_ALL) {
+                accounts = new AccountAndUser[]{new AccountAndUser(requestedAccount, userId)};
+            } else {
+                for (AccountAndUser runningAccount : mRunningAccounts) {
+                    if (requestedAccount.equals(runningAccount.account)) {
+                        accounts = ArrayUtils.appendElement(AccountAndUser.class,
+                                accounts, runningAccount);
+                    }
+                }
+            }
         } else {
             accounts = mRunningAccounts;
-            if (accounts.length == 0) {
-                if (isLoggable) {
-                    Slog.v(TAG, "scheduleSync: no accounts configured, dropping");
-                }
-                return;
+        }
+
+        if (ArrayUtils.isEmpty(accounts)) {
+            if (isLoggable) {
+                Slog.v(TAG, "scheduleSync: no accounts configured, dropping");
             }
+            return;
         }
 
         final boolean uploadOnly = extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false);
@@ -808,29 +829,41 @@
             }
 
             for (String authority : syncableAuthorities) {
-                int isSyncable = getIsSyncable(account.account, account.userId,
-                        authority);
+                int isSyncable = computeSyncable(account.account, account.userId, authority);
+
                 if (isSyncable == AuthorityInfo.NOT_SYNCABLE) {
                     continue;
                 }
-                final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
-                syncAdapterInfo = mSyncAdapters.getServiceInfo(
-                        SyncAdapterType.newKey(authority, account.account.type), account.userId);
+
+                final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
+                        mSyncAdapters.getServiceInfo(SyncAdapterType.newKey(authority,
+                                account.account.type), account.userId);
                 if (syncAdapterInfo == null) {
                     continue;
                 }
+
                 final int owningUid = syncAdapterInfo.uid;
-                final String owningPackage = syncAdapterInfo.componentName.getPackageName();
-                try {
-                    if (ActivityManagerNative.getDefault().getAppStartMode(owningUid,
-                            owningPackage) == ActivityManager.APP_START_MODE_DISABLED) {
-                        Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":"
-                                + syncAdapterInfo.componentName
-                                + " -- package not allowed to start");
-                        continue;
+
+                if (isSyncable == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {
+                    if (isLoggable) {
+                        Slog.v(TAG, "    Not scheduling sync operation: "
+                                + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
                     }
-                } catch (RemoteException e) {
+                    Bundle finalExtras = new Bundle(extras);
+                    mAccountManagerInternal.requestAccountAccess(account.account,
+                            syncAdapterInfo.componentName.getPackageName(),
+                            UserHandle.getUserId(owningUid),
+                            new RemoteCallback((Bundle result) -> {
+                                if (result != null
+                                        && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
+                                    scheduleSync(account.account, userId, reason, authority,
+                                            finalExtras, onlyThoseWithUnkownSyncableState);
+                                }
+                            }
+                        ));
+                    continue;
                 }
+
                 final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs();
                 final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable();
                 if (isSyncable < 0 && isAlwaysSyncable) {
@@ -838,6 +871,7 @@
                             account.account, account.userId, authority, AuthorityInfo.SYNCABLE);
                     isSyncable = AuthorityInfo.SYNCABLE;
                 }
+
                 if (onlyThoseWithUnkownSyncableState && isSyncable >= 0) {
                     continue;
                 }
@@ -863,6 +897,9 @@
                                 account.account, authority, account.userId);
                 long delayUntil =
                         mSyncStorageEngine.getDelayUntilTime(info);
+
+                final String owningPackage = syncAdapterInfo.componentName.getPackageName();
+
                 if (isSyncable < 0) {
                     // Initialisation sync.
                     Bundle newExtras = new Bundle();
@@ -887,8 +924,6 @@
                     if (isLoggable) {
                         Slog.v(TAG, "scheduleSync:"
                                 + " delay until " + delayUntil
-                                + " run by " + runtimeMillis
-                                + " flexMillis " + beforeRuntimeMillis
                                 + ", source " + source
                                 + ", account " + account
                                 + ", authority " + authority
@@ -904,6 +939,56 @@
         }
     }
 
+    public int computeSyncable(Account account, int userId, String authority) {
+        final int status = getIsSyncable(account, userId, authority);
+        if (status == AuthorityInfo.NOT_SYNCABLE) {
+            return AuthorityInfo.NOT_SYNCABLE;
+        }
+        final SyncAdapterType type = SyncAdapterType.newKey(authority, account.type);
+        final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
+                mSyncAdapters.getServiceInfo(type, userId);
+        if (syncAdapterInfo == null) {
+            return AuthorityInfo.NOT_SYNCABLE;
+        }
+        final int owningUid = syncAdapterInfo.uid;
+        final String owningPackage = syncAdapterInfo.componentName.getPackageName();
+        try {
+            if (ActivityManagerNative.getDefault().getAppStartMode(owningUid,
+                    owningPackage) == ActivityManager.APP_START_MODE_DISABLED) {
+                Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":"
+                        + syncAdapterInfo.componentName
+                        + " -- package not allowed to start");
+                return AuthorityInfo.NOT_SYNCABLE;
+            }
+        } catch (RemoteException e) {
+            /* ignore - local call */
+        }
+        if (!canAccessAccount(account, owningPackage, owningUid)) {
+            Log.w(TAG, "Access to " + account + " denied for package "
+                    + owningPackage + " in UID " + syncAdapterInfo.uid);
+            return AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS;
+        }
+
+        return status;
+    }
+
+    private boolean canAccessAccount(Account account, String packageName, int uid) {
+        if (mAccountManager.hasAccountAccess(account, packageName,
+                UserHandle.getUserHandleForUid(uid))) {
+            return true;
+        }
+        // We relax the account access rule to also include the system apps as
+        // they are trusted and we want to minimize the cases where the user
+        // involvement is required to grant access to the synced account.
+        try {
+            mContext.getPackageManager().getApplicationInfoAsUser(packageName,
+                    PackageManager.MATCH_SYSTEM_ONLY, UserHandle.getUserId(uid));
+            return true;
+        } catch (NameNotFoundException e) {
+            return false;
+        }
+    }
+
     private void removeSyncsForAuthority(EndPoint info) {
         verifyJobScheduler();
         List<SyncOperation> ops = getAllPendingSyncs();
@@ -960,8 +1045,6 @@
         final Bundle extras = new Bundle();
         extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
         scheduleSync(account, userId, reason, authority, extras,
-                LOCAL_SYNC_DELAY /* earliest run time */,
-                2 * LOCAL_SYNC_DELAY /* latest sync time. */,
                 false /* onlyThoseWithUnkownSyncableState */);
     }
 
@@ -1421,7 +1504,6 @@
                 mContext.getOpPackageName());
         for (Account account : accounts) {
             scheduleSync(account, userId, SyncOperation.REASON_USER_START, null, null,
-                    0 /* no delay */, 0 /* No flexMillis */,
                     true /* onlyThoseWithUnknownSyncableState */);
         }
     }
@@ -2530,13 +2612,18 @@
                 }
             }
 
-            if (isOperationValid(op)) {
-                if (!dispatchSyncOperation(op)) {
+            final int syncOpState = computeSyncOpState(op);
+            switch (syncOpState) {
+                case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS:
+                case SYNC_OP_STATE_INVALID: {
                     mSyncJobService.callJobFinished(op.jobId, false);
-                }
-            } else {
+                } return;
+            }
+
+            if (!dispatchSyncOperation(op)) {
                 mSyncJobService.callJobFinished(op.jobId, false);
             }
+
             setAuthorityPendingState(op.target);
         }
 
@@ -2596,8 +2683,7 @@
 
             if (syncTargets != null) {
                 scheduleSync(syncTargets.account, syncTargets.userId,
-                        SyncOperation.REASON_ACCOUNTS_UPDATED, syncTargets.provider, null, 0, 0,
-                        true);
+                        SyncOperation.REASON_ACCOUNTS_UPDATED, syncTargets.provider, null, true);
             }
         }
 
@@ -2665,6 +2751,26 @@
                     SyncStorageEngine.SOURCE_PERIODIC, extras,
                     syncAdapterInfo.type.allowParallelSyncs(), true, SyncOperation.NO_JOB_ID,
                     pollFrequencyMillis, flexMillis);
+
+            final int syncOpState = computeSyncOpState(op);
+            switch (syncOpState) {
+                case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS: {
+                    mAccountManagerInternal.requestAccountAccess(op.target.account,
+                            op.owningPackage, UserHandle.getUserId(op.owningUid),
+                            new RemoteCallback((Bundle result) -> {
+                                if (result != null
+                                        && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
+                                    updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
+                                }
+                            }
+                        ));
+                } return;
+
+                case SYNC_OP_STATE_INVALID: {
+                    return;
+                }
+            }
+
             scheduleSyncOperationH(op);
             mSyncStorageEngine.reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
         }
@@ -2725,29 +2831,38 @@
         /**
          * Determine if a sync is no longer valid and should be dropped.
          */
-        private boolean isOperationValid(SyncOperation op) {
+        private int computeSyncOpState(SyncOperation op) {
             final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
             int state;
             final EndPoint target = op.target;
-            boolean syncEnabled = mSyncStorageEngine.getMasterSyncAutomatically(target.userId);
+
             // Drop the sync if the account of this operation no longer exists.
             AccountAndUser[] accounts = mRunningAccounts;
             if (!containsAccountAndUser(accounts, target.account, target.userId)) {
                 if (isLoggable) {
                     Slog.v(TAG, "    Dropping sync operation: account doesn't exist.");
                 }
-                return false;
+                return SYNC_OP_STATE_INVALID;
             }
             // Drop this sync request if it isn't syncable.
-            state = getIsSyncable(target.account, target.userId, target.provider);
-            if (state == 0) {
+            state = computeSyncable(target.account, target.userId, target.provider);
+            if (state == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {
                 if (isLoggable) {
-                    Slog.v(TAG, "    Dropping sync operation: isSyncable == 0.");
+                    Slog.v(TAG, "    Dropping sync operation: "
+                            + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
                 }
-                return false;
+                return SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS;
             }
-            syncEnabled = syncEnabled && mSyncStorageEngine.getSyncAutomatically(
-                    target.account, target.userId, target.provider);
+            if (state != AuthorityInfo.SYNCABLE) {
+                if (isLoggable) {
+                    Slog.v(TAG, "    Dropping sync operation: isSyncable != SYNCABLE");
+                }
+                return SYNC_OP_STATE_INVALID;
+            }
+
+            final boolean syncEnabled = mSyncStorageEngine.getMasterSyncAutomatically(target.userId)
+                    && mSyncStorageEngine.getSyncAutomatically(target.account,
+                            target.userId, target.provider);
 
             // We ignore system settings that specify the sync is invalid if:
             // 1) It's manual - we try it anyway. When/if it fails it will be rescheduled.
@@ -2760,9 +2875,9 @@
                 if (isLoggable) {
                     Slog.v(TAG, "    Dropping sync operation: disallowed by settings/network.");
                 }
-                return false;
+                return SYNC_OP_STATE_INVALID;
             }
-            return true;
+            return SYNC_OP_STATE_VALID;
         }
 
         private boolean dispatchSyncOperation(SyncOperation op) {
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index bc3fc6a..64849aa 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -234,6 +234,12 @@
          */
         public static final int SYNCABLE_NOT_INITIALIZED = 2;
 
+        /**
+         * The adapter is syncable but does not have access to the synced account and needs a
+         * user access approval.
+         */
+        public static final int SYNCABLE_NO_ACCOUNT_ACCESS = 3;
+
         final EndPoint target;
         final int ident;
         boolean enabled;
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 15ae846..fa6a7e7 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -50,12 +50,6 @@
     // If true, enables the use of the screen auto-brightness adjustment setting.
     private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT = true;
 
-    // Hysteresis constraints for brightening or darkening.
-    // The recent lux must have changed by at least this fraction relative to the
-    // current ambient lux before a change will be considered.
-    private static final float BRIGHTENING_LIGHT_HYSTERESIS = 0.10f;
-    private static final float DARKENING_LIGHT_HYSTERESIS = 0.20f;
-
     // How long the current sensor reading is assumed to be valid beyond the current time.
     // This provides a bit of prediction, as well as ensures that the weight for the last sample is
     // non-zero, which in turn ensures that the total weight is non-zero.
@@ -71,7 +65,7 @@
     private static final int MSG_UPDATE_AMBIENT_LUX = 1;
     private static final int MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE = 2;
 
-    // Callbacks for requesting updates to the the display's power state
+    // Callbacks for requesting updates to the display's power state
     private final Callbacks mCallbacks;
 
     // The sensor manager.
@@ -115,6 +109,9 @@
     // weighting values positive.
     private final int mWeightingIntercept;
 
+    // accessor object for determining thresholds to change brightness dynamically
+    private final HysteresisLevels mDynamicHysteresis;
+
     // Amount of time to delay auto-brightness after screen on while waiting for
     // the light sensor to warm-up in milliseconds.
     // May be 0 if no warm-up is required.
@@ -190,7 +187,8 @@
             int brightnessMin, int brightnessMax, float dozeScaleFactor,
             int lightSensorRate, long brighteningLightDebounceConfig,
             long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
-            int ambientLightHorizon, float autoBrightnessAdjustmentMaxGamma ) {
+            int ambientLightHorizon, float autoBrightnessAdjustmentMaxGamma,
+            HysteresisLevels dynamicHysteresis) {
         mCallbacks = callbacks;
         mTwilight = LocalServices.getService(TwilightManager.class);
         mSensorManager = sensorManager;
@@ -206,6 +204,7 @@
         mAmbientLightHorizon = ambientLightHorizon;
         mWeightingIntercept = ambientLightHorizon;
         mScreenAutoBrightnessAdjustmentMaxGamma = autoBrightnessAdjustmentMaxGamma;
+        mDynamicHysteresis = dynamicHysteresis;
 
         mHandler = new AutomaticBrightnessHandler(looper);
         mAmbientLightRingBuffer =
@@ -344,8 +343,8 @@
 
     private void setAmbientLux(float lux) {
         mAmbientLux = lux;
-        mBrighteningLuxThreshold = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS);
-        mDarkeningLuxThreshold = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS);
+        mBrighteningLuxThreshold = mDynamicHysteresis.getBrighteningThreshold(lux);
+        mDarkeningLuxThreshold = mDynamicHysteresis.getDarkeningThreshold(lux);
     }
 
     private float calculateAmbientLux(long now) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index d6cc9fc..df5def9 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -72,7 +72,7 @@
     private static final String TAG = "DisplayPowerController";
     private static final String SCREEN_ON_BLOCKED_TRACE_NAME = "Screen on blocked";
 
-    private static boolean DEBUG = false;
+    private static final boolean DEBUG = false;
     private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false;
 
     // If true, uses the color fade on animation.
@@ -322,6 +322,15 @@
                 com.android.internal.R.fraction.config_autoBrightnessAdjustmentMaxGamma,
                 1, 1);
 
+        int[] brightLevels = resources.getIntArray(
+                com.android.internal.R.array.config_dynamicHysteresisBrightLevels);
+        int[] darkLevels = resources.getIntArray(
+                com.android.internal.R.array.config_dynamicHysteresisDarkLevels);
+        int[] luxLevels = resources.getIntArray(
+                com.android.internal.R.array.config_dynamicHysteresisLuxLevels);
+        HysteresisLevels dynamicHysteresis = new HysteresisLevels(
+                brightLevels, darkLevels, luxLevels);
+
         if (mUseSoftwareAutoBrightnessConfig) {
             int[] lux = resources.getIntArray(
                     com.android.internal.R.array.config_autoBrightnessLevels);
@@ -358,8 +367,8 @@
                         lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum,
                         mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
                         brighteningLightDebounce, darkeningLightDebounce,
-                        autoBrightnessResetAmbientLuxAfterWarmUp,
-                        ambientLightHorizon, autoBrightnessAdjustmentMaxGamma);
+                        autoBrightnessResetAmbientLuxAfterWarmUp, ambientLightHorizon,
+                        autoBrightnessAdjustmentMaxGamma, dynamicHysteresis);
             }
         }
 
diff --git a/services/core/java/com/android/server/display/HysteresisLevels.java b/services/core/java/com/android/server/display/HysteresisLevels.java
new file mode 100644
index 0000000..b062225
--- /dev/null
+++ b/services/core/java/com/android/server/display/HysteresisLevels.java
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+package com.android.server.display;
+
+import android.util.Slog;
+
+/**
+ * A helper class for handling access to illuminance hysteresis level values.
+ */
+final class HysteresisLevels {
+    private static final String TAG = "HysteresisLevels";
+
+    // Default hysteresis constraints for brightening or darkening.
+    // The recent lux must have changed by at least this fraction relative to the
+    // current ambient lux before a change will be considered.
+    private static final float DEFAULT_BRIGHTENING_HYSTERESIS = 0.10f;
+    private static final float DEFAULT_DARKENING_HYSTERESIS = 0.20f;
+
+    private static final boolean DEBUG = false;
+
+    private final float[] mBrightLevels;
+    private final float[] mDarkLevels;
+    private final float[] mLuxLevels;
+
+  /**
+   * Creates a {@code HysteresisLevels} object with the given equal-length
+   * integer arrays.
+   * @param brightLevels an array of brightening hysteresis constraint constants
+   * @param darkLevels an array of darkening hysteresis constraint constants
+   * @param luxLevels a monotonically increasing array of illuminance
+   *                  thresholds in units of lux
+   */
+    public HysteresisLevels(int[] brightLevels, int[] darkLevels, int[] luxLevels) {
+        if (brightLevels.length != darkLevels.length || darkLevels.length != luxLevels.length + 1) {
+            throw new IllegalArgumentException("Mismatch between hysteresis array lengths.");
+        }
+        mBrightLevels = setArrayFormat(brightLevels, 1000.0f);
+        mDarkLevels = setArrayFormat(darkLevels, 1000.0f);
+        mLuxLevels = setArrayFormat(luxLevels, 1.0f);
+    }
+
+    /**
+     * Return the brightening hysteresis threshold for the given lux level.
+     */
+    public float getBrighteningThreshold(float lux) {
+        float brightConstant = getReferenceLevel(lux, mBrightLevels);
+        float brightThreshold = lux * (1.0f + brightConstant);
+        if (DEBUG) {
+            Slog.d(TAG, "bright hysteresis constant=: " + brightConstant + ", threshold="
+                + brightThreshold + ", lux=" + lux);
+        }
+        return brightThreshold;
+    }
+
+    /**
+     * Return the darkening hysteresis threshold for the given lux level.
+     */
+    public float getDarkeningThreshold(float lux) {
+        float darkConstant = getReferenceLevel(lux, mDarkLevels);
+        float darkThreshold = lux * (1.0f - darkConstant);
+        if (DEBUG) {
+            Slog.d(TAG, "dark hysteresis constant=: " + darkConstant + ", threshold="
+                + darkThreshold + ", lux=" + lux);
+        }
+        return darkThreshold;
+    }
+
+    /**
+     * Return the hysteresis constant for the closest lux threshold value to the
+     * current illuminance from the given array.
+     */
+    private float getReferenceLevel(float lux, float[] referenceLevels) {
+        int index = 0;
+        while (mLuxLevels.length > index && lux >= mLuxLevels[index]) {
+            ++index;
+        }
+        return referenceLevels[index];
+    }
+
+    /**
+     * Return a float array where each i-th element equals {@code configArray[i]/divideFactor}.
+     */
+    private float[] setArrayFormat(int[] configArray, float divideFactor) {
+        float[] levelArray = new float[configArray.length];
+        for (int index = 0; levelArray.length > index; ++index) {
+            levelArray[index] = (float)configArray[index] / divideFactor;
+        }
+        return levelArray;
+    }
+}
diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java
index 07fa2ce..e7fd3d8 100644
--- a/services/core/java/com/android/server/display/NightDisplayService.java
+++ b/services/core/java/com/android/server/display/NightDisplayService.java
@@ -182,6 +182,8 @@
     }
 
     private void setUp() {
+        Slog.d(TAG, "setUp: currentUser=" + mCurrentUser);
+
         // Create a new controller for the current user and start listening for changes.
         mController = new NightDisplayController(getContext(), mCurrentUser);
         mController.setListener(this);
@@ -196,6 +198,8 @@
     }
 
     private void tearDown() {
+        Slog.d(TAG, "tearDown: currentUser=" + mCurrentUser);
+
         if (mController != null) {
             mController.setListener(null);
             mController = null;
@@ -273,6 +277,8 @@
 
     @Override
     public void onAutoModeChanged(int autoMode) {
+        Slog.d(TAG, "onAutoModeChanged: autoMode=" + autoMode);
+
         if (mAutoMode != null) {
             mAutoMode.onStop();
             mAutoMode = null;
@@ -291,6 +297,8 @@
 
     @Override
     public void onCustomStartTimeChanged(NightDisplayController.LocalTime startTime) {
+        Slog.d(TAG, "onCustomStartTimeChanged: startTime=" + startTime);
+
         if (mAutoMode != null) {
             mAutoMode.onCustomStartTimeChanged(startTime);
         }
@@ -298,6 +306,8 @@
 
     @Override
     public void onCustomEndTimeChanged(NightDisplayController.LocalTime endTime) {
+        Slog.d(TAG, "onCustomEndTimeChanged: endTime=" + endTime);
+
         if (mAutoMode != null) {
             mAutoMode.onCustomEndTimeChanged(endTime);
         }
@@ -419,7 +429,7 @@
 
         @Override
         public void onAlarm() {
-            if (DEBUG) Slog.d(TAG, "onAlarm");
+            Slog.d(TAG, "onAlarm");
             updateActivated();
         }
     }
@@ -477,7 +487,8 @@
 
         @Override
         public void onTwilightStateChanged(@Nullable TwilightState state) {
-            if (DEBUG) Slog.d(TAG, "onTwilightStateChanged");
+            Slog.d(TAG, "onTwilightStateChanged: isNight="
+                    + (state == null ? null : state.isNight()));
             updateActivated(state);
         }
     }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 9ca609f..72f465c 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -46,6 +46,7 @@
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
+import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
@@ -57,6 +58,7 @@
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
 import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
 import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
+import static android.net.NetworkPolicyManager.uidPoliciesToString;
 import static android.net.NetworkPolicyManager.uidRulesToString;
 import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
 import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
@@ -152,7 +154,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
-import android.util.DebugUtils;
 import android.util.Log;
 import android.util.NtpTrustedTime;
 import android.util.Pair;
@@ -357,12 +358,6 @@
     private final SparseBooleanArray mPowerSaveTempWhitelistAppIds = new SparseBooleanArray();
 
     /**
-     * UIDs that have been white-listed to avoid restricted background.
-     */
-    @GuardedBy("mUidRulesFirstLock")
-    private final SparseBooleanArray mRestrictBackgroundWhitelistUids = new SparseBooleanArray();
-
-    /**
      * UIDs that have been initially white-listed by system to avoid restricted background.
      */
     @GuardedBy("mUidRulesFirstLock")
@@ -486,7 +481,7 @@
      * Whitelists pre-defined apps for restrict background, but only if the user didn't already
      * revoke the whitelist.
      *
-     * @return whether any uid has been added to {@link #mRestrictBackgroundWhitelistUids}.
+     * @return whether any uid has been whitelisted.
      */
     boolean addDefaultRestrictBackgroundWhitelistUidsUL() {
         final List<UserInfo> users = mUserManager.getUsers();
@@ -531,7 +526,7 @@
             if (!mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
                 Slog.i(TAG, "adding default package " + pkg + " (uid " + uid + " for user "
                         + userId + ") to restrict background whitelist");
-                mRestrictBackgroundWhitelistUids.append(uid, true);
+                setUidPolicyUncheckedUL(uid, POLICY_ALLOW_METERED_BACKGROUND, false);
                 changed = true;
             }
         }
@@ -1460,6 +1455,10 @@
             final XmlPullParser in = Xml.newPullParser();
             in.setInput(fis, StandardCharsets.UTF_8.name());
 
+             // Must save the <restrict-background> tags and convert them to <uid-policy> later,
+             // to skip UIDs that were explicitly blacklisted.
+            final SparseBooleanArray whitelistedRestrictBackground = new SparseBooleanArray();
+
             int type;
             int version = VERSION_INIT;
             boolean insideWhitelist = false;
@@ -1568,7 +1567,7 @@
                         insideWhitelist = true;
                     } else if (TAG_RESTRICT_BACKGROUND.equals(tag) && insideWhitelist) {
                         final int uid = readIntAttribute(in, ATTR_UID);
-                        mRestrictBackgroundWhitelistUids.put(uid, true);
+                        whitelistedRestrictBackground.append(uid, true);
                     } else if (TAG_REVOKED_RESTRICT_BACKGROUND.equals(tag) && insideWhitelist) {
                         final int uid = readIntAttribute(in, ATTR_UID);
                         mRestrictBackgroundWhitelistRevokedUids.put(uid, true);
@@ -1581,6 +1580,25 @@
                 }
             }
 
+            final int size = whitelistedRestrictBackground.size();
+            for (int i = 0; i < size; i++) {
+                final int uid = whitelistedRestrictBackground.keyAt(i);
+                final int policy = mUidPolicy.get(uid, POLICY_NONE);
+                if ((policy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
+                    Slog.w(TAG, "ignoring restrict-background-whitelist for " + uid
+                            + " because its policy is " + uidPoliciesToString(policy));
+                    continue;
+                }
+                if (UserHandle.isApp(uid)) {
+                    final int newPolicy = policy | POLICY_ALLOW_METERED_BACKGROUND;
+                    if (LOGV)
+                        Log.v(TAG, "new policy for " + uid + ": " + uidPoliciesToString(newPolicy));
+                    setUidPolicyUncheckedUL(uid, newPolicy, false);
+                } else {
+                    Slog.w(TAG, "unable to update policy on UID " + uid);
+                }
+            }
+
         } catch (FileNotFoundException e) {
             // missing policy is okay, probably first boot
             upgradeLegacyBackgroundDataUL();
@@ -1670,17 +1688,8 @@
             // write all whitelists
             out.startTag(null, TAG_WHITELIST);
 
-            // restrict background whitelist
-            int size = mRestrictBackgroundWhitelistUids.size();
-            for (int i = 0; i < size; i++) {
-                final int uid = mRestrictBackgroundWhitelistUids.keyAt(i);
-                out.startTag(null, TAG_RESTRICT_BACKGROUND);
-                writeIntAttribute(out, ATTR_UID, uid);
-                out.endTag(null, TAG_RESTRICT_BACKGROUND);
-            }
-
             // revoked restrict background whitelist
-            size = mRestrictBackgroundWhitelistRevokedUids.size();
+            int size = mRestrictBackgroundWhitelistRevokedUids.size();
             for (int i = 0; i < size; i++) {
                 final int uid = mRestrictBackgroundWhitelistRevokedUids.keyAt(i);
                 out.startTag(null, TAG_REVOKED_RESTRICT_BACKGROUND);
@@ -1817,22 +1826,6 @@
         if (LOGV) Slog.v(TAG, "removeUserStateUL()");
         boolean changed = false;
 
-        // Remove entries from restricted background UID whitelist
-        int[] wlUids = new int[0];
-        for (int i = 0; i < mRestrictBackgroundWhitelistUids.size(); i++) {
-            final int uid = mRestrictBackgroundWhitelistUids.keyAt(i);
-            if (UserHandle.getUserId(uid) == userId) {
-                wlUids = appendInt(wlUids, uid);
-            }
-        }
-
-        if (wlUids.length > 0) {
-            for (int uid : wlUids) {
-                removeRestrictBackgroundWhitelistedUidUL(uid, false, false);
-            }
-            changed = true;
-        }
-
         // Remove entries from revoked default restricted background UID whitelist
         for (int i = mRestrictBackgroundWhitelistRevokedUids.size() - 1; i >= 0; i--) {
             final int uid = mRestrictBackgroundWhitelistRevokedUids.keyAt(i);
@@ -2068,21 +2061,26 @@
         }
     }
 
+    /**
+     * @deprecated - should use {@link #setUidPolicy(int, int)} directly.
+     */
     @Override
+    @Deprecated
     public void addRestrictBackgroundWhitelistedUid(int uid) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
         final boolean oldStatus;
         final boolean needFirewallRules;
         int changed;
         synchronized (mUidRulesFirstLock) {
-            oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
+            final int oldUidPolicy = mUidPolicy.get(uid, POLICY_NONE);
+            oldStatus = (oldUidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0;
             if (oldStatus) {
                 if (LOGD) Slog.d(TAG, "uid " + uid + " is already whitelisted");
                 return;
             }
             needFirewallRules = isUidValidForWhitelistRules(uid);
             Slog.i(TAG, "adding uid " + uid + " to restrict background whitelist");
-            mRestrictBackgroundWhitelistUids.append(uid, true);
+            setUidPolicyUncheckedUL(uid, oldUidPolicy, POLICY_ALLOW_METERED_BACKGROUND, false);
             if (mDefaultRestrictBackgroundWhitelistUids.get(uid)
                     && mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
                 if (LOGD) Slog.d(TAG, "Removing uid " + uid
@@ -2103,7 +2101,11 @@
                 Boolean.TRUE).sendToTarget();
     }
 
+    /**
+     * @deprecated - should use {@link #setUidPolicy(int, int)} directly.
+     */
     @Override
+    @Deprecated
     public void removeRestrictBackgroundWhitelistedUid(int uid) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
         final boolean changed;
@@ -2120,7 +2122,8 @@
      */
     private boolean removeRestrictBackgroundWhitelistedUidUL(int uid, boolean uidDeleted,
             boolean updateNow) {
-        final boolean oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
+        final boolean oldStatus =
+                (mUidPolicy.get(uid, POLICY_NONE) & POLICY_ALLOW_METERED_BACKGROUND) != 0;
         if (!oldStatus && !uidDeleted) {
             if (LOGD) Slog.d(TAG, "uid " + uid + " was not whitelisted before");
             return false;
@@ -2128,7 +2131,7 @@
         final boolean needFirewallRules = uidDeleted || isUidValidForWhitelistRules(uid);
         if (oldStatus) {
             Slog.i(TAG, "removing uid " + uid + " from restrict background whitelist");
-            mRestrictBackgroundWhitelistUids.delete(uid);
+            mUidPolicy.delete(uid);
         }
         if (mDefaultRestrictBackgroundWhitelistUids.get(uid)
                 && !mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
@@ -2151,21 +2154,41 @@
         return mRestrictBackground && needFirewallRules;
     }
 
+    /**
+     * @deprecated - should use {@link #getUidsWithPolicy(int)} instead, but first need to change
+     * that method to use logical OR (|).
+     */
     @Override
+    @Deprecated
     public int[] getRestrictBackgroundWhitelistedUids() {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+        int[] whitelist = null;
         synchronized (mUidRulesFirstLock) {
-            final int size = mRestrictBackgroundWhitelistUids.size();
-            final int[] whitelist = new int[size];
-            for (int i = 0; i < size; i++) {
-                whitelist[i] = mRestrictBackgroundWhitelistUids.keyAt(i);
+            // First calculate size
+            int size = 0;
+            int policySize = mUidPolicy.size();
+            for (int i = 0; i < policySize; i++) {
+                if ((mUidPolicy.valueAt(i) & POLICY_ALLOW_METERED_BACKGROUND) != 0) {
+                    size ++;
+                }
             }
-            if (LOGV) {
-                Slog.v(TAG, "getRestrictBackgroundWhitelistedUids(): "
-                        + mRestrictBackgroundWhitelistUids);
+            whitelist = new int[size];
+            // Then populate it.
+            if (size > 0) {
+                int index = 0;
+                for (int i = 0; i < policySize; i++) {
+                    final int uid = mUidPolicy.keyAt(i);
+                    if ((mUidPolicy.valueAt(i) & POLICY_ALLOW_METERED_BACKGROUND) != 0) {
+                        whitelist[index++] = uid;
+                    }
+                }
             }
-            return whitelist;
         }
+        if (LOGV) {
+            Slog.v(TAG, "getRestrictBackgroundWhitelistedUids(): "
+                    + Arrays.toString(whitelist));
+        }
+        return whitelist;
     }
 
     @Override
@@ -2189,7 +2212,7 @@
             if (!mRestrictBackground) {
                 return RESTRICT_BACKGROUND_STATUS_DISABLED;
             }
-            return mRestrictBackgroundWhitelistUids.get(uid)
+            return (mUidPolicy.get(uid) & POLICY_ALLOW_METERED_BACKGROUND) != 0
                     ? RESTRICT_BACKGROUND_STATUS_WHITELISTED
                     : RESTRICT_BACKGROUND_STATUS_ENABLED;
         }
@@ -2352,7 +2375,7 @@
                     fout.print("UID=");
                     fout.print(uid);
                     fout.print(" policy=");
-                    fout.print(DebugUtils.flagsToString(NetworkPolicyManager.class, "POLICY_", policy));
+                    fout.print(uidPoliciesToString(policy));
                     fout.println();
                 }
                 fout.decreaseIndent();
@@ -2385,13 +2408,15 @@
                     fout.decreaseIndent();
                 }
 
-                size = mRestrictBackgroundWhitelistUids.size();
+                final int[] restrictBackgroundWhitelistUids =
+                        getRestrictBackgroundWhitelistedUids();
+                size = restrictBackgroundWhitelistUids.length;
                 if (size > 0) {
                     fout.println("Restrict background whitelist uids:");
                     fout.increaseIndent();
                     for (int i = 0; i < size; i++) {
                         fout.print("UID=");
-                        fout.print(mRestrictBackgroundWhitelistUids.keyAt(i));
+                        fout.print(restrictBackgroundWhitelistUids[i]);
                         fout.println();
                     }
                     fout.decreaseIndent();
@@ -2915,7 +2940,7 @@
         final boolean isForeground = isUidForegroundOnRestrictBackgroundUL(uid);
 
         final boolean isBlacklisted = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
-        final boolean isWhitelisted = mRestrictBackgroundWhitelistUids.get(uid);
+        final boolean isWhitelisted = (uidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0;
         final int oldRule = oldUidRules & MASK_METERED_NETWORKS;
         int newRule = RULE_NONE;
 
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 7c89e9f..b2198d7 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -203,6 +203,7 @@
         pw.println(prefix + "  key=" + sbn.getKey());
         pw.println(prefix + "  seen=" + mIsSeen);
         pw.println(prefix + "  groupKey=" + getGroupKey());
+        pw.println(prefix + "  fullscreenIntent=" + notification.fullScreenIntent);
         pw.println(prefix + "  contentIntent=" + notification.contentIntent);
         pw.println(prefix + "  deleteIntent=" + notification.deleteIntent);
         pw.println(prefix + "  tickerText=" + notification.tickerText);
diff --git a/services/core/java/com/android/server/os/SchedulingPolicyService.java b/services/core/java/com/android/server/os/SchedulingPolicyService.java
index f98012b..62c9f4c 100644
--- a/services/core/java/com/android/server/os/SchedulingPolicyService.java
+++ b/services/core/java/com/android/server/os/SchedulingPolicyService.java
@@ -55,7 +55,8 @@
             Process.setThreadGroup(tid, Binder.getCallingPid() == pid ?
                     Process.THREAD_GROUP_AUDIO_SYS : Process.THREAD_GROUP_AUDIO_APP);
             // must be in this order or it fails the schedulability constraint
-            Process.setThreadScheduler(tid, Process.SCHED_FIFO, prio);
+            Process.setThreadScheduler(tid, Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK,
+                prio);
         } catch (RuntimeException e) {
             return PackageManager.PERMISSION_DENIED;
         }
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 87f0581..cec1058 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -28,10 +28,13 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.BatteryManager;
+import android.os.Environment;
 import android.os.ServiceManager;
+import android.os.storage.StorageManager;
 import android.util.ArraySet;
 import android.util.Log;
 
+import java.io.File;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.TimeUnit;
 
@@ -66,6 +69,8 @@
      */
     final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false);
 
+    private final File dataDir = Environment.getDataDirectory();
+
     public static void schedule(Context context) {
         JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
 
@@ -113,6 +118,16 @@
         return (100 * level / scale);
     }
 
+    private long getLowStorageThreshold() {
+        @SuppressWarnings("deprecation")
+        final long lowThreshold = StorageManager.from(this).getStorageLowBytes(dataDir);
+        if (lowThreshold == 0) {
+            Log.e(TAG, "Invalid low storage threshold");
+        }
+
+        return lowThreshold;
+    }
+
     private boolean runPostBootUpdate(final JobParameters jobParams,
             final PackageManagerService pm, final ArraySet<String> pkgs) {
         if (mExitPostBootUpdate.get()) {
@@ -124,6 +139,8 @@
         final int lowBatteryThreshold = getResources().getInteger(
                 com.android.internal.R.integer.config_lowBatteryWarningLevel);
 
+        final long lowThreshold = getLowStorageThreshold();
+
         mAbortPostBootUpdate.set(false);
         new Thread("BackgroundDexOptService_PostBootUpdate") {
             @Override
@@ -141,6 +158,14 @@
                         // Rather bail than completely drain the battery.
                         break;
                     }
+                    long usableSpace = dataDir.getUsableSpace();
+                    if (usableSpace < lowThreshold) {
+                        // Rather bail than completely fill up the disk.
+                        Log.w(TAG, "Aborting background dex opt job due to low storage: " +
+                                usableSpace);
+                        break;
+                    }
+
                     if (DEBUG_DEXOPT) {
                         Log.i(TAG, "Updating package " + pkg);
                     }
@@ -171,6 +196,9 @@
         mExitPostBootUpdate.set(true);
 
         mAbortIdleOptimization.set(false);
+
+        final long lowThreshold = getLowStorageThreshold();
+
         new Thread("BackgroundDexOptService_IdleOptimization") {
             @Override
             public void run() {
@@ -183,6 +211,15 @@
                         // Skip previously failing package
                         continue;
                     }
+
+                    long usableSpace = dataDir.getUsableSpace();
+                    if (usableSpace < lowThreshold) {
+                        // Rather bail than completely fill up the disk.
+                        Log.w(TAG, "Aborting background dex opt job due to low storage: " +
+                                usableSpace);
+                        break;
+                    }
+
                     // Conservatively add package to the list of failing ones in case performDexOpt
                     // never returns.
                     synchronized (sFailedPackageNames) {
@@ -213,6 +250,9 @@
             Log.i(TAG, "onStartJob");
         }
 
+        // NOTE: PackageManagerService.isStorageLow uses a different set of criteria from
+        // the checks above. This check is not "live" - the value is determined by a background
+        // restart with a period of ~1 minute.
         PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package");
         if (pm.isStorageLow()) {
             if (DEBUG_DEXOPT) {
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 9c9e97e..d1dbdd8 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -17,6 +17,7 @@
 package com.android.server.pm;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.app.DownloadManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.Intent;
@@ -30,6 +31,9 @@
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
 import android.os.Build;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Message;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
 import android.print.PrintManager;
@@ -39,12 +43,23 @@
 import android.provider.Telephony.Sms.Intents;
 import android.telephony.TelephonyManager;
 import android.security.Credentials;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.Slog;
+import android.util.Xml;
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
 
+import java.io.BufferedInputStream;
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import static android.os.Process.FIRST_APPLICATION_UID;
@@ -65,6 +80,13 @@
 
     private static final String AUDIO_MIME_TYPE = "audio/mpeg";
 
+    private static final String TAG_EXCEPTIONS = "exceptions";
+    private static final String TAG_EXCEPTION = "exception";
+    private static final String TAG_PERMISSION = "permission";
+    private static final String ATTR_PACKAGE = "package";
+    private static final String ATTR_NAME = "name";
+    private static final String ATTR_FIXED = "fixed";
+
     private static final Set<String> PHONE_PERMISSIONS = new ArraySet<>();
     static {
         PHONE_PERMISSIONS.add(Manifest.permission.READ_PHONE_STATE);
@@ -126,7 +148,10 @@
         STORAGE_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
     }
 
+    private static final int MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS = 1;
+
     private final PackageManagerService mService;
+    private final Handler mHandler;
 
     private PackagesProvider mLocationPackagesProvider;
     private PackagesProvider mVoiceInteractionPackagesProvider;
@@ -135,8 +160,22 @@
     private PackagesProvider mSimCallManagerPackagesProvider;
     private SyncAdapterPackagesProvider mSyncAdapterPackagesProvider;
 
+    private ArrayMap<String, List<DefaultPermissionGrant>> mGrantExceptions;
+
     public DefaultPermissionGrantPolicy(PackageManagerService service) {
         mService = service;
+        mHandler = new Handler(mService.mHandlerThread.getLooper()) {
+            @Override
+            public void handleMessage(Message msg) {
+                if (msg.what == MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS) {
+                    synchronized (mService.mPackages) {
+                        if (mGrantExceptions == null) {
+                            mGrantExceptions = readDefaultPermissionExceptionsLPw();
+                        }
+                    }
+                }
+            }
+        };
     }
 
     public void setLocationPackagesProviderLPw(PackagesProvider provider) {
@@ -166,6 +205,11 @@
     public void grantDefaultPermissions(int userId) {
         grantPermissionsToSysComponentsAndPrivApps(userId);
         grantDefaultSystemHandlerPermissions(userId);
+        grantDefaultPermissionExceptions(userId);
+    }
+
+    public void scheduleReadDefaultPermissionExceptions() {
+        mHandler.sendEmptyMessage(MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS);
     }
 
     private void grantPermissionsToSysComponentsAndPrivApps(int userId) {
@@ -916,7 +960,175 @@
                 pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
     }
 
+    private void grantDefaultPermissionExceptions(int userId) {
+        synchronized (mService.mPackages) {
+            mHandler.removeMessages(MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS);
+
+            if (mGrantExceptions == null) {
+                mGrantExceptions = readDefaultPermissionExceptionsLPw();
+            }
+
+            // mGrantExceptions is null only before the first read and then
+            // it serves as a cache of the default grants that should be
+            // performed for every user. If there is an entry then the app
+            // is on the system image and supports runtime permissions.
+            Set<String> permissions = null;
+            final int exceptionCount = mGrantExceptions.size();
+            for (int i = 0; i < exceptionCount; i++) {
+                String packageName = mGrantExceptions.keyAt(i);
+                PackageParser.Package pkg = getSystemPackageLPr(packageName);
+                List<DefaultPermissionGrant> permissionGrants = mGrantExceptions.valueAt(i);
+                final int permissionGrantCount = permissionGrants.size();
+                for (int j = 0; j < permissionGrantCount; j++) {
+                    DefaultPermissionGrant permissionGrant = permissionGrants.get(j);
+                    if (permissions == null) {
+                        permissions = new ArraySet<>();
+                    } else {
+                        permissions.clear();
+                    }
+                    permissions.add(permissionGrant.name);
+                    grantRuntimePermissionsLPw(pkg, permissions, false,
+                            permissionGrant.fixed, userId);
+                }
+            }
+        }
+    }
+
+    private @NonNull ArrayMap<String, List<DefaultPermissionGrant>>
+            readDefaultPermissionExceptionsLPw() {
+        File dir = new File(Environment.getRootDirectory(), "etc/default-permissions");
+        if (!dir.exists() || !dir.isDirectory() || !dir.canRead()) {
+            return new ArrayMap<>(0);
+        }
+
+        File[] files = dir.listFiles();
+        if (files == null) {
+            return new ArrayMap<>(0);
+        }
+
+        ArrayMap<String, List<DefaultPermissionGrant>> grantExceptions = new ArrayMap<>();
+
+        // Iterate over the files in the directory and scan .xml files
+        for (File file : files) {
+            if (!file.getPath().endsWith(".xml")) {
+                Slog.i(TAG, "Non-xml file " + file + " in " + dir + " directory, ignoring");
+                continue;
+            }
+            if (!file.canRead()) {
+                Slog.w(TAG, "Default permissions file " + file + " cannot be read");
+                continue;
+            }
+            try (
+                InputStream str = new BufferedInputStream(new FileInputStream(file))
+            ) {
+                XmlPullParser parser = Xml.newPullParser();
+                parser.setInput(str, null);
+                parse(parser, grantExceptions);
+            } catch (XmlPullParserException | IOException e) {
+                Slog.w(TAG, "Error reading default permissions file " + file, e);
+            }
+        }
+
+        return grantExceptions;
+    }
+
+    private void parse(XmlPullParser parser, Map<String, List<DefaultPermissionGrant>>
+            outGrantExceptions) throws IOException, XmlPullParserException {
+        final int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            if (TAG_EXCEPTIONS.equals(parser.getName())) {
+                parseExceptions(parser, outGrantExceptions);
+            } else {
+                Log.e(TAG, "Unknown tag " + parser.getName());
+            }
+        }
+    }
+
+    private void parseExceptions(XmlPullParser parser, Map<String, List<DefaultPermissionGrant>>
+            outGrantExceptions) throws IOException, XmlPullParserException {
+        final int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            if (TAG_EXCEPTION.equals(parser.getName())) {
+                String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+
+                List<DefaultPermissionGrant> packageExceptions =
+                        outGrantExceptions.get(packageName);
+                if (packageExceptions == null) {
+                    // The package must be on the system image
+                    PackageParser.Package pkg = getSystemPackageLPr(packageName);
+                    if (pkg == null) {
+                        Log.w(TAG, "Unknown package:" + packageName);
+                        XmlUtils.skipCurrentTag(parser);
+                        return;
+                    }
+
+                    // The package must support runtime permissions
+                    if (!doesPackageSupportRuntimePermissions(pkg)) {
+                        Log.w(TAG, "Skipping non supporting runtime permissions package:"
+                                + packageName);
+                        XmlUtils.skipCurrentTag(parser);
+                        return;
+                    }
+                    packageExceptions = new ArrayList<>();
+                    outGrantExceptions.put(packageName, packageExceptions);
+                }
+
+                parsePermission(parser, packageExceptions);
+            } else {
+                Log.e(TAG, "Unknown tag " + parser.getName() + "under <exceptions>");
+            }
+        }
+    }
+
+    private void parsePermission(XmlPullParser parser, List<DefaultPermissionGrant>
+            outPackageExceptions) throws IOException, XmlPullParserException {
+        final int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            if (TAG_PERMISSION.contains(parser.getName())) {
+                String name = parser.getAttributeValue(null, ATTR_NAME);
+                if (name == null) {
+                    Log.w(TAG, "Mandatory name attribute missing for permission tag");
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                }
+
+                final boolean fixed = XmlUtils.readBooleanAttribute(parser, ATTR_FIXED);
+
+                DefaultPermissionGrant exception = new DefaultPermissionGrant(name, fixed);
+                outPackageExceptions.add(exception);
+            } else {
+                Log.e(TAG, "Unknown tag " + parser.getName() + "under <exception>");
+            }
+        }
+    }
+
     private static boolean doesPackageSupportRuntimePermissions(PackageParser.Package pkg) {
         return pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
     }
+
+    private static final class DefaultPermissionGrant {
+        final String name;
+        final boolean fixed;
+
+        public DefaultPermissionGrant(String name, boolean fixed) {
+            this.name = name;
+            this.fixed = fixed;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 53e328c..37c54cf 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -363,7 +363,7 @@
 
         private void ensureShortcutPermission(@NonNull String callingPackage, int userId) {
             verifyCallingPackage(callingPackage);
-            ensureInUserProfiles(userId, "Cannot start activity for unrelated profile " + userId);
+            ensureInUserProfiles(userId, "Cannot access shortcuts for unrelated profile " + userId);
 
             if (!mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(),
                     callingPackage)) {
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 836b588..bff6d2d 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -93,38 +93,39 @@
         if (mDexoptCommands != null) {
             throw new IllegalStateException("already called prepare()");
         }
+        final List<PackageParser.Package> important;
+        final List<PackageParser.Package> others;
         synchronized (mPackageManagerService.mPackages) {
             // Important: the packages we need to run with ab-ota compiler-reason.
-            List<PackageParser.Package> important = PackageManagerServiceUtils.getPackagesForDexopt(
+            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 = 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 : 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");
             }
-            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));
-            }
+            mDexoptCommands.addAll(
+                    generatePackageDexopts(p, PackageManagerService.REASON_FIRST_BOOT));
         }
         completeSize = mDexoptCommands.size();
     }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 6a56fa6..d25abbf 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -870,13 +870,8 @@
                 IntentSender statusReceiver, int userId) {
         final int callingUid = Binder.getCallingUid();
         mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
-        boolean allowSilentUninstall = true;
         if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
             mAppOps.checkPackage(callingUid, callerPackageName);
-            final String installerPackageName = mPm.getInstallerPackageName(packageName);
-            allowSilentUninstall = mPm.isOrphaned(packageName) ||
-                    (installerPackageName != null
-                            && installerPackageName.equals(callerPackageName));
         }
 
         // Check whether the caller is device owner, in which case we do it silently.
@@ -887,8 +882,8 @@
 
         final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
                 statusReceiver, packageName, isDeviceOwner, userId);
-        if (allowSilentUninstall && mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.DELETE_PACKAGES) == PackageManager.PERMISSION_GRANTED) {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
+                    == PackageManager.PERMISSION_GRANTED) {
             // Sweet, call straight through!
             mPm.deletePackage(packageName, adapter.getBinder(), userId, flags);
         } else if (isDeviceOwner) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 6cdc40f..5831284 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -109,6 +109,7 @@
     final int installerUid;
     final SessionParams params;
     final long createdMillis;
+    final int defaultContainerGid;
 
     /** Staging location where client data is written. */
     final File stageDir;
@@ -199,13 +200,19 @@
     private final Handler.Callback mHandlerCallback = new Handler.Callback() {
         @Override
         public boolean handleMessage(Message msg) {
+            // Cache package manager data without the lock held
+            final PackageInfo pkgInfo = mPm.getPackageInfo(
+                    params.appPackageName, PackageManager.GET_SIGNATURES /*flags*/, userId);
+            final ApplicationInfo appInfo = mPm.getApplicationInfo(
+                    params.appPackageName, 0, userId);
+
             synchronized (mLock) {
                 if (msg.obj != null) {
                     mRemoteObserver = (IPackageInstallObserver2) msg.obj;
                 }
 
                 try {
-                    commitLocked();
+                    commitLocked(pkgInfo, appInfo);
                 } catch (PackageManagerException e) {
                     final String completeMsg = ExceptionUtils.getCompleteMessage(e);
                     Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
@@ -264,6 +271,9 @@
         } else {
             mPermissionsAccepted = false;
         }
+        final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
+                PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
+        defaultContainerGid = UserHandle.getSharedAppGid(uid);
     }
 
     public SessionInfo generateInfo() {
@@ -520,7 +530,8 @@
         mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
     }
 
-    private void commitLocked() throws PackageManagerException {
+    private void commitLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
+            throws PackageManagerException {
         if (mDestroyed) {
             throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
         }
@@ -538,7 +549,7 @@
         // Verify that stage looks sane with respect to existing application.
         // This currently only ensures packageName, versionCode, and certificate
         // consistency.
-        validateInstallLocked();
+        validateInstallLocked(pkgInfo, appInfo);
 
         Preconditions.checkNotNull(mPackageName);
         Preconditions.checkNotNull(mSignatures);
@@ -650,7 +661,8 @@
      * Note that upgrade compatibility is still performed by
      * {@link PackageManagerService}.
      */
-    private void validateInstallLocked() throws PackageManagerException {
+    private void validateInstallLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
+            throws PackageManagerException {
         mPackageName = null;
         mVersionCode = -1;
         mSignatures = null;
@@ -729,10 +741,8 @@
 
         if (removeSplitList.size() > 0) {
             // validate split names marked for removal
-            final int flags = mSignatures == null ? PackageManager.GET_SIGNATURES : 0;
-            final PackageInfo pkg = mPm.getPackageInfo(params.appPackageName, flags, userId);
             for (String splitName : removeSplitList) {
-                if (!ArrayUtils.contains(pkg.splitNames, splitName)) {
+                if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
                     throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                             "Split not found: " + splitName);
                 }
@@ -740,11 +750,11 @@
 
             // ensure we've got appropriate package name, version code and signatures
             if (mPackageName == null) {
-                mPackageName = pkg.packageName;
-                mVersionCode = pkg.versionCode;
+                mPackageName = pkgInfo.packageName;
+                mVersionCode = pkgInfo.versionCode;
             }
             if (mSignatures == null) {
-                mSignatures = pkg.signatures;
+                mSignatures = pkgInfo.signatures;
             }
         }
 
@@ -757,8 +767,7 @@
 
         } else {
             // Partial installs must be consistent with existing install
-            final ApplicationInfo app = mPm.getApplicationInfo(mPackageName, 0, userId);
-            if (app == null) {
+            if (appInfo == null) {
                 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                         "Missing existing base package for " + mPackageName);
             }
@@ -766,8 +775,8 @@
             final PackageLite existing;
             final ApkLite existingBase;
             try {
-                existing = PackageParser.parsePackageLite(new File(app.getCodePath()), 0);
-                existingBase = PackageParser.parseApkLite(new File(app.getBaseCodePath()),
+                existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
+                existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()),
                         PackageParser.PARSE_COLLECT_CERTIFICATES);
             } catch (PackageParserException e) {
                 throw PackageManagerException.from(e);
@@ -777,7 +786,7 @@
 
             // Inherit base if not overridden
             if (mResolvedBaseFile == null) {
-                mResolvedBaseFile = new File(app.getBaseCodePath());
+                mResolvedBaseFile = new File(appInfo.getBaseCodePath());
                 mResolvedInheritedFiles.add(mResolvedBaseFile);
             }
 
@@ -794,7 +803,7 @@
             }
 
             // Inherit compiled oat directory.
-            final File packageInstallDir = (new File(app.getBaseCodePath())).getParentFile();
+            final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
             mInheritedFilesBase = packageInstallDir;
             final File oatDir = new File(packageInstallDir, "oat");
             if (oatDir.exists()) {
@@ -822,7 +831,8 @@
         }
     }
 
-    private void assertApkConsistent(String tag, ApkLite apk) throws PackageManagerException {
+    private void assertApkConsistent(String tag, ApkLite apk)
+            throws PackageManagerException {
         if (!mPackageName.equals(apk.packageName)) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
                     + apk.packageName + " inconsistent with " + mPackageName);
@@ -1035,10 +1045,7 @@
                     "Failed to finalize container " + cid);
         }
 
-        final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
-                PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
-        final int gid = UserHandle.getSharedAppGid(uid);
-        if (!PackageHelper.fixSdPermissions(cid, gid, null)) {
+        if (!PackageHelper.fixSdPermissions(cid, defaultContainerGid, null)) {
             throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
                     "Failed to fix permissions on container " + cid);
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ab83c11..3d6fab1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -35,7 +35,6 @@
 import static android.content.pm.PackageManager.INSTALL_EXTERNAL;
 import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
 import static android.content.pm.PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER;
-import static android.content.pm.PackageManager.INSTALL_FAILED_DEXOPT;
 import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
 import static android.content.pm.PackageManager.INSTALL_FAILED_EPHEMERAL_INVALID;
@@ -101,7 +100,6 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
@@ -739,8 +737,7 @@
     final SparseArray<IntentFilterVerificationState> mIntentFilterVerificationStates
             = new SparseArray<IntentFilterVerificationState>();
 
-    final DefaultPermissionGrantPolicy mDefaultPermissionPolicy =
-            new DefaultPermissionGrantPolicy(this);
+    final DefaultPermissionGrantPolicy mDefaultPermissionPolicy;
 
     // List of packages names to keep cached, even if they are uninstalled for all users
     private List<String> mKeepUninstalledPackages;
@@ -2125,6 +2122,8 @@
             mProcessLoggingHandler = new ProcessLoggingHandler();
             Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
 
+            mDefaultPermissionPolicy = new DefaultPermissionGrantPolicy(this);
+
             File dataDir = Environment.getDataDirectory();
             mAppInstallDir = new File(dataDir, "app");
             mAppLib32InstallDir = new File(dataDir, "app-lib");
@@ -3998,7 +3997,7 @@
             // their permissions as always granted runtime ones since we need
             // to keep the review required permission flag per user while an
             // install permission's state is shared across all users.
-            if ((mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED)
+            if (mPermissionReviewRequired
                     && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
                     && bp.isRuntime()) {
                 return;
@@ -4109,7 +4108,7 @@
             // their permissions as always granted runtime ones since we need
             // to keep the review required permission flag per user while an
             // install permission's state is shared across all users.
-            if ((mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED)
+            if (mPermissionReviewRequired
                     && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
                     && bp.isRuntime()) {
                 return;
@@ -8423,6 +8422,10 @@
             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
         }
 
+        if (isSystemApp(pkg)) {
+            pkgSetting.isOrphaned = true;
+        }
+
         ArrayList<PackageParser.Package> clientLibPkgs = null;
 
         if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
@@ -8706,7 +8709,9 @@
             for (i=0; i<N; i++) {
                 PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);
                 PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name);
-                if (cur == null) {
+                final String curPackageName = cur == null ? null : cur.info.packageName;
+                final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName);
+                if (cur == null || isPackageUpdate) {
                     mPermissionGroups.put(pg.info.name, pg);
                     if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
                         if (r == null) {
@@ -8714,6 +8719,9 @@
                         } else {
                             r.append(' ');
                         }
+                        if (isPackageUpdate) {
+                            r.append("UPD:");
+                        }
                         r.append(pg.info.name);
                     }
                 } else {
@@ -9947,8 +9955,7 @@
                     // their permissions as always granted runtime ones since we need
                     // to keep the review required permission flag per user while an
                     // install permission's state is shared across all users.
-                    if (!appSupportsRuntimePermissions && !mPermissionReviewRequired
-                            && !Build.PERMISSIONS_REVIEW_REQUIRED) {
+                    if (!appSupportsRuntimePermissions && !mPermissionReviewRequired) {
                         // For legacy apps dangerous permissions are install time ones.
                         grant = GRANT_INSTALL;
                     } else if (origPermissions.hasInstallPermission(bp.name)) {
@@ -10034,7 +10041,7 @@
                                             changedRuntimePermissionUserIds, userId);
                                 }
                                 // If the app supports runtime permissions no need for a review.
-                                if ((mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED)
+                                if (mPermissionReviewRequired
                                         && appSupportsRuntimePermissions
                                         && (flags & PackageManager
                                                 .FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
@@ -10043,8 +10050,7 @@
                                     changedRuntimePermissionUserIds = ArrayUtils.appendInt(
                                             changedRuntimePermissionUserIds, userId);
                                 }
-                            } else if ((mPermissionReviewRequired
-                                        || Build.PERMISSIONS_REVIEW_REQUIRED)
+                            } else if (mPermissionReviewRequired
                                     && !appSupportsRuntimePermissions) {
                                 // For legacy apps that need a permission review, every new
                                 // runtime permission is granted but it is pending a review.
@@ -15379,6 +15385,19 @@
         Preconditions.checkNotNull(packageName);
         Preconditions.checkNotNull(observer);
         final int uid = Binder.getCallingUid();
+        if (uid != Process.SHELL_UID && uid != Process.ROOT_UID && uid != Process.SYSTEM_UID
+                && uid != getPackageUid(mRequiredInstallerPackage, 0, UserHandle.getUserId(uid))
+                && !isOrphaned(packageName)
+                && !isCallerSameAsInstaller(uid, packageName)) {
+            try {
+                final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
+                intent.setData(Uri.fromParts("package", packageName, null));
+                intent.putExtra(PackageInstaller.EXTRA_CALLBACK, observer.asBinder());
+                observer.onUserActionRequired(intent);
+            } catch (RemoteException re) {
+            }
+            return;
+        }
         final boolean deleteAllUsers = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0;
         final int[] users = deleteAllUsers ? sUserManager.getUserIds() : new int[]{ userId };
         if (UserHandle.getUserId(uid) != userId || (deleteAllUsers && users.length > 1)) {
@@ -15447,6 +15466,12 @@
         });
     }
 
+    private boolean isCallerSameAsInstaller(int callingUid, String pkgName) {
+        final int installerPkgUid = getPackageUid(getInstallerPackageName(pkgName),
+                0 /* flags */, UserHandle.getUserId(callingUid));
+        return installerPkgUid == callingUid;
+    }
+
     private int[] getBlockUninstallForUsers(String packageName, int[] userIds) {
         int[] result = EMPTY_INT_ARRAY;
         for (int userId : userIds) {
@@ -16533,7 +16558,7 @@
             // If permission review is enabled and this is a legacy app, mark the
             // permission as requiring a review as this is the initial state.
             int flags = 0;
-            if ((mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED)
+            if (mPermissionReviewRequired
                     && ps.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
                 flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
             }
@@ -18005,6 +18030,13 @@
             mDefaultPermissionPolicy.grantDefaultPermissions(userId);
         }
 
+        // If we did not grant default permissions, we preload from this the
+        // default permission exceptions lazily to ensure we don't hit the
+        // disk on a new user creation.
+        if (grantPermissionsUserIds == EMPTY_INT_ARRAY) {
+            mDefaultPermissionPolicy.scheduleReadDefaultPermissionExceptions();
+        }
+
         // Kick off any messages waiting for system ready
         if (mPostSystemReadyMessages != null) {
             for (Message msg : mPostSystemReadyMessages) {
@@ -20408,7 +20440,7 @@
         // permissions to keep per user flag state whether review is needed.
         // Hence, if a new user is added we have to propagate dangerous
         // permission grants for these legacy apps.
-        if (mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) {
+        if (mPermissionReviewRequired) {
             updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL
                     | UPDATE_PERMISSIONS_REPLACE_ALL);
         }
@@ -20862,7 +20894,7 @@
         public boolean isPermissionsReviewRequired(String packageName, int userId) {
             synchronized (mPackages) {
                 // If we do not support permission review, done.
-                if (!mPermissionReviewRequired && !Build.PERMISSIONS_REVIEW_REQUIRED) {
+                if (!mPermissionReviewRequired) {
                     return false;
                 }
 
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 827b88a..6f6fd7c 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -667,6 +667,12 @@
                 // - version code hasn't change
                 // - lastUpdateTime hasn't change
                 // - all target activities are still enabled.
+
+                // Note, system apps timestamps do *not* change after OTAs.  (But they do
+                // after an adb sync or a local flash.)
+                // This means if a system app's version code doesn't change on an OTA,
+                // we don't notice it's updated.  But that's fine since their version code *should*
+                // really change on OTAs.
                 if ((getPackageInfo().getVersionCode() == pi.versionCode)
                         && (getPackageInfo().getLastUpdateTime() == pi.lastUpdateTime)
                         && areAllActivitiesStillEnabled()) {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index c1fc7f1..adf19dc 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -54,6 +54,7 @@
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.Handler;
@@ -324,10 +325,30 @@
         int CHECK_LAUNCHER_ACTIVITY = 12;
         int IS_ACTIVITY_ENABLED = 13;
         int PACKAGE_UPDATE_CHECK = 14;
+        int ASYNC_PRELOAD_USER_DELAY = 15;
 
-        int COUNT = PACKAGE_UPDATE_CHECK + 1;
+        int COUNT = ASYNC_PRELOAD_USER_DELAY + 1;
     }
 
+    private static final String[] STAT_LABELS = {
+            "getHomeActivities()",
+            "Launcher permission check",
+            "getPackageInfo()",
+            "getPackageInfo(SIG)",
+            "getApplicationInfo",
+            "cleanupDanglingBitmaps",
+            "getActivity+metadata",
+            "getInstalledPackages",
+            "checkPackageChanges",
+            "getApplicationResources",
+            "resourceNameLookup",
+            "getLauncherActivity",
+            "checkLauncherActivity",
+            "isActivityEnabled",
+            "packageUpdateCheck",
+            "asyncPreloadUserDelay"
+    };
+
     final Object mStatLock = new Object();
 
     @GuardedBy("mStatLock")
@@ -533,19 +554,26 @@
     /** lifecycle event */
     void handleUnlockUser(int userId) {
         if (DEBUG) {
-            Slog.d(TAG, "handleUnlockUser: user=" + userId);
+        Slog.d(TAG, "handleUnlockUser: user=" + userId);
         }
         synchronized (mLock) {
             mUnlockedUsers.put(userId, true);
-
-            // Preload the user's shortcuts.
-            // Also see if the locale has changed.
-            // Note as of nyc, the locale is per-user, so the locale shouldn't change
-            // when the user is locked.  However due to b/30119489 it still happens.
-            getUserShortcutsLocked(userId).detectLocaleChange();
-
-            checkPackageChanges(userId);
         }
+
+        // Preload the user data.
+        // Note, we don't use mHandler here but instead just start a new thread.
+        // This is because mHandler (which uses com.android.internal.os.BackgroundThread) is very
+        // busy at this point and this could take hundreds of milliseconds, which would be too
+        // late since the launcher would already have started.
+        // So we just create a new thread.  This code runs rarely, so we don't use a thread pool
+        // or anything.
+        final long start = injectElapsedRealtime();
+        injectRunOnNewThread(() -> {
+            synchronized (mLock) {
+                logDurationStat(Stats.ASYNC_PRELOAD_USER_DELAY, start);
+                getUserShortcutsLocked(userId);
+            }
+        });
     }
 
     /** lifecycle event */
@@ -1110,6 +1138,9 @@
                 userPackages = new ShortcutUser(this, userId);
             }
             mUsers.put(userId, userPackages);
+
+            // Also when a user's data is first accessed, scan all packages.
+            checkPackageChanges(userId);
         }
         return userPackages;
     }
@@ -1468,6 +1499,10 @@
         mHandler.post(r);
     }
 
+    void injectRunOnNewThread(Runnable r) {
+        new Thread(r).start();
+    }
+
     /**
      * @throws IllegalArgumentException if {@code numShortcuts} is bigger than
      *                                  {@link #getMaxActivityShortcuts()}.
@@ -2625,10 +2660,14 @@
             boolean forceRescan) {
         final ShortcutUser user = getUserShortcutsLocked(userId);
 
+        // Note after each OTA, we'll need to rescan all system apps, as their lastUpdateTime
+        // is not reliable.
         final long now = injectCurrentTimeMillis();
+        final boolean afterOta =
+                !injectBuildFingerprint().equals(user.getLastAppScanOsFingerprint());
 
         // Then for each installed app, publish manifest shortcuts when needed.
-        forUpdatedPackages(userId, lastScanTime, ai -> {
+        forUpdatedPackages(userId, lastScanTime, afterOta, ai -> {
             user.attemptToRestoreIfNeededAndSave(this, ai.packageName, userId);
             user.rescanPackageIfNeeded(ai.packageName, forceRescan);
         });
@@ -2636,6 +2675,7 @@
         // Write the time just before the scan, because there may be apps that have just
         // been updated, and we want to catch them in the next time.
         user.setLastAppScanTime(now);
+        user.setLastAppScanOsFingerprint(injectBuildFingerprint());
         scheduleSaveUser(userId);
     }
 
@@ -2874,7 +2914,7 @@
         return parceledList.getList();
     }
 
-    private void forUpdatedPackages(@UserIdInt int userId, long lastScanTime,
+    private void forUpdatedPackages(@UserIdInt int userId, long lastScanTime, boolean afterOta,
             Consumer<ApplicationInfo> callback) {
         if (DEBUG) {
             Slog.d(TAG, "forUpdatedPackages for user " + userId + ", lastScanTime=" + lastScanTime);
@@ -2886,7 +2926,8 @@
             // If the package has been updated since the last scan time, then scan it.
             // Also if it's a system app with no update, lastUpdateTime is not reliable, so
             // just scan it.
-            if (pi.lastUpdateTime >= lastScanTime || isPureSystemApp(pi.applicationInfo)) {
+            if (pi.lastUpdateTime >= lastScanTime
+                    || (afterOta && isPureSystemApp(pi.applicationInfo))) {
                 if (DEBUG) {
                     Slog.d(TAG, "Found updated package " + pi.packageName);
                 }
@@ -3218,23 +3259,9 @@
 
             pw.println("  Stats:");
             synchronized (mStatLock) {
-                final String p = "    ";
-                dumpStatLS(pw, p, Stats.GET_DEFAULT_HOME, "getHomeActivities()");
-                dumpStatLS(pw, p, Stats.LAUNCHER_PERMISSION_CHECK, "Launcher permission check");
-
-                dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO, "getPackageInfo()");
-                dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO_WITH_SIG, "getPackageInfo(SIG)");
-                dumpStatLS(pw, p, Stats.GET_APPLICATION_INFO, "getApplicationInfo");
-                dumpStatLS(pw, p, Stats.CLEANUP_DANGLING_BITMAPS, "cleanupDanglingBitmaps");
-                dumpStatLS(pw, p, Stats.GET_ACTIVITY_WITH_METADATA, "getActivity+metadata");
-                dumpStatLS(pw, p, Stats.GET_INSTALLED_PACKAGES, "getInstalledPackages");
-                dumpStatLS(pw, p, Stats.CHECK_PACKAGE_CHANGES, "checkPackageChanges");
-                dumpStatLS(pw, p, Stats.GET_APPLICATION_RESOURCES, "getApplicationResources");
-                dumpStatLS(pw, p, Stats.RESOURCE_NAME_LOOKUP, "resourceNameLookup");
-                dumpStatLS(pw, p, Stats.GET_LAUNCHER_ACTIVITY, "getLauncherActivity");
-                dumpStatLS(pw, p, Stats.CHECK_LAUNCHER_ACTIVITY, "checkLauncherActivity");
-                dumpStatLS(pw, p, Stats.IS_ACTIVITY_ENABLED, "isActivityEnabled");
-                dumpStatLS(pw, p, Stats.PACKAGE_UPDATE_CHECK, "packageUpdateCheck");
+                for (int i = 0; i < Stats.COUNT; i++) {
+                    dumpStatLS(pw, "    ", i);
+                }
             }
 
             pw.println();
@@ -3277,12 +3304,12 @@
         return tobj.format("%Y-%m-%d %H:%M:%S");
     }
 
-    private void dumpStatLS(PrintWriter pw, String prefix, int statId, String label) {
+    private void dumpStatLS(PrintWriter pw, String prefix, int statId) {
         pw.print(prefix);
         final int count = mCountStats[statId];
         final long dur = mDurationStats[statId];
         pw.println(String.format("%s: count=%d, total=%dms, avg=%.1fms",
-                label, count, dur,
+                STAT_LABELS[statId], count, dur,
                 (count == 0 ? 0 : ((double) dur) / count)));
     }
 
@@ -3578,6 +3605,12 @@
         Binder.restoreCallingIdentity(token);
     }
 
+    // Injection point.
+    @VisibleForTesting
+    String injectBuildFingerprint() {
+        return Build.FINGERPRINT;
+    }
+
     final void wtf(String message) {
         wtf(message, /* exception= */ null);
     }
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index ce3ed9c..c05c66f 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -60,6 +60,7 @@
 
     // Suffix "2" was added to force rescan all packages after the next OTA.
     private static final String ATTR_LAST_APP_SCAN_TIME = "last-app-scan-time2";
+    private static final String ATTR_LAST_APP_SCAN_OS_FINGERPRINT = "last-app-scan-fp";
     private static final String KEY_USER_ID = "userId";
     private static final String KEY_LAUNCHERS = "launchers";
     private static final String KEY_PACKAGES = "packages";
@@ -125,6 +126,8 @@
 
     private long mLastAppScanTime;
 
+    private String mLastAppScanOsFingerprint;
+
     public ShortcutUser(ShortcutService service, int userId) {
         mService = service;
         mUserId = userId;
@@ -142,6 +145,14 @@
         mLastAppScanTime = lastAppScanTime;
     }
 
+    public String getLastAppScanOsFingerprint() {
+        return mLastAppScanOsFingerprint;
+    }
+
+    public void setLastAppScanOsFingerprint(String lastAppScanOsFingerprint) {
+        mLastAppScanOsFingerprint = lastAppScanOsFingerprint;
+    }
+
     // We don't expose this directly to non-test code because only ShortcutUser should add to/
     // remove from it.
     @VisibleForTesting
@@ -318,6 +329,8 @@
         ShortcutService.writeAttr(out, ATTR_KNOWN_LOCALES, mKnownLocales);
         ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_TIME,
                 mLastAppScanTime);
+        ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_OS_FINGERPRINT,
+                mLastAppScanOsFingerprint);
 
         ShortcutService.writeTagValue(out, TAG_LAUNCHER, mLastKnownLauncher);
 
@@ -364,7 +377,8 @@
                 ATTR_LAST_APP_SCAN_TIME);
         final long currentTime = s.injectCurrentTimeMillis();
         ret.mLastAppScanTime = lastAppScanTime < currentTime ? lastAppScanTime : 0;
-
+        ret.mLastAppScanOsFingerprint = ShortcutService.parseStringAttribute(parser,
+                ATTR_LAST_APP_SCAN_OS_FINGERPRINT);
         final int outerDepth = parser.getDepth();
         int type;
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -457,6 +471,8 @@
         pw.print(mLastAppScanTime);
         pw.print("] ");
         pw.print(ShortcutService.formatTime(mLastAppScanTime));
+        pw.print("  Last app scan FP: ");
+        pw.print(mLastAppScanOsFingerprint);
         pw.println();
 
         prefix += prefix + "  ";
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 7083ab7..4fff6ae 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -5401,6 +5401,9 @@
             mKeyguardOccluded = false;
             mKeyguardDelegate.setOccluded(false);
             mStatusBar.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD;
+            if (!mKeyguardDelegate.hasLockscreenWallpaper()) {
+                mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
+            }
             return true;
         } else if (!wasOccluded && isOccluded && showing) {
             mKeyguardOccluded = true;
@@ -7831,6 +7834,9 @@
         }
 
         final WindowState w = mTopFullscreenOpaqueWindowState;
+        if (w != mFocusedWindow) {
+            return false;
+        }
 
         // We only enable seamless rotation if the top window has requested
         // it and is in the fullscreen opaque state. Seamless rotation
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 ef6d92f..e4a9254 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -210,6 +210,13 @@
         return false;
     }
 
+    public boolean hasLockscreenWallpaper() {
+        if (mKeyguardService != null) {
+            return mKeyguardService.hasLockscreenWallpaper();
+        }
+        return false;
+    }
+
     public boolean isInputRestricted() {
         if (mKeyguardService != null) {
             mKeyguardState.inputRestricted = mKeyguardService.isInputRestricted();
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index 0274cb5..5a43568 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -247,6 +247,10 @@
         return mKeyguardStateMonitor.isTrusted();
     }
 
+    public boolean hasLockscreenWallpaper() {
+        return mKeyguardStateMonitor.hasLockscreenWallpaper();
+    }
+
     public boolean isSecure(int userId) {
         return mKeyguardStateMonitor.isSecure(userId);
     }
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index f3238c8..08eaaa9 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -44,6 +44,7 @@
     private volatile boolean mSimSecure = true;
     private volatile boolean mInputRestricted = true;
     private volatile boolean mTrusted = false;
+    private volatile boolean mHasLockscreenWallpaper = false;
 
     private int mCurrentUserId;
 
@@ -75,6 +76,10 @@
         return mTrusted;
     }
 
+    public boolean hasLockscreenWallpaper() {
+        return mHasLockscreenWallpaper;
+    }
+
     @Override // Binder interface
     public void onShowingStateChanged(boolean showing) {
         mIsShowing = showing;
@@ -103,6 +108,11 @@
         mTrusted = trusted;
     }
 
+    @Override // Binder interface
+    public void onHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper) {
+        mHasLockscreenWallpaper = hasLockscreenWallpaper;
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.println(prefix + TAG);
         prefix += "  ";
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index c952ee6..d219aed 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -860,16 +860,21 @@
         @Override
         public void setDeviceLockedForUser(int userId, boolean locked) {
             enforceReportPermission();
-            if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
-                synchronized (mDeviceLockedForUser) {
-                    mDeviceLockedForUser.put(userId, locked);
-                }
-                if (locked) {
-                    try {
-                        ActivityManagerNative.getDefault().notifyLockedProfile(userId);
-                    } catch (RemoteException e) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
+                    synchronized (mDeviceLockedForUser) {
+                        mDeviceLockedForUser.put(userId, locked);
+                    }
+                    if (locked) {
+                        try {
+                            ActivityManagerNative.getDefault().notifyLockedProfile(userId);
+                        } catch (RemoteException e) {
+                        }
                     }
                 }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
             }
         }
 
diff --git a/services/core/java/com/android/server/twilight/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java
index acd6587..db7df25 100644
--- a/services/core/java/com/android/server/twilight/TwilightService.java
+++ b/services/core/java/com/android/server/twilight/TwilightService.java
@@ -151,7 +151,7 @@
     }
 
     private void startListening() {
-        if (DEBUG) Slog.d(TAG, "startListening");
+        Slog.d(TAG, "startListening");
 
         // Start listening for location updates (default: low power, max 1h, min 10m).
         mLocationManager.requestLocationUpdates(
@@ -173,7 +173,7 @@
             mTimeChangedReceiver = new BroadcastReceiver() {
                 @Override
                 public void onReceive(Context context, Intent intent) {
-                    if (DEBUG) Slog.d(TAG, "onReceive: " + intent);
+                    Slog.d(TAG, "onReceive: " + intent);
                     updateTwilightState();
                 }
             };
@@ -188,7 +188,7 @@
     }
 
     private void stopListening() {
-        if (DEBUG) Slog.d(TAG, "stopListening");
+        Slog.d(TAG, "stopListening");
 
         if (mTimeChangedReceiver != null) {
             getContext().unregisterReceiver(mTimeChangedReceiver);
@@ -241,15 +241,20 @@
 
     @Override
     public void onAlarm() {
-        if (DEBUG) Slog.d(TAG, "onAlarm");
+        Slog.d(TAG, "onAlarm");
         updateTwilightState();
     }
 
     @Override
     public void onLocationChanged(Location location) {
-        if (DEBUG) Slog.d(TAG, "onLocationChanged: " + location);
-        mLastLocation = location;
-        updateTwilightState();
+        if (location != null) {
+            Slog.d(TAG, "onLocationChanged:"
+                    + " provider=" + location.getProvider()
+                    + " accuracy=" + location.getAccuracy()
+                    + " time=" + location.getTime());
+            mLastLocation = location;
+            updateTwilightState();
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 76f2f0e..8aeb626 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1350,7 +1350,9 @@
     @Override
     public ParcelFileDescriptor setWallpaper(String name, String callingPackage,
             Rect cropHint, boolean allowBackup, Bundle extras, int which,
-            IWallpaperManagerCallback completion) {
+            IWallpaperManagerCallback completion, int userId) {
+        userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
+                false /* all */, true /* full */, "changing wallpaper", null /* pkg */);
         checkPermission(android.Manifest.permission.SET_WALLPAPER);
 
         if ((which & (FLAG_LOCK|FLAG_SYSTEM)) == 0) {
@@ -1374,8 +1376,6 @@
             }
         }
 
-        final int userId = UserHandle.getCallingUserId();
-
         synchronized (mLock) {
             if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which));
             WallpaperData wallpaper;
@@ -1757,8 +1757,8 @@
         }
 
         WallpaperData wallpaper = (which == FLAG_LOCK)
-                ? mWallpaperMap.get(userId)
-                : mLockWallpaperMap.get(userId);
+                ? mLockWallpaperMap.get(userId)
+                : mWallpaperMap.get(userId);
         return (wallpaper != null) ? wallpaper.allowBackup : false;
     }
 
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 2d60f43..0605d80 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -358,6 +358,7 @@
                     }
                     switch (type) {
                         case WindowManager.LayoutParams.TYPE_APPLICATION:
+                        case WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION:
                         case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
                         case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
                         case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 05c05b1..e62d810 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1024,8 +1024,8 @@
                 //
                 // As we use this flag as a hint to freeze surface boundary updates,
                 // we'd like to only apply this to TYPE_BASE_APPLICATION,
-                // windows of TYPE_APPLICATION like dialogs, could appear
-                // to not be drag resizing while they resize, but we'd
+                // windows of TYPE_APPLICATION (or TYPE_DRAWN_APPLICATION) like dialogs,
+                // could appear to not be drag resizing while they resize, but we'd
                 // still like to manipulate their frame to update crop, etc...
                 //
                 // Anyway we don't need to synchronize position and content updates for these
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 19ad5e4..3819ebf 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -192,6 +192,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
@@ -2300,12 +2301,11 @@
                     }
                     result |= RELAYOUT_RES_SURFACE_CHANGED;
                 }
-                final WindowSurfaceController surfaceController = winAnimator.mSurfaceController;
-                if (viewVisibility == View.VISIBLE && surfaceController != null) {
+                if (viewVisibility == View.VISIBLE && winAnimator.hasSurface()) {
                     // We already told the client to go invisible, but the message may not be
                     // handled yet, or it might want to draw a last frame. If we already have a
                     // surface, let the client use that, but don't create new surface at this point.
-                    surfaceController.getSurface(outSurface);
+                    winAnimator.mSurfaceController.getSurface(outSurface);
                 } else {
                     if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Releasing surface in: " + win);
 
@@ -4890,7 +4890,8 @@
             if (w.isDrawnLw()) {
                 if (w.mAttrs.type == TYPE_BOOT_PROGRESS) {
                     haveBootMsg = true;
-                } else if (w.mAttrs.type == TYPE_APPLICATION) {
+                } else if (w.mAttrs.type == TYPE_APPLICATION
+                        || w.mAttrs.type == TYPE_DRAWN_APPLICATION) {
                     haveApp = true;
                 } else if (w.mAttrs.type == TYPE_WALLPAPER) {
                     haveWallpaper = true;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c83c083..cb8660b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -93,6 +93,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
@@ -1280,7 +1281,8 @@
         final boolean isViewVisible = (mAppToken == null || !mAppToken.clientHidden)
                 && (mViewVisibility == View.VISIBLE) && !mWindowRemovalAllowed;
         return (isOnScreenIgnoringKeyguard() && (!visibleOnly || isViewVisible)
-                || mWinAnimator.mAttrType == TYPE_BASE_APPLICATION)
+                || mWinAnimator.mAttrType == TYPE_BASE_APPLICATION
+                || mWinAnimator.mAttrType == TYPE_DRAWN_APPLICATION)
                 && !mAnimatingExit && !mDestroying;
     }
 
@@ -2272,6 +2274,8 @@
             mWinAnimator.mDrawState = READY_TO_SHOW;
             mAnimatingWithSavedSurface = true;
 
+            requestUpdateWallpaperIfNeeded();
+
             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
                 Slog.v(TAG, "Restoring saved surface: " + this);
             }
@@ -3090,12 +3094,13 @@
     // for only child windows (as the main window is handled by window preservation)
     // and the big surface.
     //
-    // Though windows of TYPE_APPLICATION (as opposed to TYPE_BASE_APPLICATION)
-    // are not children in the sense of an attached window, we also want to replace
-    // them at such phases, as they won't be covered by window preservation,
-    // and in general we expect them to return following relaunch.
+    // Though windows of TYPE_APPLICATION or TYPE_DRAWN_APPLICATION (as opposed to
+    // TYPE_BASE_APPLICATION) are not children in the sense of an attached window,
+    // we also want to replace them at such phases, as they won't be covered by window
+    // preservation, and in general we expect them to return following relaunch.
     boolean shouldBeReplacedWithChildren() {
-        return mIsChildWindow || mAttrs.type == TYPE_APPLICATION;
+        return mIsChildWindow || mAttrs.type == TYPE_APPLICATION
+                || mAttrs.type == TYPE_DRAWN_APPLICATION;
     }
 
     public int getRotationAnimationHint() {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 46ce398..b28843a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -9131,4 +9131,28 @@
             return policy.mDeviceProvisioningConfigApplied;
         }
     }
+
+    /**
+     * Force update internal persistent state from Settings.Secure.USER_SETUP_COMPLETE.
+     *
+     * It's added for testing only. Please use this API carefully if it's used by other system app
+     * and bare in mind Settings.Secure.USER_SETUP_COMPLETE can be modified by user and other system
+     * apps.
+     */
+    @Override
+    public void forceUpdateUserSetupComplete() {
+        enforceCanManageProfileAndDeviceOwners();
+        List<UserInfo> users = mUserManager.getUsers(true);
+        final int N = users.size();
+        for (int i = 0; i < N; i++) {
+            int userHandle = users.get(i).id;
+            boolean isUserCompleted = mInjector.settingsSecureGetIntForUser(
+                    Settings.Secure.USER_SETUP_COMPLETE, 0, userHandle) != 0;
+            DevicePolicyData policy = getUserData(userHandle);
+            policy.mUserSetupComplete = isUserCompleted;
+            synchronized (this) {
+                saveSettingsLocked(userHandle);
+            }
+        }
+    }
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 548f831..2524600 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -498,6 +498,9 @@
      * Starts some essential services that are not tangled up in the bootstrap process.
      */
     private void startCoreServices() {
+        // Records errors and logs, for example wtf()
+        mSystemServiceManager.startService(DropBoxManagerService.class);
+
         // Tracks the battery level.  Requires LightService.
         mSystemServiceManager.startService(BatteryService.class);
 
@@ -930,8 +933,6 @@
                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
 
-            mSystemServiceManager.startService(DropBoxManagerService.class);
-
             if (!disableNonCoreServices && context.getResources().getBoolean(
                         R.bool.config_enableWallpaperService)) {
                 traceBeginAndSlog("StartWallpaperManagerService");
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 654ef18..6d90203 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -382,6 +382,7 @@
     private final State mStoppedState = new StoppedState();
     private final State mStoppingState = new StoppingState();
     private final State mStartedState = new StartedState();
+    private final State mRunningState = new RunningState();
 
     private final String mTag;
     private final Context mContext;
@@ -476,6 +477,7 @@
         // Super simple StateMachine.
         addState(mStoppedState);
         addState(mStartedState);
+            addState(mRunningState, mStartedState);
         addState(mStoppingState);
 
         setInitialState(mStoppedState);
@@ -570,7 +572,7 @@
         pw.decreaseIndent();
 
         pw.println();
-        pw.println("StateMachine dump:");
+        pw.println(mTag + " StateMachine dump:");
         pw.increaseIndent();
         mLocalLog.readOnlyLocalLog().dump(fd, pw, args);
         pw.decreaseIndent();
@@ -768,6 +770,11 @@
         //         - IPv6 addresses
         //         - IPv6 routes
         //         - IPv6 DNS servers
+        //
+        // N.B.: this is fundamentally race-prone and should be fixed by
+        // changing NetlinkTracker from a hybrid edge/level model to an
+        // edge-only model, or by giving IpManager its own netlink socket(s)
+        // so as to track all required information directly.
         LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties();
         newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
         for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
@@ -939,16 +946,30 @@
         return true;
     }
 
+    private void stopAllIP() {
+        // We don't need to worry about routes, just addresses, because:
+        //     - disableIpv6() will clear autoconf IPv6 routes as well, and
+        //     - we don't get IPv4 routes from netlink
+        // so we neither react to nor need to wait for changes in either.
+
+        try {
+            mNwService.disableIpv6(mInterfaceName);
+        } catch (Exception e) {
+            Log.e(mTag, "Failed to disable IPv6" + e);
+        }
+
+        try {
+            mNwService.clearInterfaceAddresses(mInterfaceName);
+        } catch (Exception e) {
+            Log.e(mTag, "Failed to clear addresses " + e);
+        }
+    }
+
 
     class StoppedState extends State {
         @Override
         public void enter() {
-            try {
-                mNwService.disableIpv6(mInterfaceName);
-                mNwService.clearInterfaceAddresses(mInterfaceName);
-            } catch (Exception e) {
-                Log.e(mTag, "Failed to clear addresses or disable IPv6" + e);
-            }
+            stopAllIP();
 
             resetLinkProperties();
             if (mStartTimeMillis > 0) {
@@ -1023,12 +1044,71 @@
     }
 
     class StartedState extends State {
-        private boolean mDhcpActionInFlight;
-
         @Override
         public void enter() {
             mStartTimeMillis = SystemClock.elapsedRealtime();
 
+            if (mConfiguration.mProvisioningTimeoutMs > 0) {
+                final long alarmTime = SystemClock.elapsedRealtime() +
+                        mConfiguration.mProvisioningTimeoutMs;
+                mProvisioningTimeoutAlarm.schedule(alarmTime);
+            }
+
+            if (readyToProceed()) {
+                transitionTo(mRunningState);
+            } else {
+                // Clear all IPv4 and IPv6 before proceeding to RunningState.
+                // Clean up any leftover state from an abnormal exit from
+                // tethering or during an IpManager restart.
+                stopAllIP();
+            }
+        }
+
+        @Override
+        public void exit() {
+            mProvisioningTimeoutAlarm.cancel();
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_STOP:
+                    transitionTo(mStoppingState);
+                    break;
+
+                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
+                    handleLinkPropertiesUpdate(NO_CALLBACKS);
+                    if (readyToProceed()) {
+                        transitionTo(mRunningState);
+                    }
+                    break;
+
+                case EVENT_PROVISIONING_TIMEOUT:
+                    handleProvisioningFailure();
+                    break;
+
+                default:
+                    // It's safe to process messages out of order because the
+                    // only message that can both
+                    //     a) be received at this time and
+                    //     b) affect provisioning state
+                    // is EVENT_NETLINK_LINKPROPERTIES_CHANGED (handled above).
+                    deferMessage(msg);
+            }
+            return HANDLED;
+        }
+
+        boolean readyToProceed() {
+            return (!mLinkProperties.hasIPv4Address() &&
+                    !mLinkProperties.hasGlobalIPv6Address());
+        }
+    }
+
+    class RunningState extends State {
+        private boolean mDhcpActionInFlight;
+
+        @Override
+        public void enter() {
             mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
                     mCallback, mMulticastFiltering);
             // TODO: investigate the effects of any multicast filtering racing/interfering with the
@@ -1037,12 +1117,6 @@
                 mCallback.setFallbackMulticastFilter(mMulticastFiltering);
             }
 
-            if (mConfiguration.mProvisioningTimeoutMs > 0) {
-                final long alarmTime = SystemClock.elapsedRealtime() +
-                        mConfiguration.mProvisioningTimeoutMs;
-                mProvisioningTimeoutAlarm.schedule(alarmTime);
-            }
-
             if (mConfiguration.mEnableIPv6) {
                 // TODO: Consider transitionTo(mStoppingState) if this fails.
                 startIPv6();
@@ -1070,7 +1144,6 @@
 
         @Override
         public void exit() {
-            mProvisioningTimeoutAlarm.cancel();
             stopDhcpAction();
 
             if (mIpReachabilityMonitor != null) {
@@ -1167,10 +1240,6 @@
                     break;
                 }
 
-                case EVENT_PROVISIONING_TIMEOUT:
-                    handleProvisioningFailure();
-                    break;
-
                 case EVENT_DHCPACTION_TIMEOUT:
                     stopDhcpAction();
                     break;
diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
index 6b273210..1612b99 100644
--- a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
+++ b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
@@ -26,7 +26,6 @@
 import android.app.RetailDemoModeServiceInternal;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
-import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -63,6 +62,7 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
@@ -81,7 +81,8 @@
     private static final String DEMO_USER_NAME = "Demo";
     private static final String ACTION_RESET_DEMO =
             "com.android.server.retaildemo.ACTION_RESET_DEMO";
-    private static final String SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED = "sys.retaildemo.enabled";
+    @VisibleForTesting
+    static final String SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED = "sys.retaildemo.enabled";
 
     private static final int MSG_TURN_SCREEN_ON = 0;
     private static final int MSG_INACTIVITY_TIME_OUT = 1;
@@ -93,7 +94,8 @@
     private static final long WARNING_DIALOG_TIMEOUT_DEFAULT = 0;
     private static final long MILLIS_PER_SECOND = 1000;
 
-    private static final int[] VOLUME_STREAMS_TO_MUTE = {
+    @VisibleForTesting
+    static final int[] VOLUME_STREAMS_TO_MUTE = {
             AudioSystem.STREAM_RING,
             AudioSystem.STREAM_MUSIC
     };
@@ -106,19 +108,10 @@
     int mCurrentUserId = UserHandle.USER_SYSTEM;
     long mUserInactivityTimeout;
     long mWarningDialogTimeout;
-    private ActivityManagerService mAms;
-    private ActivityManagerInternal mAmi;
-    private AudioManager mAudioManager;
-    private NotificationManager mNm;
-    private UserManager mUm;
-    private PowerManager mPm;
-    private PowerManager.WakeLock mWakeLock;
+    private Injector mInjector;
     Handler mHandler;
     private ServiceThread mHandlerThread;
-    private PendingIntent mResetDemoPendingIntent;
-    private CameraManager mCameraManager;
     private String[] mCameraIdsWithFlash;
-    private Configuration mSystemUserConfiguration;
     private PreloadAppsInstaller mPreloadAppsInstaller;
 
     final Object mActivityLock = new Object();
@@ -158,10 +151,10 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_TURN_SCREEN_ON:
-                    if (mWakeLock.isHeld()) {
-                        mWakeLock.release();
+                    if (mInjector.isWakeLockHeld()) {
+                        mInjector.releaseWakeLock();
                     }
-                    mWakeLock.acquire();
+                    mInjector.acquireWakeLock();
                     break;
                 case MSG_INACTIVITY_TIME_OUT:
                     if (isDemoLauncherDisabled()) {
@@ -178,18 +171,19 @@
                     if (mCurrentUserId != UserHandle.USER_SYSTEM) {
                         logSessionDuration();
                     }
-                    final UserInfo demoUser = getUserManager().createUser(DEMO_USER_NAME,
+                    final UserInfo demoUser = mInjector.getUserManager().createUser(DEMO_USER_NAME,
                             UserInfo.FLAG_DEMO | UserInfo.FLAG_EPHEMERAL);
                     if (demoUser != null) {
                         setupDemoUser(demoUser);
-                        getActivityManager().switchUser(demoUser.id);
+                        mInjector.switchUser(demoUser.id);
                     }
                     break;
             }
         }
     }
 
-    private class SettingsObserver extends ContentObserver {
+    @VisibleForTesting
+    class SettingsObserver extends ContentObserver {
 
         private final static String KEY_USER_INACTIVITY_TIMEOUT = "user_inactivity_timeout_ms";
         private final static String KEY_WARNING_DIALOG_TIMEOUT = "warning_dialog_timeout_ms";
@@ -208,7 +202,7 @@
         }
 
         public void register() {
-            ContentResolver cr = getContext().getContentResolver();
+            ContentResolver cr = mInjector.getContentResolver();
             cr.registerContentObserver(mDeviceDemoModeUri, false, this, UserHandle.USER_SYSTEM);
             cr.registerContentObserver(mDeviceProvisionedUri, false, this, UserHandle.USER_SYSTEM);
             cr.registerContentObserver(mRetailDemoConstantsUri, false, this,
@@ -226,9 +220,9 @@
                 if (mDeviceInDemoMode) {
                     putDeviceInDemoMode();
                 } else {
-                    SystemProperties.set(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, "0");
-                    if (mWakeLock.isHeld()) {
-                        mWakeLock.release();
+                    mInjector.systemPropertiesSet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, "0");
+                    if (mInjector.isWakeLockHeld()) {
+                        mInjector.releaseWakeLock();
                     }
                 }
             }
@@ -248,8 +242,8 @@
 
         private void refreshTimeoutConstants() {
             try {
-                mParser.setString(Settings.Global.getString(getContext().getContentResolver(),
-                    Settings.Global.RETAIL_DEMO_MODE_CONSTANTS));
+                mParser.setString(Settings.Global.getString(mInjector.getContentResolver(),
+                        Settings.Global.RETAIL_DEMO_MODE_CONSTANTS));
             } catch (IllegalArgumentException exc) {
                 Slog.e(TAG, "Invalid string passed to KeyValueListParser");
                 // Consuming the exception to fall back to default values.
@@ -282,35 +276,21 @@
     }
 
     public RetailDemoModeService(Context context) {
-        super(context);
+        this(new Injector(context));
+    }
+
+    @VisibleForTesting
+    RetailDemoModeService(Injector injector) {
+        super(injector.getContext());
+
+        mInjector = injector;
         synchronized (mActivityLock) {
             mFirstUserActivityTime = mLastUserActivityTime = SystemClock.uptimeMillis();
         }
     }
 
-    private Notification createResetNotification() {
-        return new Notification.Builder(getContext())
-                .setContentTitle(getContext().getString(R.string.reset_retail_demo_mode_title))
-                .setContentText(getContext().getString(R.string.reset_retail_demo_mode_text))
-                .setOngoing(true)
-                .setSmallIcon(R.drawable.platlogo)
-                .setShowWhen(false)
-                .setVisibility(Notification.VISIBILITY_PUBLIC)
-                .setContentIntent(getResetDemoPendingIntent())
-                .setColor(getContext().getColor(R.color.system_notification_accent_color))
-                .build();
-    }
-
-    private PendingIntent getResetDemoPendingIntent() {
-        if (mResetDemoPendingIntent == null) {
-            Intent intent = new Intent(ACTION_RESET_DEMO);
-            mResetDemoPendingIntent = PendingIntent.getBroadcast(getContext(), 0, intent, 0);
-        }
-        return mResetDemoPendingIntent;
-    }
-
     boolean isDemoLauncherDisabled() {
-        IPackageManager pm = AppGlobals.getPackageManager();
+        IPackageManager pm = mInjector.getIPackageManager();
         int enabledState = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
         String demoLauncherComponent = getContext().getResources()
                 .getString(R.string.config_demoModeLauncherComponent);
@@ -325,7 +305,7 @@
     }
 
     private void setupDemoUser(UserInfo userInfo) {
-        UserManager um = getUserManager();
+        UserManager um = mInjector.getUserManager();
         UserHandle user = UserHandle.of(userInfo.id);
         um.setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, user);
         um.setUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true, user);
@@ -336,19 +316,19 @@
         // Set this to false because the default is true on user creation
         um.setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, false, user);
         // Disallow rebooting in safe mode - controlled by user 0
-        getUserManager().setUserRestriction(UserManager.DISALLOW_SAFE_BOOT, true,
-                UserHandle.SYSTEM);
-        Settings.Secure.putIntForUser(getContext().getContentResolver(),
+        um.setUserRestriction(UserManager.DISALLOW_SAFE_BOOT, true, UserHandle.SYSTEM);
+        Settings.Secure.putIntForUser(mInjector.getContentResolver(),
                 Settings.Secure.SKIP_FIRST_USE_HINTS, 1, userInfo.id);
-        Settings.Global.putInt(getContext().getContentResolver(),
+        Settings.Global.putInt(mInjector.getContentResolver(),
                 Settings.Global.PACKAGE_VERIFIER_ENABLE, 0);
+
         grantRuntimePermissionToCamera(user);
         clearPrimaryCallLog();
     }
 
     private void grantRuntimePermissionToCamera(UserHandle user) {
         final Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
-        final PackageManager pm = getContext().getPackageManager();
+        final PackageManager pm = mInjector.getPackageManager();
         final ResolveInfo handler = pm.resolveActivityAsUser(cameraIntent,
                 PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                 user.getIdentifier());
@@ -364,7 +344,7 @@
     }
 
     private void clearPrimaryCallLog() {
-        final ContentResolver resolver = getContext().getContentResolver();
+        final ContentResolver resolver = mInjector.getContentResolver();
 
         // Deleting primary user call log so that it doesn't get copied to the new demo user
         final Uri uri = CallLog.Calls.CONTENT_URI;
@@ -380,37 +360,16 @@
         synchronized (mActivityLock) {
             sessionDuration = (int) ((mLastUserActivityTime - mFirstUserActivityTime) / 1000);
         }
-        MetricsLogger.histogram(getContext(), DEMO_SESSION_DURATION, sessionDuration);
-    }
-
-    private ActivityManagerService getActivityManager() {
-        if (mAms == null) {
-            mAms = (ActivityManagerService) ActivityManagerNative.getDefault();
-        }
-        return mAms;
-    }
-
-    private UserManager getUserManager() {
-        if (mUm == null) {
-            mUm = getContext().getSystemService(UserManager.class);
-        }
-        return mUm;
-    }
-
-    private AudioManager getAudioManager() {
-        if (mAudioManager == null) {
-            mAudioManager = getContext().getSystemService(AudioManager.class);
-        }
-        return mAudioManager;
+        mInjector.logSessionDuration(sessionDuration);
     }
 
     private boolean isDeviceProvisioned() {
         return Settings.Global.getInt(
-                getContext().getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+                mInjector.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0;
     }
 
     private boolean deletePreloadsFolderContents() {
-        final File dir = Environment.getDataPreloadsDirectory();
+        final File dir = mInjector.getDataPreloadsDirectory();
         Slog.i(TAG, "Deleting contents of " + dir);
         return FileUtils.deleteContents(dir);
     }
@@ -424,46 +383,31 @@
 
     private String[] getCameraIdsWithFlash() {
         ArrayList<String> cameraIdsList = new ArrayList<String>();
-        try {
-            for (String cameraId : mCameraManager.getCameraIdList()) {
-                CameraCharacteristics c = mCameraManager.getCameraCharacteristics(cameraId);
-                if (Boolean.TRUE.equals(c.get(CameraCharacteristics.FLASH_INFO_AVAILABLE))) {
-                    cameraIdsList.add(cameraId);
+        final CameraManager cm = mInjector.getCameraManager();
+        if (cm != null) {
+            try {
+                for (String cameraId : cm.getCameraIdList()) {
+                    CameraCharacteristics c = cm.getCameraCharacteristics(cameraId);
+                    if (Boolean.TRUE.equals(c.get(CameraCharacteristics.FLASH_INFO_AVAILABLE))) {
+                        cameraIdsList.add(cameraId);
+                    }
                 }
+            } catch (CameraAccessException e) {
+                Slog.e(TAG, "Unable to access camera while getting camera id list", e);
             }
-        } catch (CameraAccessException e) {
-            Slog.e(TAG, "Unable to access camera while getting camera id list", e);
         }
         return cameraIdsList.toArray(new String[cameraIdsList.size()]);
     }
 
-    private void turnOffAllFlashLights() {
-        for (String cameraId : mCameraIdsWithFlash) {
-            try {
-                mCameraManager.setTorchMode(cameraId, false);
-            } catch (CameraAccessException e) {
-                Slog.e(TAG, "Unable to access camera " + cameraId + " while turning off flash", e);
-            }
-        }
-    }
-
     private void muteVolumeStreams() {
         for (int stream : VOLUME_STREAMS_TO_MUTE) {
-            getAudioManager().setStreamVolume(stream, getAudioManager().getStreamMinVolume(stream),
-                    0);
+            mInjector.getAudioManager().setStreamVolume(stream,
+                    mInjector.getAudioManager().getStreamMinVolume(stream), 0);
         }
     }
 
-    private Configuration getSystemUsersConfiguration() {
-        if (mSystemUserConfiguration == null) {
-            Settings.System.getConfiguration(getContext().getContentResolver(),
-                    mSystemUserConfiguration = new Configuration());
-        }
-        return mSystemUserConfiguration;
-    }
-
     private void putDeviceInDemoMode() {
-        SystemProperties.set(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, "1");
+        mInjector.systemPropertiesSet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, "1");
         mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
     }
 
@@ -483,16 +427,8 @@
     public void onBootPhase(int bootPhase) {
         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);
+                mPreloadAppsInstaller = mInjector.getPreloadAppsInstaller();
+                mInjector.initializeWakeLock();
                 mCameraIdsWithFlash = getCameraIdsWithFlash();
                 SettingsObserver settingsObserver = new SettingsObserver(mHandler);
                 settingsObserver.register();
@@ -516,27 +452,28 @@
         if (DEBUG) {
             Slog.d(TAG, "onSwitchUser: " + userId);
         }
-        final UserInfo ui = getUserManager().getUserInfo(userId);
+        final UserInfo ui = mInjector.getUserManager().getUserInfo(userId);
         if (!ui.isDemo()) {
             Slog.wtf(TAG, "Should not allow switch to non-demo user in demo mode");
             return;
         }
-        if (!mWakeLock.isHeld()) {
-            mWakeLock.acquire();
+        if (!mInjector.isWakeLockHeld()) {
+            mInjector.acquireWakeLock();
         }
         mCurrentUserId = userId;
-        mAmi.updatePersistentConfigurationForUser(getSystemUsersConfiguration(), userId);
-        turnOffAllFlashLights();
+        mInjector.getActivityManagerInternal().updatePersistentConfigurationForUser(
+                mInjector.getSystemUsersConfiguration(), userId);
+        mInjector.turnOffAllFlashLights(mCameraIdsWithFlash);
         muteVolumeStreams();
         // Disable lock screen for demo users.
-        LockPatternUtils lockPatternUtils = new LockPatternUtils(getContext());
-        lockPatternUtils.setLockScreenDisabled(true, userId);
-        mNm.notifyAsUser(TAG, 1, createResetNotification(), UserHandle.of(userId));
+        mInjector.getLockPatternUtils().setLockScreenDisabled(true, userId);
+        mInjector.getNotificationManager().notifyAsUser(TAG,
+                1, mInjector.createResetNotification(), UserHandle.of(userId));
 
         synchronized (mActivityLock) {
             mUserUntouched = true;
         }
-        MetricsLogger.count(getContext(), DEMO_SESSION_COUNT, 1);
+        mInjector.logSessionCount(1);
         mHandler.removeMessages(MSG_INACTIVITY_TIME_OUT);
         mHandler.post(new Runnable() {
             @Override
@@ -570,4 +507,174 @@
             mHandler.sendEmptyMessageDelayed(MSG_INACTIVITY_TIME_OUT, mUserInactivityTimeout);
         }
     };
+
+    static class Injector {
+        private Context mContext;
+        private UserManager mUm;
+        private PackageManager mPm;
+        private NotificationManager mNm;
+        private ActivityManagerService mAms;
+        private ActivityManagerInternal mAmi;
+        private AudioManager mAudioManager;
+        private PowerManager mPowerManager;
+        private CameraManager mCameraManager;
+        private PowerManager.WakeLock mWakeLock;
+        private Configuration mSystemUserConfiguration;
+        private PendingIntent mResetDemoPendingIntent;
+
+        Injector(Context context) {
+            mContext = context;
+        }
+
+        Context getContext() {
+            return mContext;
+        }
+
+        UserManager getUserManager() {
+            if (mUm == null) {
+                mUm = getContext().getSystemService(UserManager.class);
+            }
+            return mUm;
+        }
+
+        void switchUser(int userId) {
+            if (mAms == null) {
+                mAms = (ActivityManagerService) ActivityManagerNative.getDefault();
+            }
+            mAms.switchUser(userId);
+        }
+
+        AudioManager getAudioManager() {
+            if (mAudioManager == null) {
+                mAudioManager = getContext().getSystemService(AudioManager.class);
+            }
+            return mAudioManager;
+        }
+
+        private PowerManager getPowerManager() {
+            if (mPowerManager == null) {
+                mPowerManager = (PowerManager) getContext().getSystemService(
+                        Context.POWER_SERVICE);
+            }
+            return mPowerManager;
+        }
+
+        NotificationManager getNotificationManager() {
+            if (mNm == null) {
+                mNm = NotificationManager.from(getContext());
+            }
+            return mNm;
+        }
+
+        ActivityManagerInternal getActivityManagerInternal() {
+            if (mAmi == null) {
+                mAmi = LocalServices.getService(ActivityManagerInternal.class);
+            }
+            return mAmi;
+        }
+
+        CameraManager getCameraManager() {
+            if (mCameraManager == null) {
+                mCameraManager = (CameraManager) getContext().getSystemService(
+                        Context.CAMERA_SERVICE);
+            }
+            return mCameraManager;
+        }
+
+        PackageManager getPackageManager() {
+            if (mPm == null) {
+                mPm = getContext().getPackageManager();
+            }
+            return mPm;
+        }
+
+        IPackageManager getIPackageManager() {
+            return AppGlobals.getPackageManager();
+        }
+
+        ContentResolver getContentResolver() {
+            return getContext().getContentResolver();
+        }
+
+        PreloadAppsInstaller getPreloadAppsInstaller() {
+            return new PreloadAppsInstaller(getContext());
+        }
+
+        void systemPropertiesSet(String key, String value) {
+            SystemProperties.set(key, value);
+        }
+
+        void turnOffAllFlashLights(String[] cameraIdsWithFlash) {
+            for (String cameraId : cameraIdsWithFlash) {
+                try {
+                    getCameraManager().setTorchMode(cameraId, false);
+                } catch (CameraAccessException e) {
+                    Slog.e(TAG, "Unable to access camera " + cameraId
+                            + " while turning off flash", e);
+                }
+            }
+        }
+
+        void initializeWakeLock() {
+            mWakeLock = getPowerManager().newWakeLock(
+                    PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, TAG);
+        }
+
+        boolean isWakeLockHeld() {
+            return mWakeLock.isHeld();
+        }
+
+        void acquireWakeLock() {
+            mWakeLock.acquire();
+        }
+
+        void releaseWakeLock() {
+            mWakeLock.release();
+        }
+
+        void logSessionDuration(int duration) {
+            MetricsLogger.histogram(getContext(), DEMO_SESSION_DURATION, duration);
+        }
+
+        void logSessionCount(int count) {
+            MetricsLogger.count(getContext(), DEMO_SESSION_COUNT, count);
+        }
+
+        Configuration getSystemUsersConfiguration() {
+            if (mSystemUserConfiguration == null) {
+                Settings.System.getConfiguration(getContentResolver(),
+                        mSystemUserConfiguration = new Configuration());
+            }
+            return mSystemUserConfiguration;
+        }
+
+        LockPatternUtils getLockPatternUtils() {
+            return new LockPatternUtils(getContext());
+        }
+
+        Notification createResetNotification() {
+            return new Notification.Builder(getContext())
+                    .setContentTitle(getContext().getString(R.string.reset_retail_demo_mode_title))
+                    .setContentText(getContext().getString(R.string.reset_retail_demo_mode_text))
+                    .setOngoing(true)
+                    .setSmallIcon(R.drawable.platlogo)
+                    .setShowWhen(false)
+                    .setVisibility(Notification.VISIBILITY_PUBLIC)
+                    .setContentIntent(getResetDemoPendingIntent())
+                    .setColor(getContext().getColor(R.color.system_notification_accent_color))
+                    .build();
+        }
+
+        private PendingIntent getResetDemoPendingIntent() {
+            if (mResetDemoPendingIntent == null) {
+                Intent intent = new Intent(ACTION_RESET_DEMO);
+                mResetDemoPendingIntent = PendingIntent.getBroadcast(getContext(), 0, intent, 0);
+            }
+            return mResetDemoPendingIntent;
+        }
+
+        File getDataPreloadsDirectory() {
+            return Environment.getDataPreloadsDirectory();
+        }
+    }
 }
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index fb8d814..89b5adc 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -17,8 +17,8 @@
     services.core \
     services.devicepolicy \
     services.net \
+    services.retaildemo \
     services.usage \
-    easymocklib \
     guava \
     android-support-test \
     mockito-target \
diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-lists-mixed-format.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-lists-mixed-format.xml
new file mode 100644
index 0000000..c58b6d6
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-lists-mixed-format.xml
@@ -0,0 +1,13 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<whitelist>
+  <restrict-background uid="10004" />
+  <restrict-background uid="10008" />
+  <restrict-background uid="10015" />
+  <restrict-background uid="10016" />
+</whitelist>
+<policy-list version="10">
+  <uid-policy uid="10004" policy="0" />
+  <uid-policy uid="10008" policy="1" />
+  <uid-policy uid="10015" policy="2" />
+  <uid-policy uid="10016" policy="4" />
+</policy-list>
diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-lists-uid-policy-format.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-lists-uid-policy-format.xml
new file mode 100644
index 0000000..36c54ea
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-lists-uid-policy-format.xml
@@ -0,0 +1,9 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policy-list version="10">
+  <uid-policy uid="10004" policy="4" />
+  <uid-policy uid="10008" policy="4" />
+  <uid-policy uid="10015" policy="4" />
+  <uid-policy uid="10016" policy="0" />
+  <uid-policy uid="10023" policy="1" />
+  <uid-policy uid="10042" policy="2" />
+</policy-list>
diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-lists-whitelist-format.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-lists-whitelist-format.xml
new file mode 100644
index 0000000..5976003
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-lists-whitelist-format.xml
@@ -0,0 +1,11 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<whitelist>
+  <restrict-background uid="10004" />
+  <restrict-background uid="10008" />
+  <restrict-background uid="10015" />
+</whitelist>
+<policy-list version="10">
+  <uid-policy uid="10016" policy="0" />
+  <uid-policy uid="10023" policy="1" />
+  <uid-policy uid="10042" policy="2" />
+</policy-list>
diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
index 026a2ad..6e3e6c6 100644
--- a/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
@@ -131,18 +131,10 @@
     public void testSendAccessibilityEvent_AccessibilityEnabled() throws Exception {
         AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
 
-        when(mMockService.sendAccessibilityEvent(eq(sentEvent), anyInt()))
-                .thenReturn(true  /* should recycle event object */)
-                .thenReturn(false /* should not recycle event object */);
-
         AccessibilityManager manager = createManager(true);
         manager.sendAccessibilityEvent(sentEvent);
 
         assertSame("The event should be recycled.", sentEvent, AccessibilityEvent.obtain());
-
-        manager.sendAccessibilityEvent(sentEvent);
-
-        assertNotSame("The event should not be recycled.", sentEvent, AccessibilityEvent.obtain());
     }
 
     @MediumTest
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 59ccbd9..be1642e 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -1047,7 +1047,8 @@
         NETWORK_CAPABILITIES,
         LINK_PROPERTIES,
         LOSING,
-        LOST
+        LOST,
+        UNAVAILABLE
     }
 
     /**
@@ -1088,6 +1089,11 @@
         }
 
         @Override
+        public void onUnavailable() {
+            setLastCallback(CallbackState.UNAVAILABLE, null, null);
+        }
+
+        @Override
         public void onLosing(Network network, int maxMsToLive) {
             setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */);
         }
@@ -1953,6 +1959,79 @@
         handlerThread.quit();
     }
 
+    /**
+     * Validate that a satisfied network request does not trigger onUnavailable() once the
+     * time-out period expires.
+     */
+    @SmallTest
+    public void testSatisfiedNetworkRequestDoesNotTriggerOnUnavailable() {
+        NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
+                NetworkCapabilities.TRANSPORT_WIFI).build();
+        final TestNetworkCallback networkCallback = new TestNetworkCallback();
+        mCm.requestNetwork(nr, networkCallback, 10);
+
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(false);
+        networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+
+        // pass timeout and validate that UNAVAILABLE is not called
+        try {
+            Thread.sleep(15);
+        } catch (InterruptedException e) {
+        }
+        networkCallback.assertNoCallback();
+    }
+
+    /**
+     * Validate that when a time-out is specified for a network request the onUnavailable()
+     * callback is called when time-out expires. Then validate that if network request is
+     * (somehow) satisfied - the callback isn't called later.
+     */
+    @SmallTest
+    public void testTimedoutNetworkRequest() {
+        NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
+                NetworkCapabilities.TRANSPORT_WIFI).build();
+        final TestNetworkCallback networkCallback = new TestNetworkCallback();
+        mCm.requestNetwork(nr, networkCallback, 10);
+
+        // pass timeout and validate that UNAVAILABLE is called
+        networkCallback.expectCallback(CallbackState.UNAVAILABLE, null);
+
+        // create a network satisfying request - validate that request not triggered
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(false);
+        networkCallback.assertNoCallback();
+    }
+
+    /**
+     * Validate that when a network request is unregistered (cancelled) the time-out for that
+     * request doesn't trigger the onUnavailable() callback.
+     */
+    @SmallTest
+    public void testTimedoutAfterUnregisteredNetworkRequest() {
+        NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
+                NetworkCapabilities.TRANSPORT_WIFI).build();
+        final TestNetworkCallback networkCallback = new TestNetworkCallback();
+        mCm.requestNetwork(nr, networkCallback, 10);
+
+        // remove request
+        mCm.unregisterNetworkCallback(networkCallback);
+
+        // pass timeout and validate that no callbacks
+        // Note: doesn't validate that nothing called from CS since even if called the CM already
+        // unregisters the callback and won't pass it through!
+        try {
+            Thread.sleep(15);
+        } catch (InterruptedException e) {
+        }
+        networkCallback.assertNoCallback();
+
+        // create a network satisfying request - validate that request not triggered
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(false);
+        networkCallback.assertNoCallback();
+    }
+
     private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
 
         public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 6247089..2075328 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -20,10 +20,12 @@
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.NetworkPolicy.LIMIT_DISABLED;
 import static android.net.NetworkPolicy.WARNING_DISABLED;
+import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
 import static android.net.NetworkPolicyManager.computeNextCycleBoundary;
+import static android.net.NetworkPolicyManager.uidPoliciesToString;
 import static android.net.TrafficStats.KB_IN_BYTES;
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
@@ -71,6 +73,7 @@
 import android.net.INetworkStatsService;
 import android.net.LinkProperties;
 import android.net.NetworkInfo;
+import android.net.NetworkPolicyManager;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkPolicy;
 import android.net.NetworkState;
@@ -82,6 +85,7 @@
 import android.os.UserHandle;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
+import android.text.TextUtils;
 import android.text.format.Time;
 import android.util.Log;
 import android.util.TrustedTime;
@@ -90,14 +94,19 @@
 import com.android.server.net.NetworkPolicyManagerService;
 
 import libcore.io.IoUtils;
+import libcore.io.Streams;
 
 import com.google.common.util.concurrent.AbstractFuture;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.MethodRule;
 import org.junit.runner.RunWith;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -105,7 +114,15 @@
 import org.mockito.stubbing.Answer;
 
 import java.io.File;
-import java.util.ArrayList;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Arrays;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
@@ -113,6 +130,7 @@
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.stream.Collectors;
 
 /**
  * Tests for {@link NetworkPolicyManagerService}.
@@ -127,9 +145,22 @@
 
     private static NetworkTemplate sTemplateWifi = NetworkTemplate.buildTemplateWifi(TEST_SSID);
 
+    /**
+     * Path on assets where files used by {@link NetPolicyXml} are located.
+     */
+    private static final String NETPOLICY_DIR = "NetworkPolicyManagerServiceTest/netpolicy";
+
     private BroadcastInterceptingContext mServiceContext;
     private File mPolicyDir;
 
+    /**
+     * Relative path of the XML file that will be used as {@code netpolicy.xml}.
+     *
+     * <p>Typically set through a {@link NetPolicyXml} annotation in the test method.
+     */
+    private String mNetpolicyXml;
+
+
     private @Mock IActivityManager mActivityManager;
     private @Mock INetworkStatsService mStatsService;
     private @Mock INetworkManagementService mNetworkManager;
@@ -149,14 +180,24 @@
 
     private static final int USER_ID = 0;
 
-    private static final int APP_ID_A = android.os.Process.FIRST_APPLICATION_UID + 800;
-    private static final int APP_ID_B = android.os.Process.FIRST_APPLICATION_UID + 801;
+    private static final int APP_ID_A = android.os.Process.FIRST_APPLICATION_UID + 4;
+    private static final int APP_ID_B = android.os.Process.FIRST_APPLICATION_UID + 8;
+    private static final int APP_ID_C = android.os.Process.FIRST_APPLICATION_UID + 15;
+    private static final int APP_ID_D = android.os.Process.FIRST_APPLICATION_UID + 16;
+    private static final int APP_ID_E = android.os.Process.FIRST_APPLICATION_UID + 23;
+    private static final int APP_ID_F = android.os.Process.FIRST_APPLICATION_UID + 42;
 
     private static final int UID_A = UserHandle.getUid(USER_ID, APP_ID_A);
     private static final int UID_B = UserHandle.getUid(USER_ID, APP_ID_B);
+    private static final int UID_C = UserHandle.getUid(USER_ID, APP_ID_C);
+    private static final int UID_D = UserHandle.getUid(USER_ID, APP_ID_D);
+    private static final int UID_E = UserHandle.getUid(USER_ID, APP_ID_E);
+    private static final int UID_F = UserHandle.getUid(USER_ID, APP_ID_F);
 
     private static final String PKG_NAME_A = "name.is.A,pkg.A";
 
+    public final @Rule NetPolicyMethodRule mNetPolicyXmlRule = new NetPolicyMethodRule();
+
     @BeforeClass
     public static void registerLocalServices() {
         addLocalServiceMock(PowerManagerInternal.class);
@@ -187,10 +228,7 @@
             }
         };
 
-        mPolicyDir = context.getFilesDir();
-        if (mPolicyDir.exists()) {
-            IoUtils.deleteContents(mPolicyDir);
-        }
+        setNetpolicyXml(context);
 
         doAnswer(new Answer<Void>() {
 
@@ -257,6 +295,61 @@
         LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
     }
 
+    @Test
+    @NetPolicyXml("restrict-background-lists-whitelist-format.xml")
+    public void testRestrictBackgroundLists_whitelistFormat() throws Exception {
+        restrictBackgroundListsTest();
+    }
+
+    @Test
+    @NetPolicyXml("restrict-background-lists-uid-policy-format.xml")
+    public void testRestrictBackgroundLists_uidPolicyFormat() throws Exception {
+        restrictBackgroundListsTest();
+    }
+
+    private void restrictBackgroundListsTest() throws Exception {
+        // UIds that are whitelisted.
+        assertWhitelistUids(UID_A, UID_B, UID_C);
+        assertUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND);
+        assertUidPolicy(UID_B, POLICY_ALLOW_METERED_BACKGROUND);
+        assertUidPolicy(UID_C, POLICY_ALLOW_METERED_BACKGROUND);
+
+        // UIDs that are blacklisted.
+        assertUidPolicy(UID_D, POLICY_NONE);
+        assertUidPolicy(UID_E, POLICY_REJECT_METERED_BACKGROUND);
+
+        // UIDS that have legacy policies.
+        assertUidPolicy(UID_F, 2); // POLICY_ALLOW_BACKGROUND_BATTERY_SAVE
+
+        // Remove whitelist.
+        mService.removeRestrictBackgroundWhitelistedUid(UID_A);
+        assertUidPolicy(UID_A, POLICY_NONE);
+        assertWhitelistUids(UID_B, UID_C);
+
+        // Add whitelist when blacklisted.
+        mService.addRestrictBackgroundWhitelistedUid(UID_E);
+        assertUidPolicy(UID_E, POLICY_ALLOW_METERED_BACKGROUND);
+        assertWhitelistUids(UID_B, UID_C, UID_E);
+
+        // Add blacklist when whitelisted.
+        mService.setUidPolicy(UID_B, POLICY_REJECT_METERED_BACKGROUND);
+        assertUidPolicy(UID_B, POLICY_REJECT_METERED_BACKGROUND);
+        assertWhitelistUids(UID_C, UID_E);
+    }
+
+    /**
+     * Tests scenario where an UID had {@code restrict-background} and {@code uid-policy} tags.
+     */
+    @Test
+    @NetPolicyXml("restrict-background-lists-mixed-format.xml")
+    public void testRestrictBackgroundLists_mixedFormat() throws Exception {
+        assertWhitelistUids(UID_A, UID_C, UID_D);
+        assertUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND);
+        assertUidPolicy(UID_B, POLICY_REJECT_METERED_BACKGROUND);
+        assertUidPolicy(UID_C, (POLICY_ALLOW_METERED_BACKGROUND | 2));
+        assertUidPolicy(UID_D, POLICY_ALLOW_METERED_BACKGROUND);
+    }
+
     // NOTE: testPolicyChangeTriggersListener() and testUidForeground() are too superficial, they
     // don't check for side-effects (like calls to NetworkManagementService) neither cover all
     // different modes (Data Saver, Battery Saver, Doze, App idle, etc...).
@@ -739,6 +832,40 @@
                 Integer.toString(expected), actualTag.substring(actualTag.lastIndexOf(':') + 1));
     }
 
+    private void assertUidPolicy(int uid, int expected) {
+        final int actual = mService.getUidPolicy(uid);
+        if (expected != actual) {
+            fail("Wrong policy for UID " + uid + ": expected " + uidPoliciesToString(expected)
+                    + ", actual " + uidPoliciesToString(actual));
+        }
+    }
+
+    private void assertWhitelistUids(int... uids) {
+        assertContainsInAnyOrder(mService.getRestrictBackgroundWhitelistedUids(), uids);
+    }
+
+    // TODO: replace by Truth, Hamcrest, or a similar tool.
+    private void assertContainsInAnyOrder(int[] actual, int...expected) {
+        final StringBuilder errors = new StringBuilder();
+        if (actual.length != expected.length) {
+            errors.append("\tsize does not match\n");
+        }
+        final List<Integer> actualList =
+                Arrays.stream(actual).boxed().collect(Collectors.<Integer>toList());
+        final List<Integer> expectedList =
+                Arrays.stream(expected).boxed().collect(Collectors.<Integer>toList());
+        if (!actualList.containsAll(expectedList)) {
+            errors.append("\tmissing elements on actual list\n");
+        }
+        if (!expectedList.containsAll(actualList)) {
+            errors.append("\tmissing elements on expected list\n");
+        }
+        if (errors.length() > 0) {
+            fail("assertContainsInAnyOrder(expected=" + Arrays.toString(expected)
+                    + ", actual=" + Arrays.toString(actual) +") failed: \n" + errors);
+        }
+    }
+
     private long getElapsedRealtime() {
         return mElapsedRealtime;
     }
@@ -811,4 +938,51 @@
             return verify(listener, atLeastOnce());
         }
     }
+
+    private void setNetpolicyXml(Context context) throws Exception {
+        mPolicyDir = context.getFilesDir();
+        if (mPolicyDir.exists()) {
+            IoUtils.deleteContents(mPolicyDir);
+        }
+        if (!TextUtils.isEmpty(mNetpolicyXml)) {
+            final String assetPath = NETPOLICY_DIR + "/" + mNetpolicyXml;
+            final File netConfigFile = new File(mPolicyDir, "netpolicy.xml");
+            Log.d(TAG, "Creating " + netConfigFile + " from asset " + assetPath);
+            try (final InputStream in = context.getResources().getAssets().open(assetPath);
+                    final OutputStream out = new FileOutputStream(netConfigFile)) {
+                Streams.copy(in, out);
+            }
+        }
+    }
+
+    /**
+     * Annotation used to define the relative path of the {@code netpolicy.xml} file.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    public @interface NetPolicyXml {
+
+        public String value() default "";
+
+    }
+
+    /**
+     * Rule used to set {@code mNetPolicyXml} according to the {@link NetPolicyXml} annotation.
+     */
+    public static class NetPolicyMethodRule implements MethodRule {
+
+        @Override
+        public Statement apply(Statement base, FrameworkMethod method, Object target) {
+            for (Annotation annotation : method.getAnnotations()) {
+                if ((annotation instanceof NetPolicyXml)) {
+                    final String path = ((NetPolicyXml) annotation).value();
+                    if (!path.isEmpty()) {
+                        ((NetworkPolicyManagerServiceTest) target).mNetpolicyXml = path;
+                        break;
+                    }
+                }
+            }
+            return base;
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
index 94c6711..8c96226 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
@@ -40,21 +40,21 @@
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
+
 import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
-import static org.easymock.EasyMock.anyInt;
-import static org.easymock.EasyMock.anyLong;
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.capture;
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.EasyMock.isA;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
 
 import android.app.AlarmManager;
-import android.app.IAlarmListener;
-import android.app.IAlarmManager;
-import android.app.PendingIntent;
 import android.app.usage.NetworkStatsManager;
 import android.content.Context;
 import android.content.Intent;
@@ -63,6 +63,7 @@
 import android.net.INetworkManagementEventObserver;
 import android.net.INetworkStatsSession;
 import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkState;
@@ -80,11 +81,10 @@
 import android.os.MessageQueue.IdleHandler;
 import android.os.Message;
 import android.os.PowerManager;
-import android.os.WorkSource;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 import android.telephony.TelephonyManager;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.util.TrustedTime;
 
 import com.android.internal.net.VpnInfo;
@@ -95,8 +95,14 @@
 
 import libcore.io.IoUtils;
 
-import org.easymock.Capture;
-import org.easymock.EasyMock;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -106,11 +112,11 @@
 /**
  * Tests for {@link NetworkStatsService}.
  *
- * TODO: This test is really brittle, largely due to overly-strict use of Easymock.
- * Rewrite w/ Mockito.
+ * TODO: This test used to be really brittle because it used Easymock - it uses Mockito now, but
+ * still uses the Easymock structure, which could be simplified.
  */
-@LargeTest
-public class NetworkStatsServiceTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class NetworkStatsServiceTest {
     private static final String TAG = "NetworkStatsServiceTest";
 
     private static final String TEST_IFACE = "test0";
@@ -137,10 +143,12 @@
     private BroadcastInterceptingContext mServiceContext;
     private File mStatsDir;
 
-    private INetworkManagementService mNetManager;
-    private TrustedTime mTime;
-    private NetworkStatsSettings mSettings;
-    private IConnectivityManager mConnManager;
+    private @Mock INetworkManagementService mNetManager;
+    private @Mock TrustedTime mTime;
+    private @Mock NetworkStatsSettings mSettings;
+    private @Mock IConnectivityManager mConnManager;
+    private @Mock IBinder mBinder;
+    private @Mock AlarmManager mAlarmManager;
     private IdleableHandlerThread mHandlerThread;
     private Handler mHandler;
 
@@ -148,32 +156,24 @@
     private INetworkStatsSession mSession;
     private INetworkManagementEventObserver mNetworkObserver;
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
+        MockitoAnnotations.initMocks(this);
+        final Context context = InstrumentationRegistry.getContext();
 
-        mServiceContext = new BroadcastInterceptingContext(getContext());
-        mStatsDir = getContext().getFilesDir();
+        mServiceContext = new BroadcastInterceptingContext(context);
+        mStatsDir = context.getFilesDir();
         if (mStatsDir.exists()) {
             IoUtils.deleteContents(mStatsDir);
         }
 
-        mNetManager = createMock(INetworkManagementService.class);
-
-        // TODO: Mock AlarmManager when migrating this test to Mockito.
-        AlarmManager alarmManager = (AlarmManager) mServiceContext
-                .getSystemService(Context.ALARM_SERVICE);
-        mTime = createMock(TrustedTime.class);
-        mSettings = createMock(NetworkStatsSettings.class);
-        mConnManager = createMock(IConnectivityManager.class);
-
         PowerManager powerManager = (PowerManager) mServiceContext.getSystemService(
                 Context.POWER_SERVICE);
         PowerManager.WakeLock wakeLock =
                 powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
 
         mService = new NetworkStatsService(
-                mServiceContext, mNetManager, alarmManager, wakeLock, mTime,
+                mServiceContext, mNetManager, mAlarmManager, wakeLock, mTime,
                 TelephonyManager.getDefault(), mSettings, new NetworkStatsObservers(),
                 mStatsDir, getBaseDir(mStatsDir));
         mHandlerThread = new IdleableHandlerThread("HandlerThread");
@@ -190,22 +190,20 @@
         expectNetworkStatsUidDetail(buildEmptyStats());
         expectSystemReady();
 
-        // catch INetworkManagementEventObserver during systemReady()
-        final Capture<INetworkManagementEventObserver> networkObserver = new Capture<
-                INetworkManagementEventObserver>();
-        mNetManager.registerObserver(capture(networkObserver));
-        expectLastCall().atLeastOnce();
-
-        replay();
         mService.systemReady();
         mSession = mService.openSession();
-        verifyAndReset();
+        assertNotNull("openSession() failed", mSession);
 
+
+        // catch INetworkManagementEventObserver during systemReady()
+        ArgumentCaptor<INetworkManagementEventObserver> networkObserver =
+              ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
+        verify(mNetManager).registerObserver(networkObserver.capture());
         mNetworkObserver = networkObserver.getValue();
 
     }
 
-    @Override
+    @After
     public void tearDown() throws Exception {
         IoUtils.deleteContents(mStatsDir);
 
@@ -219,10 +217,9 @@
 
         mSession.close();
         mService = null;
-
-        super.tearDown();
     }
 
+    @Test
     public void testNetworkStatsWifi() throws Exception {
         // pretend that wifi network comes online; service should ask about full
         // network state, and poll any existing interfaces before updating.
@@ -231,15 +228,13 @@
         expectNetworkState(buildWifiState());
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
-        expectNetworkStatsPoll();
         expectBandwidthControlCheck();
 
-        replay();
         mService.forceUpdateIfaces();
 
         // verify service has empty history for wifi
         assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
-        verifyAndReset();
+
 
         // modify some number on wifi, and trigger poll event
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -248,14 +243,11 @@
         expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
                 .addIfaceValues(TEST_IFACE, 1024L, 1L, 2048L, 2L));
         expectNetworkStatsUidDetail(buildEmptyStats());
-        expectNetworkStatsPoll();
-
-        replay();
         forcePollAndWaitForIdle();
 
         // verify service recorded history
         assertNetworkTotal(sTemplateWifi, 1024L, 1L, 2048L, 2L, 0);
-        verifyAndReset();
+
 
         // and bump forward again, with counters going higher. this is
         // important, since polling should correctly subtract last snapshot.
@@ -265,17 +257,14 @@
         expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
                 .addIfaceValues(TEST_IFACE, 4096L, 4L, 8192L, 8L));
         expectNetworkStatsUidDetail(buildEmptyStats());
-        expectNetworkStatsPoll();
-
-        replay();
         forcePollAndWaitForIdle();
 
         // verify service recorded history
         assertNetworkTotal(sTemplateWifi, 4096L, 4L, 8192L, 8L, 0);
-        verifyAndReset();
 
     }
 
+    @Test
     public void testStatsRebootPersist() throws Exception {
         assertStatsFilesExist(false);
 
@@ -286,15 +275,13 @@
         expectNetworkState(buildWifiState());
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
-        expectNetworkStatsPoll();
         expectBandwidthControlCheck();
 
-        replay();
         mService.forceUpdateIfaces();
 
         // verify service has empty history for wifi
         assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
-        verifyAndReset();
+
 
         // modify some number on wifi, and trigger poll event
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -308,14 +295,11 @@
                 .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
                 .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 256L, 2L, 128L, 1L, 0L)
                 .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 0L));
-        expectNetworkStatsPoll();
-
         mService.setUidForeground(UID_RED, false);
         mService.incrementOperationCount(UID_RED, 0xFAAD, 4);
         mService.setUidForeground(UID_RED, true);
         mService.incrementOperationCount(UID_RED, 0xFAAD, 6);
 
-        replay();
         forcePollAndWaitForIdle();
 
         // verify service recorded history
@@ -325,16 +309,13 @@
         assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, ROAMING_NO, 512L, 4L, 256L, 2L,
                 6);
         assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0);
-        verifyAndReset();
+
 
         // graceful shutdown system, which should trigger persist of stats, and
         // clear any values in memory.
         expectCurrentTime();
         expectDefaultSettings();
-        replay();
         mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SHUTDOWN));
-        verifyAndReset();
-
         assertStatsFilesExist(true);
 
         // boot through serviceReady() again
@@ -343,17 +324,8 @@
         expectNetworkStatsUidDetail(buildEmptyStats());
         expectSystemReady();
 
-        // catch INetworkManagementEventObserver during systemReady()
-        final Capture<INetworkManagementEventObserver> networkObserver = new Capture<
-                INetworkManagementEventObserver>();
-        mNetManager.registerObserver(capture(networkObserver));
-        expectLastCall().atLeastOnce();
-
-        replay();
         mService.systemReady();
 
-        mNetworkObserver = networkObserver.getValue();
-
         // after systemReady(), we should have historical stats loaded again
         assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0);
         assertUidTotal(sTemplateWifi, UID_RED, 1024L, 8L, 512L, 4L, 10);
@@ -361,12 +333,12 @@
         assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, ROAMING_NO, 512L, 4L, 256L, 2L,
                 6);
         assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0);
-        verifyAndReset();
 
     }
 
     // TODO: simulate reboot to test bucket resize
-    @Suppress
+    @Test
+    @Ignore
     public void testStatsBucketResize() throws Exception {
         NetworkStatsHistory history = null;
 
@@ -379,12 +351,10 @@
         expectNetworkState(buildWifiState());
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
-        expectNetworkStatsPoll();
         expectBandwidthControlCheck();
 
-        replay();
         mService.forceUpdateIfaces();
-        verifyAndReset();
+
 
         // modify some number on wifi, and trigger poll event
         incrementCurrentTime(2 * HOUR_IN_MILLIS);
@@ -393,9 +363,6 @@
         expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
                 .addIfaceValues(TEST_IFACE, 512L, 4L, 512L, 4L));
         expectNetworkStatsUidDetail(buildEmptyStats());
-        expectNetworkStatsPoll();
-
-        replay();
         forcePollAndWaitForIdle();
 
         // verify service recorded history
@@ -403,7 +370,7 @@
         assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0);
         assertEquals(HOUR_IN_MILLIS, history.getBucketDuration());
         assertEquals(2, history.size());
-        verifyAndReset();
+
 
         // now change bucket duration setting and trigger another poll with
         // exact same values, which should resize existing buckets.
@@ -411,9 +378,6 @@
         expectSettings(0L, 30 * MINUTE_IN_MILLIS, WEEK_IN_MILLIS);
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
-        expectNetworkStatsPoll();
-
-        replay();
         forcePollAndWaitForIdle();
 
         // verify identical stats, but spread across 4 buckets now
@@ -421,10 +385,10 @@
         assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0);
         assertEquals(30 * MINUTE_IN_MILLIS, history.getBucketDuration());
         assertEquals(4, history.size());
-        verifyAndReset();
 
     }
 
+    @Test
     public void testUidStatsAcrossNetworks() throws Exception {
         // pretend first mobile network comes online
         expectCurrentTime();
@@ -432,12 +396,10 @@
         expectNetworkState(buildMobile3gState(IMSI_1));
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
-        expectNetworkStatsPoll();
         expectBandwidthControlCheck();
 
-        replay();
         mService.forceUpdateIfaces();
-        verifyAndReset();
+
 
         // create some traffic on first network
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -449,11 +411,8 @@
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
                 .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
-        expectNetworkStatsPoll();
-
         mService.incrementOperationCount(UID_RED, 0xF00D, 10);
 
-        replay();
         forcePollAndWaitForIdle();
 
         // verify service recorded history
@@ -461,7 +420,7 @@
         assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
         assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 512L, 4L, 10);
         assertUidTotal(sTemplateImsi1, UID_BLUE, 512L, 4L, 0L, 0L, 0);
-        verifyAndReset();
+
 
         // now switch networks; this also tests that we're okay with interfaces
         // disappearing, to verify we don't count backwards.
@@ -475,13 +434,11 @@
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
                 .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
-        expectNetworkStatsPoll();
         expectBandwidthControlCheck();
 
-        replay();
         mService.forceUpdateIfaces();
         forcePollAndWaitForIdle();
-        verifyAndReset();
+
 
         // create traffic on second network
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -494,11 +451,8 @@
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
                 .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 640L, 5L, 1024L, 8L, 0L)
                 .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xFAAD, 128L, 1L, 1024L, 8L, 0L));
-        expectNetworkStatsPoll();
-
         mService.incrementOperationCount(UID_BLUE, 0xFAAD, 10);
 
-        replay();
         forcePollAndWaitForIdle();
 
         // verify original history still intact
@@ -511,10 +465,10 @@
         assertNetworkTotal(sTemplateImsi2, 128L, 1L, 1024L, 8L, 0);
         assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
         assertUidTotal(sTemplateImsi2, UID_BLUE, 128L, 1L, 1024L, 8L, 10);
-        verifyAndReset();
 
     }
 
+    @Test
     public void testUidRemovedIsMoved() throws Exception {
         // pretend that network comes online
         expectCurrentTime();
@@ -522,12 +476,10 @@
         expectNetworkState(buildWifiState());
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
-        expectNetworkStatsPoll();
         expectBandwidthControlCheck();
 
-        replay();
         mService.forceUpdateIfaces();
-        verifyAndReset();
+
 
         // create some traffic
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -540,11 +492,8 @@
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L)
                 .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L)
                 .addValues(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L));
-        expectNetworkStatsPoll();
-
         mService.incrementOperationCount(UID_RED, 0xFAAD, 10);
 
-        replay();
         forcePollAndWaitForIdle();
 
         // verify service recorded history
@@ -552,7 +501,7 @@
         assertUidTotal(sTemplateWifi, UID_RED, 16L, 1L, 16L, 1L, 10);
         assertUidTotal(sTemplateWifi, UID_BLUE, 4096L, 258L, 512L, 32L, 0);
         assertUidTotal(sTemplateWifi, UID_GREEN, 16L, 1L, 16L, 1L, 0);
-        verifyAndReset();
+
 
         // now pretend two UIDs are uninstalled, which should migrate stats to
         // special "removed" bucket.
@@ -565,9 +514,6 @@
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L)
                 .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L)
                 .addValues(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L));
-        expectNetworkStatsPoll();
-
-        replay();
         final Intent intent = new Intent(ACTION_UID_REMOVED);
         intent.putExtra(EXTRA_UID, UID_BLUE);
         mServiceContext.sendBroadcast(intent);
@@ -581,10 +527,10 @@
         assertUidTotal(sTemplateWifi, UID_BLUE, 0L, 0L, 0L, 0L, 0);
         assertUidTotal(sTemplateWifi, UID_GREEN, 16L, 1L, 16L, 1L, 0);
         assertUidTotal(sTemplateWifi, UID_REMOVED, 4112L, 259L, 528L, 33L, 10);
-        verifyAndReset();
 
     }
 
+    @Test
     public void testUid3g4gCombinedByTemplate() throws Exception {
         // pretend that network comes online
         expectCurrentTime();
@@ -592,12 +538,10 @@
         expectNetworkState(buildMobile3gState(IMSI_1));
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
-        expectNetworkStatsPoll();
         expectBandwidthControlCheck();
 
-        replay();
         mService.forceUpdateIfaces();
-        verifyAndReset();
+
 
         // create some traffic
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -607,16 +551,13 @@
         expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
-        expectNetworkStatsPoll();
-
         mService.incrementOperationCount(UID_RED, 0xF00D, 5);
 
-        replay();
         forcePollAndWaitForIdle();
 
         // verify service recorded history
         assertUidTotal(sTemplateImsi1, UID_RED, 1024L, 8L, 1024L, 8L, 5);
-        verifyAndReset();
+
 
         // now switch over to 4g network
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -627,13 +568,11 @@
         expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
-        expectNetworkStatsPoll();
         expectBandwidthControlCheck();
 
-        replay();
         mService.forceUpdateIfaces();
         forcePollAndWaitForIdle();
-        verifyAndReset();
+
 
         // create traffic on second network
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -645,19 +584,15 @@
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
                 .addValues(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
                 .addValues(TEST_IFACE2, UID_RED, SET_DEFAULT, 0xFAAD, 512L, 4L, 256L, 2L, 0L));
-        expectNetworkStatsPoll();
-
         mService.incrementOperationCount(UID_RED, 0xFAAD, 5);
 
-        replay();
         forcePollAndWaitForIdle();
 
         // verify that ALL_MOBILE template combines both
         assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 1280L, 10L, 10);
-
-        verifyAndReset();
     }
 
+    @Test
     public void testSummaryForAllUid() throws Exception {
         // pretend that network comes online
         expectCurrentTime();
@@ -665,12 +600,10 @@
         expectNetworkState(buildWifiState());
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
-        expectNetworkStatsPoll();
         expectBandwidthControlCheck();
 
-        replay();
         mService.forceUpdateIfaces();
-        verifyAndReset();
+
 
         // create some traffic for two apps
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -681,17 +614,14 @@
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L)
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L)
                 .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0L));
-        expectNetworkStatsPoll();
-
         mService.incrementOperationCount(UID_RED, 0xF00D, 1);
 
-        replay();
         forcePollAndWaitForIdle();
 
         // verify service recorded history
         assertUidTotal(sTemplateWifi, UID_RED, 50L, 5L, 50L, 5L, 1);
         assertUidTotal(sTemplateWifi, UID_BLUE, 1024L, 8L, 512L, 4L, 0);
-        verifyAndReset();
+
 
         // now create more traffic in next hour, but only for one app
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -702,9 +632,6 @@
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L)
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L)
                 .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 2048L, 16L, 1024L, 8L, 0L));
-        expectNetworkStatsPoll();
-
-        replay();
         forcePollAndWaitForIdle();
 
         // first verify entire history present
@@ -725,10 +652,9 @@
         assertEquals(1, stats.size());
         assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, ROAMING_NO, 1024L, 8L,
                 512L, 4L, 0);
-
-        verifyAndReset();
     }
 
+    @Test
     public void testForegroundBackground() throws Exception {
         // pretend that network comes online
         expectCurrentTime();
@@ -736,12 +662,10 @@
         expectNetworkState(buildWifiState());
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
-        expectNetworkStatsPoll();
         expectBandwidthControlCheck();
 
-        replay();
         mService.forceUpdateIfaces();
-        verifyAndReset();
+
 
         // create some initial traffic
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -751,16 +675,13 @@
         expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L)
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L));
-        expectNetworkStatsPoll();
-
         mService.incrementOperationCount(UID_RED, 0xF00D, 1);
 
-        replay();
         forcePollAndWaitForIdle();
 
         // verify service recorded history
         assertUidTotal(sTemplateWifi, UID_RED, 128L, 2L, 128L, 2L, 1);
-        verifyAndReset();
+
 
         // now switch to foreground
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -772,12 +693,9 @@
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L)
                 .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 0L)
                 .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 1L, 1L, 1L, 1L, 0L));
-        expectNetworkStatsPoll();
-
         mService.setUidForeground(UID_RED, true);
         mService.incrementOperationCount(UID_RED, 0xFAAD, 1);
 
-        replay();
         forcePollAndWaitForIdle();
 
         // test that we combined correctly
@@ -795,10 +713,9 @@
                 32L, 2L, 1);
         assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, 0xFAAD, ROAMING_NO, 1L, 1L, 1L,
                 1L, 1);
-
-        verifyAndReset();
     }
 
+    @Test
     public void testRoaming() throws Exception {
         // pretend that network comes online
         expectCurrentTime();
@@ -806,12 +723,10 @@
         expectNetworkState(buildMobile3gState(IMSI_1, true /* isRoaming */));
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
-        expectNetworkStatsPoll();
         expectBandwidthControlCheck();
 
-        replay();
         mService.forceUpdateIfaces();
-        verifyAndReset();
+
 
         // Create some traffic
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -826,9 +741,6 @@
                         128L, 2L, 0L)
                 .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_NO, 64L, 1L, 64L,
                         1L, 0L));
-        expectNetworkStatsPoll();
-
-        replay();
         forcePollAndWaitForIdle();
 
         // verify service recorded history
@@ -842,10 +754,9 @@
                 128L, 2L, 0);
         assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_YES, 64L, 1L, 64L,
                 1L, 0);
-
-        verifyAndReset();
     }
 
+    @Test
     public void testTethering() throws Exception {
         // pretend first mobile network comes online
         expectCurrentTime();
@@ -853,12 +764,10 @@
         expectNetworkState(buildMobile3gState(IMSI_1));
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
-        expectNetworkStatsPoll();
         expectBandwidthControlCheck();
 
-        replay();
         mService.forceUpdateIfaces();
-        verifyAndReset();
+
 
         // create some tethering traffic
         incrementCurrentTime(HOUR_IN_MILLIS);
@@ -874,19 +783,16 @@
                 .addValues(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L, 0L);
 
         expectNetworkStatsUidDetail(uidStats, tetherIfacePairs, tetherStats);
-        expectNetworkStatsPoll();
-
-        replay();
         forcePollAndWaitForIdle();
 
         // verify service recorded history
         assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
         assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0);
         assertUidTotal(sTemplateImsi1, UID_TETHERING, 1920L, 14L, 384L, 2L, 0);
-        verifyAndReset();
 
     }
 
+    @Test
     public void testRegisterUsageCallback() throws Exception {
         // pretend that wifi network comes online; service should ask about full
         // network state, and poll any existing interfaces before updating.
@@ -895,16 +801,12 @@
         expectNetworkState(buildWifiState());
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
-        expectNetworkStatsPoll();
         expectBandwidthControlCheck();
 
-        replay();
         mService.forceUpdateIfaces();
 
         // verify service has empty history for wifi
         assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
-        verifyAndReset();
-
         String callingPackage = "the.calling.package";
         long thresholdInBytes = 1L;  // very small; should be overriden by framework
         DataUsageRequest inputRequest = new DataUsageRequest(
@@ -915,23 +817,18 @@
         LatchedHandler latchedHandler = new LatchedHandler(Looper.getMainLooper(), cv);
         Messenger messenger = new Messenger(latchedHandler);
 
-        // Allow binder to connect
-        IBinder mockBinder = createMock(IBinder.class);
-        mockBinder.linkToDeath((IBinder.DeathRecipient) anyObject(), anyInt());
-        EasyMock.replay(mockBinder);
-
         // Force poll
         expectCurrentTime();
         expectDefaultSettings();
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(buildEmptyStats());
-        expectNetworkStatsPoll();
-        replay();
+
+
 
         // Register and verify request and that binder was called
         DataUsageRequest request =
                 mService.registerUsageCallback(callingPackage, inputRequest,
-                        messenger, mockBinder);
+                        messenger, mBinder);
         assertTrue(request.requestId > 0);
         assertTrue(Objects.equals(sTemplateWifi, request.template));
         long minThresholdInBytes = 2 * 1024 * 1024; // 2 MB
@@ -941,11 +838,11 @@
         mHandler.sendMessage(mHandler.obtainMessage(-1));
         mHandlerThread.waitForIdle(WAIT_TIMEOUT);
 
-        verifyAndReset();
+
 
         // Make sure that the caller binder gets connected
-        EasyMock.verify(mockBinder);
-        EasyMock.reset(mockBinder);
+        verify(mBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
 
         // modify some number on wifi, and trigger poll event
         // not enough traffic to call data usage callback
@@ -955,13 +852,9 @@
         expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
                 .addIfaceValues(TEST_IFACE, 1024L, 1L, 2048L, 2L));
         expectNetworkStatsUidDetail(buildEmptyStats());
-        expectNetworkStatsPoll();
-
-        replay();
         forcePollAndWaitForIdle();
 
         // verify service recorded history
-        verifyAndReset();
         assertNetworkTotal(sTemplateWifi, 1024L, 1L, 2048L, 2L, 0);
 
         // make sure callback has not being called
@@ -975,14 +868,11 @@
         expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
                 .addIfaceValues(TEST_IFACE, 4096000L, 4L, 8192000L, 8L));
         expectNetworkStatsUidDetail(buildEmptyStats());
-        expectNetworkStatsPoll();
-
-        replay();
         forcePollAndWaitForIdle();
 
         // verify service recorded history
         assertNetworkTotal(sTemplateWifi, 4096000L, 4L, 8192000L, 8L, 0);
-        verifyAndReset();
+
 
         // Wait for the caller to ack receipt of CALLBACK_LIMIT_REACHED
         assertTrue(cv.block(WAIT_TIMEOUT));
@@ -990,9 +880,7 @@
         cv.close();
 
         // Allow binder to disconnect
-        expect(mockBinder.unlinkToDeath((IBinder.DeathRecipient) anyObject(), anyInt()))
-                .andReturn(true);
-        EasyMock.replay(mockBinder);
+        when(mBinder.unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt())).thenReturn(true);
 
         // Unregister request
         mService.unregisterUsageRequest(request);
@@ -1002,9 +890,10 @@
         assertEquals(NetworkStatsManager.CALLBACK_RELEASED, latchedHandler.mLastMessageType);
 
         // Make sure that the caller binder gets disconnected
-        EasyMock.verify(mockBinder);
+        verify(mBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
     }
 
+    @Test
     public void testUnregisterUsageCallback_unknown_noop() throws Exception {
         String callingPackage = "the.calling.package";
         long thresholdInBytes = 10 * 1024 * 1024;  // 10 MB
@@ -1061,33 +950,30 @@
     }
 
     private void expectSystemReady() throws Exception {
-        mNetManager.setGlobalAlert(anyLong());
-        expectLastCall().atLeastOnce();
-
         expectNetworkStatsSummary(buildEmptyStats());
         expectBandwidthControlCheck();
     }
 
     private void expectNetworkState(NetworkState... state) throws Exception {
-        expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
+        when(mConnManager.getAllNetworkState()).thenReturn(state);
 
         final LinkProperties linkProp = state.length > 0 ? state[0].linkProperties : null;
-        expect(mConnManager.getActiveLinkProperties()).andReturn(linkProp).atLeastOnce();
+        when(mConnManager.getActiveLinkProperties()).thenReturn(linkProp);
     }
 
     private void expectNetworkStatsSummary(NetworkStats summary) throws Exception {
-        expect(mConnManager.getAllVpnInfo()).andReturn(new VpnInfo[0]).atLeastOnce();
+        when(mConnManager.getAllVpnInfo()).thenReturn(new VpnInfo[0]);
 
         expectNetworkStatsSummaryDev(summary);
         expectNetworkStatsSummaryXt(summary);
     }
 
     private void expectNetworkStatsSummaryDev(NetworkStats summary) throws Exception {
-        expect(mNetManager.getNetworkStatsSummaryDev()).andReturn(summary).atLeastOnce();
+        when(mNetManager.getNetworkStatsSummaryDev()).thenReturn(summary);
     }
 
     private void expectNetworkStatsSummaryXt(NetworkStats summary) throws Exception {
-        expect(mNetManager.getNetworkStatsSummaryXt()).andReturn(summary).atLeastOnce();
+        when(mNetManager.getNetworkStatsSummaryXt()).thenReturn(summary);
     }
 
     private void expectNetworkStatsUidDetail(NetworkStats detail) throws Exception {
@@ -1097,11 +983,10 @@
     private void expectNetworkStatsUidDetail(
             NetworkStats detail, String[] tetherIfacePairs, NetworkStats tetherStats)
             throws Exception {
-        expect(mNetManager.getNetworkStatsUidDetail(eq(UID_ALL))).andReturn(detail).atLeastOnce();
+        when(mNetManager.getNetworkStatsUidDetail(UID_ALL)).thenReturn(detail);
 
         // also include tethering details, since they are folded into UID
-        expect(mNetManager.getNetworkStatsTethering())
-                .andReturn(tetherStats).atLeastOnce();
+        when(mNetManager.getNetworkStatsTethering()).thenReturn(tetherStats);
     }
 
     private void expectDefaultSettings() throws Exception {
@@ -1110,38 +995,33 @@
 
     private void expectSettings(long persistBytes, long bucketDuration, long deleteAge)
             throws Exception {
-        expect(mSettings.getPollInterval()).andReturn(HOUR_IN_MILLIS).anyTimes();
-        expect(mSettings.getTimeCacheMaxAge()).andReturn(DAY_IN_MILLIS).anyTimes();
-        expect(mSettings.getSampleEnabled()).andReturn(true).anyTimes();
+        when(mSettings.getPollInterval()).thenReturn(HOUR_IN_MILLIS);
+        when(mSettings.getTimeCacheMaxAge()).thenReturn(DAY_IN_MILLIS);
+        when(mSettings.getSampleEnabled()).thenReturn(true);
 
         final Config config = new Config(bucketDuration, deleteAge, deleteAge);
-        expect(mSettings.getDevConfig()).andReturn(config).anyTimes();
-        expect(mSettings.getXtConfig()).andReturn(config).anyTimes();
-        expect(mSettings.getUidConfig()).andReturn(config).anyTimes();
-        expect(mSettings.getUidTagConfig()).andReturn(config).anyTimes();
+        when(mSettings.getDevConfig()).thenReturn(config);
+        when(mSettings.getXtConfig()).thenReturn(config);
+        when(mSettings.getUidConfig()).thenReturn(config);
+        when(mSettings.getUidTagConfig()).thenReturn(config);
 
-        expect(mSettings.getGlobalAlertBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes();
-        expect(mSettings.getDevPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes();
-        expect(mSettings.getXtPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes();
-        expect(mSettings.getUidPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes();
-        expect(mSettings.getUidTagPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes();
+        when(mSettings.getGlobalAlertBytes(anyLong())).thenReturn(MB_IN_BYTES);
+        when(mSettings.getDevPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
+        when(mSettings.getXtPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
+        when(mSettings.getUidPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
+        when(mSettings.getUidTagPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
     }
 
     private void expectCurrentTime() throws Exception {
-        expect(mTime.forceRefresh()).andReturn(false).anyTimes();
-        expect(mTime.hasCache()).andReturn(true).anyTimes();
-        expect(mTime.currentTimeMillis()).andReturn(currentTimeMillis()).anyTimes();
-        expect(mTime.getCacheAge()).andReturn(0L).anyTimes();
-        expect(mTime.getCacheCertainty()).andReturn(0L).anyTimes();
-    }
-
-    private void expectNetworkStatsPoll() throws Exception {
-        mNetManager.setGlobalAlert(anyLong());
-        expectLastCall().anyTimes();
+        when(mTime.forceRefresh()).thenReturn(false);
+        when(mTime.hasCache()).thenReturn(true);
+        when(mTime.currentTimeMillis()).thenReturn(currentTimeMillis());
+        when(mTime.getCacheAge()).thenReturn(0L);
+        when(mTime.getCacheCertainty()).thenReturn(0L);
     }
 
     private void expectBandwidthControlCheck() throws Exception {
-        expect(mNetManager.isBandwidthControlEnabled()).andReturn(true).atLeastOnce();
+        when(mNetManager.isBandwidthControlEnabled()).thenReturn(true);
     }
 
     private void assertStatsFilesExist(boolean exist) {
@@ -1204,7 +1084,8 @@
         info.setDetailedState(DetailedState.CONNECTED, null, null);
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(TEST_IFACE);
-        return new NetworkState(info, prop, null, null, null, TEST_SSID);
+        final NetworkCapabilities capabilities = new NetworkCapabilities();
+        return new NetworkState(info, prop, capabilities, null, null, TEST_SSID);
     }
 
     private static NetworkState buildMobile3gState(String subscriberId) {
@@ -1218,7 +1099,8 @@
         info.setRoaming(isRoaming);
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(TEST_IFACE);
-        return new NetworkState(info, prop, null, null, subscriberId, null);
+        final NetworkCapabilities capabilities = new NetworkCapabilities();
+        return new NetworkState(info, prop, capabilities, null, subscriberId, null);
     }
 
     private static NetworkState buildMobile4gState(String iface) {
@@ -1226,7 +1108,8 @@
         info.setDetailedState(DetailedState.CONNECTED, null, null);
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(iface);
-        return new NetworkState(info, prop, null, null, null, null);
+        final NetworkCapabilities capabilities = new NetworkCapabilities();
+        return new NetworkState(info, prop, capabilities, null, null, null);
     }
 
     private NetworkStats buildEmptyStats() {
@@ -1249,15 +1132,6 @@
         mElapsedRealtime += duration;
     }
 
-    private void replay() {
-        EasyMock.replay(mNetManager, mTime, mSettings, mConnManager);
-    }
-
-    private void verifyAndReset() {
-        EasyMock.verify(mNetManager, mTime, mSettings, mConnManager);
-        EasyMock.reset(mNetManager, mTime, mSettings, mConnManager);
-    }
-
     private void forcePollAndWaitForIdle() {
         mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
         // Send dummy message to make sure that any previous message has been handled
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 1c7a138..792f300 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -390,6 +390,11 @@
         }
 
         @Override
+        void injectRunOnNewThread(Runnable r) {
+            runOnHandler(r);
+        }
+
+        @Override
         void injectEnforceCallingPermission(String permission, String message) {
             if (!mCallerPermissions.contains(permission)) {
                 throw new SecurityException("Missing permission: " + permission);
@@ -402,6 +407,11 @@
         }
 
         @Override
+        String injectBuildFingerprint() {
+            return mInjectedBuildFingerprint;
+        }
+
+        @Override
         void wtf(String message, Throwable th) {
             // During tests, WTF is fatal.
             fail(message + "  exception: " + th + "\n" + Log.getStackTraceString(th));
@@ -523,6 +533,7 @@
     protected Map<String, PackageInfo> mInjectedPackages;
 
     protected Set<PackageWithUser> mUninstalledPackages;
+    protected Set<String> mSystemPackages;
 
     protected PackageManager mMockPackageManager;
     protected PackageManagerInternal mMockPackageManagerInternal;
@@ -623,6 +634,8 @@
     protected static final String PACKAGE_FALLBACK_LAUNCHER_NAME = "fallback";
     protected static final int PACKAGE_FALLBACK_LAUNCHER_PRIORITY = -999;
 
+    protected String mInjectedBuildFingerprint = "build1";
+
     static {
         QUERY_ALL.setQueryFlags(
                 ShortcutQuery.FLAG_GET_ALL_KINDS);
@@ -672,6 +685,7 @@
                 pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
 
         mUninstalledPackages = new HashSet<>();
+        mSystemPackages = new HashSet<>();
 
         mInjectedFilePathRoot = new File(getTestContext().getCacheDir(), "test-files");
 
@@ -921,6 +935,12 @@
         });
     }
 
+    protected void setPackageLastUpdateTime(String packageName, long value) {
+        updatePackageInfo(packageName, pi -> {
+            pi.lastUpdateTime = value;
+        });
+    }
+
     protected void uninstallPackage(int userId, String packageName) {
         if (ENABLE_DUMP) {
             Log.v(TAG, "Unnstall package " + packageName + " / " + userId);
@@ -952,6 +972,9 @@
         if (mUninstalledPackages.contains(PackageWithUser.of(userId, packageName))) {
             ret.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
         }
+        if (mSystemPackages.contains(packageName)) {
+            ret.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+        }
 
         if (getSignatures) {
             ret.signatures = pi.signatures;
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 253334e..46ac7ce 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -3945,11 +3945,11 @@
         mInjectedPackages.remove(CALLING_PACKAGE_1);
         mInjectedPackages.remove(CALLING_PACKAGE_3);
 
-        mService.handleUnlockUser(USER_0);
+        mService.checkPackageChanges(USER_0);
 
         assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
         assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
-        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));  // ---------------
         assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
         assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
         assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
@@ -3961,7 +3961,7 @@
         assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
         assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
 
-        mService.handleUnlockUser(USER_10);
+        mService.checkPackageChanges(USER_10);
 
         assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
         assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
@@ -4154,7 +4154,7 @@
         updatePackageVersion(CALLING_PACKAGE_1, 1);
 
         // Then send the broadcast, to only user-0.
-                mService.mPackageMonitor.onReceive(getTestContext(),
+        mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
 
         waitOnMainThread();
@@ -4186,10 +4186,13 @@
         mInjectedCurrentTimeMillis = START_TIME + 200;
 
         mRunningUsers.put(USER_10, true);
+        mUnlockedUsers.put(USER_10, true);
 
         reset(c0);
         reset(c10);
+        setPackageLastUpdateTime(CALLING_PACKAGE_1, mInjectedCurrentTimeMillis);
         mService.handleUnlockUser(USER_10);
+        mService.checkPackageChanges(USER_10);
 
         waitOnMainThread();
 
@@ -4221,7 +4224,7 @@
         // Then send the broadcast, to only user-0.
                 mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageUpdateIntent(CALLING_PACKAGE_2, USER_0));
-        mService.handleUnlockUser(USER_10);
+        mService.checkPackageChanges(USER_10);
 
         waitOnMainThread();
 
@@ -4243,9 +4246,9 @@
         updatePackageVersion(CALLING_PACKAGE_3, 100);
 
         // Then send the broadcast, to only user-0.
-                mService.mPackageMonitor.onReceive(getTestContext(),
+        mService.mPackageMonitor.onReceive(getTestContext(),
                 genPackageUpdateIntent(CALLING_PACKAGE_3, USER_0));
-        mService.handleUnlockUser(USER_10);
+        mService.checkPackageChanges(USER_10);
 
         waitOnMainThread();
 
@@ -4344,6 +4347,128 @@
         });
     }
 
+    public void testHandlePackageUpdate_systemAppUpdate() {
+
+        // Package1 is a system app.  Package 2 is not a system app, so it's not scanned
+        // in this test at all.
+        mSystemPackages.add(CALLING_PACKAGE_1);
+
+        // Initial state: no shortcuts.
+        mService.checkPackageChanges(USER_0);
+
+        assertEquals(mInjectedCurrentTimeMillis,
+                mService.getUserShortcutsLocked(USER_0).getLastAppScanTime());
+        assertEquals(mInjectedBuildFingerprint,
+                mService.getUserShortcutsLocked(USER_0).getLastAppScanOsFingerprint());
+
+        // They have no shortcuts.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        // Next.
+        // Update the packages -- now they have 1 manifest shortcut.
+        // But checkPackageChanges() don't notice it, since their version code / timestamp haven't
+        // changed.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_1);
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
+                R.xml.shortcut_1);
+        mInjectedCurrentTimeMillis += 1000;
+        mService.checkPackageChanges(USER_0);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        // Next.
+        // Update the build finger print.  All system apps will be scanned now.
+        mInjectedBuildFingerprint = "update1";
+        mInjectedCurrentTimeMillis += 1000;
+        mService.checkPackageChanges(USER_0);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1");
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        // Next.
+        // Update manifest shortcuts.
+        mInjectedBuildFingerprint = "update2";
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_2);
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
+                R.xml.shortcut_2);
+        mInjectedCurrentTimeMillis += 1000;
+        mService.checkPackageChanges(USER_0);
+
+        // Fingerprint hasn't changed, so CALLING_PACKAGE_1 wasn't scanned.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1");
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        // Update the fingerprint, but CALLING_PACKAGE_1's version code hasn't changed, so
+        // still not scanned.
+        mInjectedBuildFingerprint = "update2";
+        mInjectedCurrentTimeMillis += 1000;
+        mService.checkPackageChanges(USER_0);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1");
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        // Now update the version code, so CALLING_PACKAGE_1 is scanned again.
+        mInjectedBuildFingerprint = "update3";
+        mInjectedCurrentTimeMillis += 1000;
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        mService.checkPackageChanges(USER_0);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1", "ms2");
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertWith(getCallerShortcuts())
+                    .isEmpty();
+        });
+
+        // Make sure getLastAppScanTime / getLastAppScanOsFingerprint are persisted.
+        initService();
+        assertEquals(mInjectedCurrentTimeMillis,
+                mService.getUserShortcutsLocked(USER_0).getLastAppScanTime());
+        assertEquals(mInjectedBuildFingerprint,
+                mService.getUserShortcutsLocked(USER_0).getLastAppScanOsFingerprint());
+    }
+
     public void testHandlePackageChanged() {
         final ComponentName ACTIVITY1 = new ComponentName(CALLING_PACKAGE_1, "act1");
         final ComponentName ACTIVITY2 = new ComponentName(CALLING_PACKAGE_1, "act2");
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 34e86e7..0a7adb0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -41,7 +41,6 @@
 public class UserManagerTest extends AndroidTestCase {
     private static final int REMOVE_CHECK_INTERVAL_MILLIS = 500; // 0.5 seconds
     private static final int REMOVE_TIMEOUT_MILLIS = 60 * 1000; // 60 seconds
-    private static final int SWITCH_CHECK_INTERVAL_MILLIS = 2 * 1000; // 2 seconds
     private static final int SWITCH_USER_TIMEOUT_MILLIS = 40 * 1000; // 40 seconds
 
     private final Object mUserRemoveLock = new Object();
@@ -347,16 +346,14 @@
             ActivityManager am = getContext().getSystemService(ActivityManager.class);
             am.switchUser(userId);
             long time = System.currentTimeMillis();
-            while (am.getCurrentUser() != userId) {
-                try {
-                    mUserSwitchLock.wait(SWITCH_CHECK_INTERVAL_MILLIS);
-                } catch (InterruptedException ie) {
-                    Thread.currentThread().interrupt();
-                    return;
-                }
-                if (System.currentTimeMillis() - time > SWITCH_USER_TIMEOUT_MILLIS) {
-                    fail("Timeout waiting for the user switch to u" + userId);
-                }
+            try {
+                mUserSwitchLock.wait(SWITCH_USER_TIMEOUT_MILLIS);
+            } catch (InterruptedException ie) {
+                Thread.currentThread().interrupt();
+                return;
+            }
+            if (System.currentTimeMillis() - time > SWITCH_USER_TIMEOUT_MILLIS) {
+                fail("Timeout waiting for the user switch to u" + userId);
             }
         }
     }
diff --git a/services/tests/servicestests/src/com/android/server/retaildemo/PreloadAppsInstallerTest.java b/services/tests/servicestests/src/com/android/server/retaildemo/PreloadAppsInstallerTest.java
new file mode 100644
index 0000000..222436c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/retaildemo/PreloadAppsInstallerTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+package com.android.server.retaildemo;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.IPackageInstallObserver2;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.os.FileUtils;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.test.mock.MockContentResolver;
+
+import com.android.internal.util.FakeSettingsProvider;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.util.ArrayList;
+
+@RunWith(JUnit4.class)
+@SmallTest
+public class PreloadAppsInstallerTest {
+    private static final int TEST_DEMO_USER = 111;
+
+    private @Mock Context mContext;
+    private @Mock IPackageManager mIpm;
+    private MockContentResolver mContentResolver;
+    private File mPreloadsAppsDirectory;
+    private String[] mPreloadedApps =
+            new String[] {"test1.apk.preload", "test2.apk.preload", "test3.apk.preload"};
+    private ArrayList<String> mPreloadedAppPaths = new ArrayList<>();
+
+    private PreloadAppsInstaller mInstaller;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mContentResolver = new MockContentResolver(mContext);
+        mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+        when(mContext.getContentResolver()).thenReturn(mContentResolver);
+        initializePreloadedApps();
+        Settings.Secure.putStringForUser(mContentResolver,
+                Settings.Secure.DEMO_USER_SETUP_COMPLETE, "0", TEST_DEMO_USER);
+
+        mInstaller = new PreloadAppsInstaller(mContext, mIpm, mPreloadsAppsDirectory);
+    }
+
+    private void initializePreloadedApps() throws Exception {
+        mPreloadsAppsDirectory = new File(InstrumentationRegistry.getContext().getFilesDir(),
+                 "test_preload_apps_dir");
+        mPreloadsAppsDirectory.mkdir();
+        for (String name : mPreloadedApps) {
+            final File f = new File(mPreloadsAppsDirectory, name);
+            f.createNewFile();
+            mPreloadedAppPaths.add(f.getPath());
+        }
+    }
+
+    @After
+    public void tearDown() {
+        FileUtils.deleteContentsAndDir(mPreloadsAppsDirectory);
+    }
+
+    @Test
+    public void testInstallApps() throws Exception {
+        mInstaller.installApps(TEST_DEMO_USER);
+        for (String path : mPreloadedAppPaths) {
+            ArgumentCaptor<IPackageInstallObserver2> observer =
+                    ArgumentCaptor.forClass(IPackageInstallObserver2.class);
+            verify(mIpm).installPackageAsUser(eq(path), observer.capture(), anyInt(),
+                    anyString(), eq(TEST_DEMO_USER));
+            observer.getValue().onPackageInstalled(path, PackageManager.INSTALL_SUCCEEDED,
+                    null, null);
+            // Verify that we try to install the package in system user.
+            verify(mIpm).installExistingPackageAsUser(path, UserHandle.USER_SYSTEM);
+        }
+        assertEquals("DEMO_USER_SETUP should be set to 1 after preloaded apps are installed",
+                "1",
+                Settings.Secure.getStringForUser(mContentResolver,
+                        Settings.Secure.DEMO_USER_SETUP_COMPLETE, TEST_DEMO_USER));
+    }
+
+    @Test
+    public void testInstallApps_noPreloads() throws Exception {
+        // Delete all files in preloaded apps directory - no preloaded apps
+        FileUtils.deleteContents(mPreloadsAppsDirectory);
+        mInstaller.installApps(TEST_DEMO_USER);
+        assertEquals("DEMO_USER_SETUP should be set to 1 after preloaded apps are installed",
+                "1",
+                Settings.Secure.getStringForUser(mContentResolver,
+                        Settings.Secure.DEMO_USER_SETUP_COMPLETE, TEST_DEMO_USER));
+    }
+
+    @Test
+    public void testInstallApps_installationFails() throws Exception {
+        mInstaller.installApps(TEST_DEMO_USER);
+        for (int i = 0; i < mPreloadedAppPaths.size(); ++i) {
+            ArgumentCaptor<IPackageInstallObserver2> observer =
+                    ArgumentCaptor.forClass(IPackageInstallObserver2.class);
+            final String path = mPreloadedAppPaths.get(i);
+            verify(mIpm).installPackageAsUser(eq(path), observer.capture(), anyInt(),
+                    anyString(), eq(TEST_DEMO_USER));
+            if (i == 0) {
+                observer.getValue().onPackageInstalled(path, PackageManager.INSTALL_FAILED_DEXOPT,
+                        null, null);
+                continue;
+            }
+            observer.getValue().onPackageInstalled(path, PackageManager.INSTALL_SUCCEEDED,
+                    null, null);
+            // Verify that we try to install the package in system user.
+            verify(mIpm).installExistingPackageAsUser(path, UserHandle.USER_SYSTEM);
+        }
+        assertEquals("DEMO_USER_SETUP should be set to 1 after preloaded apps are installed",
+                "1",
+                Settings.Secure.getStringForUser(mContentResolver,
+                        Settings.Secure.DEMO_USER_SETUP_COMPLETE, TEST_DEMO_USER));
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java b/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java
new file mode 100644
index 0000000..ddc2b53
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java
@@ -0,0 +1,418 @@
+/*
+ * 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.
+ */
+
+package com.android.server.retaildemo;
+
+import static com.android.server.retaildemo.RetailDemoModeService.SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.app.ActivityManagerInternal;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.RetailDemoModeServiceInternal;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
+import android.content.res.Configuration;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.CallLog;
+import android.provider.MediaStore;
+import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.test.mock.MockContentProvider;
+import android.test.mock.MockContentResolver;
+import android.util.ArrayMap;
+
+import com.android.internal.util.FakeSettingsProvider;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.retaildemo.RetailDemoModeService.Injector;
+
+import org.hamcrest.Description;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(JUnit4.class)
+@SmallTest
+public class RetailDemoModeServiceTest {
+    private static final int TEST_DEMO_USER = 111;
+    private static final long SETUP_COMPLETE_TIMEOUT_MS = 2000; // 2 sec
+    private static final String TEST_CAMERA_PKG = "test.cameraapp";
+    private static final String TEST_PRELOADS_DIR_NAME = "test_preloads";
+
+    private @Mock Context mContext;
+    private @Mock UserManager mUm;
+    private @Mock PackageManager mPm;
+    private @Mock IPackageManager mIpm;
+    private @Mock NotificationManager mNm;
+    private @Mock ActivityManagerInternal mAmi;
+    private @Mock AudioManager mAudioManager;
+    private @Mock LockPatternUtils mLockPatternUtils;
+    private PreloadAppsInstaller mPreloadAppsInstaller;
+    private MockContentResolver mContentResolver;
+    private MockContactsProvider mContactsProvider;
+    private Configuration mConfiguration;
+    private File mTestPreloadsDir;
+    private CountDownLatch mLatch;
+
+    private RetailDemoModeService mService;
+    private TestInjector mInjector;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mContentResolver = new MockContentResolver(mContext);
+        mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+        mContactsProvider = new MockContactsProvider(mContext);
+        mContentResolver.addProvider(CallLog.AUTHORITY, mContactsProvider);
+        when(mContext.getContentResolver()).thenReturn(mContentResolver);
+        mPreloadAppsInstaller = new PreloadAppsInstaller(Mockito.mock(Context.class),
+                Mockito.mock(IPackageManager.class), Mockito.mock(File.class));
+        mConfiguration = new Configuration();
+        mTestPreloadsDir = new File(InstrumentationRegistry.getContext().getFilesDir(),
+                TEST_PRELOADS_DIR_NAME);
+
+        Settings.Global.putString(mContentResolver,
+                Settings.Global.RETAIL_DEMO_MODE_CONSTANTS, "");
+        Settings.Global.putInt(mContentResolver,
+                Settings.Global.DEVICE_PROVISIONED, 1);
+        Settings.Global.putInt(mContentResolver,
+                Settings.Global.DEVICE_DEMO_MODE, 1);
+        // Initialize RetailDemoModeService
+        mInjector = new TestInjector();
+        mService = new RetailDemoModeService(mInjector);
+        mService.onStart();
+    }
+
+    @After
+    public void tearDown() {
+        // Remove the RetailDemoModeServiceInternal from LocalServices which would've been
+        // added during initialization of RetailDemoModeService in setUp().
+        LocalServices.removeServiceForTest(RetailDemoModeServiceInternal.class);
+        FileUtils.deleteContentsAndDir(mTestPreloadsDir);
+    }
+
+    @Test
+    public void testDemoUserSetup() throws Exception {
+        mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
+
+        final ArgumentCaptor<IntentFilter> intentFilter =
+                ArgumentCaptor.forClass(IntentFilter.class);
+        verify(mContext).registerReceiver(any(BroadcastReceiver.class), intentFilter.capture());
+        assertTrue("Not registered for " + Intent.ACTION_SCREEN_OFF,
+                intentFilter.getValue().hasAction(Intent.ACTION_SCREEN_OFF));
+
+        mLatch = new CountDownLatch(1);
+
+        mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+        assertEquals(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED + " property not set",
+                "1", mInjector.systemPropertiesGet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED));
+
+        final UserInfo userInfo = new UserInfo();
+        userInfo.id = TEST_DEMO_USER;
+        when(mUm.createUser(anyString(), anyInt())).thenReturn(userInfo);
+        mInjector.setDemoUserId(TEST_DEMO_USER);
+        setCameraPackage(TEST_CAMERA_PKG);
+        // Wait for the setup to complete.
+        mLatch.await(SETUP_COMPLETE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        ArgumentCaptor<Integer> flags = ArgumentCaptor.forClass(Integer.class);
+        verify(mUm).createUser(anyString(), flags.capture());
+        assertTrue("FLAG_DEMO not set during user creation",
+                (flags.getValue() & UserInfo.FLAG_DEMO) != 0);
+        assertTrue("FLAG_EPHEMERAL not set during user creation",
+                (flags.getValue() & UserInfo.FLAG_EPHEMERAL) != 0);
+        // Verify if necessary restrictions are being set.
+        final UserHandle user = UserHandle.of(TEST_DEMO_USER);
+        verify(mUm).setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, user);
+        verify(mUm).setUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true, user);
+        verify(mUm).setUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, true, user);
+        verify(mUm).setUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER, true, user);
+        verify(mUm).setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user);
+        verify(mUm).setUserRestriction(UserManager.DISALLOW_CONFIG_BLUETOOTH, true, user);
+        verify(mUm).setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, false, user);
+        verify(mUm).setUserRestriction(UserManager.DISALLOW_SAFE_BOOT, true, UserHandle.SYSTEM);
+        // Verify if necessary settings are updated.
+        assertEquals("SKIP_FIRST_USE_HINTS setting is not set for demo user",
+                Settings.Secure.getIntForUser(mContentResolver,
+                        Settings.Secure.SKIP_FIRST_USE_HINTS, TEST_DEMO_USER),
+                1);
+        assertEquals("PACKAGE_VERIFIER_ENABLE settings should be set to 0 for demo user",
+                Settings.Global.getInt(mContentResolver,
+                        Settings.Global.PACKAGE_VERIFIER_ENABLE),
+                0);
+        // Verify if camera is granted location permission.
+        verify(mPm).grantRuntimePermission(TEST_CAMERA_PKG,
+                Manifest.permission.ACCESS_FINE_LOCATION, user);
+        // Verify call logs are cleared.
+        assertTrue("Call logs should be deleted", mContactsProvider.isCallLogDeleted());
+    }
+
+    @Test
+    public void testSettingsObserver() throws Exception {
+        final RetailDemoModeService.SettingsObserver observer =
+                mService.new SettingsObserver(new Handler(Looper.getMainLooper()));
+        final Uri deviceDemoModeUri = Settings.Global.getUriFor(Settings.Global.DEVICE_DEMO_MODE);
+        // Settings.Global.DEVICE_DEMO_MODE has been set to 1 initially.
+        observer.onChange(false, deviceDemoModeUri);
+        assertEquals(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED + " property not set",
+                "1", mInjector.systemPropertiesGet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED));
+
+        new File(mTestPreloadsDir, "dir1").mkdirs();
+        new File(mTestPreloadsDir, "file1").createNewFile();
+        Settings.Global.putInt(mContentResolver, Settings.Global.DEVICE_DEMO_MODE, 0);
+        observer.onChange(false, deviceDemoModeUri);
+        Thread.sleep(20); // Wait for the deletion to complete.
+        // verify that the preloaded directory is emptied.
+        assertEquals("Preloads directory is not emptied",
+                0, mTestPreloadsDir.list().length);
+    }
+
+    @Test
+    public void testSwitchToDemoUser() {
+        // To make the RetailDemoModeService update it's internal state.
+        mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
+        final RetailDemoModeService.SettingsObserver observer =
+                mService.new SettingsObserver(new Handler(Looper.getMainLooper()));
+        observer.onChange(false, Settings.Global.getUriFor(Settings.Global.DEVICE_DEMO_MODE));
+
+        final UserInfo userInfo = new UserInfo(TEST_DEMO_USER, "demo_user",
+                UserInfo.FLAG_DEMO | UserInfo.FLAG_EPHEMERAL);
+        when(mUm.getUserInfo(TEST_DEMO_USER)).thenReturn(userInfo);
+        final int minVolume = -111;
+        for (int stream : RetailDemoModeService.VOLUME_STREAMS_TO_MUTE) {
+            when(mAudioManager.getStreamMinVolume(stream)).thenReturn(minVolume);
+        }
+
+        mService.onSwitchUser(TEST_DEMO_USER);
+        verify(mAmi).updatePersistentConfigurationForUser(mConfiguration, TEST_DEMO_USER);
+        for (int stream : RetailDemoModeService.VOLUME_STREAMS_TO_MUTE) {
+            verify(mAudioManager).setStreamVolume(stream, minVolume, 0);
+        }
+        verify(mLockPatternUtils).setLockScreenDisabled(true, TEST_DEMO_USER);
+    }
+
+    private void setCameraPackage(String pkgName) {
+        final ResolveInfo ri = new ResolveInfo();
+        final ActivityInfo ai = new ActivityInfo();
+        ai.packageName = pkgName;
+        ri.activityInfo = ai;
+        when(mPm.resolveActivityAsUser(
+                argThat(new IntentMatcher(MediaStore.ACTION_IMAGE_CAPTURE)),
+                anyInt(),
+                eq(TEST_DEMO_USER))).thenReturn(ri);
+    }
+
+    private class IntentMatcher extends ArgumentMatcher<Intent> {
+        private final Intent mIntent;
+
+        IntentMatcher(String action) {
+            mIntent = new Intent(action);
+        }
+
+        @Override
+        public boolean matches(Object argument) {
+            if (argument instanceof Intent) {
+                return ((Intent) argument).filterEquals(mIntent);
+            }
+            return false;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("Expected: " + mIntent);
+        }
+    }
+
+    private class MockContactsProvider extends MockContentProvider {
+        private boolean mCallLogDeleted;
+
+        MockContactsProvider(Context context) {
+            super(context);
+        }
+
+        @Override
+        public int delete(Uri uri, String selection, String[] selectionArgs) {
+            if (CallLog.Calls.CONTENT_URI.equals(uri)) {
+                mCallLogDeleted = true;
+            }
+            return 0;
+        }
+
+        public boolean isCallLogDeleted() {
+            return mCallLogDeleted;
+        }
+    }
+
+    private class TestInjector extends Injector {
+        private ArrayMap<String, String> mSystemProperties = new ArrayMap<>();
+        private int mDemoUserId = UserHandle.USER_NULL;
+
+        TestInjector() {
+            super(mContext);
+        }
+
+        @Override
+        Context getContext() {
+            return mContext;
+        }
+
+        @Override
+        UserManager getUserManager() {
+            return mUm;
+        }
+
+        @Override
+        void switchUser(int userId) {
+            if (mLatch != null) {
+                mLatch.countDown();
+            }
+        }
+
+        @Override
+        AudioManager getAudioManager() {
+            return mAudioManager;
+        }
+
+        @Override
+        NotificationManager getNotificationManager() {
+            return mNm;
+        }
+
+        @Override
+        ActivityManagerInternal getActivityManagerInternal() {
+            return mAmi;
+        }
+
+        @Override
+        PackageManager getPackageManager() {
+            return mPm;
+        }
+
+        @Override
+        IPackageManager getIPackageManager() {
+            return mIpm;
+        }
+
+        @Override
+        ContentResolver getContentResolver() {
+            return mContentResolver;
+        }
+
+        @Override
+        PreloadAppsInstaller getPreloadAppsInstaller() {
+            return mPreloadAppsInstaller;
+        }
+
+        @Override
+        void systemPropertiesSet(String key, String value) {
+            mSystemProperties.put(key, value);
+        }
+
+        @Override
+        void turnOffAllFlashLights(String[] cameraIdsWithFlash) {
+        }
+
+        @Override
+        void initializeWakeLock() {
+        }
+
+        @Override
+        boolean isWakeLockHeld() {
+            return false;
+        }
+
+        @Override
+        void acquireWakeLock() {
+        }
+
+        @Override
+        void releaseWakeLock() {
+        }
+
+        @Override
+        void logSessionDuration(int duration) {
+        }
+
+        @Override
+        void logSessionCount(int count) {
+        }
+
+        @Override
+        Configuration getSystemUsersConfiguration() {
+            return mConfiguration;
+        }
+
+        @Override
+        LockPatternUtils getLockPatternUtils() {
+            return mLockPatternUtils;
+        }
+
+        @Override
+        Notification createResetNotification() {
+            return null;
+        }
+
+        @Override
+        File getDataPreloadsDirectory() {
+            return mTestPreloadsDir;
+        }
+
+        String systemPropertiesGet(String key) {
+            return mSystemProperties.get(key);
+        }
+
+        void setDemoUserId(int userId) {
+            mDemoUserId = userId;
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
index 9ccb1a6..0bd014c 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
@@ -67,7 +67,7 @@
         // Screen on time should not keep progressing with screen is off
         assertEquals(aih.getScreenOnTimeLocked(7000), 3000);
         assertEquals(aih.getScreenOnTimeLocked(8000), 3000);
-        aih.writeElapsedTimeLocked();
+        aih.writeAppIdleDurationsLocked();
 
         // Check if the screen on time is persisted across instantiations
         AppIdleHistory aih2 = new AppIdleHistory(mStorageDir, 0);
diff --git a/services/tests/shortcutmanagerutils/Android.mk b/services/tests/shortcutmanagerutils/Android.mk
index 701e058..2818457 100644
--- a/services/tests/shortcutmanagerutils/Android.mk
+++ b/services/tests/shortcutmanagerutils/Android.mk
@@ -26,6 +26,6 @@
 
 LOCAL_MODULE := ShortcutManagerTestUtils
 
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := test_current
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
index 78f95c4..1fe5cb7 100644
--- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
+++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
@@ -156,10 +156,10 @@
         return result;
     }
 
-    private static List<String> runCommand(Instrumentation instrumentation, String command) {
+    public static List<String> runCommand(Instrumentation instrumentation, String command) {
         return runCommand(instrumentation, command, null);
     }
-    private static List<String> runCommand(Instrumentation instrumentation, String command,
+    public static List<String> runCommand(Instrumentation instrumentation, String command,
             Predicate<List<String>> resultAsserter) {
         Log.d(TAG, "Running command: " + command);
         final List<String> result;
@@ -175,11 +175,11 @@
         return result;
     }
 
-    private static void runCommandForNoOutput(Instrumentation instrumentation, String command) {
+    public static void runCommandForNoOutput(Instrumentation instrumentation, String command) {
         runCommand(instrumentation, command, result -> result.size() == 0);
     }
 
-    private static List<String> runShortcutCommand(Instrumentation instrumentation, String command,
+    public static List<String> runShortcutCommand(Instrumentation instrumentation, String command,
             Predicate<List<String>> resultAsserter) {
         return runCommand(instrumentation, "cmd shortcut " + command, resultAsserter);
     }
@@ -204,7 +204,8 @@
     }
 
     public static void setDefaultLauncher(Instrumentation instrumentation, String component) {
-        runCommand(instrumentation, "cmd package set-home-activity " + component,
+        runCommand(instrumentation, "cmd package set-home-activity --user "
+                + instrumentation.getContext().getUserId() + " " + component,
                 result -> result.contains("Success"));
     }
 
@@ -1053,7 +1054,11 @@
     }
 
     public static void retryUntil(BooleanSupplier checker, String message) {
-        final long timeOut = System.currentTimeMillis() + 30 * 1000; // wait for 30 seconds.
+        retryUntil(checker, message, 30);
+    }
+
+    public static void retryUntil(BooleanSupplier checker, String message, long timeoutSeconds) {
+        final long timeOut = System.currentTimeMillis() + timeoutSeconds * 1000;
         while (!checker.getAsBoolean()) {
             if (System.currentTimeMillis() > timeOut) {
                 break;
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index a3313c9..f69dae4 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -118,7 +118,6 @@
         } else {
             mScreenOnDuration += elapsedRealtime - mScreenOnSnapshot;
             mElapsedDuration += elapsedRealtime - mElapsedSnapshot;
-            writeScreenOnTimeLocked();
             mElapsedSnapshot = elapsedRealtime;
         }
     }
@@ -167,7 +166,7 @@
     /**
      * To be called periodically to keep track of elapsed time when app idle times are written
      */
-    public void writeElapsedTimeLocked() {
+    public void writeAppIdleDurationsLocked() {
         final long elapsedRealtime = SystemClock.elapsedRealtime();
         // Only bump up and snapshot the elapsed time. Don't change screen on duration.
         mElapsedDuration += elapsedRealtime - mElapsedSnapshot;
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 69cf1a2..8284773 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -304,9 +304,9 @@
 
         @Override public void onDisplayChanged(int displayId) {
             if (displayId == Display.DEFAULT_DISPLAY) {
+                final boolean displayOn = isDisplayOn();
                 synchronized (UsageStatsService.this.mLock) {
-                    mAppIdleHistory.updateDisplayLocked(isDisplayOn(),
-                            SystemClock.elapsedRealtime());
+                    mAppIdleHistory.updateDisplayLocked(displayOn, SystemClock.elapsedRealtime());
                 }
             }
         }
@@ -1005,9 +1005,9 @@
             service.persistActiveStats();
             mAppIdleHistory.writeAppIdleTimesLocked(mUserState.keyAt(i));
         }
-        // Persist elapsed time periodically, in case screen doesn't get toggled
-        // until the next boot
-        mAppIdleHistory.writeElapsedTimeLocked();
+        // Persist elapsed and screen on time. If this fails for whatever reason, the apps will be
+        // considered not-idle, which is the safest outcome in such an event.
+        mAppIdleHistory.writeAppIdleDurationsLocked();
         mHandler.removeMessages(MSG_FLUSH_TO_DISK);
     }
 
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 43d2a1f..a04034e 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -535,6 +535,18 @@
                     + " user=" + userHandle);
         }
 
+        ComponentName getCurAssistant(int userHandle) {
+            String curAssistant = Settings.Secure.getStringForUser(
+                    mContext.getContentResolver(),
+                    Settings.Secure.ASSISTANT, userHandle);
+            if (TextUtils.isEmpty(curAssistant)) {
+                return null;
+            }
+            if (DEBUG) Slog.d(TAG, "getCurAssistant curAssistant=" + curAssistant
+                    + " user=" + userHandle);
+            return ComponentName.unflattenFromString(curAssistant);
+        }
+
         void resetCurAssistant(int userHandle) {
             Settings.Secure.putStringForUser(mContext.getContentResolver(),
                     Settings.Secure.ASSISTANT, null, userHandle);
@@ -1178,6 +1190,7 @@
                 synchronized (VoiceInteractionManagerServiceStub.this) {
                     ComponentName curInteractor = getCurInteractor(userHandle);
                     ComponentName curRecognizer = getCurRecognizer(userHandle);
+                    ComponentName curAssistant = getCurAssistant(userHandle);
                     if (curRecognizer == null) {
                         // Could a new recognizer appear when we don't have one pre-installed?
                         if (anyPackagesAppearing()) {
@@ -1196,6 +1209,7 @@
                             // the default config.
                             setCurInteractor(null, userHandle);
                             setCurRecognizer(null, userHandle);
+                            resetCurAssistant(userHandle);
                             initForUser(userHandle);
                             return;
                         }
@@ -1212,6 +1226,20 @@
                         return;
                     }
 
+                    if (curAssistant != null) {
+                        int change = isPackageDisappearing(curAssistant.getPackageName());
+                        if (change == PACKAGE_PERMANENT_CHANGE) {
+                            // If the currently set assistant is being removed, then we should
+                            // reset back to the default state (which is probably that we prefer
+                            // to have the default full voice interactor enabled).
+                            setCurInteractor(null, userHandle);
+                            setCurRecognizer(null, userHandle);
+                            resetCurAssistant(userHandle);
+                            initForUser(userHandle);
+                            return;
+                        }
+                    }
+
                     // There is no interactor, so just deal with a simple recognizer.
                     int change = isPackageDisappearing(curRecognizer.getPackageName());
                     if (change == PACKAGE_PERMANENT_CHANGE
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 4da5ff2..a093d54 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -461,6 +461,32 @@
      */
     public static final String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED";
 
+    /**
+     * Connection event used to inform {@link InCallService}s when a call has been put on hold by
+     * the remote party.
+     * <p>
+     * This is different than the {@link Connection#STATE_HOLDING} state which indicates that the
+     * call is being held locally on the device.  When a capable {@link ConnectionService} receives
+     * signalling to indicate that the remote party has put the call on hold, it can send this
+     * connection event.
+     * @hide
+     */
+    public static final String EVENT_CALL_REMOTELY_HELD =
+            "android.telecom.event.CALL_REMOTELY_HELD";
+
+    /**
+     * Connection event used to inform {@link InCallService}s when a call which was remotely held
+     * (see {@link #EVENT_CALL_REMOTELY_HELD}) has been un-held by the remote party.
+     * <p>
+     * This is different than the {@link Connection#STATE_HOLDING} state which indicates that the
+     * call is being held locally on the device.  When a capable {@link ConnectionService} receives
+     * signalling to indicate that the remote party has taken the call off hold, it can send this
+     * connection event.
+     * @hide
+     */
+    public static final String EVENT_CALL_REMOTELY_UNHELD =
+            "android.telecom.event.CALL_REMOTELY_UNHELD";
+
     // Flag controlling whether PII is emitted into the logs
     private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index e666986..fe9a93c 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -246,6 +246,29 @@
     public static final String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
 
     /**
+     * Flag specifying whether the carrier wants to notify the user when a VT call has been handed
+     * over from WIFI to LTE.
+     * <p>
+     * The handover notification is sent as a
+     * {@link TelephonyManager#EVENT_HANDOVER_VIDEO_FROM_WIFI_TO_LTE}
+     * {@link android.telecom.Connection} event, which an {@link android.telecom.InCallService}
+     * should use to trigger the display of a user-facing message.
+     * <p>
+     * The Connection event is sent to the InCallService only once, the first time it occurs.
+     * @hide
+     */
+    public static final String KEY_NOTIFY_HANDOVER_VIDEO_FROM_WIFI_TO_LTE_BOOL =
+            "notify_handover_video_from_wifi_to_lte_bool";
+
+    /**
+     * Flag specifying whether the carrier supports downgrading a video call (tx, rx or tx/rx)
+     * directly to an audio call.
+     * @hide
+     */
+    public static final String KEY_SUPPORT_DOWNGRADE_VT_TO_AUDIO_BOOL =
+            "support_downgrade_vt_to_audio_bool";
+
+    /**
      * Flag specifying whether WFC over IMS should be available for carrier: independent of
      * carrier provisioning. If false: hard disabled. If true: then depends on carrier
      * provisioning, availability etc.
@@ -919,6 +942,15 @@
     public static final String KEY_NOTIFY_VT_HANDOVER_TO_WIFI_FAILURE_BOOL =
             "notify_vt_handover_to_wifi_failure_bool";
 
+    /**
+     * A upper case list of CNAP names that are unhelpful to the user for distinguising calls and
+     * should be filtered out of the CNAP information. This includes CNAP names such as "WIRELESS
+     * CALLER" or "UNKNOWN NAME". By default, if there are no filtered names for this carrier, null
+     * is returned.
+     * @hide
+     */
+    public static final String FILTERED_CNAP_NAMES_STRING_ARRAY = "filtered_cnap_names_string_array";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -933,6 +965,8 @@
         sDefaults.putBoolean(KEY_CARRIER_SETTINGS_ENABLE_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VT_AVAILABLE_BOOL, false);
+        sDefaults.putBoolean(KEY_NOTIFY_HANDOVER_VIDEO_FROM_WIFI_TO_LTE_BOOL, false);
+        sDefaults.putBoolean(KEY_SUPPORT_DOWNGRADE_VT_TO_AUDIO_BOOL, true);
         sDefaults.putBoolean(KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL, false);
@@ -1085,6 +1119,7 @@
         sDefaults.putStringArray(KEY_IMS_REASONINFO_MAPPING_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_ENHANCED_4G_LTE_TITLE_VARIANT_BOOL, false);
         sDefaults.putBoolean(KEY_NOTIFY_VT_HANDOVER_TO_WIFI_FAILURE_BOOL, false);
+        sDefaults.putStringArray(FILTERED_CNAP_NAMES_STRING_ARRAY, null);
     }
 
     /**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 4138aa0..68a390d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -705,6 +705,17 @@
             "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT";
 
     /**
+     * {@link android.telecom.Connection} event used to indicate that an IMS call has be
+     * successfully handed over from WIFI to LTE.
+     * <p>
+     * Sent via {@link android.telecom.Connection#sendConnectionEvent(String, Bundle)}.
+     * The {@link Bundle} parameter is expected to be null when this connection event is used.
+     * @hide
+     */
+    public static final String EVENT_HANDOVER_VIDEO_FROM_WIFI_TO_LTE =
+            "android.telephony.event.EVENT_HANDOVER_VIDEO_FROM_WIFI_TO_LTE";
+
+    /**
      * {@link android.telecom.Connection} event used to indicate that an IMS call failed to be
      * handed over from LTE to WIFI.
      * <p>
@@ -716,6 +727,28 @@
             "android.telephony.event.EVENT_HANDOVER_TO_WIFI_FAILED";
 
     /**
+     * {@link android.telecom.Connection} event used to indicate that a video call was downgraded to
+     * audio because the data limit was reached.
+     * <p>
+     * Sent via {@link android.telecom.Connection#sendConnectionEvent(String, Bundle)}.
+     * The {@link Bundle} parameter is expected to be null when this connection event is used.
+     * @hide
+     */
+    public static final String EVENT_DOWNGRADE_DATA_LIMIT_REACHED =
+            "android.telephony.event.EVENT_DOWNGRADE_DATA_LIMIT_REACHED";
+
+    /**
+     * {@link android.telecom.Connection} event used to indicate that a video call was downgraded to
+     * audio because the data was disabled.
+     * <p>
+     * Sent via {@link android.telecom.Connection#sendConnectionEvent(String, Bundle)}.
+     * The {@link Bundle} parameter is expected to be null when this connection event is used.
+     * @hide
+     */
+    public static final String EVENT_DOWNGRADE_DATA_DISABLED =
+            "android.telephony.event.EVENT_DOWNGRADE_DATA_DISABLED";
+
+    /**
      * Response codes for sim activation. Activation completed successfully.
      * @hide
      */
diff --git a/tests/TouchLatency/.gitignore b/tests/TouchLatency/.gitignore
new file mode 100644
index 0000000..cfb7164
--- /dev/null
+++ b/tests/TouchLatency/.gitignore
@@ -0,0 +1,5 @@
+.gradle
+/local.properties
+/.idea
+.DS_Store
+/build
diff --git a/tests/TouchLatency/Android.mk b/tests/TouchLatency/Android.mk
new file mode 100644
index 0000000..73b5b6c
--- /dev/null
+++ b/tests/TouchLatency/Android.mk
@@ -0,0 +1,27 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_MANIFEST_FILE := app/src/main/AndroidManifest.xml
+
+# omit gradle 'build' dir
+LOCAL_SRC_FILES := $(call all-java-files-under,app/src/main/java)
+
+# use appcompat/support lib from the tree, so improvements/
+# regressions are reflected in test data
+LOCAL_RESOURCE_DIR := \
+    $(LOCAL_PATH)/app/src/main/res \
+    frameworks/support/v7/appcompat/res
+
+LOCAL_AAPT_FLAGS := \
+    --auto-add-overlay \
+    --extra-packages android.support.v7.appcompat
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-v4 \
+    android-support-v7-appcompat
+
+LOCAL_PACKAGE_NAME := TouchLatency
+
+include $(BUILD_PACKAGE)
diff --git a/tests/TouchLatency/TouchLatency.iml b/tests/TouchLatency/TouchLatency.iml
new file mode 100644
index 0000000..cd87cea
--- /dev/null
+++ b/tests/TouchLatency/TouchLatency.iml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
+  <component name="FacetManager">
+    <facet type="java-gradle" name="Java-Gradle">
+      <configuration>
+        <option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
+        <option name="BUILDABLE" value="false" />
+      </configuration>
+    </facet>
+  </component>
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/.gradle" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/tests/TouchLatency/app/.gitignore b/tests/TouchLatency/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/tests/TouchLatency/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/tests/TouchLatency/app/app.iml b/tests/TouchLatency/app/app.iml
new file mode 100644
index 0000000..689e5e0
--- /dev/null
+++ b/tests/TouchLatency/app/app.iml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="TouchLatency" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
+  <component name="FacetManager">
+    <facet type="android-gradle" name="Android-Gradle">
+      <configuration>
+        <option name="GRADLE_PROJECT_PATH" value=":app" />
+      </configuration>
+    </facet>
+    <facet type="android" name="Android">
+      <configuration>
+        <option name="SELECTED_BUILD_VARIANT" value="debug" />
+        <option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
+        <option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
+        <option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
+        <option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
+        <option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" />
+        <option name="TEST_SOURCE_GEN_TASK_NAME" value="generateDebugAndroidTestSources" />
+        <option name="ALLOW_USER_CONFIGURATION" value="false" />
+        <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
+        <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
+        <option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
+        <option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
+      </configuration>
+    </facet>
+  </component>
+  <component name="NewModuleRootManager" inherit-compiler-output="false">
+    <output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
+    <output-test url="file://$MODULE_DIR$/build/intermediates/classes/androidTest/debug" />
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/debug" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/androidTest/debug" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/libs" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndk" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
+      <excludeFolder url="file://$MODULE_DIR$/build/outputs" />
+      <excludeFolder url="file://$MODULE_DIR$/build/tmp" />
+    </content>
+    <orderEntry type="jdk" jdkName="Android API 21 Platform" jdkType="Android SDK" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" exported="" name="appcompat-v7-21.0.3" level="project" />
+    <orderEntry type="library" exported="" name="support-annotations-21.0.3" level="project" />
+    <orderEntry type="library" exported="" name="support-v4-21.0.3" level="project" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/tests/TouchLatency/app/build.gradle b/tests/TouchLatency/app/build.gradle
new file mode 100644
index 0000000..7133beb
--- /dev/null
+++ b/tests/TouchLatency/app/build.gradle
@@ -0,0 +1,25 @@
+apply plugin: 'com.android.application'
+
+android {
+    compileSdkVersion 21
+    buildToolsVersion "21.1.2"
+
+    defaultConfig {
+        applicationId "com.prefabulated.touchlatency"
+        minSdkVersion 21
+        targetSdkVersion 21
+        versionCode 1
+        versionName "1.0"
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+}
+
+dependencies {
+    compile fileTree(dir: 'libs', include: ['*.jar'])
+    compile 'com.android.support:appcompat-v7:21.0.3'
+}
diff --git a/tests/TouchLatency/app/proguard-rules.pro b/tests/TouchLatency/app/proguard-rules.pro
new file mode 100644
index 0000000..de32a74
--- /dev/null
+++ b/tests/TouchLatency/app/proguard-rules.pro
@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /usr/local/google/home/stoza/android-sdk-linux/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
diff --git a/tests/TouchLatency/app/src/androidTest/java/com/prefabulated/touchlatency/ApplicationTest.java b/tests/TouchLatency/app/src/androidTest/java/com/prefabulated/touchlatency/ApplicationTest.java
new file mode 100644
index 0000000..717e397
--- /dev/null
+++ b/tests/TouchLatency/app/src/androidTest/java/com/prefabulated/touchlatency/ApplicationTest.java
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package com.prefabulated.touchlatency;
+
+import android.app.Application;
+import android.test.ApplicationTestCase;
+
+/**
+ * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
+ */
+public class ApplicationTest extends ApplicationTestCase<Application> {
+    public ApplicationTest() {
+        super(Application.class);
+    }
+}
diff --git a/tests/TouchLatency/app/src/main/AndroidManifest.xml b/tests/TouchLatency/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..e4aa4dc
--- /dev/null
+++ b/tests/TouchLatency/app/src/main/AndroidManifest.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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.prefabulated.touchlatency" >
+
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name=".TouchLatencyActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java b/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java
new file mode 100644
index 0000000..7c13974
--- /dev/null
+++ b/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java
@@ -0,0 +1,210 @@
+/*
+ * 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.
+ */
+
+package com.prefabulated.touchlatency;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.os.CountDownTimer;
+import android.support.v7.app.ActionBarActivity;
+import android.os.Bundle;
+import android.text.method.Touch;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+class TouchLatencyView extends View implements View.OnTouchListener {
+    private static final String LOG_TAG = "TouchLatency";
+    private static final int BACKGROUND_COLOR = 0xFF400080;
+    private static final int INNER_RADIUS = 70;
+    private static final int BALL_RADIUS = 100;
+
+    public TouchLatencyView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setOnTouchListener(this);
+        setWillNotDraw(false);
+        mBluePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mBluePaint.setColor(0xFF0000FF);
+        mBluePaint.setStyle(Paint.Style.FILL);
+        mGreenPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mGreenPaint.setColor(0xFF00FF00);
+        mGreenPaint.setStyle(Paint.Style.FILL);
+        mYellowPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mYellowPaint.setColor(0xFFFFFF00);
+        mYellowPaint.setStyle(Paint.Style.FILL);
+        mRedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mRedPaint.setColor(0xFFFF0000);
+        mRedPaint.setStyle(Paint.Style.FILL);
+
+        mTouching = false;
+
+        mBallX = 100.0f;
+        mBallY = 100.0f;
+        mVelocityX = 7.0f;
+        mVelocityY = 7.0f;
+    }
+
+    @Override
+    public boolean onTouch(View view, MotionEvent event) {
+        int action = event.getActionMasked();
+        if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE) {
+            mTouching = true;
+            invalidate();
+        } else if (action == MotionEvent.ACTION_UP) {
+            mTouching = false;
+            invalidate();
+            return true;
+        } else {
+            return true;
+        }
+        mTouchX = event.getX();
+        mTouchY = event.getY();
+        return true;
+    }
+
+    private void drawTouch(Canvas canvas) {
+        if (!mTouching) {
+            Log.d(LOG_TAG, "Filling background");
+            canvas.drawColor(BACKGROUND_COLOR);
+            return;
+        }
+
+        float deltaX = (mTouchX - mLastDrawnX);
+        float deltaY = (mTouchY - mLastDrawnY);
+        float scaleFactor = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY) * 1.5f;
+
+        mLastDrawnX = mTouchX;
+        mLastDrawnY = mTouchY;
+
+        canvas.drawColor(BACKGROUND_COLOR);
+        canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 3 * scaleFactor, mRedPaint);
+        canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 2 * scaleFactor, mYellowPaint);
+        canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + scaleFactor, mGreenPaint);
+        canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS, mBluePaint);
+    }
+
+    private void drawBall(Canvas canvas) {
+        int width = canvas.getWidth();
+        int height = canvas.getHeight();
+
+        // Update position
+        mBallX += mVelocityX;
+        mBallY += mVelocityY;
+
+        // Clamp and change velocity if necessary
+        float left = mBallX - BALL_RADIUS;
+        if (left < 0) {
+            left = 0;
+            mVelocityX *= -1;
+        }
+
+        float top = mBallY - BALL_RADIUS;
+        if (top < 0) {
+            top = 0;
+            mVelocityY *= -1;
+        }
+
+        float right = mBallX + BALL_RADIUS;
+        if (right > width) {
+            right = width;
+            mVelocityX *= -1;
+        }
+
+        float bottom = mBallY + BALL_RADIUS;
+        if (bottom > height) {
+            bottom = height;
+            mVelocityY *= -1;
+        }
+
+        // Draw the ball
+        canvas.drawColor(BACKGROUND_COLOR);
+        canvas.drawOval(left, top, right, bottom, mYellowPaint);
+        invalidate();
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+
+        if (mMode == 0) {
+            drawTouch(canvas);
+        } else {
+            drawBall(canvas);
+        }
+    }
+
+    public void changeMode(MenuItem item) {
+        final int NUM_MODES = 2;
+        final String modes[] = {"Touch", "Ball"};
+        mMode = (mMode + 1) % NUM_MODES;
+        invalidate();
+        item.setTitle(modes[mMode]);
+    }
+
+    private Paint mBluePaint, mGreenPaint, mYellowPaint, mRedPaint;
+    private int mMode;
+
+    private boolean mTouching;
+    private float mTouchX, mTouchY;
+    private float mLastDrawnX, mLastDrawnY;
+
+    private float mBallX, mBallY;
+    private float mVelocityX, mVelocityY;
+}
+
+public class TouchLatencyActivity extends ActionBarActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_touch_latency);
+
+        mTouchView = (TouchLatencyView) findViewById(R.id.canvasView);
+    }
+
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // Inflate the menu; this adds items to the action bar if it is present.
+        getMenuInflater().inflate(R.menu.menu_touch_latency, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        // Handle action bar item clicks here. The action bar will
+        // automatically handle clicks on the Home/Up button, so long
+        // as you specify a parent activity in AndroidManifest.xml.
+        int id = item.getItemId();
+
+        //noinspection SimplifiableIfStatement
+        if (id == R.id.action_settings) {
+            mTouchView.changeMode(item);
+        }
+
+        return super.onOptionsItemSelected(item);
+    }
+
+    private TouchLatencyView mTouchView;
+}
diff --git a/tests/TouchLatency/app/src/main/res/layout/activity_touch_latency.xml b/tests/TouchLatency/app/src/main/res/layout/activity_touch_latency.xml
new file mode 100644
index 0000000..8d20ff2
--- /dev/null
+++ b/tests/TouchLatency/app/src/main/res/layout/activity_touch_latency.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
+    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".TouchLatencyActivity">
+
+    <com.prefabulated.touchlatency.TouchLatencyView
+        android:id = "@+id/canvasView"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent" />
+
+</RelativeLayout>
diff --git a/tests/TouchLatency/app/src/main/res/menu/menu_touch_latency.xml b/tests/TouchLatency/app/src/main/res/menu/menu_touch_latency.xml
new file mode 100644
index 0000000..1824f4a
--- /dev/null
+++ b/tests/TouchLatency/app/src/main/res/menu/menu_touch_latency.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools" tools:context=".TouchLatencyActivity">
+    <item android:id="@+id/action_settings" android:title="@string/mode"
+        android:orderInCategory="100" app:showAsAction="always" />
+</menu>
diff --git a/tests/TouchLatency/app/src/main/res/mipmap-hdpi/ic_launcher.png b/tests/TouchLatency/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
--- /dev/null
+++ b/tests/TouchLatency/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/tests/TouchLatency/app/src/main/res/mipmap-mdpi/ic_launcher.png b/tests/TouchLatency/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
--- /dev/null
+++ b/tests/TouchLatency/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/tests/TouchLatency/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/tests/TouchLatency/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
--- /dev/null
+++ b/tests/TouchLatency/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/TouchLatency/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/tests/TouchLatency/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
--- /dev/null
+++ b/tests/TouchLatency/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/TouchLatency/app/src/main/res/values-w820dp/dimens.xml b/tests/TouchLatency/app/src/main/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000..1f222e1
--- /dev/null
+++ b/tests/TouchLatency/app/src/main/res/values-w820dp/dimens.xml
@@ -0,0 +1,21 @@
+<?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>
+    <!-- Example customization of dimensions originally defined in res/values/dimens.xml
+         (such as screen margins) for screens with more than 820dp of available width. This
+         would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
+    <dimen name="activity_horizontal_margin">64dp</dimen>
+</resources>
diff --git a/tests/TouchLatency/app/src/main/res/values/dimens.xml b/tests/TouchLatency/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..5eeebd7
--- /dev/null
+++ b/tests/TouchLatency/app/src/main/res/values/dimens.xml
@@ -0,0 +1,20 @@
+<?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>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">0dp</dimen>
+    <dimen name="activity_vertical_margin">0dp</dimen>
+</resources>
diff --git a/tests/TouchLatency/app/src/main/res/values/strings.xml b/tests/TouchLatency/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..b97f095
--- /dev/null
+++ b/tests/TouchLatency/app/src/main/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?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>
+    <string name="app_name">Touch Latency</string>
+
+    <string name="mode">Touch</string>
+</resources>
diff --git a/tests/TouchLatency/app/src/main/res/values/styles.xml b/tests/TouchLatency/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..aa7c09f
--- /dev/null
+++ b/tests/TouchLatency/app/src/main/res/values/styles.xml
@@ -0,0 +1,23 @@
+<?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>
+
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+        <!-- Customize your theme here. -->
+    </style>
+
+</resources>
diff --git a/tests/TouchLatency/build.gradle b/tests/TouchLatency/build.gradle
new file mode 100644
index 0000000..d3ff69d
--- /dev/null
+++ b/tests/TouchLatency/build.gradle
@@ -0,0 +1,19 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+    repositories {
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:1.1.0'
+
+        // NOTE: Do not place your application dependencies here; they belong
+        // in the individual module build.gradle files
+    }
+}
+
+allprojects {
+    repositories {
+        jcenter()
+    }
+}
diff --git a/tests/TouchLatency/gradle.properties b/tests/TouchLatency/gradle.properties
new file mode 100644
index 0000000..1d3591c
--- /dev/null
+++ b/tests/TouchLatency/gradle.properties
@@ -0,0 +1,18 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+# Default value: -Xmx10248m -XX:MaxPermSize=256m
+# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
\ No newline at end of file
diff --git a/tests/TouchLatency/gradle/wrapper/gradle-wrapper.jar b/tests/TouchLatency/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..8c0fb64
--- /dev/null
+++ b/tests/TouchLatency/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties b/tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..0c71e76
--- /dev/null
+++ b/tests/TouchLatency/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Apr 10 15:27:10 PDT 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
diff --git a/tests/TouchLatency/gradlew b/tests/TouchLatency/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/tests/TouchLatency/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/tests/TouchLatency/gradlew.bat b/tests/TouchLatency/gradlew.bat
new file mode 100644
index 0000000..aec9973
--- /dev/null
+++ b/tests/TouchLatency/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off

+@rem ##########################################################################

+@rem

+@rem  Gradle startup script for Windows

+@rem

+@rem ##########################################################################

+

+@rem Set local scope for the variables with windows NT shell

+if "%OS%"=="Windows_NT" setlocal

+

+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.

+set DEFAULT_JVM_OPTS=

+

+set DIRNAME=%~dp0

+if "%DIRNAME%" == "" set DIRNAME=.

+set APP_BASE_NAME=%~n0

+set APP_HOME=%DIRNAME%

+

+@rem Find java.exe

+if defined JAVA_HOME goto findJavaFromJavaHome

+

+set JAVA_EXE=java.exe

+%JAVA_EXE% -version >NUL 2>&1

+if "%ERRORLEVEL%" == "0" goto init

+

+echo.

+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:findJavaFromJavaHome

+set JAVA_HOME=%JAVA_HOME:"=%

+set JAVA_EXE=%JAVA_HOME%/bin/java.exe

+

+if exist "%JAVA_EXE%" goto init

+

+echo.

+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:init

+@rem Get command-line arguments, handling Windowz variants

+

+if not "%OS%" == "Windows_NT" goto win9xME_args

+if "%@eval[2+2]" == "4" goto 4NT_args

+

+:win9xME_args

+@rem Slurp the command line arguments.

+set CMD_LINE_ARGS=

+set _SKIP=2

+

+:win9xME_args_slurp

+if "x%~1" == "x" goto execute

+

+set CMD_LINE_ARGS=%*

+goto execute

+

+:4NT_args

+@rem Get arguments from the 4NT Shell from JP Software

+set CMD_LINE_ARGS=%$

+

+:execute

+@rem Setup the command line

+

+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

+

+@rem Execute Gradle

+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

+

+:end

+@rem End local scope for the variables with windows NT shell

+if "%ERRORLEVEL%"=="0" goto mainEnd

+

+:fail

+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of

+rem the _cmd.exe /c_ return code!

+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1

+exit /b 1

+

+:mainEnd

+if "%OS%"=="Windows_NT" endlocal

+

+:omega

diff --git a/tests/TouchLatency/settings.gradle b/tests/TouchLatency/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/tests/TouchLatency/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 76c59dd..661409e 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -4860,24 +4860,39 @@
         const Vector<sp<Type> >& types = mOrderedPackages[p]->getOrderedTypes();
         const size_t typeCount = types.size();
         for (size_t t = 0; t < typeCount; t++) {
-            const Vector<sp<ConfigList> >& configs = types[t]->getOrderedConfigs();
+            const sp<Type>& type = types[t];
+            if (type == NULL) {
+                continue;
+            }
+
+            const Vector<sp<ConfigList> >& configs = type->getOrderedConfigs();
             const size_t configCount = configs.size();
             for (size_t c = 0; c < configCount; c++) {
+                const sp<ConfigList>& configList = configs[c];
+                if (configList == NULL) {
+                    continue;
+                }
+
                 const DefaultKeyedVector<ConfigDescription, sp<Entry> >& configEntries
-                        = configs[c]->getEntries();
+                        = configList->getEntries();
                 const size_t configEntryCount = configEntries.size();
                 for (size_t ce = 0; ce < configEntryCount; ce++) {
+                    const sp<Entry>& entry = configEntries.valueAt(ce);
+                    if (entry == NULL) {
+                        continue;
+                    }
+
                     const ConfigDescription& config = configEntries.keyAt(ce);
                     if (AaptConfig::isDensityOnly(config)) {
                         // This configuration only varies with regards to density.
                         const Symbol symbol(
                                 mOrderedPackages[p]->getName(),
-                                types[t]->getName(),
-                                configs[c]->getName(),
+                                type->getName(),
+                                configList->getName(),
                                 getResId(mOrderedPackages[p], types[t],
-                                         configs[c]->getEntryIndex()));
+                                         configList->getEntryIndex()));
 
-                        const sp<Entry>& entry = configEntries.valueAt(ce);
+
                         AaptUtil::appendValue(resources, symbol,
                                               SymbolDefinition(symbol, config, entry->getPos()));
                     }
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index 4f38e94..b52c530 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -40,6 +40,7 @@
 	link/ReferenceLinker.cpp \
 	link/TableMerger.cpp \
 	link/VersionCollapser.cpp \
+	link/XmlNamespaceRemover.cpp \
 	link/XmlReferenceLinker.cpp \
 	process/SymbolTable.cpp \
 	proto/ProtoHelpers.cpp \
@@ -89,6 +90,7 @@
 	link/ReferenceLinker_test.cpp \
 	link/TableMerger_test.cpp \
 	link/VersionCollapser_test.cpp \
+	link/XmlNamespaceRemover_test.cpp \
 	link/XmlReferenceLinker_test.cpp \
 	process/SymbolTable_test.cpp \
 	proto/TableProtoSerializer_test.cpp \
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index 09a04e0..2969b8c 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -82,6 +82,8 @@
     ResourceName() : type(ResourceType::kRaw) {}
     ResourceName(const StringPiece& p, ResourceType t, const StringPiece& e);
 
+    int compare(const ResourceName& other) const;
+
     bool isValid() const;
     std::string toString() const;
 };
@@ -258,6 +260,15 @@
         package(p.toString()), type(t), entry(e.toString()) {
 }
 
+inline int ResourceName::compare(const ResourceName& other) const {
+    int cmp = package.compare(other.package);
+    if (cmp != 0) return cmp;
+    cmp = static_cast<int>(type) - static_cast<int>(other.type);
+    if (cmp != 0) return cmp;
+    cmp = entry.compare(other.entry);
+    return cmp;
+}
+
 inline bool ResourceName::isValid() const {
     return !package.empty() && !entry.empty();
 }
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index 460de0e..ae5d299 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -203,11 +203,38 @@
 /**
  * The default handler for collisions. A return value of -1 means keep the
  * existing value, 0 means fail, and +1 means take the incoming value.
+ *
+ * Typically, a weak value will be overridden by a strong value. An existing weak
+ * value will not be overridden by an incoming weak value.
+ *
+ * There are some exceptions:
+ *
+ * Attributes: There are two types of Attribute values: USE and DECL.
+ *
+ * USE is anywhere an Attribute is declared without a format, and in a place that would
+ * be legal to declare if the Attribute already existed. This is typically in a
+ * <declare-styleable> tag. Attributes defined in a <declare-styleable> are also weak.
+ *
+ * DECL is an absolute declaration of an Attribute and specifies an explicit format.
+ *
+ * A DECL will override a USE without error. Two DECLs must match in their format for there to be
+ * no error.
+ *
+ * Styleables: Styleables are not actual resources, but they are treated as such during the
+ * compilation phase. Styleables are allowed to override each other, and their definitions merge
+ * and accumulate. If both values are Styleables, we just merge them into the existing value.
  */
 int ResourceTable::resolveValueCollision(Value* existing, Value* incoming) {
+    if (Styleable* existingStyleable = valueCast<Styleable>(existing)) {
+        if (Styleable* incomingStyleable = valueCast<Styleable>(incoming)) {
+            // Styleables get merged.
+            existingStyleable->mergeWith(incomingStyleable);
+            return -1;
+        }
+    }
+
     Attribute* existingAttr = valueCast<Attribute>(existing);
     Attribute* incomingAttr = valueCast<Attribute>(incoming);
-
     if (!incomingAttr) {
         if (incoming->isWeak()) {
             // We're trying to add a weak resource but a resource
diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp
index 4db40a6..feaca4e 100644
--- a/tools/aapt2/ResourceTable_test.cpp
+++ b/tools/aapt2/ResourceTable_test.cpp
@@ -118,6 +118,39 @@
     EXPECT_FALSE(attr->isWeak());
 }
 
+TEST(ResourceTable, MergeStyleables) {
+    ResourceTable table;
+
+    ASSERT_TRUE(table.addResource(
+            test::parseNameOrDie("android:styleable/Foo"),
+            ConfigDescription{}, "",
+            test::StyleableBuilder()
+                    .addItem("android:attr/bar")
+                    .addItem("android:attr/foo")
+                    .build(),
+            test::getDiagnostics()));
+
+    ASSERT_TRUE(table.addResource(
+            test::parseNameOrDie("android:styleable/Foo"),
+            ConfigDescription{}, "",
+            test::StyleableBuilder()
+                    .addItem("android:attr/bat")
+                    .addItem("android:attr/foo")
+                    .build(),
+            test::getDiagnostics()));
+
+    Styleable* styleable = test::getValue<Styleable>(&table, "android:styleable/Foo");
+    ASSERT_NE(nullptr, styleable);
+
+    std::vector<Reference> expectedRefs = {
+            Reference(test::parseNameOrDie("android:attr/bar")),
+            Reference(test::parseNameOrDie("android:attr/bat")),
+            Reference(test::parseNameOrDie("android:attr/foo")),
+    };
+
+    EXPECT_EQ(expectedRefs, styleable->entries);
+}
+
 TEST(ResourceTableTest, ProductVaryingValues) {
     ResourceTable table;
 
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index 73682ab..321f776 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -24,6 +24,7 @@
 #include <algorithm>
 #include <androidfw/ResourceTypes.h>
 #include <limits>
+#include <set>
 
 namespace aapt {
 
@@ -732,4 +733,27 @@
         << "]";
 }
 
+bool operator<(const Reference& a, const Reference& b) {
+    int cmp = a.name.valueOrDefault({}).compare(b.name.valueOrDefault({}));
+    if (cmp != 0) return cmp < 0;
+    return a.id < b.id;
+}
+
+bool operator==(const Reference& a, const Reference& b) {
+    return a.name == b.name && a.id == b.id;
+}
+
+bool operator!=(const Reference& a, const Reference& b) {
+    return a.name != b.name || a.id != b.id;
+}
+
+void Styleable::mergeWith(Styleable* other) {
+    std::set<Reference> references;
+    references.insert(entries.begin(), entries.end());
+    references.insert(other->entries.begin(), other->entries.end());
+    entries.clear();
+    entries.reserve(references.size());
+    entries.insert(entries.end(), references.begin(), references.end());
+}
+
 } // namespace aapt
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index e6af716..eb7559a 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -179,6 +179,9 @@
     void print(std::ostream* out) const override;
 };
 
+bool operator<(const Reference&, const Reference&);
+bool operator==(const Reference&, const Reference&);
+
 /**
  * An ID resource. Has no real value, just a place holder.
  */
@@ -334,6 +337,7 @@
     bool equals(const Value* value) const override;
     Styleable* clone(StringPool* newPool) const override;
     void print(std::ostream* out) const override;
+    void mergeWith(Styleable* styleable);
 };
 
 /**
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index 5a2bb6a..ea95dd1 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -74,6 +74,7 @@
     bool generateNonFinalIds = false;
     std::vector<std::string> javadocAnnotations;
     bool outputToDirectory = false;
+    bool noXmlNamespaces = false;
     bool autoAddOverlay = false;
     bool doNotCompressAnything = false;
     std::unordered_set<std::string> extensionsToNotCompress;
@@ -293,6 +294,7 @@
 struct ResourceFileFlattenerOptions {
     bool noAutoVersion = false;
     bool noVersionVectors = false;
+    bool noXmlNamespaces = false;
     bool keepRawValues = false;
     bool doNotCompressAnything = false;
     bool updateProguardSpec = false;
@@ -382,6 +384,13 @@
         return false;
     }
 
+    if (mOptions.noXmlNamespaces) {
+        XmlNamespaceRemover namespaceRemover;
+        if (!namespaceRemover.consume(mContext, outFileOp->xmlToFlatten.get())) {
+            return false;
+        }
+    }
+
     if (!mOptions.noAutoVersion) {
         if (mOptions.noVersionVectors) {
             // Skip this if it is a vector or animated-vector.
@@ -1296,6 +1305,7 @@
         fileFlattenerOptions.extensionsToNotCompress = mOptions.extensionsToNotCompress;
         fileFlattenerOptions.noAutoVersion = mOptions.noAutoVersion;
         fileFlattenerOptions.noVersionVectors = mOptions.noVersionVectors;
+        fileFlattenerOptions.noXmlNamespaces = mOptions.noXmlNamespaces;
         fileFlattenerOptions.updateProguardSpec =
                 static_cast<bool>(mOptions.generateProguardRulesPath);
 
@@ -1594,6 +1604,14 @@
                         error = true;
                     }
                 }
+
+                if (mOptions.noXmlNamespaces) {
+                    // PackageParser will fail if URIs are removed from AndroidManifest.xml.
+                    XmlNamespaceRemover namespaceRemover(true /* keepUris */);
+                    if (!namespaceRemover.consume(mContext, manifestXml.get())) {
+                        error = true;
+                    }
+                }
             } else {
                 error = true;
             }
@@ -1732,6 +1750,9 @@
             .optionalSwitch("--output-to-dir", "Outputs the APK contents to a directory specified "
                             "by -o",
                             &options.outputToDirectory)
+            .optionalSwitch("--no-xml-namespaces", "Removes XML namespace prefix and URI "
+                            "information from AndroidManifest.xml\nand XML binaries in res/*.",
+                            &options.noXmlNamespaces)
             .optionalFlag("--min-sdk-version", "Default minimum SDK version to use for "
                           "AndroidManifest.xml",
                           &options.manifestFixerOptions.minSdkVersionDefault)
diff --git a/tools/aapt2/link/Linkers.h b/tools/aapt2/link/Linkers.h
index 43b8fb4..82e2868 100644
--- a/tools/aapt2/link/Linkers.h
+++ b/tools/aapt2/link/Linkers.h
@@ -86,6 +86,23 @@
 };
 
 /**
+ * Removes namespace nodes and URI information from the XmlResource.
+ *
+ * Once an XmlResource is processed by this consumer, it is no longer able to have its attributes
+ * parsed. As such, this XmlResource must have already been processed by XmlReferenceLinker.
+ */
+class XmlNamespaceRemover : public IXmlResourceConsumer {
+private:
+    bool mKeepUris;
+
+public:
+    XmlNamespaceRemover(bool keepUris = false) : mKeepUris(keepUris) {
+    };
+
+    bool consume(IAaptContext* context, xml::XmlResource* resource) override;
+};
+
+/**
  * Resolves attributes in the XmlResource and compiles string values to resource values.
  * Once an XmlResource is processed by this linker, it is ready to be flattened.
  */
diff --git a/tools/aapt2/link/XmlNamespaceRemover.cpp b/tools/aapt2/link/XmlNamespaceRemover.cpp
new file mode 100644
index 0000000..9f95177
--- /dev/null
+++ b/tools/aapt2/link/XmlNamespaceRemover.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#include "ResourceTable.h"
+#include "link/Linkers.h"
+
+#include <algorithm>
+
+namespace aapt {
+
+namespace {
+
+/**
+ * Visits each xml Node, removing URI references and nested namespaces.
+ */
+class XmlVisitor : public xml::Visitor {
+public:
+    XmlVisitor(bool keepUris) : mKeepUris(keepUris) {
+    }
+
+    void visit(xml::Element* el) override {
+        // Strip namespaces
+        for (auto& child : el->children) {
+            while (child && xml::nodeCast<xml::Namespace>(child.get())) {
+                if (child->children.empty()) {
+                    child = {};
+                } else {
+                    child = std::move(child->children.front());
+                    child->parent = el;
+                }
+            }
+        }
+        el->children.erase(std::remove_if(el->children.begin(), el->children.end(),
+                [](const std::unique_ptr<xml::Node>& child) -> bool {
+            return child == nullptr;
+        }), el->children.end());
+
+        if (!mKeepUris) {
+            for (xml::Attribute& attr : el->attributes) {
+                attr.namespaceUri = std::string();
+            }
+            el->namespaceUri = std::string();
+        }
+        xml::Visitor::visit(el);
+    }
+
+private:
+    bool mKeepUris;
+};
+
+} // namespace
+
+bool XmlNamespaceRemover::consume(IAaptContext* context, xml::XmlResource* resource) {
+    if (!resource->root) {
+        return false;
+    }
+    // Replace any root namespaces until the root is a non-namespace node
+    while (xml::nodeCast<xml::Namespace>(resource->root.get())) {
+        if (resource->root->children.empty()) {
+            break;
+        }
+        resource->root = std::move(resource->root->children.front());
+        resource->root->parent = nullptr;
+    }
+    XmlVisitor visitor(mKeepUris);
+    resource->root->accept(&visitor);
+    return true;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/link/XmlNamespaceRemover_test.cpp b/tools/aapt2/link/XmlNamespaceRemover_test.cpp
new file mode 100644
index 0000000..e72ea439
--- /dev/null
+++ b/tools/aapt2/link/XmlNamespaceRemover_test.cpp
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+#include "link/Linkers.h"
+#include "test/Test.h"
+
+namespace aapt {
+
+class XmlUriTestVisitor : public xml::Visitor {
+public:
+    void visit(xml::Element* el) override {
+        for (const auto& attr : el->attributes) {
+            EXPECT_EQ(std::string(), attr.namespaceUri);
+        }
+        EXPECT_EQ(std::string(), el->namespaceUri);
+        xml::Visitor::visit(el);
+    }
+
+    void visit(xml::Namespace* ns) override {
+        EXPECT_EQ(std::string(), ns->namespaceUri);
+        xml::Visitor::visit(ns);
+    }
+};
+
+class XmlNamespaceTestVisitor : public xml::Visitor {
+public:
+    void visit(xml::Namespace* ns) override {
+        ADD_FAILURE() << "Detected namespace: "
+                << ns->namespacePrefix << "=\"" << ns->namespaceUri << "\"";
+        xml::Visitor::visit(ns);
+    }
+};
+
+class XmlNamespaceRemoverTest : public ::testing::Test {
+public:
+    void SetUp() override {
+        mContext = test::ContextBuilder()
+                .setCompilationPackage("com.app.test")
+                .build();
+    }
+
+protected:
+    std::unique_ptr<IAaptContext> mContext;
+};
+
+TEST_F(XmlNamespaceRemoverTest, RemoveUris) {
+    std::unique_ptr<xml::XmlResource> doc = test::buildXmlDomForPackageName(mContext.get(), R"EOF(
+            <View xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:text="hello" />)EOF");
+
+    XmlNamespaceRemover remover;
+    ASSERT_TRUE(remover.consume(mContext.get(), doc.get()));
+
+    xml::Node* root = doc.get()->root.get();
+    ASSERT_NE(root, nullptr);
+
+    XmlUriTestVisitor visitor;
+    root->accept(&visitor);
+}
+
+TEST_F(XmlNamespaceRemoverTest, RemoveNamespaces) {
+    std::unique_ptr<xml::XmlResource> doc = test::buildXmlDomForPackageName(mContext.get(), R"EOF(
+            <View xmlns:android="http://schemas.android.com/apk/res/android"
+                  xmlns:foo="http://schemas.android.com/apk/res/foo"
+                  foo:bar="foobar"
+                  android:text="hello" />)EOF");
+
+    XmlNamespaceRemover remover;
+    ASSERT_TRUE(remover.consume(mContext.get(), doc.get()));
+
+    xml::Node* root = doc.get()->root.get();
+    ASSERT_NE(root, nullptr);
+
+    XmlNamespaceTestVisitor visitor;
+    root->accept(&visitor);
+}
+
+TEST_F(XmlNamespaceRemoverTest, RemoveNestedNamespaces) {
+    std::unique_ptr<xml::XmlResource> doc = test::buildXmlDomForPackageName(mContext.get(), R"EOF(
+            <View xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:text="hello">
+              <View xmlns:foo="http://schemas.example.com/foo"
+                    android:text="foo"/>
+            </View>)EOF");
+
+    XmlNamespaceRemover remover;
+    ASSERT_TRUE(remover.consume(mContext.get(), doc.get()));
+
+    xml::Node* root = doc.get()->root.get();
+    ASSERT_NE(root, nullptr);
+
+    XmlNamespaceTestVisitor visitor;
+    root->accept(&visitor);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/tools/consumers/__init__.py b/tools/aapt2/tools/consumers/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/aapt2/tools/consumers/__init__.py
diff --git a/tools/aapt2/tools/consumers/duplicates.py b/tools/aapt2/tools/consumers/duplicates.py
new file mode 100644
index 0000000..c27979a
--- /dev/null
+++ b/tools/aapt2/tools/consumers/duplicates.py
@@ -0,0 +1,132 @@
+"""
+Looks for duplicate resource definitions and removes all but the last one.
+"""
+
+import os.path
+import xml.parsers.expat
+
+class DuplicateRemover:
+    def matches(self, file_path):
+        dirname, basename = os.path.split(file_path)
+        dirname = os.path.split(dirname)[1]
+        return dirname.startswith("values") and basename.endswith(".xml")
+
+    def consume(self, xml_path, input):
+        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}: removing duplicate resource '{3}'".format( xml_path, 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 "deduped {0}".format(xml_path)
+            return "".join(output_lines).encode("utf-8")
+        return input
+
+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
diff --git a/tools/aapt2/tools/consumers/positional_arguments.py b/tools/aapt2/tools/consumers/positional_arguments.py
new file mode 100644
index 0000000..176e4c9
--- /dev/null
+++ b/tools/aapt2/tools/consumers/positional_arguments.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+
+"""
+Looks for strings with multiple substitution arguments (%d, &s, etc)
+and replaces them with positional arguments (%1$d, %2$s).
+"""
+
+import os.path
+import re
+import xml.parsers.expat
+
+class PositionalArgumentFixer:
+    def matches(self, file_path):
+        dirname, basename = os.path.split(file_path)
+        dirname = os.path.split(dirname)[1]
+        return dirname.startswith("values") and basename.endswith(".xml")
+
+    def consume(self, xml_path, input):
+        parser = xml.parsers.expat.ParserCreate("utf-8")
+        locator = SubstitutionArgumentLocator(parser)
+        parser.returns_unicode = True
+        parser.StartElementHandler = locator.start_element
+        parser.EndElementHandler = locator.end_element
+        parser.CharacterDataHandler = locator.character_data
+        parser.Parse(input)
+
+        if len(locator.arguments) > 0:
+            output = ""
+            last_index = 0
+            for arg in locator.arguments:
+                output += input[last_index:arg.start]
+                output += "%{0}$".format(arg.number)
+                last_index = arg.start + 1
+            output += input[last_index:]
+            print "fixed {0}".format(xml_path)
+            return output
+        return input
+
+class Argument:
+    def __init__(self, start, number):
+        self.start = start
+        self.number = number
+
+class SubstitutionArgumentLocator:
+    """Callback class for xml.parsers.expat which records locations of
+    substitution arguments in strings when there are more than 1 of
+    them in a single <string> tag (and they are not positional).
+    """
+    def __init__(self, parser):
+        self.arguments = []
+        self._parser = parser
+        self._depth = 0
+        self._within_string = False
+        self._current_arguments = []
+        self._next_number = 1
+
+    def start_element(self, tag_name, attrs):
+        self._depth += 1
+        if self._depth == 2 and tag_name == "string" and "translateable" not in attrs:
+            self._within_string = True
+
+    def character_data(self, data):
+        if self._within_string:
+            for m in re.finditer("%[-#+ 0,(]?\d*[bBhHsScCdoxXeEfgGaAtTn]", data):
+                start, end = m.span()
+                self._current_arguments.append(\
+                        Argument(self._parser.CurrentByteIndex + start, self._next_number))
+                self._next_number += 1
+
+    def end_element(self, tag_name):
+        if self._within_string and self._depth == 2:
+            if len(self._current_arguments) > 1:
+                self.arguments += self._current_arguments
+            self._current_arguments = []
+            self._within_string = False
+            self._next_number = 1
+        self._depth -= 1
diff --git a/tools/aapt2/tools/fix_resources.py b/tools/aapt2/tools/fix_resources.py
new file mode 100644
index 0000000..b6fcd91
--- /dev/null
+++ b/tools/aapt2/tools/fix_resources.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+
+"""
+Scans each resource file in res/ applying various transformations
+to fix invalid resource files.
+"""
+
+import os
+import os.path
+import sys
+import tempfile
+
+from consumers.duplicates import DuplicateRemover
+from consumers.positional_arguments import PositionalArgumentFixer
+
+def do_it(res_path, consumers):
+    for file_path in enumerate_files(res_path):
+        eligible_consumers = filter(lambda c: c.matches(file_path), consumers)
+        if len(eligible_consumers) > 0:
+            print "checking {0} ...".format(file_path)
+
+            original_contents = read_contents(file_path)
+            contents = original_contents
+            for c in eligible_consumers:
+                contents = c.consume(file_path, contents)
+            if original_contents != contents:
+                write_contents(file_path, contents)
+
+def enumerate_files(res_path):
+    """Enumerates all files in the resource directory."""
+    values_directories = os.listdir(res_path)
+    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 = map(lambda f: os.path.join(dir, f), files)
+        for f in files:
+            yield f
+
+def read_contents(file_path):
+    """Reads the contents of file_path without decoding."""
+    with open(file_path) as fin:
+        return fin.read()
+
+def write_contents(file_path, contents):
+    """Writes the bytes in contents to file_path by first writing to a temporary, then
+    renaming the temporary to file_path, ensuring a consistent write.
+    """
+    dirname, basename = os.path.split(file_path)
+    temp_name = ""
+    with tempfile.NamedTemporaryFile(prefix=basename, dir=dirname, delete=False) as temp:
+        temp_name = temp.name
+        temp.write(contents)
+    os.rename(temp.name, file_path)
+
+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)
+    do_it(res_path, [DuplicateRemover(), PositionalArgumentFixer()])
diff --git a/tools/aapt2/tools/remove-duplicates.py b/tools/aapt2/tools/remove-duplicates.py
deleted file mode 100644
index fb98bb7..0000000
--- a/tools/aapt2/tools/remove-duplicates.py
+++ /dev/null
@@ -1,181 +0,0 @@
-#!/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/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index b134cf7..2b73fac 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1143,7 +1143,7 @@
 
     /**
      * @return true if this adapter supports Neighbour Awareness Network APIs
-     * @hide PROPOSED_NAN_API
+     * @hide
      */
     public boolean isNanSupported() {
         return isFeatureSupported(WIFI_FEATURE_NAN);
diff --git a/wifi/java/android/net/wifi/nan/ConfigRequest.java b/wifi/java/android/net/wifi/nan/ConfigRequest.java
index cd47359..44544de 100644
--- a/wifi/java/android/net/wifi/nan/ConfigRequest.java
+++ b/wifi/java/android/net/wifi/nan/ConfigRequest.java
@@ -23,9 +23,9 @@
 /**
  * Defines a request object to configure a Wi-Fi NAN network. Built using
  * {@link ConfigRequest.Builder}. Configuration is requested using
- * {@link WifiNanManager#connect(android.os.Looper, WifiNanEventCallback, ConfigRequest)}
- * . Note that the actual achieved configuration may be different from the
- * requested configuration - since multiple applications may request different
+ * {@link WifiNanManager#connect(android.os.Looper, ConfigRequest, WifiNanEventCallback)}.
+ * Note that the actual achieved configuration may be different from the
+ * requested configuration - since different applications may request different
  * configurations.
  *
  * @hide PROPOSED_NAN_API
@@ -155,6 +155,7 @@
      * @param o Object to compare to.
      * @return true if configuration objects have the same on-the-air
      *         configuration, false otherwise.
+     *
      * @hide
      */
     public boolean equalsOnTheAir(Object o) {
@@ -172,6 +173,18 @@
                 && mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh;
     }
 
+    /**
+     * Checks whether the configuration's settings which impact on-air behavior are non-default.
+     *
+     * @return true if any of the on-air-impacting settings are non-default.
+     *
+     * @hide
+     */
+    public boolean isNonDefaultOnTheAir() {
+        return mSupport5gBand || mMasterPreference != 0 || mClusterLow != CLUSTER_ID_MIN
+                || mClusterHigh != CLUSTER_ID_MAX;
+    }
+
     @Override
     public int hashCode() {
         int result = 17;
@@ -186,7 +199,7 @@
     }
 
     /**
-     * Validates that the contents of the ConfigRequest are valid. Otherwise
+     * Verifies that the contents of the ConfigRequest are valid. Otherwise
      * throws an IllegalArgumentException.
      *
      * @hide
@@ -229,11 +242,13 @@
         private boolean mEnableIdentityChangeCallback = false;
 
         /**
-         * Specify whether 5G band support is required in this request.
+         * Specify whether 5G band support is required in this request. Disabled by default.
          *
          * @param support5gBand Support for 5G band is required.
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
+         *
          * @hide PROPOSED_NAN_SYSTEM_API
          */
         public Builder setSupport5gBand(boolean support5gBand) {
@@ -242,12 +257,14 @@
         }
 
         /**
-         * Specify the Master Preference requested. The permitted range is 0 to
+         * Specify the Master Preference requested. The permitted range is 0 (the default) to
          * 255 with 1 and 255 excluded (reserved).
          *
          * @param masterPreference The requested master preference
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
+         *
          * @hide PROPOSED_NAN_SYSTEM_API
          */
         public Builder setMasterPreference(int masterPreference) {
@@ -268,13 +285,15 @@
          * The Cluster ID is generated randomly for new NAN networks. Specify
          * the lower range of the cluster ID. The upper range is specified using
          * the {@link ConfigRequest.Builder#setClusterHigh(int)}. The permitted
-         * range is 0 to the value specified by
-         * {@link ConfigRequest.Builder#setClusterHigh(int)}. Equality is
+         * range is 0 (the default) to the value specified by
+         * {@link ConfigRequest.Builder#setClusterHigh(int)}. Equality of Low and High is
          * permitted which restricts the Cluster ID to the specified value.
          *
          * @param clusterLow The lower range of the generated cluster ID.
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setClusterLow(..).setClusterHigh(..)}.
+         *
          * @hide PROPOSED_NAN_SYSTEM_API
          */
         public Builder setClusterLow(int clusterLow) {
@@ -294,12 +313,14 @@
          * the lower upper of the cluster ID. The lower range is specified using
          * the {@link ConfigRequest.Builder#setClusterLow(int)}. The permitted
          * range is the value specified by
-         * {@link ConfigRequest.Builder#setClusterLow(int)} to 0xFFFF. Equality
-         * is permitted which restricts the Cluster ID to the specified value.
+         * {@link ConfigRequest.Builder#setClusterLow(int)} to 0xFFFF (the default). Equality of
+         * Low and High is permitted which restricts the Cluster ID to the specified value.
          *
          * @param clusterHigh The upper range of the generated cluster ID.
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setClusterLow(..).setClusterHigh(..)}.
+         *
          * @hide PROPOSED_NAN_SYSTEM_API
          */
         public Builder setClusterHigh(int clusterHigh) {
@@ -315,13 +336,15 @@
         }
 
         /**
-         * Indicate whether or not we want to enable the callback to the
-         * listener on the event when the NAN device identity is changed. A
-         * device identity is it's Discovery MAC address. Depending on use-case
-         * we may want to perform some activity (e.g. re-publish). In other
-         * use-cases (typically where we're silent) there's no reason to be
-         * woken up repeatedly. Note that the MAC address is randomized at
-         * regular intervals - so do not enable unless specifically required.
+         * Indicate whether or not we want to enable the
+         * {@link WifiNanEventCallback#onIdentityChanged(byte[])} callback. A
+         * device identity is its Discovery MAC address which is randomized at regular intervals.
+         * An application may need to know the MAC address, e.g. when using OOB (out-of-band)
+         * discovery together with NAN connections.
+         * <p>
+         *     The callbacks are disabled by default since it may result in additional wake-ups
+         *     of the host -
+         *     increasing power.
          *
          * @param enableIdentityChangeCallback Enable the callback informing
          *            listener when identity is changed.
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
index b8dd1a5..17ec1bc 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
@@ -38,7 +38,7 @@
     boolean isUsageEnabled();
 
     // client API
-    int connect(in IBinder binder, in IWifiNanEventCallback callback,
+    int connect(in IBinder binder, in String callingPackage, in IWifiNanEventCallback callback,
             in ConfigRequest configRequest);
     void disconnect(int clientId, in IBinder binder);
 
diff --git a/wifi/java/android/net/wifi/nan/PublishConfig.java b/wifi/java/android/net/wifi/nan/PublishConfig.java
index 3fd756e..71f99d9 100644
--- a/wifi/java/android/net/wifi/nan/PublishConfig.java
+++ b/wifi/java/android/net/wifi/nan/PublishConfig.java
@@ -31,13 +31,14 @@
 
 /**
  * Defines the configuration of a NAN publish session. Built using
- * {@link PublishConfig.Builder}. Publish is done using
- * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback)} or
+ * {@link PublishConfig.Builder}. A publish session is created using
+ * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback)} or updated using
  * {@link WifiNanPublishSession#updatePublish(PublishConfig)}.
  *
  * @hide PROPOSED_NAN_API
  */
 public class PublishConfig implements Parcelable {
+    /** @hide */
     @IntDef({
             PUBLISH_TYPE_UNSOLICITED, PUBLISH_TYPE_SOLICITED })
     @Retention(RetentionPolicy.SOURCE)
@@ -45,67 +46,48 @@
     }
 
     /**
-     * Defines an unsolicited publish session - i.e. a publish session where
-     * publish packets are transmitted over-the-air. Configuration is done using
-     * {@link PublishConfig.Builder#setPublishType(int)}.
+     * Defines an unsolicited publish session - a publish session where the publisher is
+     * advertising itself by broadcasting on-the-air. An unsolicited publish session is paired
+     * with an passive subscribe session {@link SubscribeConfig#SUBSCRIBE_TYPE_PASSIVE}.
+     * Configuration is done using {@link PublishConfig.Builder#setPublishType(int)}.
      */
     public static final int PUBLISH_TYPE_UNSOLICITED = 0;
 
     /**
-     * Defines a solicited publish session - i.e. a publish session where
-     * publish packets are not transmitted over-the-air and the device listens
-     * and matches to transmitted subscribe packets. Configuration is done using
+     * Defines a solicited publish session - a publish session which is silent, waiting for a
+     * matching active subscribe session - and responding to it in unicast. A
+     * solicited publish session is paired with an active subscribe session
+     * {@link SubscribeConfig#SUBSCRIBE_TYPE_ACTIVE}. Configuration is done using
      * {@link PublishConfig.Builder#setPublishType(int)}.
      */
     public static final int PUBLISH_TYPE_SOLICITED = 1;
 
-    /**
-     * @hide
-     */
+    /** @hide */
     public final byte[] mServiceName;
 
-    /**
-     * @hide
-     */
+    /** @hide */
     public final byte[] mServiceSpecificInfo;
 
-    /**
-     * @hide
-     */
-    public final byte[] mTxFilter;
+    /** @hide */
+    public final byte[] mMatchFilter;
 
-    /**
-     * @hide
-     */
-    public final byte[] mRxFilter;
-
-    /**
-     * @hide
-     */
+    /** @hide */
     public final int mPublishType;
 
-    /**
-     * @hide
-     */
+    /** @hide */
     public final int mPublishCount;
 
-    /**
-     * @hide
-     */
+    /** @hide */
     public final int mTtlSec;
 
-    /**
-     * @hide
-     */
+    /** @hide */
     public final boolean mEnableTerminateNotification;
 
-    private PublishConfig(byte[] serviceName, byte[] serviceSpecificInfo,
-            byte[] txFilter, byte[] rxFilter, int publishType, int publichCount, int ttlSec,
-            boolean enableTerminateNotification) {
+    private PublishConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter,
+            int publishType, int publichCount, int ttlSec, boolean enableTerminateNotification) {
         mServiceName = serviceName;
         mServiceSpecificInfo = serviceSpecificInfo;
-        mTxFilter = txFilter;
-        mRxFilter = rxFilter;
+        mMatchFilter = matchFilter;
         mPublishType = publishType;
         mPublishCount = publichCount;
         mTtlSec = ttlSec;
@@ -116,8 +98,7 @@
     public String toString() {
         return "PublishConfig [mServiceName='" + mServiceName + ", mServiceSpecificInfo='" + (
                 (mServiceSpecificInfo == null) ? "null" : HexEncoding.encode(mServiceSpecificInfo))
-                + ", mTxFilter=" + (new LvBufferUtils.LvIterable(1, mTxFilter)).toString()
-                + ", mRxFilter=" + (new LvBufferUtils.LvIterable(1, mRxFilter)).toString()
+                + ", mTxFilter=" + (new LvBufferUtils.LvIterable(1, mMatchFilter)).toString()
                 + ", mPublishType=" + mPublishType + ", mPublishCount=" + mPublishCount
                 + ", mTtlSec=" + mTtlSec + ", mEnableTerminateNotification="
                 + mEnableTerminateNotification + "]";
@@ -132,8 +113,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeByteArray(mServiceName);
         dest.writeByteArray(mServiceSpecificInfo);
-        dest.writeByteArray(mTxFilter);
-        dest.writeByteArray(mRxFilter);
+        dest.writeByteArray(mMatchFilter);
         dest.writeInt(mPublishType);
         dest.writeInt(mPublishCount);
         dest.writeInt(mTtlSec);
@@ -150,15 +130,14 @@
         public PublishConfig createFromParcel(Parcel in) {
             byte[] serviceName = in.createByteArray();
             byte[] ssi = in.createByteArray();
-            byte[] txFilter = in.createByteArray();
-            byte[] rxFilter = in.createByteArray();
+            byte[] matchFilter = in.createByteArray();
             int publishType = in.readInt();
             int publishCount = in.readInt();
             int ttlSec = in.readInt();
             boolean enableTerminateNotification = in.readInt() != 0;
 
-            return new PublishConfig(serviceName, ssi, txFilter, rxFilter, publishType,
-                    publishCount, ttlSec, enableTerminateNotification);
+            return new PublishConfig(serviceName, ssi, matchFilter, publishType, publishCount,
+                    ttlSec, enableTerminateNotification);
         }
     };
 
@@ -175,9 +154,9 @@
         PublishConfig lhs = (PublishConfig) o;
 
         return Arrays.equals(mServiceName, lhs.mServiceName) && Arrays.equals(mServiceSpecificInfo,
-                lhs.mServiceSpecificInfo) && Arrays.equals(mTxFilter, lhs.mTxFilter)
-                && Arrays.equals(mRxFilter, lhs.mRxFilter) && mPublishType == lhs.mPublishType
-                && mPublishCount == lhs.mPublishCount && mTtlSec == lhs.mTtlSec
+                lhs.mServiceSpecificInfo) && Arrays.equals(mMatchFilter, lhs.mMatchFilter)
+                && mPublishType == lhs.mPublishType && mPublishCount == lhs.mPublishCount
+                && mTtlSec == lhs.mTtlSec
                 && mEnableTerminateNotification == lhs.mEnableTerminateNotification;
     }
 
@@ -187,8 +166,7 @@
 
         result = 31 * result + Arrays.hashCode(mServiceName);
         result = 31 * result + Arrays.hashCode(mServiceSpecificInfo);
-        result = 31 * result + Arrays.hashCode(mTxFilter);
-        result = 31 * result + Arrays.hashCode(mRxFilter);
+        result = 31 * result + Arrays.hashCode(mMatchFilter);
         result = 31 * result + mPublishType;
         result = 31 * result + mPublishCount;
         result = 31 * result + mTtlSec;
@@ -198,7 +176,7 @@
     }
 
     /**
-     * Validates that the contents of the PublishConfig are valid. Otherwise
+     * Verifies that the contents of the PublishConfig are valid. Otherwise
      * throws an IllegalArgumentException.
      *
      * @hide
@@ -206,14 +184,10 @@
     public void validate() throws IllegalArgumentException {
         WifiNanUtils.validateServiceName(mServiceName);
 
-        if (!LvBufferUtils.isValid(mTxFilter, 1)) {
+        if (!LvBufferUtils.isValid(mMatchFilter, 1)) {
             throw new IllegalArgumentException(
                     "Invalid txFilter configuration - LV fields do not match up to length");
         }
-        if (!LvBufferUtils.isValid(mRxFilter, 1)) {
-            throw new IllegalArgumentException(
-                    "Invalid rxFilter configuration - LV fields do not match up to length");
-        }
         if (mPublishType < PUBLISH_TYPE_UNSOLICITED || mPublishType > PUBLISH_TYPE_SOLICITED) {
             throw new IllegalArgumentException("Invalid publishType - " + mPublishType);
         }
@@ -223,16 +197,6 @@
         if (mTtlSec < 0) {
             throw new IllegalArgumentException("Invalid ttlSec - must be non-negative");
         }
-        if (mPublishType == PublishConfig.PUBLISH_TYPE_UNSOLICITED && mRxFilter != null
-                && mRxFilter.length != 0) {
-            throw new IllegalArgumentException("Invalid publish config: UNSOLICITED "
-                    + "publishes (active) can't have an Rx filter");
-        }
-        if (mPublishType == PublishConfig.PUBLISH_TYPE_SOLICITED && mTxFilter != null
-                && mTxFilter.length != 0) {
-            throw new IllegalArgumentException("Invalid publish config: SOLICITED "
-                    + "publishes (passive) can't have a Tx filter");
-        }
     }
 
     /**
@@ -241,8 +205,7 @@
     public static final class Builder {
         private byte[] mServiceName;
         private byte[] mServiceSpecificInfo;
-        private byte[] mTxFilter;
-        private byte[] mRxFilter;
+        private byte[] mMatchFilter;
         private int mPublishType = PUBLISH_TYPE_UNSOLICITED;
         private int mPublishCount = 0;
         private int mTtlSec = 0;
@@ -251,13 +214,16 @@
         /**
          * Specify the service name of the publish session. The actual on-air
          * value is a 6 byte hashed representation of this string.
-         *
-         * Per spec: The Service Name is a UTF-8 encoded string from 1 to 255 bytes in length.
+         * <p>
+         * The Service Name is a UTF-8 encoded string from 1 to 255 bytes in length.
          * The only acceptable single-byte UTF-8 symbols for a Service Name are alphanumeric
          * values (A-Z, a-z, 0-9), the hyphen ('-'), and the period ('.'). All valid multi-byte
          * UTF-8 characters are acceptable in a Service Name.
+         * <p>
+         * Must be called - an empty ServiceName is not valid.
          *
          * @param serviceName The service name for the publish session.
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
@@ -272,12 +238,15 @@
         /**
          * Specify service specific information for the publish session. This is
          * a free-form byte array available to the application to send
-         * additional information as part of the discovery operation - i.e. it
+         * additional information as part of the discovery operation - it
          * will not be used to determine whether a publish/subscribe match
          * occurs.
+         * <p>
+         *     Optional. Empty by default.
          *
          * @param serviceSpecificInfo A byte-array for the service-specific
          *            information field.
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
@@ -287,13 +256,16 @@
         }
 
         /**
-         * Specify service specific information for the publish session - same
-         * as {@link PublishConfig.Builder#setServiceSpecificInfo(byte[])}
-         * but obtaining the data from a String.
+         * Specify service specific information for the publish session - a simple wrapper
+         * of {@link PublishConfig.Builder#setServiceSpecificInfo(byte[])}
+         * obtaining the data from a String.
+         * <p>
+         *     Optional. Empty by default.
          *
          * @param serviceSpecificInfoStr The service specific information string
          *            to be included (as a byte array) in the publish
          *            information.
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
@@ -303,57 +275,34 @@
         }
 
         /**
-         * The transmit filter for an active publish session
-         * {@link PublishConfig.Builder#setPublishType(int)} and
-         * {@link PublishConfig#PUBLISH_TYPE_UNSOLICITED}. Included in
-         * transmitted publish packets and used by receivers (subscribers) to
-         * determine whether they match - in addition to just relying on the
-         * service name.
+         * The match filter for a publish session. Used to determine whether a service
+         * discovery occurred - in addition to relying on the service name.
          * <p>
-         * Format is an LV byte array - the {@link LvBufferUtils} utility class
-         * is available to form and parse.
+         * Format is an LV byte array: a single byte Length field followed by L bytes (the value of
+         * the Length field) of a value blob.
+         * <p>
+         *     Optional. Empty by default.
          *
-         * @param txFilter The byte-array containing the LV formatted transmit
-         *            filter.
+         * @param matchFilter The byte-array containing the LV formatted match filter.
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
-        public Builder setTxFilter(@Nullable byte[] txFilter) {
-            mTxFilter = txFilter;
+        public Builder setMatchFilter(@Nullable byte[] matchFilter) {
+            mMatchFilter = matchFilter;
             return this;
         }
 
         /**
-         * The transmit filter for a passive publish session
-         * {@link PublishConfig.Builder#setPublishType(int)} and
-         * {@link PublishConfig#PUBLISH_TYPE_SOLICITED}. Used by the publisher
-         * to determine whether they match transmitted subscriber packets
-         * (active subscribers) - in addition to just relying on the service
-         * name.
-         * <p>
-         * Format is an LV byte array - the {@link LvBufferUtils} utility class
-         * is available to form and parse.
-         *
-         * @param rxFilter The byte-array containing the LV formatted receive
-         *            filter.
-         * @return The builder to facilitate chaining
-         *         {@code builder.setXXX(..).setXXX(..)}.
-         */
-        public Builder setRxFilter(@Nullable byte[] rxFilter) {
-            mRxFilter = rxFilter;
-            return this;
-        }
-
-        /**
-         * Sets the type of the publish session: solicited (aka active - publish
+         * Specify the type of the publish session: solicited (aka active - publish
          * packets are transmitted over-the-air), or unsolicited (aka passive -
          * no publish packets are transmitted, a match is made against an active
          * subscribe session whose packets are transmitted over-the-air).
          *
-         * @param publishType Publish session type: solicited (
-         *            {@link PublishConfig#PUBLISH_TYPE_SOLICITED}) or
-         *            unsolicited (
-         *            {@link PublishConfig#PUBLISH_TYPE_UNSOLICITED}).
+         * @param publishType Publish session type:
+         *            {@link PublishConfig#PUBLISH_TYPE_SOLICITED} or
+         *            {@link PublishConfig#PUBLISH_TYPE_UNSOLICITED} (the default).
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
@@ -366,13 +315,18 @@
         }
 
         /**
-         * Sets the number of times a solicited (
+         * Sets the number of times an unsolicited (configured using
          * {@link PublishConfig.Builder#setPublishType(int)}) publish session
-         * will transmit a packet. When the count is reached an event will be
+         * will be broadcast. When the count is reached an event will be
          * generated for {@link WifiNanSessionCallback#onSessionTerminated(int)}
-         * with reason={@link WifiNanSessionCallback#TERMINATE_REASON_DONE}.
+         * with {@link WifiNanSessionCallback#TERMINATE_REASON_DONE} [unless
+         * {@link #setEnableTerminateNotification(boolean)} disables the callback].
+         * <p>
+         *     Optional. 0 by default - indicating the session doesn't terminate on its own.
+         *     Session will be terminated when {@link WifiNanSession#terminate()} is called.
          *
-         * @param publishCount Number of publish packets to transmit.
+         * @param publishCount Number of publish packets to broadcast.
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
@@ -385,14 +339,19 @@
         }
 
         /**
-         * Sets the time interval (in seconds) a solicited (
-         * {@link PublishConfig.Builder#setPublishCount(int)}) publish session
-         * will be alive - i.e. transmitting a packet. When the TTL is reached
+         * Sets the time interval (in seconds) an unsolicited (
+         * {@link PublishConfig.Builder#setPublishType(int)}) publish session
+         * will be alive - broadcasting a packet. When the TTL is reached
          * an event will be generated for
-         * {@link WifiNanSessionCallback#onSessionTerminated(int)} with reason=
-         * {@link WifiNanSessionCallback#TERMINATE_REASON_DONE}.
+         * {@link WifiNanSessionCallback#onSessionTerminated(int)} with
+         * {@link WifiNanSessionCallback#TERMINATE_REASON_DONE}  [unless
+         * {@link #setEnableTerminateNotification(boolean)} disables the callback].
+         * <p>
+         *     Optional. 0 by default - indicating the session doesn't terminate on its own.
+         *     Session will be terminated when {@link WifiNanSession#terminate()} is called.
          *
          * @param ttlSec Lifetime of a publish session in seconds.
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
@@ -411,6 +370,7 @@
          *
          * @param enable If true the terminate callback will be called when the
          *            publish is terminated. Otherwise it will not be called.
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
@@ -424,8 +384,8 @@
          * builder.
          */
         public PublishConfig build() {
-            return new PublishConfig(mServiceName, mServiceSpecificInfo, mTxFilter, mRxFilter,
-                    mPublishType, mPublishCount, mTtlSec, mEnableTerminateNotification);
+            return new PublishConfig(mServiceName, mServiceSpecificInfo, mMatchFilter, mPublishType,
+                    mPublishCount, mTtlSec, mEnableTerminateNotification);
         }
     }
 }
diff --git a/wifi/java/android/net/wifi/nan/SubscribeConfig.java b/wifi/java/android/net/wifi/nan/SubscribeConfig.java
index fd19ddb..7904875 100644
--- a/wifi/java/android/net/wifi/nan/SubscribeConfig.java
+++ b/wifi/java/android/net/wifi/nan/SubscribeConfig.java
@@ -38,6 +38,7 @@
  * @hide PROPOSED_NAN_API
  */
 public class SubscribeConfig implements Parcelable {
+    /** @hide */
     @IntDef({
             SUBSCRIBE_TYPE_PASSIVE, SUBSCRIBE_TYPE_ACTIVE })
     @Retention(RetentionPolicy.SOURCE)
@@ -45,7 +46,7 @@
     }
 
     /**
-     * Defines a passive subscribe session - i.e. a subscribe session where
+     * Defines a passive subscribe session - a subscribe session where
      * subscribe packets are not transmitted over-the-air and the device listens
      * and matches to transmitted publish packets. Configuration is done using
      * {@link SubscribeConfig.Builder#setSubscribeType(int)}.
@@ -53,12 +54,13 @@
     public static final int SUBSCRIBE_TYPE_PASSIVE = 0;
 
     /**
-     * Defines an active subscribe session - i.e. a subscribe session where
+     * Defines an active subscribe session - a subscribe session where
      * subscribe packets are transmitted over-the-air. Configuration is done
      * using {@link SubscribeConfig.Builder#setSubscribeType(int)}.
      */
     public static final int SUBSCRIBE_TYPE_ACTIVE = 1;
 
+    /** @hide */
     @IntDef({
             MATCH_STYLE_FIRST_ONLY, MATCH_STYLE_ALL })
     @Retention(RetentionPolicy.SOURCE)
@@ -67,68 +69,48 @@
 
     /**
      * Specifies that only the first match of a set of identical matches (same
-     * publish) will be reported to the subscriber.
+     * publish) will be reported to the subscriber. Configuration is done using
+     * {@link SubscribeConfig.Builder#setMatchStyle(int)}.
      */
     public static final int MATCH_STYLE_FIRST_ONLY = 0;
 
     /**
      * Specifies that all matches of a set of identical matches (same publish)
-     * will be reported to the subscriber.
+     * will be reported to the subscriber. Configuration is done using
+     * {@link SubscribeConfig.Builder#setMatchStyle(int)}.
      */
     public static final int MATCH_STYLE_ALL = 1;
 
-    /**
-     * @hide
-     */
+    /** @hide */
     public final byte[] mServiceName;
 
-    /**
-     * @hide
-     */
+    /** @hide */
     public final byte[] mServiceSpecificInfo;
 
-    /**
-     * @hide
-     */
-    public final byte[] mTxFilter;
+    /** @hide */
+    public final byte[] mMatchFilter;
 
-    /**
-     * @hide
-     */
-    public final byte[] mRxFilter;
-
-    /**
-     * @hide
-     */
+    /** @hide */
     public final int mSubscribeType;
 
-    /**
-     * @hide
-     */
+    /** @hide */
     public final int mSubscribeCount;
 
-    /**
-     * @hide
-     */
+    /** @hide */
     public final int mTtlSec;
 
-    /**
-     * @hide
-     */
+    /** @hide */
     public final int mMatchStyle;
 
-    /**
-     * @hide
-     */
+    /** @hide */
     public final boolean mEnableTerminateNotification;
 
-    private SubscribeConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] txFilter,
-            byte[] rxFilter, int subscribeType, int publichCount, int ttlSec, int matchStyle,
+    private SubscribeConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter,
+            int subscribeType, int publichCount, int ttlSec, int matchStyle,
             boolean enableTerminateNotification) {
         mServiceName = serviceName;
         mServiceSpecificInfo = serviceSpecificInfo;
-        mTxFilter = txFilter;
-        mRxFilter = rxFilter;
+        mMatchFilter = matchFilter;
         mSubscribeType = subscribeType;
         mSubscribeCount = publichCount;
         mTtlSec = ttlSec;
@@ -140,8 +122,7 @@
     public String toString() {
         return "SubscribeConfig [mServiceName='" + mServiceName + ", mServiceSpecificInfo='" + (
                 (mServiceSpecificInfo == null) ? "null" : HexEncoding.encode(mServiceSpecificInfo))
-                + ", mTxFilter=" + (new LvBufferUtils.LvIterable(1, mTxFilter)).toString()
-                + ", mRxFilter=" + (new LvBufferUtils.LvIterable(1, mRxFilter)).toString()
+                + ", mMatchFilter=" + (new LvBufferUtils.LvIterable(1, mMatchFilter)).toString()
                 + ", mSubscribeType=" + mSubscribeType + ", mSubscribeCount=" + mSubscribeCount
                 + ", mTtlSec=" + mTtlSec + ", mMatchType=" + mMatchStyle
                 + ", mEnableTerminateNotification=" + mEnableTerminateNotification + "]";
@@ -156,8 +137,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeByteArray(mServiceName);
         dest.writeByteArray(mServiceSpecificInfo);
-        dest.writeByteArray(mTxFilter);
-        dest.writeByteArray(mRxFilter);
+        dest.writeByteArray(mMatchFilter);
         dest.writeInt(mSubscribeType);
         dest.writeInt(mSubscribeCount);
         dest.writeInt(mTtlSec);
@@ -175,16 +155,15 @@
         public SubscribeConfig createFromParcel(Parcel in) {
             byte[] serviceName = in.createByteArray();
             byte[] ssi = in.createByteArray();
-            byte[] txFilter = in.createByteArray();
-            byte[] rxFilter = in.createByteArray();
+            byte[] matchFilter = in.createByteArray();
             int subscribeType = in.readInt();
             int subscribeCount = in.readInt();
             int ttlSec = in.readInt();
             int matchStyle = in.readInt();
             boolean enableTerminateNotification = in.readInt() != 0;
 
-            return new SubscribeConfig(serviceName, ssi, txFilter, rxFilter, subscribeType,
-                    subscribeCount, ttlSec, matchStyle, enableTerminateNotification);
+            return new SubscribeConfig(serviceName, ssi, matchFilter, subscribeType, subscribeCount,
+                    ttlSec, matchStyle, enableTerminateNotification);
         }
     };
 
@@ -201,10 +180,9 @@
         SubscribeConfig lhs = (SubscribeConfig) o;
 
         return Arrays.equals(mServiceName, lhs.mServiceName) && Arrays.equals(mServiceSpecificInfo,
-                lhs.mServiceSpecificInfo) && Arrays.equals(mTxFilter, lhs.mTxFilter)
-                && Arrays.equals(mRxFilter, lhs.mRxFilter) && mSubscribeType == lhs.mSubscribeType
-                && mSubscribeCount == lhs.mSubscribeCount && mTtlSec == lhs.mTtlSec
-                && mMatchStyle == lhs.mMatchStyle
+                lhs.mServiceSpecificInfo) && Arrays.equals(mMatchFilter, lhs.mMatchFilter)
+                && mSubscribeType == lhs.mSubscribeType && mSubscribeCount == lhs.mSubscribeCount
+                && mTtlSec == lhs.mTtlSec && mMatchStyle == lhs.mMatchStyle
                 && mEnableTerminateNotification == lhs.mEnableTerminateNotification;
     }
 
@@ -214,8 +192,7 @@
 
         result = 31 * result + Arrays.hashCode(mServiceName);
         result = 31 * result + Arrays.hashCode(mServiceSpecificInfo);
-        result = 31 * result + Arrays.hashCode(mTxFilter);
-        result = 31 * result + Arrays.hashCode(mRxFilter);
+        result = 31 * result + Arrays.hashCode(mMatchFilter);
         result = 31 * result + mSubscribeType;
         result = 31 * result + mSubscribeCount;
         result = 31 * result + mTtlSec;
@@ -226,7 +203,7 @@
     }
 
     /**
-     * Validates that the contents of the SubscribeConfig are valid. Otherwise
+     * Verifies that the contents of the SubscribeConfig are valid. Otherwise
      * throws an IllegalArgumentException.
      *
      * @hide
@@ -234,13 +211,9 @@
     public void validate() throws IllegalArgumentException {
         WifiNanUtils.validateServiceName(mServiceName);
 
-        if (!LvBufferUtils.isValid(mTxFilter, 1)) {
+        if (!LvBufferUtils.isValid(mMatchFilter, 1)) {
             throw new IllegalArgumentException(
-                    "Invalid txFilter configuration - LV fields do not match up to length");
-        }
-        if (!LvBufferUtils.isValid(mRxFilter, 1)) {
-            throw new IllegalArgumentException(
-                    "Invalid rxFilter configuration - LV fields do not match up to length");
+                    "Invalid matchFilter configuration - LV fields do not match up to length");
         }
         if (mSubscribeType < SUBSCRIBE_TYPE_PASSIVE || mSubscribeType > SUBSCRIBE_TYPE_ACTIVE) {
             throw new IllegalArgumentException("Invalid subscribeType - " + mSubscribeType);
@@ -255,16 +228,6 @@
             throw new IllegalArgumentException(
                     "Invalid matchType - must be MATCH_FIRST_ONLY or MATCH_ALL");
         }
-        if (mSubscribeType == SubscribeConfig.SUBSCRIBE_TYPE_ACTIVE && mRxFilter != null
-                && mRxFilter.length != 0) {
-            throw new IllegalArgumentException(
-                    "Invalid subscribe config: ACTIVE subscribes can't have an Rx filter");
-        }
-        if (mSubscribeType == SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE && mTxFilter != null
-                && mTxFilter.length != 0) {
-            throw new IllegalArgumentException(
-                    "Invalid subscribe config: PASSIVE subscribes can't have a Tx filter");
-        }
     }
 
     /**
@@ -273,8 +236,7 @@
     public static final class Builder {
         private byte[] mServiceName;
         private byte[] mServiceSpecificInfo;
-        private byte[] mTxFilter;
-        private byte[] mRxFilter;
+        private byte[] mMatchFilter;
         private int mSubscribeType = SUBSCRIBE_TYPE_PASSIVE;
         private int mSubscribeCount = 0;
         private int mTtlSec = 0;
@@ -284,13 +246,16 @@
         /**
          * Specify the service name of the subscribe session. The actual on-air
          * value is a 6 byte hashed representation of this string.
-         *
-         * Per spec: The Service Name is a UTF-8 encoded string from 1 to 255 bytes in length.
+         * <p>
+         * The Service Name is a UTF-8 encoded string from 1 to 255 bytes in length.
          * The only acceptable single-byte UTF-8 symbols for a Service Name are alphanumeric
          * values (A-Z, a-z, 0-9), the hyphen ('-'), and the period ('.'). All valid multi-byte
          * UTF-8 characters are acceptable in a Service Name.
+         * <p>
+         * Must be called - an empty ServiceName is not valid.
          *
          * @param serviceName The service name for the subscribe session.
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
@@ -303,14 +268,17 @@
         }
 
         /**
-         * Specify service specific information for the subscribe session. This
-         * is a free-form byte array available to the application to send
+         * Specify service specific information for the subscribe session. This is
+         * a free-form byte array available to the application to send
          * additional information as part of the discovery operation - i.e. it
          * will not be used to determine whether a publish/subscribe match
          * occurs.
+         * <p>
+         *     Optional. Empty by default.
          *
          * @param serviceSpecificInfo A byte-array for the service-specific
          *            information field.
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
@@ -320,14 +288,16 @@
         }
 
         /**
-         * Specify service specific information for the subscribe session - same
-         * as
-         * {@link SubscribeConfig.Builder#setServiceSpecificInfo(byte[])}
-         * but obtaining the data from a String.
+         * Specify service specific information for the subscribe session - a simple wrapper
+         * of {@link SubscribeConfig.Builder#setServiceSpecificInfo(byte[])}
+         * obtaining the data from a String.
+         * <p>
+         *     Optional. Empty by default.
          *
          * @param serviceSpecificInfoStr The service specific information string
          *            to be included (as a byte array) in the subscribe
          *            information.
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
@@ -337,43 +307,21 @@
         }
 
         /**
-         * The transmit filter for an active subscribe session
-         * {@link SubscribeConfig.Builder#setSubscribeType(int)} and
-         * {@link SubscribeConfig#SUBSCRIBE_TYPE_ACTIVE}. Included in
-         * transmitted subscribe packets and used by receivers (passive
-         * publishers) to determine whether they match - in addition to just
-         * relying on the service name.
+         * The match filter for a subscribe session. Used to determine whether a service
+         * discovery occurred - in addition to relying on the service name.
          * <p>
-         * Format is an LV byte array - the {@link LvBufferUtils} utility class
-         * is available to form and parse.
+         * Format is an LV byte array: a single byte Length field followed by L bytes (the value of
+         * the Length field) of a value blob.
+         * <p>
+         *     Optional. Empty by default.
          *
-         * @param txFilter The byte-array containing the LV formatted transmit
-         *            filter.
+         * @param matchFilter The byte-array containing the LV formatted match filter.
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
-        public Builder setTxFilter(@Nullable byte[] txFilter) {
-            mTxFilter = txFilter;
-            return this;
-        }
-
-        /**
-         * The transmit filter for a passive subsribe session
-         * {@link SubscribeConfig.Builder#setSubscribeType(int)} and
-         * {@link SubscribeConfig#SUBSCRIBE_TYPE_PASSIVE}. Used by the
-         * subscriber to determine whether they match transmitted publish
-         * packets - in addition to just relying on the service name.
-         * <p>
-         * Format is an LV byte array - the {@link LvBufferUtils} utility class
-         * is available to form and parse.
-         *
-         * @param rxFilter The byte-array containing the LV formatted receive
-         *            filter.
-         * @return The builder to facilitate chaining
-         *         {@code builder.setXXX(..).setXXX(..)}.
-         */
-        public Builder setRxFilter(@Nullable byte[] rxFilter) {
-            mRxFilter = rxFilter;
+        public Builder setMatchFilter(@Nullable byte[] matchFilter) {
+            mMatchFilter = matchFilter;
             return this;
         }
 
@@ -383,9 +331,10 @@
          * transmitted, a match is made against a solicited/active publish
          * session whose packets are transmitted over-the-air).
          *
-         * @param subscribeType Subscribe session type: active (
-         *            {@link SubscribeConfig#SUBSCRIBE_TYPE_ACTIVE}) or passive
-         *            ( {@link SubscribeConfig#SUBSCRIBE_TYPE_PASSIVE} ).
+         * @param subscribeType Subscribe session type:
+         *            {@link SubscribeConfig#SUBSCRIBE_TYPE_ACTIVE} or
+         *            {@link SubscribeConfig#SUBSCRIBE_TYPE_PASSIVE}.
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
@@ -399,13 +348,16 @@
 
         /**
          * Sets the number of times an active (
-         * {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe
-         * session will transmit a packet. When the count is reached an event
-         * will be generated for
-         * {@link WifiNanSessionCallback#onSessionTerminated(int)} with reason=
-         * {@link WifiNanSessionCallback#TERMINATE_REASON_DONE}.
+         * {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe session
+         * will broadcast. When the count is reached an event will be
+         * generated for {@link WifiNanSessionCallback#onSessionTerminated(int)}
+         * with {@link WifiNanSessionCallback#TERMINATE_REASON_DONE}.
+         * <p>
+         *     Optional. 0 by default - indicating the session doesn't terminate on its own.
+         *     Session will be terminated when {@link WifiNanSession#terminate()} is called.
          *
-         * @param subscribeCount Number of subscribe packets to transmit.
+         * @param subscribeCount Number of subscribe packets to broadcast.
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
@@ -419,13 +371,17 @@
 
         /**
          * Sets the time interval (in seconds) an active (
-         * {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe
-         * session will be alive - i.e. transmitting a packet. When the TTL is
-         * reached an event will be generated for
-         * {@link WifiNanSessionCallback#onSessionTerminated(int)} with reason=
+         * {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe session
+         * will be alive - i.e. broadcasting a packet. When the TTL is reached
+         * an event will be generated for
+         * {@link WifiNanSessionCallback#onSessionTerminated(int)} with
          * {@link WifiNanSessionCallback#TERMINATE_REASON_DONE}.
+         * <p>
+         *     Optional. 0 by default - indicating the session doesn't terminate on its own.
+         *     Session will be terminated when {@link WifiNanSession#terminate()} is called.
          *
          * @param ttlSec Lifetime of a subscribe session in seconds.
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
@@ -444,7 +400,7 @@
          * {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])}
          * ). The options are: only report the first match and ignore the rest
          * {@link SubscribeConfig#MATCH_STYLE_FIRST_ONLY} or report every single
-         * match {@link SubscribeConfig#MATCH_STYLE_ALL}.
+         * match {@link SubscribeConfig#MATCH_STYLE_ALL} (the default).
          *
          * @param matchStyle The reporting style for the discovery match.
          * @return The builder to facilitate chaining
@@ -466,6 +422,7 @@
          *
          * @param enable If true the terminate callback will be called when the
          *            subscribe is terminated. Otherwise it will not be called.
+         *
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
@@ -479,7 +436,7 @@
          * builder.
          */
         public SubscribeConfig build() {
-            return new SubscribeConfig(mServiceName, mServiceSpecificInfo, mTxFilter, mRxFilter,
+            return new SubscribeConfig(mServiceName, mServiceSpecificInfo, mMatchFilter,
                     mSubscribeType, mSubscribeCount, mTtlSec, mMatchStyle,
                     mEnableTerminateNotification);
         }
diff --git a/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java b/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java
index 148307d..6e714f1 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java
@@ -22,14 +22,15 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * Base class for NAN events callbacks. Should be extended by applications
- * wanting notifications. These are callbacks applying to the NAN connection as
- * a whole - not to specific publish or subscribe sessions - for that see
- * {@link WifiNanSessionCallback}.
+ * Base class for NAN events callbacks. Should be extended by applications and set when calling
+ * {@link WifiNanManager#connect(android.os.Looper, WifiNanEventCallback)}. These are callbacks
+ * applying to the NAN connection as a whole - not to specific publish or subscribe sessions -
+ * for that see {@link WifiNanSessionCallback}.
  *
  * @hide PROPOSED_NAN_API
  */
 public class WifiNanEventCallback {
+    /** @hide */
     @IntDef({
             REASON_INVALID_ARGS, REASON_ALREADY_CONNECTED_INCOMPAT_CONFIG, REASON_OTHER
     })
@@ -38,31 +39,29 @@
     }
 
     /**
-     * Failure reason flag for {@link WifiNanEventCallback} callbacks. Indicates
-     * invalid argument in the requested operation.
+     * Indicates invalid argument in the requested operation. Failure reason flag for
+     * {@link WifiNanEventCallback#onConnectFail(int)}.
      */
     public static final int REASON_INVALID_ARGS = 1000;
 
     /**
-     * Failure reason flag for {@link WifiNanEventCallback} callbacks. Indicates
-     * that a {@link ConfigRequest} passed in
-     * {@link WifiNanManager#connect(android.os.Looper, WifiNanEventCallback, ConfigRequest)}
-     * couldn't be applied since other connections already exist with an
-     * incompatible configurations.
+     * Indicates that a {@link ConfigRequest} passed in
+     * {@link WifiNanManager#connect(android.os.Looper, ConfigRequest, WifiNanEventCallback)}
+     * couldn't be applied since other connections already exist with an incompatible
+     * configurations. Failure reason flag for {@link WifiNanEventCallback#onConnectFail(int)}.
      */
     public static final int REASON_ALREADY_CONNECTED_INCOMPAT_CONFIG = 1001;
 
     /**
-     * Failure reason flag for {@link WifiNanEventCallback} callbacks. Indicates
-     * an unspecified error occurred during the operation.
+     * Indicates an unspecified error occurred during the operation. Failure reason flag for
+     * {@link WifiNanEventCallback#onConnectFail(int)}.
      */
-    public static final int REASON_OTHER = 1003;
+    public static final int REASON_OTHER = 1002;
 
     /**
      * Called when NAN connect operation
      * {@link WifiNanManager#connect(android.os.Looper, WifiNanEventCallback)}
-     * is completed. Doesn't necessarily mean that have joined or started a NAN
-     * cluster. An indication is provided by {@link #onIdentityChanged(byte[])}.
+     * is completed and that we can now start discovery sessions or connections.
      */
     public void onConnectSuccess() {
         /* empty */
@@ -70,8 +69,7 @@
 
     /**
      * Called when NAN connect operation
-     * {@code WifiNanManager#connect(android.os.Looper, WifiNanEventCallback)}
-     * failed.
+     * {@link WifiNanManager#connect(android.os.Looper, WifiNanEventCallback)} failed.
      *
      * @param reason Failure reason code, see
      *            {@code WifiNanEventCallback.REASON_*}.
@@ -81,12 +79,25 @@
     }
 
     /**
-     * Called when NAN identity has changed and after {@link #onConnectSuccess()}. Call may be
-     * due to joining a cluster, starting a cluster, or discovery interface change. The
-     * implication is that peers you've been communicating with may no longer recognize you and
-     * you need to re-establish your identity.
-     * @param mac The MAC address of the NAN discovery interface. Depending on the permission
-     *            model may be all 0's.
+     * Called when NAN identity (the MAC address representing our NAN discovery interface) has
+     * changed. Change may be due to device joining a cluster, starting a cluster, or discovery
+     * interface change (addresses are randomized at regular intervals). The implication is that
+     * peers you've been communicating with may no longer recognize you and you need to
+     * re-establish your identity - e.g. by starting a discovery session. This actual MAC address
+     * of the interface may also be useful if the application uses alternative (non-NAN)
+     * discovery but needs to set up a NAN connection. The provided NAN discovery interface MAC
+     * address can then be used in
+     * {@link WifiNanManager#createNetworkSpecifier(int, byte[], byte[])}.
+     * <p>
+     *     This callback is only called if the NAN connection enables it using
+     *     {@link ConfigRequest.Builder#setEnableIdentityChangeCallback(boolean)} in
+     *     {@link WifiNanManager#connect(android.os.Looper, ConfigRequest, WifiNanEventCallback)}
+     *     . It is disabled by default since it may result in additional wake-ups of the host -
+     *     increasing power.
+     *
+     * @param mac The MAC address of the NAN discovery interface. The application must have the
+     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} to get the actual MAC address,
+     *            otherwise all 0's will be provided.
      */
     public void onIdentityChanged(byte[] mac) {
         /* empty */
diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java
index ff612fe7..82d22bc 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanManager.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java
@@ -22,6 +22,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
+import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.NetworkRequest;
 import android.net.wifi.RttManager;
@@ -38,6 +39,8 @@
 
 import com.android.internal.annotations.GuardedBy;
 
+import dalvik.system.CloseGuard;
+
 import libcore.util.HexEncoding;
 
 import org.json.JSONException;
@@ -49,17 +52,67 @@
 import java.util.Arrays;
 
 /**
- * This class provides the primary API for managing Wi-Fi NAN operation:
- * including discovery and data-links. Get an instance of this class by calling
+ * This class provides the primary API for managing Wi-Fi NAN operations:
+ * discovery and peer-to-peer data connections. Get an instance of this class by calling
  * {@link android.content.Context#getSystemService(String)
  * Context.getSystemService(Context.WIFI_NAN_SERVICE)}.
  * <p>
  * The class provides access to:
  * <ul>
- * <li>Configure a NAN connection and register for events.
- * <li>Create publish and subscribe sessions.
- * <li>Create NAN network specifier to be used to create a NAN network.
+ * <li>Initialize a NAN cluster (peer-to-peer synchronization). Refer to
+ * {@link #connect(Looper, WifiNanEventCallback)}.
+ * <li>Create discovery sessions (publish or subscribe sessions).
+ * Refer to {@link #publish(PublishConfig, WifiNanSessionCallback)} and
+ * {@link #subscribe(SubscribeConfig, WifiNanSessionCallback)}.
+ * <li>Create a NAN network specifier to be used with
+ * {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}
+ * to set-up a NAN connection with a peer. Refer to
+ * {@link WifiNanSession#createNetworkSpecifier(int, int, byte[])} and
+ * {@link #createNetworkSpecifier(int, byte[], byte[])}.
  * </ul>
+ * <p>
+ *     NAN may not be usable when Wi-Fi is disabled (and other conditions). To validate that
+ *     the functionality is available use the {@link #isUsageEnabled()} function. To track
+ *     changes in NAN usability register for the {@link #ACTION_WIFI_NAN_STATE_CHANGED} broadcast.
+ *     Note that this broadcast is not sticky - you should register for it and then check the
+ *     above API to avoid a race condition.
+ * <p>
+ *     An application must use {@link #connect(Looper, WifiNanEventCallback)} to initialize a NAN
+ *     cluster - before making any other NAN operation. NAN cluster membership is a device-wide
+ *     operation - the API guarantees that the device is in a cluster or joins a NAN cluster (or
+ *     starts one if none can be found). Information about connection success (or failure) are
+ *     returned in callbacks of {@link WifiNanEventCallback}. Proceed with NAN discovery or
+ *     connection setup only after receiving confirmation that NAN connection succeeded -
+ *     {@link WifiNanEventCallback#onConnectSuccess()}.
+ *     When an application is finished using NAN it <b>must</b> use the {@link #disconnect()} API
+ *     to indicate to the NAN service that the device may disconnect from the NAN cluster. The
+ *     device will actually disconnect from the NAN cluster once the last application disconnects.
+ * <p>
+ *     Once a NAN connection is confirmed use the
+ *     {@link #publish(PublishConfig, WifiNanSessionCallback)} or
+ *     {@link #subscribe(SubscribeConfig, WifiNanSessionCallback)} to create publish or subscribe
+ *     NAN discovery sessions. Events are called on the provided callback object
+ *     {@link WifiNanSessionCallback}. Specifically, the
+ *     {@link WifiNanSessionCallback#onPublishStarted(WifiNanPublishSession)} and
+ *     {@link WifiNanSessionCallback#onSubscribeStarted(WifiNanSubscribeSession)} return
+ *     {@link WifiNanPublishSession} and {@link WifiNanSubscribeSession} objects respectively on
+ *     which additional session operations can be performed, e.g. updating the session
+ *     {@link WifiNanPublishSession#updatePublish(PublishConfig)} and
+ *     {@link WifiNanSubscribeSession#updateSubscribe(SubscribeConfig)}. Sessions can also be
+ *     used to send messages using the {@link WifiNanSession#sendMessage(int, byte[], int)} APIs.
+ *     When an application is finished with a discovery session it <b>must</b> terminate it using
+ *     the {@link WifiNanSession#terminate()} API.
+ * <p>
+ *    Creating connections between NAN devices is managed by the standard
+ *    {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}.
+ *    The {@link NetworkRequest} object should be constructed with:
+ *    <ul>
+ *        <li>{@link NetworkRequest.Builder#addTransportType(int)} of
+ *        {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_NAN}.
+ *        <li>{@link NetworkRequest.Builder#setNetworkSpecifier(String)} using
+ *        {@link #createNetworkSpecifier(int, byte[], byte[])} or
+ *        {@link WifiNanSession#createNetworkSpecifier(int, int, byte[])}.
+ *    </ul>
  *
  * @hide PROPOSED_NAN_API
  */
@@ -123,82 +176,69 @@
      */
     public static final int NETWORK_SPECIFIER_TYPE_2D = 7;
 
-    /**
-     * @hide
-     */
+    /** @hide */
     public static final int NETWORK_SPECIFIER_TYPE_MAX_VALID = NETWORK_SPECIFIER_TYPE_2D;
 
-    /**
-     * @hide
-     */
-
+    /** @hide */
     public static final String NETWORK_SPECIFIER_KEY_TYPE = "type";
 
-    /**
-     * @hide
-     */
-
+    /** @hide */
     public static final String NETWORK_SPECIFIER_KEY_ROLE = "role";
 
-    /**
-     * @hide
-     */
-
+    /** @hide */
     public static final String NETWORK_SPECIFIER_KEY_CLIENT_ID = "client_id";
-    /**
-     * @hide
-     */
+
+    /** @hide */
     public static final String NETWORK_SPECIFIER_KEY_SESSION_ID = "session_id";
 
-    /**
-     * @hide
-     */
+    /** @hide */
     public static final String NETWORK_SPECIFIER_KEY_PEER_ID = "peer_id";
 
-    /**
-     * @hide
-     */
+    /** @hide */
     public static final String NETWORK_SPECIFIER_KEY_PEER_MAC = "peer_mac";
 
-    /**
-     * @hide
-     */
+    /** @hide */
     public static final String NETWORK_SPECIFIER_KEY_TOKEN = "token";
 
     /**
      * Broadcast intent action to indicate whether Wi-Fi NAN is enabled or
      * disabled. An extra {@link #EXTRA_WIFI_STATE} provides the state
-     * information as int.
+     * information as int using {@link #WIFI_NAN_STATE_DISABLED} and
+     * {@link #WIFI_NAN_STATE_ENABLED} constants. This broadcast is <b>not</b> sticky,
+     * use the {@link #isUsageEnabled()} API after registering the broadcast to check the current
+     * state of Wi-Fi NAN.
      *
      * @see #EXTRA_WIFI_STATE
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String WIFI_NAN_STATE_CHANGED_ACTION = "android.net.wifi.nan.STATE_CHANGED";
+    public static final String ACTION_WIFI_NAN_STATE_CHANGED =
+            "android.net.wifi.nan.action.WIFI_NAN_STATE_CHANGED";
 
     /**
-     * The lookup key for an int that indicates whether Wi-Fi NAN is enabled or
+     * The lookup key for an int value indicating whether Wi-Fi NAN is enabled or
      * disabled. Retrieve it with
      * {@link android.content.Intent#getIntExtra(String,int)}.
      *
      * @see #WIFI_NAN_STATE_DISABLED
      * @see #WIFI_NAN_STATE_ENABLED
      */
-    public static final String EXTRA_WIFI_STATE = "wifi_nan_state";
+    public static final String EXTRA_WIFI_STATE = "android.net.wifi.nan.extra.WIFI_STATE";
 
     /**
      * Wi-Fi NAN is disabled.
      *
-     * @see #WIFI_NAN_STATE_CHANGED_ACTION
+     * @see #ACTION_WIFI_NAN_STATE_CHANGED
      */
     public static final int WIFI_NAN_STATE_DISABLED = 1;
 
     /**
      * Wi-Fi NAN is enabled.
      *
-     * @see #WIFI_NAN_STATE_CHANGED_ACTION
+     * @see #ACTION_WIFI_NAN_STATE_CHANGED
      */
     public static final int WIFI_NAN_STATE_ENABLED = 2;
 
+    /** @hide */
     @IntDef({
             WIFI_NAN_DATA_PATH_ROLE_INITIATOR, WIFI_NAN_DATA_PATH_ROLE_RESPONDER})
     @Retention(RetentionPolicy.SOURCE)
@@ -206,21 +246,26 @@
     }
 
     /**
-     * Data-path creation role is that of INITIATOR. Used in
-     * {@link #createNetworkSpecifier(int, byte[], byte[])} and
-     * {@link WifiNanSession#createNetworkSpecifier(int, int, byte[])}.
+     * Connection creation role is that of INITIATOR. Used to create a network specifier string
+     * when requesting a NAN network.
+     *
+     * @see WifiNanSession#createNetworkSpecifier(int, int, byte[])
+     * @see #createNetworkSpecifier(int, byte[], byte[])
      */
     public static final int WIFI_NAN_DATA_PATH_ROLE_INITIATOR = 0;
 
     /**
-     * Data-path creation role is that of RESPONDER. Used in
-     * {@link #createNetworkSpecifier(int, byte[], byte[])} and
-     * {@link WifiNanSession#createNetworkSpecifier(int, int, byte[])}.
+     * Connection creation role is that of RESPONDER. Used to create a network specifier string
+     * when requesting a NAN network.
+     *
+     * @see WifiNanSession#createNetworkSpecifier(int, int, byte[])
+     * @see #createNetworkSpecifier(int, byte[], byte[])
      */
-
     public static final int WIFI_NAN_DATA_PATH_ROLE_RESPONDER = 1;
 
+    private final Context mContext;
     private final IWifiNanManager mService;
+    private final CloseGuard mCloseGuard = CloseGuard.get();
 
     private final Object mLock = new Object(); // lock access to the following vars
 
@@ -236,45 +281,45 @@
     @GuardedBy("mLock")
     private SparseArray<RttManager.RttListener> mRangingListeners = new SparseArray<>();
 
-    /**
-     * {@hide}
-     */
-    public WifiNanManager(IWifiNanManager service) {
+    /** @hide */
+    public WifiNanManager(Context context, IWifiNanManager service) {
+        mContext = context;
         mService = service;
     }
 
     /**
      * Enable the usage of the NAN API. Doesn't actually turn on NAN cluster formation - that only
-     * happens when a connection is made. {@link #WIFI_NAN_STATE_CHANGED_ACTION} broadcast will be
+     * happens when a connection is made. {@link #ACTION_WIFI_NAN_STATE_CHANGED} broadcast will be
      * triggered.
      *
-     * @hide PROPOSED_NAN_SYSTEM_API
+     * @hide
      */
     public void enableUsage() {
         try {
             mService.enableUsage();
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
     /**
      * Disable the usage of the NAN API. All attempts to connect() will be rejected. All open
-     * connections and sessions will be terminated. {@link #WIFI_NAN_STATE_CHANGED_ACTION} broadcast
+     * connections and sessions will be terminated. {@link #ACTION_WIFI_NAN_STATE_CHANGED} broadcast
      * will be triggered.
      *
-     * @hide PROPOSED_NAN_SYSTEM_API
+     * @hide
      */
     public void disableUsage() {
         try {
             mService.disableUsage();
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Returns the current status of NAN API: whether or not usage is enabled.
+     * Returns the current status of NAN API: whether or not usage is enabled. To track changes
+     * in the state of NAN API register for the {@link #ACTION_WIFI_NAN_STATE_CHANGED} broadcast.
      *
      * @return A boolean indicating whether the app can use the NAN API (true)
      *         or not (false).
@@ -283,15 +328,20 @@
         try {
             return mService.isUsageEnabled();
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
-
-        return false;
     }
 
     /**
-     * Connect to the Wi-Fi NAN service - enabling the application to execute
-     * {@link WifiNanManager} APIs.
+     * Connect to the Wi-Fi NAN service - enabling the application to create discovery session or
+     * create connection to peers. The device will connect to an existing cluster if it can find
+     * one or create a new cluster (if it is the first to enable NAN in its vicinity). Results
+     * (e.g. successful connection to a cluster) are provided to the {@code callback} object.
+     * An application <b>must</b> call {@link #disconnect()} when done with the Wi-Fi NAN
+     * connection.
+     * <p>
+     * Note: a NAN cluster is a shared resource - if the device is already connected to a cluster
+     * than this function will simply indicate success immediately.
      *
      * @param looper The Looper on which to execute all callbacks related to the
      *            connection - including all sessions opened as part of this
@@ -299,22 +349,30 @@
      * @param callback A callback extended from {@link WifiNanEventCallback}.
      */
     public void connect(@NonNull Looper looper, @NonNull WifiNanEventCallback callback) {
-        connect(looper, callback, null);
+        connect(looper, null, callback);
     }
 
     /**
-     * Connect to the Wi-Fi NAN service - enabling the application to execute
-     * {@link WifiNanManager} APIs. Allows requesting a specific configuration
-     * using {@link ConfigRequest} structure. Limited to privileged access.
+     * Connect to the Wi-Fi NAN service - enabling the application to create discovery session or
+     * create connection to peers. The device will connect to an existing cluster if it can find
+     * one or create a new cluster (if it is the first to enable NAN in its vicinity). Results
+     * (e.g. successful connection to a cluster) are provided to the {@code callback} object.
+     * An application <b>must</b> call {@link #disconnect()} when done with the Wi-Fi NAN
+     * connection. Allows requesting a specific configuration using {@link ConfigRequest}. If not
+     * necessary (default configuration should usually work) use the
+     * {@link #connect(Looper, WifiNanEventCallback)} method instead.
+     * <p>
+     * Note: a NAN cluster is a shared resource - if the device is already connected to a cluster
+     * than this function will simply indicate success immediately.
      *
      * @param looper The Looper on which to execute all callbacks related to the
      *            connection - including all sessions opened as part of this
      *            connection.
-     * @param callback A callback extended from {@link WifiNanEventCallback}.
      * @param configRequest The requested NAN configuration.
+     * @param callback A callback extended from {@link WifiNanEventCallback}.
      */
-    public void connect(@NonNull Looper looper, @NonNull WifiNanEventCallback callback,
-            @Nullable ConfigRequest configRequest) {
+    public void connect(@NonNull Looper looper, @Nullable ConfigRequest configRequest,
+            @NonNull WifiNanEventCallback callback) {
         if (VDBG) {
             Log.v(TAG, "connect(): looper=" + looper + ", callback=" + callback + ", configRequest="
                     + configRequest);
@@ -324,23 +382,26 @@
             mLooper = looper;
 
             try {
-                mClientId = mService.connect(mBinder,
+                mClientId = mService.connect(mBinder, mContext.getOpPackageName(),
                         new WifiNanEventCallbackProxy(this, looper, callback), configRequest);
             } catch (RemoteException e) {
                 mClientId = INVALID_CLIENT_ID;
                 mLooper = null;
-                e.rethrowFromSystemServer();
+                throw e.rethrowFromSystemServer();
             }
         }
+
+        mCloseGuard.open("disconnect");
     }
 
     /**
-     * Disconnect from the Wi-Fi NAN service and destroy all outstanding
-     * operations - i.e. all publish and subscribes are terminated, any
-     * outstanding data-link is shut-down, and all requested NAN configurations
-     * are cancelled.
+     * Disconnect from the Wi-Fi NAN service and, if no other applications are connected to NAN,
+     * also disconnect from the NAN cluster. This method destroys all outstanding operations -
+     * i.e. all publish and subscribes are terminated, and any outstanding data-links are
+     * shut-down. However, it is good practice to terminate these discovery sessions and
+     * connections explicitly before a disconnect.
      * <p>
-     * An application may then re-connect using
+     * An application may re-connect after a disconnect using
      * {@link WifiNanManager#connect(Looper, WifiNanEventCallback)} .
      */
     public void disconnect() {
@@ -361,31 +422,49 @@
             mClientId = INVALID_CLIENT_ID;
         }
 
+        mCloseGuard.close();
         try {
             mService.disconnect(clientId, binder);
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
+    /** @hide */
     @Override
     protected void finalize() throws Throwable {
-        disconnect();
-        super.finalize();
+        try {
+            mCloseGuard.warnIfOpen();
+            disconnect();
+        } finally {
+            super.finalize();
+        }
     }
 
     /**
-     * Request a NAN publish session. The actual publish session is provided by
-     * the
-     * {@link WifiNanSessionCallback#onPublishStarted(WifiNanPublishSession)}
-     * callback. Other results of the publish session operation will result in
-     * callbacks to the indicated callback: {@link WifiNanSessionCallback
-     * NanSessionCallback.on*}.
+     * Issue a request to the NAN service to create a new NAN publish discovery session, using
+     * the specified {@code publishConfig} configuration. The results of the publish operation
+     * are routed to the callbacks of {@link WifiNanSessionCallback}:
+     * <ul>
+     *     <li>{@link WifiNanSessionCallback#onPublishStarted(WifiNanPublishSession)} is called
+     *     when the publish session is created and provides a handle to the session. Further
+     *     operations on the publish session can be executed on that object.
+     *     <li>{@link WifiNanSessionCallback#onSessionConfigFail(int)} is called if the publish
+     *     operation failed.
+     * </ul>
+     * <p>
+     * Other results of the publish session operations will also be routed to callbacks
+     * on the {@code callback} object. The resulting publish session can be modified using
+     * {@link WifiNanPublishSession#updatePublish(PublishConfig)}.
+     * <p>
+     *      An application must use the {@link WifiNanSession#terminate()} to terminate the publish
+     *      discovery session once it isn't needed. This will free resources as well terminate
+     *      any on-air transmissions.
      *
      * @param publishConfig The {@link PublishConfig} specifying the
-     *            configuration of the publish session.
-     * @param callback The {@link WifiNanSessionCallback} derived objects to be
-     *            used for the event callbacks specified by {@code events}.
+     *            configuration of the requested publish session.
+     * @param callback A {@link WifiNanSessionCallback} derived object to be used for session
+     *                 event callbacks.
      */
     public void publish(@NonNull PublishConfig publishConfig,
             @NonNull WifiNanSessionCallback callback) {
@@ -407,13 +486,11 @@
             mService.publish(clientId, publishConfig,
                     new WifiNanSessionCallbackProxy(this, looper, true, callback));
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
-    /**
-     * {@hide}
-     */
+    /** @hide */
     public void updatePublish(int sessionId, PublishConfig publishConfig) {
         if (VDBG) Log.v(TAG, "updatePublish(): config=" + publishConfig);
 
@@ -429,22 +506,34 @@
         try {
             mService.updatePublish(clientId, sessionId, publishConfig);
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Request a NAN subscribe session. The actual subscribe session is provided
-     * by the
-     * {@link WifiNanSessionCallback#onSubscribeStarted(WifiNanSubscribeSession)}
-     * callback. Other results of the subscribe session operation will result in
-     * callbacks to the indicated callback: {@link WifiNanSessionCallback
-     * NanSessionCallback.on*}
+     * Issue a request to the NAN service to create a new NAN subscribe discovery session, using
+     * the specified {@code subscribeConfig} configuration. The results of the subscribe
+     * operation are routed to the callbacks of {@link WifiNanSessionCallback}:
+     * <ul>
+     *     <li>{@link WifiNanSessionCallback#onSubscribeStarted(WifiNanSubscribeSession)} is called
+     *     when the subscribe session is created and provides a handle to the session. Further
+     *     operations on the subscribe session can be executed on that object.
+     *     <li>{@link WifiNanSessionCallback#onSessionConfigFail(int)} is called if the subscribe
+     *     operation failed.
+     * </ul>
+     * <p>
+     * Other results of the subscribe session operations will also be routed to callbacks
+     * on the {@code callback} object. The resulting subscribe session can be modified using
+     * {@link WifiNanSubscribeSession#updateSubscribe(SubscribeConfig)}.
+     * <p>
+     *      An application must use the {@link WifiNanSession#terminate()} to terminate the
+     *      subscribe discovery session once it isn't needed. This will free resources as well
+     *      terminate any on-air transmissions.
      *
      * @param subscribeConfig The {@link SubscribeConfig} specifying the
-     *            configuration of the subscribe session.
-     * @param callback The {@link WifiNanSessionCallback} derived objects to be
-     *            used for the event callbacks specified by {@code events}.
+     *            configuration of the requested subscribe session.
+     * @param callback A {@link WifiNanSessionCallback} derived object to be used for session
+     *                 event callbacks.
      */
     public void subscribe(@NonNull SubscribeConfig subscribeConfig,
             @NonNull WifiNanSessionCallback callback) {
@@ -469,13 +558,11 @@
             mService.subscribe(clientId, subscribeConfig,
                     new WifiNanSessionCallbackProxy(this, looper, false, callback));
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
-    /**
-     * {@hide}
-     */
+    /** @hide */
     public void updateSubscribe(int sessionId, SubscribeConfig subscribeConfig) {
         if (VDBG) {
             Log.v(TAG, "subscribe(): config=" + subscribeConfig);
@@ -495,13 +582,11 @@
         try {
             mService.updateSubscribe(clientId, sessionId, subscribeConfig);
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
-    /**
-     * {@hide}
-     */
+    /** @hide */
     public void terminateSession(int sessionId) {
         if (DBG) Log.d(TAG, "Terminate NAN session #" + sessionId);
 
@@ -519,13 +604,11 @@
         try {
             mService.terminateSession(clientId, sessionId);
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
-    /**
-     * {@hide}
-     */
+    /** @hide */
     public void sendMessage(int sessionId, int peerId, byte[] message, int messageId,
             int retryCount) {
         if (VDBG) {
@@ -546,13 +629,11 @@
         try {
             mService.sendMessage(clientId, sessionId, peerId, message, messageId, retryCount);
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
-    /**
-     * {@hide}
-     */
+    /** @hide */
     public void startRanging(int sessionId, RttManager.RttParams[] params,
                              RttManager.RttListener listener) {
         if (VDBG) {
@@ -575,7 +656,7 @@
             rangingKey = mService.startRanging(clientId, sessionId,
                     new RttManager.ParcelableRttParams(params));
         } catch (RemoteException e) {
-            e.rethrowAsRuntimeException();
+            throw e.rethrowFromSystemServer();
         }
 
         synchronized (mLock) {
@@ -583,9 +664,7 @@
         }
     }
 
-    /**
-     * {@hide}
-     */
+    /** @hide */
     public String createNetworkSpecifier(@DataPathRole int role, int sessionId, int peerId,
             byte[] token) {
         if (VDBG) {
@@ -656,20 +735,29 @@
     }
 
     /**
-     * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)}  for a
-     * WiFi NAN data-path connection to the specified peer. The peer MAC cannot be obtained
-     * through {@link WifiNanManager} services - but could be obtained out-of-bound - it refers
-     * to the MAC address of the NAN discovery interface of the peer NAN device.
+     * Create a {@link NetworkRequest.Builder#setNetworkSpecifier(String)} for a
+     * WiFi NAN connection to the specified peer. The
+     * {@link NetworkRequest.Builder#addTransportType(int)} should be set to
+     * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_NAN}.
+     * <p>
+     *     This API is targeted for applications which can obtain the peer MAC address using OOB
+     *     (out-of-band) discovery. NAN discovery does not provide the MAC address of the peer -
+     *     when using NAN discovery use the alternative network specifier method -
+     *     {@link WifiNanSession#createNetworkSpecifier(int, int, byte[])}.
      *
      * @param role  The role of this device:
      *              {@link WifiNanManager#WIFI_NAN_DATA_PATH_ROLE_INITIATOR} or
      *              {@link WifiNanManager#WIFI_NAN_DATA_PATH_ROLE_RESPONDER}
-     * @param peer  The MAC address of the peer's NAN discovery interface. A null is permitted
-     *              for a RESPONDER - which implies that any peer can connect.
-     * @param token An arbitrary token (message) to be passed to the peer as part of the
-     *              data-path setup process. On the RESPONDER a null token is permitted and
-     *              matches any peer token - an empty token requires the peer token to be empty
-     *              as well.
+     * @param peer  The MAC address of the peer's NAN discovery interface. On a RESPONDER this
+     *              value is used to gate the acceptance of a connection request from only that
+     *              peer. A RESPONDER may specified a null - indicating that it will accept
+     *              connection requests from any device.
+     * @param token An arbitrary token (message) to be used to match connection initiation request
+     *              to a responder setup. A RESPONDER is set up with a {@code token} which must
+     *              be matched by the token provided by the INITIATOR. A null token is permitted
+     *              on the RESPONDER and matches any peer token. An empty ({@code ""}) token is
+     *              not the same as a null token and requires the peer token to be empty as well.
+     *
      * @return A string to be used to construct
      * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to {@link
      * android.net.ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}
@@ -773,7 +861,7 @@
 
         /**
          * Constructs a {@link WifiNanEventCallback} using the specified looper.
-         * I.e. all callbacks will delivered on the thread of the specified looper.
+         * All callbacks will delivered on the thread of the specified looper.
          *
          * @param looper The looper on which to execute the callbacks.
          */
diff --git a/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java b/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java
index a0e3fba..ccd7fae 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java
@@ -20,30 +20,37 @@
 import android.util.Log;
 
 /**
- * A representation of a NAN publish session. Created when
- * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback)} is
- * executed. The object can be used to stop and re-start (re-configure) the
- * publish session.
+ * A class representing a NAN publish session. Created when
+ * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback)} is called and a
+ * discovery session is created and returned in
+ * {@link WifiNanSessionCallback#onPublishStarted(WifiNanPublishSession)}. See baseline
+ * functionality of all discovery sessions in {@link WifiNanSession}. This object allows updating
+ * an existing/running publish discovery session using {@link #updatePublish(PublishConfig)}.
  *
  * @hide PROPOSED_NAN_API
  */
 public class WifiNanPublishSession extends WifiNanSession {
     private static final String TAG = "WifiNanPublishSession";
 
-    /**
-     * {@hide}
-     */
+    /** @hide */
     public WifiNanPublishSession(WifiNanManager manager, int sessionId) {
         super(manager, sessionId);
     }
 
     /**
-     * Re-configure the publish session. Note that the
+     * Re-configure the currently active publish session. The
      * {@link WifiNanSessionCallback} is not replaced - the same listener used
-     * at creation is still used.
+     * at creation is still used. The results of the configuration are returned using
+     * {@link WifiNanSessionCallback}:
+     * <ul>
+     *     <li>{@link WifiNanSessionCallback#onSessionConfigSuccess()}: configuration update
+     *     succeeded.
+     *     <li>{@link WifiNanSessionCallback#onSessionConfigFail(int)}: configuration update
+     *     failed. The publish discovery session is still running using its previous
+     *     configuration (i.e. update failure does not terminate the session).
+     * </ul>
      *
-     * @param publishConfig The configuration ({@link PublishConfig}) of the
-     *            publish session.
+     * @param publishConfig The new discovery publish session configuration ({@link PublishConfig}).
      */
     public void updatePublish(@NonNull PublishConfig publishConfig) {
         if (mTerminated) {
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanSession.java
index c10cd52..005ca29 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSession.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSession.java
@@ -21,12 +21,23 @@
 import android.net.wifi.RttManager;
 import android.util.Log;
 
+import dalvik.system.CloseGuard;
+
 import java.lang.ref.WeakReference;
 
 /**
- * A representation of a single publish or subscribe NAN session. This object
+ * A class representing a single publish or subscribe NAN session. This object
  * will not be created directly - only its child classes are available:
- * {@link WifiNanPublishSession} and {@link WifiNanSubscribeSession}.
+ * {@link WifiNanPublishSession} and {@link WifiNanSubscribeSession}. This class provides
+ * functionality common to both publish and subscribe discovery sessions:
+ * <ul>
+ *     <li>Sending messages: {@link #sendMessage(int, byte[], int)} or
+ *     {@link #sendMessage(int, byte[], int, int)} methods.
+ *     <li>Creating a network-specifier when requesting a NAN connection:
+ *     {@link #createNetworkSpecifier(int, int, byte[])}.
+ * </ul>
+ * The {@link #terminate()} method must be called to terminate discovery sessions once they are
+ * no longer needed.
  *
  * @hide PROPOSED_NAN_API
  */
@@ -35,38 +46,47 @@
     private static final boolean DBG = false;
     private static final boolean VDBG = false; // STOPSHIP if true
 
-    public static final int MAX_SEND_RETRY_COUNT = 5;
+    private static final int MAX_SEND_RETRY_COUNT = 5;
 
-    /**
-     * @hide
-     */
+    /** @hide */
     protected WeakReference<WifiNanManager> mMgr;
-
-    /**
-     * @hide
-     */
+    /** @hide */
     protected final int mSessionId;
-
-    /**
-     * @hide
-     */
+    /** @hide */
     protected boolean mTerminated = false;
 
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+
     /**
-     * {@hide}
+     * Return the maximum permitted retry count when sending messages using
+     * {@link #sendMessage(int, byte[], int, int)}.
+     *
+     * @return Maximum retry count when sending messages.
      */
+    public static int getMaxSendRetryCount() {
+        return MAX_SEND_RETRY_COUNT;
+    }
+
+    /** @hide */
     public WifiNanSession(WifiNanManager manager, int sessionId) {
         if (VDBG) Log.v(TAG, "New client created: manager=" + manager + ", sessionId=" + sessionId);
 
         mMgr = new WeakReference<>(manager);
         mSessionId = sessionId;
+
+        mCloseGuard.open("terminate");
     }
 
     /**
-     * Terminate the current publish or subscribe session - i.e. stop
-     * transmitting packet on-air (for an active session) or listening for
+     * Terminate the publish or subscribe session - free any resources, and stop
+     * transmitting packets on-air (for an active session) or listening for
      * matches (for a passive session). The session may not be used for any
-     * additional operations are termination.
+     * additional operations after termination.
+     * <p>
+     *     This operation must be done on a session which is no longer needed. Otherwise system
+     *     resources will continue to be utilized until the application terminates. The only
+     *     exception is a session for which we received a termination callback,
+     *     {@link WifiNanSessionCallback#onSessionTerminated(int)}.
      */
     public void terminate() {
         WifiNanManager mgr = mMgr.get();
@@ -77,6 +97,7 @@
         mgr.terminateSession(mSessionId);
         mTerminated = true;
         mMgr.clear();
+        mCloseGuard.close();
     }
 
     /**
@@ -92,34 +113,48 @@
         }
         mTerminated = true;
         mMgr.clear();
+        mCloseGuard.close();
     }
 
+    /** @hide */
     @Override
     protected void finalize() throws Throwable {
-        if (!mTerminated) {
-            Log.w(TAG, "WifiNanSession mSessionId=" + mSessionId
-                    + " was not explicitly terminated. The session may use resources until "
-                    + "terminated so step should be done explicitly");
-            terminate();
+        try {
+            if (!mTerminated) {
+                mCloseGuard.warnIfOpen();
+                terminate();
+            }
+        } finally {
+            super.finalize();
         }
-        super.finalize();
     }
 
     /**
-     * Sends a message to the specified destination. Message transmission is part of the current
-     * discovery session - i.e. executed subsequent to a publish/subscribe
+     * Sends a message to the specified destination. NAN messages are transmitted in the context
+     * of a discovery session - executed subsequent to a publish/subscribe
      * {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])} event.
+     * <p>
+     *     NAN messages are not guaranteed delivery. Callbacks on {@link WifiNanSessionCallback}
+     *     indicate message was transmitted successfully,
+     *     {@link WifiNanSessionCallback#onMessageSendSuccess(int)}, or transmission failed
+     *     (possibly after several retries) -
+     *     {@link WifiNanSessionCallback#onMessageSendFail(int, int)}.
+     * <p>
+     *     The peer will get a callback indicating a message was received using
+     *     {@link WifiNanSessionCallback#onMessageReceived(int, byte[])}.
      *
      * @param peerId The peer's ID for the message. Must be a result of an
-     *            {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])} event.
+     *            {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])} or
+     *            {@link WifiNanSessionCallback#onMessageReceived(int, byte[])} events.
      * @param message The message to be transmitted.
      * @param messageId An arbitrary integer used by the caller to identify the message. The same
-     *            integer ID will be returned in the callbacks indicated message send success or
-     *            failure.
+     *            integer ID will be returned in the callbacks indicating message send success or
+     *            failure. The {@code messageId} is not used internally by the NAN service - it
+     *                  can be arbitrary and non-unique.
      * @param retryCount An integer specifying how many additional service-level (as opposed to PHY
      *            or MAC level) retries should be attempted if there is no ACK from the receiver
      *            (note: no retransmissions are attempted in other failure cases). A value of 0
-     *            indicates no retries. Max possible value is {@link #MAX_SEND_RETRY_COUNT}.
+     *            indicates no retries. Max permitted value is {@link #getMaxSendRetryCount()}.
      */
     public void sendMessage(int peerId, @Nullable byte[] message, int messageId, int retryCount) {
         if (mTerminated) {
@@ -137,18 +172,29 @@
     }
 
     /**
-     * Sends a message to the specified destination. Message transmission is part of the current
-     * discovery session - i.e. executed subsequent to a publish/subscribe
-     * {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])} event. This is
-     * equivalent to {@link #sendMessage(int, byte[], int, int)} with a {@code retryCount} of
+     * Sends a message to the specified destination. NAN messages are transmitted in the context
+     * of a discovery session - executed subsequent to a publish/subscribe
+     * {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])} event.
+     * <p>
+     *     NAN messages are not guaranteed delivery. Callbacks on {@link WifiNanSessionCallback}
+     *     indicate message was transmitted successfully,
+     *     {@link WifiNanSessionCallback#onMessageSendSuccess(int)}, or transmission failed
+     *     (possibly after several retries) -
+     *     {@link WifiNanSessionCallback#onMessageSendFail(int, int)}.
+     * <p>
+     *     The peer will get a callback indicating a message was received using
+     *     {@link WifiNanSessionCallback#onMessageReceived(int, byte[])}.
+     * Equivalent to {@link #sendMessage(int, byte[], int, int)} with a {@code retryCount} of
      * 0.
      *
      * @param peerId The peer's ID for the message. Must be a result of an
-     *            {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])} event.
+     *            {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])} or
+     *            {@link WifiNanSessionCallback#onMessageReceived(int, byte[])} events.
      * @param message The message to be transmitted.
      * @param messageId An arbitrary integer used by the caller to identify the message. The same
-     *            integer ID will be returned in the callbacks indicated message send success or
-     *            failure.
+     *            integer ID will be returned in the callbacks indicating message send success or
+     *            failure. The {@code messageId} is not used internally by the NAN service - it
+     *                  can be arbitrary and non-unique.
      */
     public void sendMessage(int peerId, @Nullable byte[] message, int messageId) {
         sendMessage(peerId, message, messageId, 0);
@@ -157,7 +203,7 @@
     /**
      * Start a ranging operation with the specified peers. The peer IDs are obtained from an
      * {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])} or
-     * {@link WifiNanSessionCallback#onMessageReceived(int, byte[])} operation - i.e. can only
+     * {@link WifiNanSessionCallback#onMessageReceived(int, byte[])} operation - can only
      * range devices which are part of an ongoing discovery session.
      *
      * @param params   RTT parameters - each corresponding to a specific peer ID (the array sizes
@@ -183,25 +229,37 @@
     }
 
     /**
-     * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)}  for a
-     * WiFi NAN data-path connection to the specified peer. The peer ID is in the context of a
-     * previous match or received message in this session.
+     * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for a
+     * WiFi NAN connection to the specified peer. The
+     * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
+     * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_NAN}.
+     * <p>
+     * This method should be used when setting up a connection with a peer discovered through NAN
+     * discovery or communication (in such scenarios the MAC address of the peer is shielded by
+     * an opaque peer ID handle). If a NAN connection is needed to a peer discovered using other
+     * OOB (out-of-band) mechanism then use the alternative
+     * {@link WifiNanManager#createNetworkSpecifier(int, byte[], byte[])} method - which uses the
+     * peer's MAC address.
      *
      * @param role The role of this device:
      * {@link WifiNanManager#WIFI_NAN_DATA_PATH_ROLE_INITIATOR} or
      * {@link WifiNanManager#WIFI_NAN_DATA_PATH_ROLE_RESPONDER}
      * @param peerId The peer ID obtained through
      * {@link WifiNanSessionCallback#onMatch(int, byte[], byte[])} or
-     * {@link WifiNanSessionCallback#onMessageReceived(int, byte[])}. On the RESPONDER a
-     *               value of 0 is permitted which matches any peer.
-     * @param token An arbitrary token (message) to be passed to the peer as part of the
-     *              data-path setup process. On the RESPONDER a null token is permitted and
-     *              matches any peer token - an empty token requires the peer token to be empty
-     *              as well.
+     * {@link WifiNanSessionCallback#onMessageReceived(int, byte[])}. On a RESPONDER this
+     *              value is used to gate the acceptance of a connection request from only that
+     *              peer. A RESPONDER may specified a 0 - indicating that it will accept
+     *              connection requests from any device.
+     * @param token An arbitrary token (message) to be used to match connection initiation request
+     *              to a responder setup. A RESPONDER is set up with a {@code token} which must
+     *              be matched by the token provided by the INITIATOR. A null token is permitted
+     *              on the RESPONDER and matches any peer token. An empty ({@code ""}) token is
+     *              not the same as a null token and requires the peer token to be empty as well.
+     *
      * @return A string to be used to construct
-     * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to {@link
-     * android.net.ConnectivityManager#requestNetwork(NetworkRequest,
-     * ConnectivityManager.NetworkCallback)} [or other varieties of that API].
+     * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
+     * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,android.net.ConnectivityManager.NetworkCallback)}
+     * [or other varieties of that API].
      */
     public String createNetworkSpecifier(@WifiNanManager.DataPathRole int role, int peerId,
             @Nullable byte[] token) {
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java b/wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java
index f2337dd..8433b99 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java
@@ -24,17 +24,17 @@
 
 /**
  * Base class for NAN session events callbacks. Should be extended by
- * applications wanting notifications. The callbacks are registered when a
+ * applications wanting notifications. The callbacks are set when a
  * publish or subscribe session is created using
  * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback)} or
  * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionCallback)} .
- * These are callbacks applying to a specific NAN session.
  * <p>
- * A single callback is registered at session creation - it cannot be replaced.
+ * A single callback is set at session creation - it cannot be replaced.
  *
  * @hide PROPOSED_NAN_API
  */
 public class WifiNanSessionCallback {
+    /** @hide */
     @IntDef({
             REASON_NO_RESOURCES, REASON_INVALID_ARGS, REASON_NO_MATCH_SESSION,
             REASON_TX_FAIL, REASON_OTHER })
@@ -42,6 +42,7 @@
     public @interface SessionReasonCodes {
     }
 
+    /** @hide */
     @IntDef({
             TERMINATE_REASON_DONE, TERMINATE_REASON_FAIL })
     @Retention(RetentionPolicy.SOURCE)
@@ -49,58 +50,57 @@
     }
 
     /**
-     * Failure reason flag for {@link WifiNanSessionCallback} callbacks.
      * Indicates no resources to execute the requested operation.
+     * Failure reason flag for {@link WifiNanSessionCallback} callbacks.
      */
     public static final int REASON_NO_RESOURCES = 0;
 
     /**
-     * Failure reason flag for {@link WifiNanSessionCallback} callbacks.
      * Indicates invalid argument in the requested operation.
+     * Failure reason flag for {@link WifiNanSessionCallback} callbacks.
      */
     public static final int REASON_INVALID_ARGS = 1;
 
     /**
+     * Indicates a message is transmitted without a match (a discovery) or received message
+     * from peer occurring first.
      * Failure reason flag for {@link WifiNanSessionCallback} callbacks.
-     * Indicates a message is transmitted without a match (i.e. a discovery)
-     * occurring first.
      */
     public static final int REASON_NO_MATCH_SESSION = 2;
 
     /**
-     * Failure reason flag for
-     * {@link WifiNanSessionCallback#onMessageSendFail(int, int)} callback.
      * Indicates transmission failure: this may be due to local transmission
-     * failure or to no ACK received - i.e. remote device didn't receive the
-     * sent message.
+     * failure or to no ACK received - remote device didn't receive the
+     * sent message. Failure reason flag for
+     * {@link WifiNanSessionCallback#onMessageSendFail(int, int)} callback.
      */
     public static final int REASON_TX_FAIL = 3;
 
     /**
-     * Failure reason flag for {@link WifiNanSessionCallback} callbacks.
      * Indicates an unspecified error occurred during the operation.
+     * Failure reason flag for {@link WifiNanSessionCallback} callbacks.
      */
     public static final int REASON_OTHER = 4;
 
     /**
-     * Failure reason flag for
-     * {@link WifiNanSessionCallback#onSessionTerminated(int)} callback.
-     * Indicates that publish or subscribe session is done - i.e. all the
+     * Indicates that publish or subscribe session is done - all the
      * requested operations (per {@link PublishConfig} or
-     * {@link SubscribeConfig}) have been executed.
+     * {@link SubscribeConfig}) have been executed. Failure reason flag for
+     * {@link WifiNanSessionCallback#onSessionTerminated(int)} callback.
      */
     public static final int TERMINATE_REASON_DONE = 100;
 
     /**
-     * Failure reason flag for
-     * {@link WifiNanSessionCallback#onSessionTerminated(int)} callback.
      * Indicates that publish or subscribe session is terminated due to a
      * failure.
+     * Failure reason flag for
+     * {@link WifiNanSessionCallback#onSessionTerminated(int)} callback.
      */
     public static final int TERMINATE_REASON_FAIL = 101;
 
     /**
-     * Called when a publish operation is started successfully.
+     * Called when a publish operation is started successfully in response to a
+     * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback)} operation.
      *
      * @param session The {@link WifiNanPublishSession} used to control the
      *            discovery session.
@@ -110,7 +110,8 @@
     }
 
     /**
-     * Called when a subscribe operation is started successfully.
+     * Called when a subscribe operation is started successfully in response to a
+     * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionCallback)} operation.
      *
      * @param session The {@link WifiNanSubscribeSession} used to control the
      *            discovery session.
@@ -120,16 +121,24 @@
     }
 
     /**
-     * Called when a session update configuration (publish or subscribe update)
-     * succeeds.
+     * Called when a publish or subscribe discovery session configuration is update request
+     * succeeds. Called in response to {@link WifiNanPublishSession#updatePublish(PublishConfig)}
+     * or {@link WifiNanSubscribeSession#updateSubscribe(SubscribeConfig)}.
      */
     public void onSessionConfigSuccess() {
         /* empty */
     }
 
     /**
-     * Called when a session configuration (publish or subscribe setup or
-     * update) fails.
+     * Called when a publish or subscribe discovery session cannot be created:
+     * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback)} or
+     * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionCallback)},
+     * or when a configuration update fails:
+     * {@link WifiNanPublishSession#updatePublish(PublishConfig)} or
+     * {@link WifiNanSubscribeSession#updateSubscribe(SubscribeConfig)}.
+     * <p>
+     *     For discovery session updates failure leaves the session running with its previous
+     *     configuration - the discovery session is not terminated.
      *
      * @param reason The failure reason using
      *            {@code WifiNanSessionCallback.REASON_*} codes.
@@ -139,7 +148,10 @@
     }
 
     /**
-     * Called when a session (publish or subscribe) terminates.
+     * Called when a discovery session (publish or subscribe) terminates. Termination may be due
+     * to user-request (either directly through {@link WifiNanSession#terminate()} or
+     * application-specified expiration, e.g. {@link PublishConfig.Builder#setPublishCount(int)}
+     * or {@link SubscribeConfig.Builder#setTtlSec(int)}) or due to a failure.
      *
      * @param reason The termination reason using
      *            {@code WifiNanSessionCallback.TERMINATE_*} codes.
@@ -150,12 +162,12 @@
 
     /**
      * Called when a discovery (publish or subscribe) operation results in a
-     * match - i.e. when a peer is discovered.
+     * match - when a peer is discovered.
      *
      * @param peerId The ID of the peer matching our discovery operation.
      * @param serviceSpecificInfo The service specific information (arbitrary
      *            byte array) provided by the peer as part of its discovery
-     *            packet.
+     *            configuration.
      * @param matchFilter The filter (Tx on advertiser and Rx on listener) which
      *            resulted in this match.
      */
@@ -164,29 +176,31 @@
     }
 
     /**
-     * Called when a message is transmitted successfully - i.e. when we know
-     * that it was received successfully (corresponding to an ACK being
-     * received).
+     * Called in response to {@link WifiNanSession#sendMessage(int, byte[], int)} when a message
+     * is transmitted successfully - when it was received successfully by the peer
+     * (corresponds to an ACK being received).
      * <p>
      * Note that either this callback or
      * {@link WifiNanSessionCallback#onMessageSendFail(int, int)} will be
      * received - never both.
+     *
+     * @param messageId The arbitrary message ID specified when sending the message.
      */
     public void onMessageSendSuccess(@SuppressWarnings("unused") int messageId) {
         /* empty */
     }
 
     /**
-     * Called when a message transmission fails - i.e. when no ACK is received.
-     * The hardware will usually attempt to re-transmit several times - this
-     * event is received after all retries are exhausted. There is a possibility
-     * that message was received by the destination successfully but the ACK was
-     * lost
+     * Called when message transmission fails - when no ACK is received from the peer.
+     * Retries when ACKs are not received are done by hardware, MAC, and in the NAN stack (using
+     * the {@link WifiNanSession#sendMessage(int, byte[], int, int)} method) - this
+     * event is received after all retries are exhausted.
      * <p>
      * Note that either this callback or
      * {@link WifiNanSessionCallback#onMessageSendSuccess(int)} will be received
-     * - never both
+     * - never both.
      *
+     * @param messageId The arbitrary message ID specified when sending the message.
      * @param reason The failure reason using
      *            {@code WifiNanSessionCallback.REASON_*} codes.
      */
@@ -196,7 +210,9 @@
     }
 
     /**
-     * Called when a message is received from a discovery session peer.
+     * Called when a message is received from a discovery session peer - in response to the
+     * peer's {@link WifiNanSession#sendMessage(int, byte[], int)} or
+     * {@link WifiNanSession#sendMessage(int, byte[], int, int)}.
      *
      * @param peerId The ID of the peer sending the message.
      * @param message A byte array containing the message.
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java b/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java
index 2e6d769..d0e56c5 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java
@@ -20,10 +20,12 @@
 import android.util.Log;
 
 /**
- * A representation of a NAN subscribe session. Created when
- * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionCallback)} is
- * executed. The object can be used to stop and re-start (re-configure) the
- * subscribe session.
+ * A class representing a NAN subscribe session. Created when
+ * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionCallback)} is called and a
+ * discovery session is created and returned in
+ * {@link WifiNanSessionCallback#onSubscribeStarted(WifiNanSubscribeSession)}. See baseline
+ * functionality of all discovery sessions in {@link WifiNanSession}. This object allows updating
+ * an existing/running subscribe discovery session using {@link #updateSubscribe(SubscribeConfig)}.
  *
  * @hide PROPOSED_NAN_API
  */
@@ -38,12 +40,20 @@
     }
 
     /**
-     * Re-configure the subscribe session. Note that the
+     * Re-configure the currently active subscribe session. The
      * {@link WifiNanSessionCallback} is not replaced - the same listener used
-     * at creation is still used.
+     * at creation is still used. The results of the configuration are returned using
+     * {@link WifiNanSessionCallback}:
+     * <ul>
+     *     <li>{@link WifiNanSessionCallback#onSessionConfigSuccess()}: configuration update
+     *     succeeded.
+     *     <li>{@link WifiNanSessionCallback#onSessionConfigFail(int)}: configuration update
+     *     failed. The subscribe discovery session is still running using its previous
+     *     configuration (i.e. update failure does not terminate the session).
+     * </ul>
      *
-     * @param subscribeConfig The configuration ({@link SubscribeConfig}) of the
-     *            subscribe session.
+     * @param subscribeConfig The new discovery subscribe session configuration
+     *                        ({@link SubscribeConfig}).
      */
     public void updateSubscribe(@NonNull SubscribeConfig subscribeConfig) {
         if (mTerminated) {
diff --git a/wifi/java/android/net/wifi/nan/package.html b/wifi/java/android/net/wifi/nan/package.html
new file mode 100644
index 0000000..ae3cf6c
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/package.html
@@ -0,0 +1,43 @@
+<HTML>
+<BODY>
+<p>Provides classes which allow applications to use Wi-Fi NAN to discover peers and create
+    connections to them.</p>
+<p>Using the Wi-Fi NAN APIs, applications can advertise services, discover peers which are
+    advertising services, and connect to them.
+    Wi-Fi NAN is independent of Wi-Fi infrastructure (i.e. a device may or may
+    not be associated with an AP concurrent to using Wi-Fi NAN). </p>
+<p>The primary entry point to Wi-Fi NAN capabilities is the
+    {@link android.net.wifi.nan.WifiNanManager} class, which is acquired by calling
+    {@link android.content.Context#getSystemService(String)
+    Context.getSystemService(Context.WIFI_NAN_SERVICE)}</p>
+
+<p>Some APIs may require the following user permissions:</p>
+<ul>
+    <li>{@link android.Manifest.permission#ACCESS_WIFI_STATE}</li>
+    <li>{@link android.Manifest.permission#CHANGE_WIFI_STATE}</li>
+    <li>{@link android.Manifest.permission#ACCESS_COARSE_LOCATION}</li>
+</ul>
+
+<p class="note"><strong>Note:</strong> Not all Android-powered devices support Wi-Fi NAN
+    functionality.
+    If your application only works with Wi-Fi NAN (i.e. it should only be installed on devices which
+    support Wi-Fi NAN), declare so with a <a
+            href="{@docRoot}guide/topics/manifest/uses-feature-element.html">
+        {@code &lt;uses-feature&gt;}</a>
+    element in the manifest file:</p>
+<pre>
+&lt;manifest ...>
+    &lt;uses-feature android:name="android.hardware.wifi.nan" />
+    ...
+&lt;/manifest>
+</pre>
+<p>Alternatively, if you application does not require Wi-Fi NAN but can take advantage of it if
+    available, you can perform
+    the check at run-time in your code using {@link
+    android.content.pm.PackageManager#hasSystemFeature(String)} with {@link
+    android.content.pm.PackageManager#FEATURE_WIFI_NAN}:</p>
+<pre>
+    getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_NAN)
+</pre>
+</BODY>
+</HTML>